Renderer-Umschalter in die Settings; Nordstern als Default
Der WebGL2<->Nordstern-Umschalter wandert aus der Statusleiste in den Settings-Dialog. Default ist jetzt Nordstern (WASM), sofern WebGPU verfuegbar ist; WebGL2 nur noch als expliziter Fallback. So sieht man nicht mehr versehentlich die Darstellungsfehler des WebGL2-Viewers. styles.css: .sb-renderer-toggle align-self:flex-start, damit das Pill im Settings-Dialog nicht auf volle Breite zieht.
This commit is contained in:
+10
-7
@@ -2534,15 +2534,18 @@ export default function App() {
|
|||||||
// Persistiert in localStorage, damit die Wahl einen Neustart ohne URL-Param
|
// Persistiert in localStorage, damit die Wahl einen Neustart ohne URL-Param
|
||||||
// übersteht (z.B. die Electron-App startet immer auf der Basis-URL).
|
// übersteht (z.B. die Electron-App startet immer auf der Basis-URL).
|
||||||
const RENDERER_STORAGE_KEY = "cad.rendererMode";
|
const RENDERER_STORAGE_KEY = "cad.rendererMode";
|
||||||
|
const webGpuAvailable = typeof navigator !== "undefined" && "gpu" in navigator;
|
||||||
const rendererMode: RendererMode = (() => {
|
const rendererMode: RendererMode = (() => {
|
||||||
const fromUrl = new URLSearchParams(window.location.search).get("engine");
|
const fromUrl = new URLSearchParams(window.location.search).get("engine");
|
||||||
if (fromUrl === "wasm") return "wasm";
|
if (fromUrl === "wasm") return "wasm";
|
||||||
if (fromUrl === "webgl2") return "webgl2";
|
if (fromUrl === "webgl2") return "webgl2";
|
||||||
return window.localStorage.getItem(RENDERER_STORAGE_KEY) === "wasm"
|
const fromStorage = window.localStorage.getItem(RENDERER_STORAGE_KEY);
|
||||||
? "wasm"
|
if (fromStorage === "webgl2") return "webgl2";
|
||||||
: "webgl2";
|
if (fromStorage === "wasm") return "wasm";
|
||||||
|
// Keine explizite Wahl (weder URL noch localStorage) — Nordstern (WASM)
|
||||||
|
// ist Standard, sofern WebGPU verfügbar ist; sonst WebGL2 als Fallback.
|
||||||
|
return webGpuAvailable ? "wasm" : "webgl2";
|
||||||
})();
|
})();
|
||||||
const webGpuAvailable = typeof navigator !== "undefined" && "gpu" in navigator;
|
|
||||||
const setRendererMode = (mode: RendererMode) => {
|
const setRendererMode = (mode: RendererMode) => {
|
||||||
window.localStorage.setItem(RENDERER_STORAGE_KEY, mode);
|
window.localStorage.setItem(RENDERER_STORAGE_KEY, mode);
|
||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
@@ -3343,9 +3346,6 @@ export default function App() {
|
|||||||
referenceLinesEnabled={planActive}
|
referenceLinesEnabled={planActive}
|
||||||
activeFloor={activeLevel.name}
|
activeFloor={activeLevel.name}
|
||||||
activeLayer={activeLayerName}
|
activeLayer={activeLayerName}
|
||||||
rendererMode={rendererMode}
|
|
||||||
webGpuAvailable={webGpuAvailable}
|
|
||||||
onRendererModeChange={setRendererMode}
|
|
||||||
lineMode={lineMode}
|
lineMode={lineMode}
|
||||||
onLineModeChange={setLineMode}
|
onLineModeChange={setLineMode}
|
||||||
lineModeEnabled={planActive}
|
lineModeEnabled={planActive}
|
||||||
@@ -3411,6 +3411,9 @@ export default function App() {
|
|||||||
onSnapColorChange={setSnapColor}
|
onSnapColorChange={setSnapColor}
|
||||||
project={project}
|
project={project}
|
||||||
setProject={setProject}
|
setProject={setProject}
|
||||||
|
rendererMode={rendererMode}
|
||||||
|
webGpuAvailable={webGpuAvailable}
|
||||||
|
onRendererModeChange={setRendererMode}
|
||||||
onClose={() => setSettingsOpen(false)}
|
onClose={() => setSettingsOpen(false)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
+5
-3
@@ -816,12 +816,14 @@ body {
|
|||||||
background: var(--border);
|
background: var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Renderer-Umschalter (WebGL2 / Engine) in der Statusleiste — kleine
|
/* Renderer-Umschalter (WebGL2 / Nordstern) — kleine Segmentpille; ursprünglich
|
||||||
Segmentpille, an die 22px-Leiste angepasst (siehe .tb-seg für das größere
|
in der Statusleiste (22px-Leiste), jetzt im Einstellungs-Fenster. In einer
|
||||||
Vorbild in der Oberleiste). */
|
flex-column (.imp-section) würde sie sonst auf volle Breite gestreckt
|
||||||
|
werden (Standard-`align-items: stretch`) — bleibt daher inhaltsbreit. */
|
||||||
.sb-renderer-toggle {
|
.sb-renderer-toggle {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
|
align-self: flex-start;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { t } from "../i18n";
|
|||||||
import { ACCENT_SWATCHES } from "../theme/accents";
|
import { ACCENT_SWATCHES } from "../theme/accents";
|
||||||
import type { Project } from "../model/types";
|
import type { Project } from "../model/types";
|
||||||
import { ColorHexField } from "./ColorHexField";
|
import { ColorHexField } from "./ColorHexField";
|
||||||
|
import type { RendererMode } from "./StatusBar";
|
||||||
|
|
||||||
export interface SettingsDialogProps {
|
export interface SettingsDialogProps {
|
||||||
marqueeColor: string;
|
marqueeColor: string;
|
||||||
@@ -22,6 +23,15 @@ export interface SettingsDialogProps {
|
|||||||
onSnapColorChange: (hex: string) => void;
|
onSnapColorChange: (hex: string) => void;
|
||||||
project: Project;
|
project: Project;
|
||||||
setProject: (next: Project | ((p: Project) => Project)) => void;
|
setProject: (next: Project | ((p: Project) => Project)) => void;
|
||||||
|
/** Aktuell gewählter Plan-Renderer (aus dem `?engine`-URL-Param abgeleitet). */
|
||||||
|
rendererMode: RendererMode;
|
||||||
|
/** Ist `navigator.gpu` vorhanden? Steuert, ob „Nordstern" wählbar ist. */
|
||||||
|
webGpuAvailable: boolean;
|
||||||
|
/**
|
||||||
|
* Renderer wechseln (setzt/entfernt den `engine`-URL-Param und lädt neu — kein
|
||||||
|
* Live-Remount der Renderer-Hooks).
|
||||||
|
*/
|
||||||
|
onRendererModeChange: (mode: RendererMode) => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +42,9 @@ export function SettingsDialog({
|
|||||||
onSnapColorChange,
|
onSnapColorChange,
|
||||||
project,
|
project,
|
||||||
setProject,
|
setProject,
|
||||||
|
rendererMode,
|
||||||
|
webGpuAvailable,
|
||||||
|
onRendererModeChange,
|
||||||
onClose,
|
onClose,
|
||||||
}: SettingsDialogProps) {
|
}: SettingsDialogProps) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -85,6 +98,33 @@ export function SettingsDialog({
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div className="imp-body">
|
<div className="imp-body">
|
||||||
|
<section className="imp-section">
|
||||||
|
<div className="imp-section-title">{t("status.renderer")}</div>
|
||||||
|
<span className="sb-renderer-toggle" role="group" aria-label={t("status.renderer")}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`sb-renderer-btn${rendererMode === "webgl2" ? " active" : ""}`}
|
||||||
|
aria-pressed={rendererMode === "webgl2"}
|
||||||
|
onClick={() => onRendererModeChange("webgl2")}
|
||||||
|
>
|
||||||
|
{t("status.rendererWebgl")}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`sb-renderer-btn${rendererMode === "wasm" ? " active" : ""}`}
|
||||||
|
aria-pressed={rendererMode === "wasm"}
|
||||||
|
disabled={!webGpuAvailable}
|
||||||
|
title={webGpuAvailable ? undefined : t("status.rendererWasmUnavailable")}
|
||||||
|
onClick={() => onRendererModeChange("wasm")}
|
||||||
|
>
|
||||||
|
{t("status.rendererWasm")}
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
{!webGpuAvailable && (
|
||||||
|
<div className="imp-note">{t("status.rendererWasmUnavailable")}</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
|
||||||
<section className="imp-section">
|
<section className="imp-section">
|
||||||
<div className="imp-section-title">{t("settings.section.display")}</div>
|
<div className="imp-section-title">{t("settings.section.display")}</div>
|
||||||
<AccentColorField
|
<AccentColorField
|
||||||
|
|||||||
@@ -33,15 +33,6 @@ export interface StatusBarProps {
|
|||||||
activeFloor: string;
|
activeFloor: string;
|
||||||
/** Name der aktiven Ebene (Kategorie) oder „—". */
|
/** Name der aktiven Ebene (Kategorie) oder „—". */
|
||||||
activeLayer: string;
|
activeLayer: string;
|
||||||
/** Aktuell gewählter Plan-Renderer (aus dem `?engine`-URL-Param abgeleitet). */
|
|
||||||
rendererMode: RendererMode;
|
|
||||||
/** Ist `navigator.gpu` vorhanden? Steuert, ob „Engine" wählbar ist. */
|
|
||||||
webGpuAvailable: boolean;
|
|
||||||
/**
|
|
||||||
* Renderer wechseln (setzt/entfernt den `engine`-URL-Param und lädt neu — kein
|
|
||||||
* Live-Remount der Renderer-Hooks).
|
|
||||||
*/
|
|
||||||
onRendererModeChange: (mode: RendererMode) => void;
|
|
||||||
/** Linien-Darstellung: „display" (Haarlinien) oder „print" (echte mm-Stärken). */
|
/** Linien-Darstellung: „display" (Haarlinien) oder „print" (echte mm-Stärken). */
|
||||||
lineMode: "display" | "print";
|
lineMode: "display" | "print";
|
||||||
/** Linien-Darstellung wechseln. */
|
/** Linien-Darstellung wechseln. */
|
||||||
@@ -264,9 +255,6 @@ export function StatusBar({
|
|||||||
referenceLinesEnabled,
|
referenceLinesEnabled,
|
||||||
activeFloor,
|
activeFloor,
|
||||||
activeLayer,
|
activeLayer,
|
||||||
rendererMode,
|
|
||||||
webGpuAvailable,
|
|
||||||
onRendererModeChange,
|
|
||||||
lineMode,
|
lineMode,
|
||||||
onLineModeChange,
|
onLineModeChange,
|
||||||
lineModeEnabled,
|
lineModeEnabled,
|
||||||
@@ -309,30 +297,6 @@ export function StatusBar({
|
|||||||
{t("status.referenceLines")}
|
{t("status.referenceLines")}
|
||||||
</button>
|
</button>
|
||||||
<Sep />
|
<Sep />
|
||||||
<span className="sb-field">
|
|
||||||
<span className="sb-key">{t("status.renderer")}</span>
|
|
||||||
<span className="sb-renderer-toggle" role="group" aria-label={t("status.renderer")}>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`sb-renderer-btn${rendererMode === "webgl2" ? " active" : ""}`}
|
|
||||||
aria-pressed={rendererMode === "webgl2"}
|
|
||||||
onClick={() => onRendererModeChange("webgl2")}
|
|
||||||
>
|
|
||||||
{t("status.rendererWebgl")}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`sb-renderer-btn${rendererMode === "wasm" ? " active" : ""}`}
|
|
||||||
aria-pressed={rendererMode === "wasm"}
|
|
||||||
disabled={!webGpuAvailable}
|
|
||||||
title={webGpuAvailable ? undefined : t("status.rendererWasmUnavailable")}
|
|
||||||
onClick={() => onRendererModeChange("wasm")}
|
|
||||||
>
|
|
||||||
{t("status.rendererWasm")}
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<Sep />
|
|
||||||
<Field label={t("status.xy")} value={coords} />
|
<Field label={t("status.xy")} value={coords} />
|
||||||
<Sep />
|
<Sep />
|
||||||
<Field label={t("status.unit")} value={unit} />
|
<Field label={t("status.unit")} value={unit} />
|
||||||
|
|||||||
Reference in New Issue
Block a user