diff --git a/rhino/dimensionen.py b/rhino/dimensionen.py index 9fbb009..bf6b610 100644 --- a/rhino/dimensionen.py +++ b/rhino/dimensionen.py @@ -20,7 +20,6 @@ if _HERE not in sys.path: sys.path.insert(0, _HERE) import panel_base -import mass_style PANEL_GUID_STR = "9e3c8c5d-6d4a-4f3e-b3c5-d4e5f6071a2c" @@ -343,34 +342,6 @@ class DimensionenBridge(panel_base.BaseBridge): elif t == "SET_CIRCLE_RADIUS":self._set_circle_radius(p) elif t == "SET_LINE_LENGTH": self._set_line_length(p) elif t == "SET_RECTANGLE": self._set_rectangle(p) - elif t == "MASS_STYLE_SET_ACTIVE": - mass_style.set_active_id(Rhino.RhinoDoc.ActiveDoc, p.get("id")) - self._send_state(force=True) - self._broadcast_raum_regen() - elif t == "MASS_STYLE_SAVE": - mass_style.save_preset(Rhino.RhinoDoc.ActiveDoc, p.get("preset") or {}) - self._send_state(force=True) - self._broadcast_raum_regen() - elif t == "MASS_STYLE_DELETE": - mass_style.delete_preset(Rhino.RhinoDoc.ActiveDoc, p.get("id")) - self._send_state(force=True) - self._broadcast_raum_regen() - - def _broadcast_raum_regen(self): - """Beim Preset-Wechsel: alle Raeume regen damit die Stempel-Flaechen - in der neuen Default-Rundung erscheinen. Eingehaengt in elemente.""" - try: - import elemente - doc = Rhino.RhinoDoc.ActiveDoc - if doc is None: return - for obj in doc.Objects: - try: - m = elemente._read_meta(obj) - if m and m.get("type") == "raum_outline": - elemente._queue_regen(m["id"]) - except Exception: pass - except Exception as ex: - print("[DIMENSIONEN] mass_style raum-regen:", ex) # --- State-Snapshot ----------------------------------------------------- @@ -405,8 +376,6 @@ class DimensionenBridge(panel_base.BaseBridge): "refPoint": self._ref, "coordSystem": self._coord_sys, "planeName": "CPlane" if self._coord_sys == "cplane" else "Welt", - "massStyles": mass_style.list_presets(doc), - "massStyleActive": mass_style.get_active_id(doc), } shape = _detect_shape(objs) out["shape"] = shape @@ -445,8 +414,6 @@ class DimensionenBridge(panel_base.BaseBridge): tuple(sorted((state.get("position") or {}).items())), tuple(sorted((state.get("dimensions") or {}).items())), tuple(sorted((state.get("shape") or {}).items())) if state.get("shape") else None, - state.get("massStyleActive"), - len(state.get("massStyles") or []), ) if not force and sig == self._last_sig: return diff --git a/rhino/mass_style.py b/rhino/mass_style.py index e2bf189..ba99852 100644 --- a/rhino/mass_style.py +++ b/rhino/mass_style.py @@ -186,3 +186,23 @@ def dim_dezimalstellen_default(doc): def dim_einheit_default(doc): p = get_active(doc) return p["dimEinheit"] if p else "m" + + +# --------------------------------------------------------------------------- +# Cross-Module: Raum-Stempel beim Preset-Wechsel mit-aktualisieren. + +def regen_all_rooms(doc): + """Queued ein Regen fuer ALLE raum_outline-Objekte. Aufruf bei Preset- + Wechsel/Save/Delete damit Stempel-Flaechen in der neuen Rundung neu + rendern.""" + if doc is None: return + try: + import elemente + except Exception as ex: + print("[MASS_STYLE] elemente import:", ex); return + for obj in doc.Objects: + try: + m = elemente._read_meta(obj) + if m and m.get("type") == "raum_outline": + elemente._queue_regen(m["id"]) + except Exception: pass diff --git a/rhino/masse_settings.py b/rhino/masse_settings.py new file mode 100644 index 0000000..fadcf3a --- /dev/null +++ b/rhino/masse_settings.py @@ -0,0 +1,85 @@ +#! python 3 +# -*- coding: utf-8 -*- +""" +masse_settings.py +Satellite-Fenster fuer das Bearbeiten der Masse-Presets +(rhino/mass_style.py). Vom Oberleiste-Zahnrad geoeffnet. +""" +import os +import sys +import Rhino +import scriptcontext as sc + +_HERE = os.path.dirname(os.path.abspath(__file__)) +if _HERE not in sys.path: + sys.path.insert(0, _HERE) + +import panel_base +import mass_style + + +def _payload(): + doc = Rhino.RhinoDoc.ActiveDoc + return { + "presets": mass_style.list_presets(doc), + "activeId": mass_style.get_active_id(doc), + } + + +def _notify_oberleiste(): + """Topbar nach Aenderung refreshen — die zeigt den aktiven Preset im + Dropdown an.""" + try: + b = sc.sticky.get("oberleiste_bridge") + if b is not None: + b._send_state(force=True) + except Exception as ex: + print("[MASSE_SETTINGS] notify oberleiste:", ex) + + +class MasseSettingsBridge(panel_base.BaseBridge): + def __init__(self): + panel_base.BaseBridge.__init__(self, "masse_settings") + + def _on_ready(self): + self._send_state() + + def _send_state(self): + self.send("STATE", _payload()) + + def handle(self, data): + if not isinstance(data, dict): return + t = data.get("type", "") + p = data.get("payload") or {} + if not isinstance(p, dict): p = {} + doc = Rhino.RhinoDoc.ActiveDoc + + if t == "READY" or t == "REQUEST_STATE": + self._on_ready() + elif t == "SET_ACTIVE": + mass_style.set_active_id(doc, p.get("id")) + mass_style.regen_all_rooms(doc) + self._send_state() + _notify_oberleiste() + elif t == "SAVE": + mass_style.save_preset(doc, p.get("preset") or {}) + mass_style.regen_all_rooms(doc) + self._send_state() + _notify_oberleiste() + elif t == "DELETE": + mass_style.delete_preset(doc, p.get("id")) + mass_style.regen_all_rooms(doc) + self._send_state() + _notify_oberleiste() + + +def open_as_window(): + """Oeffnet das Masse-Settings-Fenster (Eto.Form + WebView). + Vom Oberleiste-Zahnrad bei OPEN_MASSE_SETTINGS aufgerufen.""" + b = MasseSettingsBridge() + sc.sticky["masse_settings_bridge"] = b + panel_base.open_satellite_window( + "masse_settings", + title="Masse", + size=(440, 520), + bridge=b) diff --git a/rhino/oberleiste.py b/rhino/oberleiste.py index 643f5fd..4050b39 100644 --- a/rhino/oberleiste.py +++ b/rhino/oberleiste.py @@ -898,6 +898,23 @@ class OberleisteBridge(panel_base.BaseBridge): except Exception as ex: print("[OBERLEISTE] open kamera:", ex) + # --- Masse (Mass-Style) ----------------------------------------- + elif t == "SET_MASSE_ACTIVE": + try: + import mass_style + doc = Rhino.RhinoDoc.ActiveDoc + mass_style.set_active_id(doc, p.get("id")) + mass_style.regen_all_rooms(doc) + except Exception as ex: + print("[OBERLEISTE] masse active:", ex) + self._send_state(force=True) + elif t == "OPEN_MASSE_SETTINGS": + try: + import masse_settings + masse_settings.open_as_window() + except Exception as ex: + print("[OBERLEISTE] open masse:", ex) + # --- Display-Mode ----------------------------------------------- elif t == "SET_DISPLAY_MODE": n = p.get("name") @@ -1119,6 +1136,14 @@ class OberleisteBridge(panel_base.BaseBridge): _names_tuple, _active_comb = self._cached_combinations info["layerCombinations"] = list(_names_tuple) info["layerCombinationActive"] = _active_comb + # Masse (Mass-Style Presets) — Liste fuer Topbar-Dropdown + aktive ID + try: + import mass_style + info["massePresets"] = mass_style.list_presets(doc) + info["masseActiveId"] = mass_style.get_active_id(doc) + except Exception: + info["massePresets"] = [] + info["masseActiveId"] = None # Command-Line State prompt = _get_command_prompt() info["cmdPrompt"] = prompt @@ -1147,6 +1172,8 @@ class OberleisteBridge(panel_base.BaseBridge): info.get("overridesActivePreset"), tuple(info.get("overridesPresets") or ()), _names_tuple, _active_comb, + info.get("masseActiveId"), + tuple((p.get("id"), p.get("name")) for p in (info.get("massePresets") or [])), prompt, ) if not force and sig == self._last_state_sig: diff --git a/src/DimensionenApp.jsx b/src/DimensionenApp.jsx index 465f5e3..f4e9290 100644 --- a/src/DimensionenApp.jsx +++ b/src/DimensionenApp.jsx @@ -5,7 +5,6 @@ import { setRefPoint, setCoordSystem, setDimPosition, setDimDimension, setDimRotationZ, setCircleRadius, setLineLength, setRectangleDims, - setMassStyleActive, saveMassStyle, deleteMassStyle, } from './lib/rhinoBridge' // ---- Helpers -------------------------------------------------------------- @@ -141,149 +140,6 @@ function Field({ label, children, style }) { ) } -// ---- Mass-Style Section --------------------------------------------------- -// Globaler Preset-Picker fuer Raum-Rundung + Mass-Linien-Dezimalstellen. -// Hostet hier weil das thematisch zu Dimensionen passt, der Preset wird aber -// dokument-weit angewendet (Raum-Stempel lesen ihn auch). - -const RAUM_RUNDUNGS_LABELS = { - 'exakt': 'Exakt (2 Nachk.)', - '0.01': 'auf 0.01 m²', - '0.1': 'auf 0.1 m²', - '0.5': 'auf 0.5 m²', - '1': 'auf 1 m²', -} - -function MassStyleSection({ massStyles, activeId }) { - const styles = Array.isArray(massStyles) ? massStyles : [] - const active = styles.find(p => p.id === activeId) || styles[0] - const update = (patch) => { - if (!active) return - saveMassStyle({ ...active, ...patch }) - } - const addNew = () => { - const name = (window.prompt('Name für neuen Mass-Style:') || '').trim() - if (!name) return - // Aktuelle Werte als Vorlage uebernehmen (oder Defaults) - const tmpl = active || { raumRundung: '0.1', dimDezimalstellen: 2, dimEinheit: 'm' } - saveMassStyle({ - name, - raumRundung: tmpl.raumRundung, - dimDezimalstellen: tmpl.dimDezimalstellen, - dimEinheit: tmpl.dimEinheit, - }) - } - const remove = () => { - if (!active) return - if (styles.length <= 1) { - window.alert('Mindestens ein Mass-Style muss erhalten bleiben.') - return - } - if (!window.confirm(`Mass-Style "${active.name}" löschen?`)) return - deleteMassStyle(active.id) - } - return ( -