Overrides als Satelliten-Fenster vom Oberleiste-Gear öffnen

OVERRIDES war als gedocktes Panel zu schmal. Jetzt: kein Panel mehr,
sondern ein echtes Rhino-Fenster (Eto.Form + WebView, frei verschieb-
und resizable), das vom Oberleiste-Gear-Button geoeffnet wird.

panel_base.open_satellite_window:
- Akzeptiert jetzt optional einen `bridge`-Parameter. Wenn gegeben,
  wird die Custom-Bridge (z.B. OverridesBridge) statt der einfachen
  inline SAVE/CANCEL-Bridge benutzt. So koennen vollwertige Panels
  (mit bidirektionalem Mess-Verkehr) als Satellite-Fenster laufen.

overrides_panel.py:
- register_and_open entfaellt — Overrides wird nicht mehr als Panel
  registriert.
- Neue Funktion open_as_window(): erstellt OverridesBridge, registriert
  sie in sticky["overrides_bridge"] und oeffnet als Satellite-Window.
  Listener werden lazy beim ersten Aufruf installiert
  (_ensure_listeners_once).

oberleiste.py:
- OPEN_OVERRIDES_PANEL ruft jetzt overrides_panel.open_as_window()
  statt RhinoUI.Panels.OpenPanel().

OberleisteApp.jsx:
- Settings-Gear (ToolButton mit icon="settings") nach dem Preset-
  Dropdown im Overrides-Bereich. Click ruft openOverridesPanel() →
  oeffnet das Satelliten-Fenster.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 01:39:07 +02:00
parent b1b2090b3e
commit 42d9c1e27b
4 changed files with 72 additions and 45 deletions
+34 -32
View File
@@ -281,16 +281,20 @@ def attach_webview(panel, bridge, mode):
# --- Satelliten-Fenster (echtes Rhino-Fenster mit eingebetteter WebView) ----
def open_satellite_window(mode, params=None, title=None, size=(420, 560),
on_save=None, on_cancel=None):
on_save=None, on_cancel=None, bridge=None):
"""Oeffnet ein echtes Rhino-Fenster (Eto.Form) mit eingebetteter WebView.
Die WebView laedt die React-App mit dem gegebenen `mode` und `params`.
Die React-App sendet via Bridge `SAVE`/`CANCEL`-Messages. Wir rufen
dann die jeweilige Callback-Funktion auf (mit dem Save-Payload) und
schliessen das Fenster.
Zwei Bridge-Modi:
- **Default (kein `bridge`-Arg):** inline SAVE/CANCEL-Bridge. React
sendet SAVE/CANCEL → on_save/on_cancel-Callback → Fenster zu. Fuer
einfache One-Shot-Dialoge (Settings etc.).
- **`bridge` uebergeben:** eine vollwertige BaseBridge-Subklasse (z.B.
OverridesBridge). Das Fenster nutzt die wie ein normales Panel,
mit allen Mess-Typen die der Bridge handlet. Save/Cancel sind dort
nicht standard; Fenster bleibt offen bis User es manuell schliesst.
Returns die Form-Instance (User kann sie speichern um sie spaeter
programmatisch zu schliessen)."""
Returns die Form-Instance."""
form = forms.Form()
if title is None: title = mode.replace('_', ' ').title()
@@ -303,33 +307,31 @@ def open_satellite_window(mode, params=None, title=None, size=(420, 560),
wv = forms.WebView()
# Inline-Bridge fuer Satelliten-Fenster: handle SAVE/CANCEL, schliesse
# bei beiden das Fenster.
class _SatelliteBridge(BaseBridge):
def __init__(self):
BaseBridge.__init__(self, mode)
def handle(self, data):
t = data.get("type", "")
p = data.get("payload") or {}
if t == "READY":
# React liest PANEL_PARAMS direkt vom window-Object — wir
# muessen also nichts mehr aktiv senden.
pass
elif t == "SAVE":
if on_save is not None:
try: on_save(p)
except Exception as ex:
print("[{}] on_save: {}".format(mode.upper(), ex))
try: form.Close()
except Exception: pass
elif t == "CANCEL":
if on_cancel is not None:
try: on_cancel()
if bridge is None:
# Inline-Bridge fuer einfache Settings-Dialoge: SAVE/CANCEL, schliesse
# bei beiden das Fenster.
class _SatelliteBridge(BaseBridge):
def __init__(self):
BaseBridge.__init__(self, mode)
def handle(self, data):
t = data.get("type", "")
p = data.get("payload") or {}
if t == "READY":
pass
elif t == "SAVE":
if on_save is not None:
try: on_save(p)
except Exception as ex:
print("[{}] on_save: {}".format(mode.upper(), ex))
try: form.Close()
except Exception: pass
try: form.Close()
except Exception: pass
bridge = _SatelliteBridge()
elif t == "CANCEL":
if on_cancel is not None:
try: on_cancel()
except Exception: pass
try: form.Close()
except Exception: pass
bridge = _SatelliteBridge()
bridge.set_webview(wv)
def on_title_(s, e):