Wand-Grips + Schnitt-Grips + Referenz-Sublayer pro Bauteil + Print-Auto-Hide

Custom-Grip-Overlays via DisplayConduit + MouseCallback:
- wand_grips.py: dicke klickbare Marker an wand_axis-Endpunkten, auch
  wenn die Referenz-Layer ausgeblendet ist. GetPoint mit fixem Anker.
- schnitt_grips.py: 3 Marker pro Schnitt (P1, P2, Mid). Mid translatiert
  ganze Linie, P1/P2 verschieben Endpunkt. Hide Clipping-Planes waehrend
  GetPoint damit kein Verbots-Cursor durch Locked-Edges erscheint.
  skip_view=True bei Re-Activate damit Drag nicht in Section springt.

Referenz-Architektur umgebaut:
- wand_axis + oeffnung_point liegen jetzt unter <Geschoss>::20_Waende::
  20r_Referenz statt eigener top-level 19_Referenzlinien-Ebene.
- Migration v4 zieht existierende Sources auf den neuen Pfad.
- Toggle in Oberleiste keyword-driven: findet alle 'Referenz'-Sub-Ebenen
  rekursiv, toggelt alle Praefixe gemeinsam. Bauteil-uebergreifend.

Oberleiste-Layout:
- Druck-Ansicht-Button hoch neben Massstab-Dropdown (Reihe 1).
- Referenzlinien-Toggle in Reihe 2 neben Zoom-Pill, symmetrisch zum
  Druck-Button. Zoom-Pill auf 3 Buttons reduziert.
- Print-View AN → Referenz-Layer automatisch ausblenden, Snapshot
  restored beim Ausschalten.

Fix: clear_schnitt_clipping respektiert Mode=Locked nicht — vor Delete
auf Normal-Mode wechseln + Modify damit's persistiert. Schnitt-Loeschen
raeumt Clipping-Planes jetzt sauber auf.

Fix: Schnitt-Doppelklick-Handler aktiviert nur bei expliziter Schnitt-
Auswahl, ignoriert andere Selektionen.

