diff --git a/rhino/rhinopanel.py b/rhino/rhinopanel.py index 52478a6..47dfeb7 100644 --- a/rhino/rhinopanel.py +++ b/rhino/rhinopanel.py @@ -1080,6 +1080,8 @@ class EbenenBridge(panel_base.BaseBridge): def on_save(updated): doc2 = Rhino.RhinoDoc.ActiveDoc if doc2 is None: return + # Snapshot OLD settings VOR dem Save fuer Stale-Detection + old_settings = load_project_settings(doc2) or {} new_settings = { "defaults": updated.get("defaults", {}), "materials": updated.get("materials", []), @@ -1102,33 +1104,79 @@ class EbenenBridge(panel_base.BaseBridge): if eb is not None: eb._send_state() except Exception as ex: print("[PROJECT-SETTINGS] elemente refresh:", ex) - # Alle wand_axis im Doc regenen damit Material-Aenderungen - # (PBR/Texturen/Hatch) auf existing Waende durchschlagen. + # Stale-Detection: welche Wand-Styles oder Materials haben sich + # geaendert? Nur betroffene Waende regenen (statt alle). try: import elemente - undo_serial = doc2.BeginUndoRecord("Material-Update Regen") - prev_redraw = doc2.Views.RedrawEnabled - doc2.Views.RedrawEnabled = False + old_styles = {s.get("id"): s for s in + (old_settings.get("wand_styles") or []) + if isinstance(s, dict) and s.get("id")} + new_styles = {s.get("id"): s for s in + (new_settings.get("wand_styles") or []) + if isinstance(s, dict) and s.get("id")} + changed_style_ids = set() + for sid in (set(old_styles) | set(new_styles)): + if old_styles.get(sid) != new_styles.get(sid): + changed_style_ids.add(sid) + old_mats = {m.get("name"): m for m in + (old_settings.get("materials") or []) + if isinstance(m, dict) and m.get("name")} + new_mats = {m.get("name"): m for m in + (new_settings.get("materials") or []) + if isinstance(m, dict) and m.get("name")} + changed_material_names = set() + for n in (set(old_mats) | set(new_mats)): + if old_mats.get(n) != new_mats.get(n): + changed_material_names.add(n) + # Welche Waende sind betroffen? wall_ids = [] + seen = set() for obj in doc2.Objects: m = elemente._read_meta(obj) - if m and m.get("type") == "wand_axis": - wall_ids.append(m["id"]) - # Chain-Anchor regent automatisch alle members — wir koennen - # trotzdem alle einzeln triggern, _REGEN_BUSY-Guard verhindert - # Doppel-Arbeit. Einfacher als Anchor-Election hier. + if not m or m.get("type") != "wand_axis": continue + wid = m["id"] + if wid in seen: continue + affected = False + sid = (m.get("wand_style_id") or "").strip() + if sid and sid in changed_style_ids: + affected = True + if not affected and m.get("wand_layered"): + for layer in (m.get("wand_layers") or []): + if isinstance(layer, dict) and layer.get("material") \ + in changed_material_names: + affected = True; break + if not affected and sid and changed_material_names: + # Solid-Wand mit Style: Material-Aenderung des + # Style-referenzierten Materials trifft sie + st = new_styles.get(sid) or old_styles.get(sid) + if st and st.get("material") in changed_material_names: + affected = True + if affected: + wall_ids.append(wid); seen.add(wid) + if not wall_ids: + print("[PROJECT-SETTINGS] keine wand-relevanten Aenderungen") + return + undo_serial = doc2.BeginUndoRecord( + "Stil-Update Regen ({})".format(len(wall_ids))) + prev_redraw = doc2.Views.RedrawEnabled + doc2.Views.RedrawEnabled = False try: + sc.sticky["_dossier_regen_batch_active"] = True for wid in wall_ids: try: elemente._regenerate_element(doc2, wid) except Exception as ex: print("[PROJECT-SETTINGS] regen", wid, ex) finally: + sc.sticky["_dossier_regen_batch_active"] = False doc2.Views.RedrawEnabled = prev_redraw try: doc2.EndUndoRecord(undo_serial) except Exception: pass try: doc2.Views.Redraw() except Exception: pass - print("[PROJECT-SETTINGS] {} Waende regenert".format(len(wall_ids))) + print("[PROJECT-SETTINGS] {} Waende regenert ({} Stile, " + "{} Materials geaendert)".format( + len(wall_ids), len(changed_style_ids), + len(changed_material_names))) except Exception as ex: print("[PROJECT-SETTINGS] wall regen:", ex) # Custom-Bridge fuer Project-Settings: handelt SAVE/CANCEL +