extends RefCounted class_name GroupState ## Gruppen-ZUSTAND über das Objekt-Feld "group" hinaus (Karte t_a4bf9b8c, U3 — ## Gruppen im Szenen-Baum). GroupOps (src/editor/group_ops.gd) besitzt die ## Zugehörigkeit (Optionales Objekt-Feld "group", int ≥ 0) — diese Datei ergänzt ## NUR ADDITIV, was der Baum additionally braucht: ## ## 1. GRUPPENNAMEN: doc["group_names"] = { "": "Lager", ... } — optionaler ## Ober-Block. Alte Maps ohne diesen Key laden unverändert (V4 prüft nur ## Pflichtblöcke, unbekannte Ober-Keys wandern 1:1 durch _canonicalize in ## SvmapIO und in die sha256-Prüfsumme — gleiche Begründung wie beim ## "group"-Feld in GroupOps). Eintrag fehlt ⇒ Anzeige-Fallback "Gruppe N". ## 2. DRAG-MITGLIDSCHAFT: Objekt in Gruppe ziehen (assign) / heraus ziehen ## (clear für EINZELNE Indizes — GroupOps.ungroup löst dagegen die GANZE ## Gruppe, was beim Drag-out nur eines Objekts nicht gewollt ist). ## ## Bewusst KEINE eigene Undo-Logik: der Aufrufer macht snapshot/commit über ## ActionHistory (["objects"] bzw. ["group_names"]) — jede Aktion bleibt EIN ## Undo-Schritt. const NAMES_KEY := "group_names" ## Rohe Namen-Tabelle (leer, wenn der Key fehlt — alte Maps). static func names_dict(doc: Dictionary) -> Dictionary: var raw: Variant = doc.get(NAMES_KEY, {}) return raw if raw is Dictionary else {} ## Gespeicherter Name einer Gruppe ("" = keiner gesetzt). static func group_name(doc: Dictionary, gid: int) -> String: var names := names_dict(doc) var value: Variant = names.get(str(gid), "") return str(value) if value is String else "" ## Anzeige-Name im Baum: gespeicherter Name oder Fallback "Gruppe N" ## (N = gid + 1 — gleiche Zählung wie in interaction.gd/selection_panel.gd). static func display_name(doc: Dictionary, gid: int) -> String: var name := group_name(doc, gid) return name if not name.is_empty() else ("Gruppe %d" % (gid + 1)) ## Namen setzen ("" oder nur Leerzeichen = Eintrag entfernen → Fallback). ## Rückgabe: true, wenn sich am Dokument etwas geändert hat. static func set_group_name(doc: Dictionary, gid: int, new_name: String) -> bool: var clean := new_name.strip_edges() var names := names_dict(doc) if clean.is_empty(): if not names.has(str(gid)): return false (doc[NAMES_KEY] as Dictionary).erase(str(gid)) return true if names.get(str(gid), "") == clean: return false if not doc.has(NAMES_KEY) or not (doc[NAMES_KEY] is Dictionary): doc[NAMES_KEY] = {} (doc[NAMES_KEY] as Dictionary)[str(gid)] = clean return true ## Namen-Einträge ohne Mitglieder entfernen (Aufräumen nach Löschen/Lösen — ## vom Aufrufer IM SELBEN Undo-Schritt mit-committet). static func prune_orphans(doc: Dictionary) -> int: var active := {} for obj in (doc.get("objects", []) as Array): var g := GroupOps.group_id(obj) if g != GroupOps.UNGROUPED: active[g] = true var names := names_dict(doc) var removed := 0 for key in names.keys(): if not active.has(int(key)): names.erase(key) removed += 1 if removed > 0: if (names as Dictionary).is_empty(): doc.erase(NAMES_KEY) # sauberes Format: leerer Block fliegt raus elif doc.has(NAMES_KEY): doc[NAMES_KEY] = names return removed ## Drag IN eine Gruppe: Objekt-Feld "group" auf die Ziel-ID setzen (Objekte, ## die schon diese ID tragen, zählen nicht als Änderung). Nur die GEBENEN ## Indizes — die restliche Gruppe bleibt unberührt. Rückgabe: geänderte Anzahl. static func assign_group(doc: Dictionary, indices: Array, gid: int) -> int: if gid < 0: return 0 var objects: Array = doc.get("objects", []) var changed := 0 for i in indices: if i is int and i >= 0 and i < objects.size() and (objects[i] is Dictionary): if GroupOps.group_id(objects[i]) != gid: objects[i]["group"] = gid changed += 1 return changed ## Drag AUS der Gruppe: "group"-Feld NUR der gegebenen Indizes entfernen ## (die Gruppe selbst bleibt mit ihren übrigen Mitgliedern bestehen). ## Rückgabe: geänderte Anzahl. static func clear_group_fields(doc: Dictionary, indices: Array) -> int: var objects: Array = doc.get("objects", []) var changed := 0 for i in indices: if i is int and i >= 0 and i < objects.size() and (objects[i] is Dictionary): if GroupOps.group_id(objects[i]) != GroupOps.UNGROUPED: (objects[i] as Dictionary).erase("group") changed += 1 return changed