Fix: _send_state Selection-Detection mit Source-ODER-Volume-Fallback —
Fenster-Properties erscheinen jetzt auch wenn oeffnung_point auf hidden
Referenz-Layer liegt.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-23 20:58:06 +02:00
parent 059cbf8d4d
commit 736325fba1
7 changed files with 1149 additions and 109 deletions
+165 -1
View File
@@ -863,7 +863,15 @@ class OberleisteBridge(panel_base.BaseBridge):
self._send_state(force=True)
elif t == "SET_LINEWEIGHTS":
doc, _ = massstab._active_vp()
massstab._set_lineweights_enabled(doc, bool(p.get("enabled")))
enabled = bool(p.get("enabled"))
massstab._set_lineweights_enabled(doc, enabled)
# Print-View AN → Referenzlinien automatisch ausblenden (im
# gedruckten Plan haben Hilfslinien nichts verloren). Beim
# Ausschalten den vorherigen Sichtbarkeits-Stand restoren.
try:
self._sync_referenz_for_print(doc, enabled)
except Exception as ex:
print("[OBERLEISTE] sync referenz for print:", ex)
self._send_state(force=True)
elif t == "SET_DPI":
doc, _ = massstab._active_vp()
@@ -1087,6 +1095,76 @@ class OberleisteBridge(panel_base.BaseBridge):
except Exception as ex:
print("[OBERLEISTE] open layer-combinations:", ex)
# --- Referenzlinien-Sichtbarkeit togglen ------------------------
# Shortcut fuer die Layer-Sichtbarkeit der Referenzlinien-Ebene
# (Code 19). Bleibt eine echte Ebene → Ausschnitte speichern den
# State automatisch mit. Oberleiste ist nur ein schnellerer Weg
# dazu als der Ebenen-Manager.
elif t == "TOGGLE_REFERENZLINIEN":
try:
doc = Rhino.RhinoDoc.ActiveDoc
if doc is None: return
want_visible = bool(p.get("visible"))
print("[OBERLEISTE] TOGGLE_REFERENZLINIEN -> {}".format(want_visible))
# Keyword-driven: alle Ebenen mit Namen 'Referenz' im JSON
# finden (rekursiv), deren Codes sammeln, dann ALLE Rhino-
# Layer mit diesen Code-Praefixen toggeln. Funktioniert
# bauteil-uebergreifend: WAENDE::20r_Referenz heute,
# DECKEN::30r_Referenz / TRAGWERK::50r_Referenz morgen.
#
# Backwards-Kompat: erfasst auch das alte top-level
# '19_Referenzlinien' (Name beginnt mit "Referenz").
raw = doc.Strings.GetValue("dossier_ebenen")
ebenen = _json.loads(raw) if raw else []
if not isinstance(ebenen, list): ebenen = []
codes = [] # alle Codes deren Layer wir toggeln
def _collect(lst):
for e in lst:
if not isinstance(e, dict): continue
nm = (e.get("name") or "").strip().lower()
cd = e.get("code")
if cd and (nm == "referenz" or nm.startswith("referenz")):
codes.append(cd)
# Visible-Flag im JSON gleich mit-setzen
if e.get("visible", True) != want_visible:
e["visible"] = want_visible
kids = e.get("children")
if isinstance(kids, list): _collect(kids)
_collect(ebenen)
if codes:
try:
doc.Strings.SetString("dossier_ebenen",
_json.dumps(ebenen, ensure_ascii=False))
except Exception: pass
print("[OBERLEISTE] Referenz-Codes gefunden: {}".format(codes))
# Rhino-Layer fuer jeden Code toggeln (Praefix-Match)
n_toggled = 0
if codes:
prefixes = tuple(c + "_" for c in codes)
for i in range(doc.Layers.Count):
layer = doc.Layers[i]
if layer is None or layer.IsDeleted: continue
if not layer.Name.startswith(prefixes): continue
try:
if layer.IsVisible != want_visible:
layer.IsVisible = want_visible
doc.Layers.Modify(layer, i, True)
n_toggled += 1
except Exception: pass
print("[OBERLEISTE] {} Rhino-Layer getoggelt".format(n_toggled))
try: doc.Views.Redraw()
except Exception: pass
rhinopanel._broadcast_state(doc)
self._send_state(force=True)
except Exception as ex:
print("[OBERLEISTE] TOGGLE_REFERENZLINIEN:", ex)
# --- Anordnen (DisplayOrder Z-Stack) ----------------------------
# Nutzt Rhinos native _BringToFront / _BringForward / _SendBackward
# / _SendToBack. Diese setzen Attributes.DisplayOrder — keine
@@ -1195,6 +1273,69 @@ class OberleisteBridge(panel_base.BaseBridge):
"autoApplyLayout": bool(cfg.get("autoApplyLayout", False)),
})
def _sync_referenz_for_print(self, doc, print_enabled):
"""Druck-View AN → alle Referenz-Sub-Layer ausblenden + Sichtbarkeits-
Snapshot in sticky speichern. AUS → vorherige States restoren.
Findet die Codes keyword-basiert via dossier_ebenen-Tree (Name
startswith 'referenz'). Aendert NICHT das visible-Flag im JSON —
das gehoert dem User, wir overriden nur fuer die Druck-Sitzung."""
if doc is None: return
try: key = "_dossier_referenz_print_snapshot_" + str(doc.RuntimeSerialNumber)
except Exception: key = "_dossier_referenz_print_snapshot_default"
# Codes sammeln
try:
raw = doc.Strings.GetValue("dossier_ebenen")
ebenen = _json.loads(raw) if raw else []
except Exception: ebenen = []
codes = []
def _collect(lst):
for e in lst:
if not isinstance(e, dict): continue
nm = (e.get("name") or "").strip().lower()
cd = e.get("code")
if cd and (nm == "referenz" or nm.startswith("referenz")):
codes.append(cd)
kids = e.get("children")
if isinstance(kids, list): _collect(kids)
_collect(ebenen)
if not codes: return
prefixes = tuple(c + "_" for c in codes)
if print_enabled:
# Snapshot + Hide
snap = {}
for i in range(doc.Layers.Count):
layer = doc.Layers[i]
if layer is None or layer.IsDeleted: continue
if not layer.Name.startswith(prefixes): continue
snap[str(layer.Id)] = bool(layer.IsVisible)
if layer.IsVisible:
layer.IsVisible = False
doc.Layers.Modify(layer, i, True)
sc.sticky[key] = snap
try: doc.Views.Redraw()
except Exception: pass
print("[OBERLEISTE] Print AN: {} Referenz-Layer ausgeblendet".format(len(snap)))
else:
# Restore
snap = sc.sticky.get(key) or {}
n = 0
for i in range(doc.Layers.Count):
layer = doc.Layers[i]
if layer is None or layer.IsDeleted: continue
if not layer.Name.startswith(prefixes): continue
was = snap.get(str(layer.Id))
if was is None: continue
if layer.IsVisible != was:
layer.IsVisible = was
doc.Layers.Modify(layer, i, True)
n += 1
try: del sc.sticky[key]
except Exception: pass
try: doc.Views.Redraw()
except Exception: pass
print("[OBERLEISTE] Print AUS: {} Referenz-Layer-Sichtbarkeit restored".format(n))
def _send_state(self, force=False):
doc, vp = massstab._active_vp()
info = massstab._compute_scale(doc, vp)
@@ -1278,6 +1419,28 @@ class OberleisteBridge(panel_base.BaseBridge):
info["northAngle"] = 0
# Letzte ueber Topbar gesetzte Ansicht (fuer Active-Highlight)
info["lastSetView"] = self._last_set_view
# Referenzlinien-Sichtbarkeit fuer den Oberleiste-Toggle: alle
# Ebenen mit Name 'Referenz...' (keyword-driven, bauteil-uebergreifend)
# finden. Wenn ALLE visible → Button-State 'an', wenn min. eine
# unsichtbar → 'aus'. Default True (= an) wenn nichts gefunden.
ref_visible = True
try:
e_raw = doc.Strings.GetValue("dossier_ebenen") if doc else None
if e_raw:
vis_states = []
def _collect(lst):
for e in lst:
if not isinstance(e, dict): continue
nm = (e.get("name") or "").strip().lower()
if nm == "referenz" or nm.startswith("referenz"):
vis_states.append(bool(e.get("visible", True)))
kids = e.get("children")
if isinstance(kids, list): _collect(kids)
_collect(_json.loads(e_raw))
if vis_states:
ref_visible = all(vis_states)
except Exception: pass
info["referenzlinienVisible"] = ref_visible
# Command-Line State
prompt = _get_command_prompt()
info["cmdPrompt"] = prompt
@@ -1315,6 +1478,7 @@ class OberleisteBridge(panel_base.BaseBridge):
info.get("textStyleActiveId"),
len(info.get("textStyles") or []),
info.get("lastSetView"),
info.get("referenzlinienVisible"),
prompt,
)
if not force and sig == self._last_state_sig: