From 872832a3cc9a4a7898cb573746c89c41f29814d6 Mon Sep 17 00:00:00 2001 From: karim Date: Thu, 21 May 2026 00:13:08 +0200 Subject: [PATCH] View-Toggle: Active aus lastSetView + Stat-Box-Hoehe angeglichen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User-Feedback: 1. View-Bars sind hoeher als andere Elemente auf der Seite 2. Active-Highlight bleibt auf Top haengen — andere Views leuchten nicht 3. Glitch: Klick auf Top → Bar zeigt weiterhin Perspektive aktiv Fix 1 (Hoehe): Stat-Box Inhalts-Hoehe BAR_H*2+4 → BAR_H*2+6, der innere Trennstrich-Gap 4 → 6. Damit visual 50 → 52 = identisch mit den 2-row- Blocks (View, Preset, Massstab). Fix 2 + 3 (Active-Highlight): Backend trackt `self._last_set_view` ← gesetzt wenn handler in SET_VIEW erfolgreich war. Frontend matchView prueft zuerst `state.lastSetView === v` — kein Race-Condition zwischen ChangeProjection und Viewport-State-Lesen mehr. Fallback auf Viewport-State-Detection wenn lastSetView noch null (initial load). N/O/S/W kriegen jetzt auch Active-Highlight (vorher hartcoded false). Co-Authored-By: Claude Opus 4.7 --- rhino/oberleiste.py | 33 +++++++++++++++------------------ src/OberleisteApp.jsx | 40 ++++++++++++++++++++++------------------ 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/rhino/oberleiste.py b/rhino/oberleiste.py index bee7e91..652c15c 100644 --- a/rhino/oberleiste.py +++ b/rhino/oberleiste.py @@ -772,6 +772,7 @@ class OberleisteBridge(panel_base.BaseBridge): self._last_state_sig = None # Fingerprint des letzten Push — dedupe self._cached_overrides = None # (enabled, count) — invalidiert bei Toggle/Update self._cached_combinations = None # (names, active) — invalidiert bei jeder Comb-Aenderung + self._last_set_view = None # Letzte ueber Topbar gesetzte Ansicht (fuer Active-Highlight) # Command-Liste LAZY laden — die Enumeration durchlaeuft alle Plugins # und ist teuer (~hundert ms). Wird erst beim ersten _send_state, oder # explizit bei Command-Input-Fokus, gebaut. @@ -880,35 +881,29 @@ class OberleisteBridge(panel_base.BaseBridge): vp = kamera._active_viewport() except Exception: vp = None + handled = False if v == "Top": - # Plan rotiert mit Norden — Up-Vektor zeigt Norden try: import kamera - kamera.set_top_view(vp) - except Exception as ex: - print("[OBERLEISTE] top:", ex) - self._send_state(force=True) + kamera.set_top_view(vp); handled = True + except Exception as ex: print("[OBERLEISTE] top:", ex) elif v == "Perspective": - _run("_-{} _Enter".format(v)) - self._send_state(force=True) + _run("_-{} _Enter".format(v)); handled = True elif v == "Iso": try: import kamera - kamera._set_iso(vp, "NE") - except Exception as ex: - print("[OBERLEISTE] iso:", ex) - self._send_state(force=True) + kamera._set_iso(vp, "NE"); handled = True + except Exception as ex: print("[OBERLEISTE] iso:", ex) elif v in ("N", "O", "S", "W"): try: import kamera - kamera.set_cardinal_view(vp, v) - except Exception as ex: - print("[OBERLEISTE] cardinal:", ex) - self._send_state(force=True) + kamera.set_cardinal_view(vp, v); handled = True + except Exception as ex: print("[OBERLEISTE] cardinal:", ex) elif v in ("Front", "Right", "Left", "Back", "Bottom"): - # Legacy direkte Rhino-Views (falls noch wo benutzt) - _run("_-{} _Enter".format(v)) - self._send_state(force=True) + _run("_-{} _Enter".format(v)); handled = True + if handled: + self._last_set_view = v + self._send_state(force=True) # --- Kamera-Panel oeffnen --------------------------------------- elif t == "OPEN_KAMERA_PANEL": @@ -1203,6 +1198,8 @@ class OberleisteBridge(panel_base.BaseBridge): info["northAngle"] = kamera.get_north_angle(doc) except Exception: info["northAngle"] = 0 + # Letzte ueber Topbar gesetzte Ansicht (fuer Active-Highlight) + info["lastSetView"] = self._last_set_view # Command-Line State prompt = _get_command_prompt() info["cmdPrompt"] = prompt diff --git a/src/OberleisteApp.jsx b/src/OberleisteApp.jsx index f88ab15..fd5421d 100644 --- a/src/OberleisteApp.jsx +++ b/src/OberleisteApp.jsx @@ -315,6 +315,7 @@ export default function OberleisteApp() { textSettings: { font: 'Helvetica', size: 0.20, bold: false, italic: false }, textFonts: [], northAngle: 0, + lastSetView: null, }) const [appliedScale, setAppliedScale] = useState(null) const appliedScaleRef = useRef(null) @@ -373,11 +374,11 @@ export default function OberleisteApp() { if (appliedScale && appliedScale > 0) setMassstab(appliedScale) } - // Aktuelles View-Match. Top/Persp/Iso werden via parallel-Flag und - // viewName unterschieden. N/O/S/W: kein zuverlaessiges View-Match - // ueber den Viewport-Namen (wir setzen die Camera direkt) — daher - // kein Active-State fuer Cardinals. + // Active-Highlight aus lastSetView (vom Backend getrackt — vermeidet + // Race-Conditions zwischen ChangeProjection und Viewport-State-Lesen). + // Fallback wenn noch nie geklickt: Viewport-State raten. const matchView = (v) => { + if (state.lastSetView) return state.lastSetView === v const name = (state.viewName || '').toLowerCase() if (v === 'Top') return name === 'top' if (v === 'Perspective') return state.parallel === false @@ -508,18 +509,21 @@ export default function OberleisteApp() { border: '1px solid var(--border)', borderRadius: 999, overflow: 'hidden', flexShrink: 0, }}> - {VIEWS_ROW2.map((v, idx) => ( - - ))} + {VIEWS_ROW2.map((v, idx) => { + const isActive = matchView(v.value) + return ( + + ) + })} ) @@ -702,7 +706,7 @@ export default function OberleisteApp() {
{isPerspective ? '—' : fmtScale(scaleVal)}
-
+