111 lines
4.3 KiB
GDScript
111 lines
4.3 KiB
GDScript
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"] = { "<gid>": "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
|