From 5fd6aefd341e2efcdf130a00383bd2598ce68d53 Mon Sep 17 00:00:00 2001 From: karim Date: Wed, 20 May 2026 02:51:22 +0200 Subject: [PATCH] =?UTF-8?q?Delete-Cascade=20in=20EINEN=20Undo-Record=20?= =?UTF-8?q?=E2=80=94=20Cmd+Z=20stellt=20Wand=20+=20Volumen=20wieder=20her?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: Bei Wand-Loeschen lief das Delete von wand_axis als Rhino-Undo-Record A, unsere Idle-Cascade (Volume-Delete, Oeffnungs-Cleanup) lief 500 ms spaeter in separaten Records B/C/D. Cmd+Z popte nur den letzten Record → nur das Volume kam zurueck, oder umgekehrt nur die Achse. Fix: BeginUndoRecord("Element-Loeschen") in _on_command_begin fuer Delete- Cmds. _flush_pending_cascades_sync laeuft in _on_command_end SOFORT (kein 500-ms-Wait noetig — bei explizitem Delete kommt die Source nicht zurueck) und WAEHREND der Record offen ist. EndUndoRecord schliesst den Record. Resultat: Rhinos User-Delete + alle Cascade-Deletes = EIN Cmd+Z. Co-Authored-By: Claude Opus 4.7 --- rhino/elemente.py | 88 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/rhino/elemente.py b/rhino/elemente.py index 31e2434..ff955be 100644 --- a/rhino/elemente.py +++ b/rhino/elemente.py @@ -9519,6 +9519,65 @@ def _suppress_redraw_until_cmd_end(): print("[ELEMENTE] suppress redraw:", ex) +def _flush_pending_cascades_sync(doc): + """Verarbeitet die wand_cascade- und source_cascade-Queues SOFORT + (ohne 500-ms-Wait). Aufgerufen aus _on_command_end fuer Delete-Cmds: + der User hat explizit geloescht, die Source kommt nicht zurueck — + also kein Grund zu warten. Vorteil: laeuft noch im selben Undo-Record + wie Rhinos User-Delete → ein Cmd+Z stellt alles wieder her. + """ + pending_cascade = sc.sticky.get("_elemente_pending_wand_cascade") + if isinstance(pending_cascade, dict) and pending_cascade: + to_run = [(wid, info.get("openings", [])) + for wid, info in list(pending_cascade.items())] + pending_cascade.clear() + for wall_id, op_ids in to_run: + still_there = False + for obj in doc.Objects: + m = _read_meta(obj) + if m and m.get("id") == wall_id and m.get("type") == "wand_axis": + still_there = True + break + if still_there: continue + _was = sc.sticky.get(_REGEN_BUSY, False) + sc.sticky[_REGEN_BUSY] = True + try: + for op_id in op_ids: + for vol_obj in _find_all_volumes(doc, op_id): + try: doc.Objects.Delete(vol_obj.Id, True) + except Exception: pass + for obj, _m in _find_objects_by_wall_id(doc, op_id): + if _m.get("type") == "oeffnung_point": + try: doc.Objects.Delete(obj.Id, True) + except Exception: pass + finally: + sc.sticky[_REGEN_BUSY] = _was + + pending_src = sc.sticky.get("_elemente_pending_source_cascade") + if isinstance(pending_src, dict) and pending_src: + to_run_src = list(pending_src.items()) + pending_src.clear() + for src_id, info in to_run_src: + still_there = False + for obj in doc.Objects: + m = _read_meta(obj) + if m and m.get("id") == src_id and m.get("type") == info.get("type"): + still_there = True + break + if still_there: continue + _was = sc.sticky.get(_REGEN_BUSY, False) + sc.sticky[_REGEN_BUSY] = True + try: + for vol_id in info.get("volumes", []): + try: doc.Objects.Delete(vol_id, True) + except Exception: pass + finally: + sc.sticky[_REGEN_BUSY] = _was + parent_id = info.get("parent") + if parent_id: + _queue_regen(parent_id) + + def _on_command_begin(sender, e): try: name = getattr(e, "CommandEnglishName", "") or "" @@ -9541,6 +9600,16 @@ def _on_command_begin(sender, e): sc.sticky["_dossier_bulk_redraw_prev"] = bool(doc.Views.RedrawEnabled) doc.Views.RedrawEnabled = False except Exception: pass + # Undo-Record umschliesst Rhinos User-Delete + unsere Cascade + # (Volume-Delete, Oeffnungs-Delete) in EINEM Cmd+Z-Schritt. + # Sonst bleibt nach Cmd+Z nur die Achse uebrig (Volumen kamen aus + # separatem Idle-Record und der hatte schon gepop't). + try: + serial = doc.BeginUndoRecord("Element-Loeschen") + sc.sticky["_dossier_bulk_undo_serial"] = serial + except Exception as ex: + print("[ELEMENTE] bulk undo record begin:", ex) + sc.sticky["_dossier_bulk_undo_serial"] = None return # Diagnose: andere Commands sehen wir hier vorbeiziehen — wenn _Delete # einen anderen Namen hat als 'Delete', sehen wir's und koennen den @@ -9570,9 +9639,26 @@ def _on_command_end(sender, e): # refresh ans Gestaltung-Panel. if sc.sticky.get(_BULK_ACTIVE_KEY): sc.sticky[_BULK_ACTIVE_KEY] = None + doc = Rhino.RhinoDoc.ActiveDoc + # Cascade synchron flushen WAEHREND der Undo-Record noch offen ist + # und RedrawEnabled noch False ist (kein Flicker, ein Cmd+Z fuer + # alles). Nur fuer Delete-Cmds relevant — andere Bulk-Cmds queuen + # nichts. + try: + if doc is not None: + _flush_pending_cascades_sync(doc) + except Exception as ex: + print("[ELEMENTE] bulk cascade flush:", ex) + # Undo-Record schliessen — alles seit BeginUndoRecord (User-Delete + + # Cascade) wird als EIN Cmd+Z behandelt. + try: + serial = sc.sticky.pop("_dossier_bulk_undo_serial", None) + if serial is not None and doc is not None: + doc.EndUndoRecord(serial) + except Exception as ex: + print("[ELEMENTE] bulk undo record end:", ex) try: prev = sc.sticky.pop("_dossier_bulk_redraw_prev", True) - doc = Rhino.RhinoDoc.ActiveDoc if doc is not None: doc.Views.RedrawEnabled = prev doc.Views.Redraw()