Stempel: Stile + Layout-Customisation (Header, Show-Toggles)
Bilanz-Stempel hat jetzt: - Custom Header (Default "Nutzflächen", frei editierbar) - Per-Stempel Show-Toggles: scope, hnf, nnf, nf, vf, ff, ngf, gf, agf, count (Anzahl Raeume), separators (Trennlinien) - Stempel-Stile (Presets) per Doc — separate Storage von Raumstempel- Stilen (dossier_stempel_stile) Backend (elemente.py): - UserStrings: dossier_stempel_header + dossier_stempel_show_* (11 Flags) + dossier_stempel_stil_id - _make_stempel_text erweitert: header_text, show_scope, show_separators, show_count, visibility-dict - _format_bilanz_lines: visibility + show_separators + show_count Args - load_stempel_stile / save_stempel_stile (eigener doc.Strings-Key) - Bridge-Handler SAVE/DELETE/APPLY_STEMPEL_STIL (analog Raum-Stil-Pattern, inkl. Bulk-Apply via Selection + applyToIds-Mechanism wie SaveRaum-Stil) - _sync_stempel_to_source spiegelt Font/Bold/Italic/TextHeight vom Live- TextEntity zur UserString-Storage (Oberleiste-Edits ueberleben Regen) - _update_wall stempel-Branch um header + show-Flags erweitert Frontend (StempelProperties): - Stil-Picker-Dropdown analog Raum (Stil wählen / + speichern / 🗑 löschen) - Header-Input (Inline-Text) - 11 Show-Toggles als kompakte Grid (Check-Box-Stil) - Live-Vorschau respektiert Visibility-Flags + bilanz.count
This commit is contained in:
+387
-25
@@ -2715,6 +2715,13 @@ def _attach_meta(obj_attrs, wall_id, type_, geschoss, dicke, uk_over, ok_over,
|
|||||||
raum_layout=None, raum_txt_modus=None,
|
raum_layout=None, raum_txt_modus=None,
|
||||||
stempel_scope=None, stempel_txt_h=None,
|
stempel_scope=None, stempel_txt_h=None,
|
||||||
stempel_font=None, stempel_bold=None, stempel_italic=None,
|
stempel_font=None, stempel_bold=None, stempel_italic=None,
|
||||||
|
stempel_header=None, stempel_show_scope=None,
|
||||||
|
stempel_show_hnf=None, stempel_show_nnf=None,
|
||||||
|
stempel_show_nf=None, stempel_show_vf=None,
|
||||||
|
stempel_show_ff=None, stempel_show_ngf=None,
|
||||||
|
stempel_show_gf=None, stempel_show_agf=None,
|
||||||
|
stempel_show_count=None, stempel_show_seps=None,
|
||||||
|
stempel_stil_id=None,
|
||||||
wand_layered=None, wand_layers=None, wand_layer_idx=None,
|
wand_layered=None, wand_layers=None, wand_layer_idx=None,
|
||||||
wand_chain_members=None,
|
wand_chain_members=None,
|
||||||
aussp_parent=None):
|
aussp_parent=None):
|
||||||
@@ -2934,6 +2941,25 @@ def _attach_meta(obj_attrs, wall_id, type_, geschoss, dicke, uk_over, ok_over,
|
|||||||
if stempel_italic is not None:
|
if stempel_italic is not None:
|
||||||
obj_attrs.SetUserString(_KEY_STEMPEL_ITAL,
|
obj_attrs.SetUserString(_KEY_STEMPEL_ITAL,
|
||||||
"1" if bool(stempel_italic) else "0")
|
"1" if bool(stempel_italic) else "0")
|
||||||
|
if stempel_header is not None:
|
||||||
|
obj_attrs.SetUserString(_KEY_STEMPEL_HEADER, str(stempel_header))
|
||||||
|
for _k, _v in (
|
||||||
|
(_KEY_STEMPEL_SHOW_SCOPE, stempel_show_scope),
|
||||||
|
(_KEY_STEMPEL_SHOW_HNF, stempel_show_hnf),
|
||||||
|
(_KEY_STEMPEL_SHOW_NNF, stempel_show_nnf),
|
||||||
|
(_KEY_STEMPEL_SHOW_NF, stempel_show_nf),
|
||||||
|
(_KEY_STEMPEL_SHOW_VF, stempel_show_vf),
|
||||||
|
(_KEY_STEMPEL_SHOW_FF, stempel_show_ff),
|
||||||
|
(_KEY_STEMPEL_SHOW_NGF, stempel_show_ngf),
|
||||||
|
(_KEY_STEMPEL_SHOW_GF, stempel_show_gf),
|
||||||
|
(_KEY_STEMPEL_SHOW_AGF, stempel_show_agf),
|
||||||
|
(_KEY_STEMPEL_SHOW_COUNT, stempel_show_count),
|
||||||
|
(_KEY_STEMPEL_SHOW_SEPS, stempel_show_seps),
|
||||||
|
):
|
||||||
|
if _v is not None:
|
||||||
|
obj_attrs.SetUserString(_k, "1" if bool(_v) else "0")
|
||||||
|
if stempel_stil_id is not None:
|
||||||
|
obj_attrs.SetUserString(_KEY_STEMPEL_STIL_ID, str(stempel_stil_id))
|
||||||
# Wand-Schichten
|
# Wand-Schichten
|
||||||
if wand_layered is not None:
|
if wand_layered is not None:
|
||||||
obj_attrs.SetUserString(_KEY_WAND_LAYERED,
|
obj_attrs.SetUserString(_KEY_WAND_LAYERED,
|
||||||
@@ -3141,6 +3167,29 @@ def _read_meta(obj):
|
|||||||
st_font = a.GetUserString(_KEY_STEMPEL_FONT) or ""
|
st_font = a.GetUserString(_KEY_STEMPEL_FONT) or ""
|
||||||
st_bold = (a.GetUserString(_KEY_STEMPEL_BOLD) == "1")
|
st_bold = (a.GetUserString(_KEY_STEMPEL_BOLD) == "1")
|
||||||
st_ital = (a.GetUserString(_KEY_STEMPEL_ITAL) == "1")
|
st_ital = (a.GetUserString(_KEY_STEMPEL_ITAL) == "1")
|
||||||
|
# Stempel-Layout-Custom (Defaults: alle "show" on ausser show_count;
|
||||||
|
# leer/None → True ausser show_count → False)
|
||||||
|
st_header = a.GetUserString(_KEY_STEMPEL_HEADER)
|
||||||
|
if st_header is None or st_header == "":
|
||||||
|
st_header = "Nutzflächen"
|
||||||
|
def _sh_on(key, default=True):
|
||||||
|
v = a.GetUserString(key)
|
||||||
|
if default:
|
||||||
|
return v != "0" # None/""/"1" → True
|
||||||
|
else:
|
||||||
|
return v == "1" # nur explizites "1" → True
|
||||||
|
st_show_scope = _sh_on(_KEY_STEMPEL_SHOW_SCOPE, True)
|
||||||
|
st_show_hnf = _sh_on(_KEY_STEMPEL_SHOW_HNF, True)
|
||||||
|
st_show_nnf = _sh_on(_KEY_STEMPEL_SHOW_NNF, True)
|
||||||
|
st_show_nf = _sh_on(_KEY_STEMPEL_SHOW_NF, True)
|
||||||
|
st_show_vf = _sh_on(_KEY_STEMPEL_SHOW_VF, True)
|
||||||
|
st_show_ff = _sh_on(_KEY_STEMPEL_SHOW_FF, True)
|
||||||
|
st_show_ngf = _sh_on(_KEY_STEMPEL_SHOW_NGF, True)
|
||||||
|
st_show_gf = _sh_on(_KEY_STEMPEL_SHOW_GF, True)
|
||||||
|
st_show_agf = _sh_on(_KEY_STEMPEL_SHOW_AGF, True)
|
||||||
|
st_show_count = _sh_on(_KEY_STEMPEL_SHOW_COUNT, False)
|
||||||
|
st_show_seps = _sh_on(_KEY_STEMPEL_SHOW_SEPS, True)
|
||||||
|
st_stil_id = a.GetUserString(_KEY_STEMPEL_STIL_ID) or ""
|
||||||
# Field-Layout — parsed JSON list of rows
|
# Field-Layout — parsed JSON list of rows
|
||||||
r_layout_raw = a.GetUserString(_KEY_RAUM_LAYOUT) or ""
|
r_layout_raw = a.GetUserString(_KEY_RAUM_LAYOUT) or ""
|
||||||
r_layout = []
|
r_layout = []
|
||||||
@@ -3268,6 +3317,19 @@ def _read_meta(obj):
|
|||||||
"stempel_font": st_font,
|
"stempel_font": st_font,
|
||||||
"stempel_bold": st_bold,
|
"stempel_bold": st_bold,
|
||||||
"stempel_italic": st_ital,
|
"stempel_italic": st_ital,
|
||||||
|
"stempel_header": st_header,
|
||||||
|
"stempel_show_scope": st_show_scope,
|
||||||
|
"stempel_show_hnf": st_show_hnf,
|
||||||
|
"stempel_show_nnf": st_show_nnf,
|
||||||
|
"stempel_show_nf": st_show_nf,
|
||||||
|
"stempel_show_vf": st_show_vf,
|
||||||
|
"stempel_show_ff": st_show_ff,
|
||||||
|
"stempel_show_ngf": st_show_ngf,
|
||||||
|
"stempel_show_gf": st_show_gf,
|
||||||
|
"stempel_show_agf": st_show_agf,
|
||||||
|
"stempel_show_count": st_show_count,
|
||||||
|
"stempel_show_seps": st_show_seps,
|
||||||
|
"stempel_stil_id": st_stil_id,
|
||||||
"wand_layered": w_layered,
|
"wand_layered": w_layered,
|
||||||
"wand_layers": w_layers,
|
"wand_layers": w_layers,
|
||||||
"wand_layer_idx": w_layer_idx,
|
"wand_layer_idx": w_layer_idx,
|
||||||
@@ -3892,6 +3954,58 @@ _KEY_STEMPEL_TXT_H = "dossier_stempel_txt_h" # Texthoehe in m
|
|||||||
_KEY_STEMPEL_FONT = "dossier_stempel_font"
|
_KEY_STEMPEL_FONT = "dossier_stempel_font"
|
||||||
_KEY_STEMPEL_BOLD = "dossier_stempel_bold"
|
_KEY_STEMPEL_BOLD = "dossier_stempel_bold"
|
||||||
_KEY_STEMPEL_ITAL = "dossier_stempel_italic"
|
_KEY_STEMPEL_ITAL = "dossier_stempel_italic"
|
||||||
|
# Layout-Customisation (per Stempel)
|
||||||
|
_KEY_STEMPEL_HEADER = "dossier_stempel_header" # default "Nutzflächen"
|
||||||
|
_KEY_STEMPEL_SHOW_SCOPE = "dossier_stempel_show_scope" # default "1"
|
||||||
|
_KEY_STEMPEL_SHOW_HNF = "dossier_stempel_show_hnf" # default "1"
|
||||||
|
_KEY_STEMPEL_SHOW_NNF = "dossier_stempel_show_nnf" # default "1"
|
||||||
|
_KEY_STEMPEL_SHOW_NF = "dossier_stempel_show_nf" # default "1"
|
||||||
|
_KEY_STEMPEL_SHOW_VF = "dossier_stempel_show_vf" # default "1"
|
||||||
|
_KEY_STEMPEL_SHOW_FF = "dossier_stempel_show_ff" # default "1"
|
||||||
|
_KEY_STEMPEL_SHOW_NGF = "dossier_stempel_show_ngf" # default "1"
|
||||||
|
_KEY_STEMPEL_SHOW_GF = "dossier_stempel_show_gf" # default "1"
|
||||||
|
_KEY_STEMPEL_SHOW_AGF = "dossier_stempel_show_agf" # default "1"
|
||||||
|
_KEY_STEMPEL_SHOW_COUNT = "dossier_stempel_show_count" # default "0"
|
||||||
|
_KEY_STEMPEL_SHOW_SEPS = "dossier_stempel_show_seps" # default "1"
|
||||||
|
_KEY_STEMPEL_STIL_ID = "dossier_stempel_stil_id" # aktiver Stil
|
||||||
|
# Storage-Key fuer Stempel-Stile (Presets, per Doc)
|
||||||
|
_KEY_STEMPEL_STILE = "dossier_stempel_stile"
|
||||||
|
_STEMPEL_STIL_FIELDS = (
|
||||||
|
"header", "showScope",
|
||||||
|
"showHnf", "showNnf", "showNf", "showVf", "showFf",
|
||||||
|
"showNgf", "showGf", "showAgf", "showCount", "showSeparators",
|
||||||
|
"font", "bold", "italic", "txtH",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def load_stempel_stile(doc):
|
||||||
|
if doc is None: return []
|
||||||
|
try: raw = doc.Strings.GetValue(_KEY_STEMPEL_STILE) or ""
|
||||||
|
except Exception: raw = ""
|
||||||
|
if not raw: return []
|
||||||
|
try:
|
||||||
|
import json as _json
|
||||||
|
data = _json.loads(raw)
|
||||||
|
if not isinstance(data, list): return []
|
||||||
|
return [s for s in data if isinstance(s, dict)
|
||||||
|
and s.get("id") and s.get("name")]
|
||||||
|
except Exception as ex:
|
||||||
|
print("[ELEMENTE] load_stempel_stile:", ex)
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def save_stempel_stile(doc, stile):
|
||||||
|
if doc is None or not isinstance(stile, list): return False
|
||||||
|
try:
|
||||||
|
import json as _json
|
||||||
|
clean = [s for s in stile if isinstance(s, dict)
|
||||||
|
and s.get("id") and s.get("name")]
|
||||||
|
doc.Strings.SetString(_KEY_STEMPEL_STILE,
|
||||||
|
_json.dumps(clean, ensure_ascii=False))
|
||||||
|
return True
|
||||||
|
except Exception as ex:
|
||||||
|
print("[ELEMENTE] save_stempel_stile:", ex)
|
||||||
|
return False
|
||||||
# Oeffnungs-Cutout: Boolean-Difference aus Wand. Zusaetzlich kriegt die
|
# Oeffnungs-Cutout: Boolean-Difference aus Wand. Zusaetzlich kriegt die
|
||||||
# Oeffnung ihr eigenes Volumen (Rahmen + Sims + Glas) als Sub-Element.
|
# Oeffnung ihr eigenes Volumen (Rahmen + Sims + Glas) als Sub-Element.
|
||||||
|
|
||||||
@@ -5061,51 +5175,89 @@ def compute_sia_bilanz(doc, scope="total"):
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def _format_bilanz_lines(bilanz, rundung="0.1"):
|
def _format_bilanz_lines(bilanz, rundung="0.1", visibility=None,
|
||||||
|
show_separators=True, show_count=False):
|
||||||
"""Baut die Stempel-Textzeilen aus einer Bilanz. Zeigt nur Kategorien
|
"""Baut die Stempel-Textzeilen aus einer Bilanz. Zeigt nur Kategorien
|
||||||
mit Flaeche > 0. Format kompakt: 'HNF 120.5 m²'."""
|
mit Flaeche > 0 UND deren visibility-Flag True ist.
|
||||||
|
|
||||||
|
visibility = dict mit Keys hnf/nnf/nf/vf/ff/ngf/gf/agf → True/False.
|
||||||
|
None heisst: alle anzeigen (Default).
|
||||||
|
"""
|
||||||
|
if visibility is None:
|
||||||
|
visibility = {}
|
||||||
|
def _v(k): return visibility.get(k, True)
|
||||||
|
sep = "────────────"
|
||||||
lines = []
|
lines = []
|
||||||
def _row(label, val):
|
def _row(label, val):
|
||||||
return "{} {} m²".format(label.ljust(4), _format_area(val, rundung))
|
return "{} {} m²".format(label.ljust(4), _format_area(val, rundung))
|
||||||
# Nutzflaechen-Block
|
# Nutzflaechen-Block
|
||||||
has_nf = bilanz["hnf"] > 0 or bilanz["nnf"] > 0
|
show_hnf = _v("hnf") and bilanz["hnf"] > 0
|
||||||
if bilanz["hnf"] > 0: lines.append(_row("HNF", bilanz["hnf"]))
|
show_nnf = _v("nnf") and bilanz["nnf"] > 0
|
||||||
if bilanz["nnf"] > 0: lines.append(_row("NNF", bilanz["nnf"]))
|
has_nf_inputs = show_hnf or show_nnf
|
||||||
if has_nf:
|
if show_hnf: lines.append(_row("HNF", bilanz["hnf"]))
|
||||||
lines.append("────────────")
|
if show_nnf: lines.append(_row("NNF", bilanz["nnf"]))
|
||||||
|
if _v("nf") and has_nf_inputs and bilanz["nf"] > 0:
|
||||||
|
if show_separators: lines.append(sep)
|
||||||
lines.append(_row("NF", bilanz["nf"]))
|
lines.append(_row("NF", bilanz["nf"]))
|
||||||
# VF/FF
|
# VF/FF
|
||||||
if bilanz["vf"] > 0: lines.append(_row("VF", bilanz["vf"]))
|
show_vf = _v("vf") and bilanz["vf"] > 0
|
||||||
if bilanz["ff"] > 0: lines.append(_row("FF", bilanz["ff"]))
|
show_ff = _v("ff") and bilanz["ff"] > 0
|
||||||
|
if show_vf: lines.append(_row("VF", bilanz["vf"]))
|
||||||
|
if show_ff: lines.append(_row("FF", bilanz["ff"]))
|
||||||
# NGF wenn was zusammenkommt
|
# NGF wenn was zusammenkommt
|
||||||
if bilanz["ngf"] > 0 and (bilanz["vf"] > 0 or bilanz["ff"] > 0):
|
if _v("ngf") and bilanz["ngf"] > 0 and (show_vf or show_ff or has_nf_inputs):
|
||||||
lines.append("────────────")
|
if show_separators: lines.append(sep)
|
||||||
lines.append(_row("NGF", bilanz["ngf"]))
|
lines.append(_row("NGF", bilanz["ngf"]))
|
||||||
# Gross-Flaechen separat
|
# Gross-Flaechen separat
|
||||||
if bilanz["gf"] > 0 or bilanz["agf"] > 0:
|
show_gf = _v("gf") and bilanz["gf"] > 0
|
||||||
lines.append("────────────")
|
show_agf = _v("agf") and bilanz["agf"] > 0
|
||||||
if bilanz["gf"] > 0: lines.append(_row("GF", bilanz["gf"]))
|
if show_gf or show_agf:
|
||||||
if bilanz["agf"] > 0: lines.append(_row("AGF", bilanz["agf"]))
|
if show_separators and lines: lines.append(sep)
|
||||||
|
if show_gf: lines.append(_row("GF", bilanz["gf"]))
|
||||||
|
if show_agf: lines.append(_row("AGF", bilanz["agf"]))
|
||||||
|
# Count optional
|
||||||
|
if show_count and bilanz.get("count", 0) > 0:
|
||||||
|
if show_separators and lines: lines.append(sep)
|
||||||
|
lines.append("{} Räume".format(bilanz["count"]))
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
def _make_stempel_text(pos, scope, doc, text_height=0.20, z=0.0,
|
def _make_stempel_text(pos, scope, doc, text_height=0.20, z=0.0,
|
||||||
font=None, bold=False, italic=False):
|
font=None, bold=False, italic=False,
|
||||||
|
header_text="Nutzflächen", show_scope=True,
|
||||||
|
show_separators=True, show_count=False,
|
||||||
|
visibility=None):
|
||||||
"""Baut die Stempel-TextEntity fuer einen Scope ("total" oder
|
"""Baut die Stempel-TextEntity fuer einen Scope ("total" oder
|
||||||
"geschoss:<id>"). Header = "Nutzflächen · {Scope-Label}"."""
|
"geschoss:<id>"). header_text + show_* steuern Layout-Customisation.
|
||||||
|
|
||||||
|
visibility = dict mit hnf/nnf/nf/vf/ff/ngf/gf/agf → True/False.
|
||||||
|
Default: alle True (= aktuelles Verhalten, nur Kategorien > 0).
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
bilanz = compute_sia_bilanz(doc, scope)
|
bilanz = compute_sia_bilanz(doc, scope)
|
||||||
|
# Header zusammenbauen
|
||||||
|
header_parts = []
|
||||||
|
if header_text and header_text.strip():
|
||||||
|
header_parts.append(header_text.strip())
|
||||||
|
if show_scope:
|
||||||
if scope == "total":
|
if scope == "total":
|
||||||
scope_label = "Total"
|
scope_label = "Total"
|
||||||
elif bilanz["geschossName"]:
|
elif bilanz["geschossName"]:
|
||||||
scope_label = bilanz["geschossName"]
|
scope_label = bilanz["geschossName"]
|
||||||
else:
|
else:
|
||||||
scope_label = "—"
|
scope_label = "—"
|
||||||
header = "Nutzflächen · {}".format(scope_label)
|
header_parts.append(scope_label)
|
||||||
body = _format_bilanz_lines(bilanz)
|
header = " · ".join(header_parts) if header_parts else ""
|
||||||
|
body = _format_bilanz_lines(bilanz, visibility=visibility,
|
||||||
|
show_separators=show_separators,
|
||||||
|
show_count=show_count)
|
||||||
if not body:
|
if not body:
|
||||||
body = ["(keine klassifizierten Räume)"]
|
body = ["(keine klassifizierten Räume)"]
|
||||||
text = "\n".join([header, "════════════"] + body)
|
lines = []
|
||||||
|
if header: lines.append(header)
|
||||||
|
if show_separators and header: lines.append("════════════")
|
||||||
|
lines.extend(body)
|
||||||
|
text = "\n".join(lines)
|
||||||
te = rg.TextEntity()
|
te = rg.TextEntity()
|
||||||
te.Text = text
|
te.Text = text
|
||||||
plane = rg.Plane(rg.Point3d(pos.X, pos.Y, float(z)),
|
plane = rg.Plane(rg.Point3d(pos.X, pos.Y, float(z)),
|
||||||
@@ -6588,9 +6740,26 @@ def _regenerate_element_body(doc, element_id, src_obj, meta, geom, geschoss_name
|
|||||||
font = meta.get("stempel_font", "") or ""
|
font = meta.get("stempel_font", "") or ""
|
||||||
bold = bool(meta.get("stempel_bold", False))
|
bold = bool(meta.get("stempel_bold", False))
|
||||||
italic = bool(meta.get("stempel_italic", False))
|
italic = bool(meta.get("stempel_italic", False))
|
||||||
new_te = _make_stempel_text(pos, scope, doc, text_height=txt_h,
|
# Layout-Customisation aus Meta
|
||||||
z=pos.Z, font=font, bold=bold,
|
header_text = meta.get("stempel_header", "Nutzflächen") or "Nutzflächen"
|
||||||
italic=italic)
|
visibility = {
|
||||||
|
"hnf": bool(meta.get("stempel_show_hnf", True)),
|
||||||
|
"nnf": bool(meta.get("stempel_show_nnf", True)),
|
||||||
|
"nf": bool(meta.get("stempel_show_nf", True)),
|
||||||
|
"vf": bool(meta.get("stempel_show_vf", True)),
|
||||||
|
"ff": bool(meta.get("stempel_show_ff", True)),
|
||||||
|
"ngf": bool(meta.get("stempel_show_ngf", True)),
|
||||||
|
"gf": bool(meta.get("stempel_show_gf", True)),
|
||||||
|
"agf": bool(meta.get("stempel_show_agf", True)),
|
||||||
|
}
|
||||||
|
new_te = _make_stempel_text(
|
||||||
|
pos, scope, doc, text_height=txt_h,
|
||||||
|
z=pos.Z, font=font, bold=bold, italic=italic,
|
||||||
|
header_text=header_text,
|
||||||
|
show_scope=bool(meta.get("stempel_show_scope", True)),
|
||||||
|
show_separators=bool(meta.get("stempel_show_seps", True)),
|
||||||
|
show_count=bool(meta.get("stempel_show_count", False)),
|
||||||
|
visibility=visibility)
|
||||||
if new_te is None: return False
|
if new_te is None: return False
|
||||||
# In-place replace
|
# In-place replace
|
||||||
try:
|
try:
|
||||||
@@ -6741,6 +6910,13 @@ class ElementeBridge(panel_base.BaseBridge):
|
|||||||
elif t == "DUPLICATE_RAUM_STIL":
|
elif t == "DUPLICATE_RAUM_STIL":
|
||||||
# p = {id, newName?} → kopiert Stil mit neuer uuid + Name
|
# p = {id, newName?} → kopiert Stil mit neuer uuid + Name
|
||||||
self._cmd_duplicate_raum_stil(p)
|
self._cmd_duplicate_raum_stil(p)
|
||||||
|
# Stempel-Stile (analog Raumstempel-Stile, eigene Storage)
|
||||||
|
elif t == "SAVE_STEMPEL_STIL":
|
||||||
|
self._cmd_save_stempel_stil(p)
|
||||||
|
elif t == "DELETE_STEMPEL_STIL":
|
||||||
|
self._cmd_delete_stempel_stil(p)
|
||||||
|
elif t == "APPLY_STEMPEL_STIL":
|
||||||
|
self._cmd_apply_stempel_stil(p)
|
||||||
elif t == "OPEN_ELEMENTE_UEBERSICHT":
|
elif t == "OPEN_ELEMENTE_UEBERSICHT":
|
||||||
try:
|
try:
|
||||||
import elemente_uebersicht
|
import elemente_uebersicht
|
||||||
@@ -6971,6 +7147,19 @@ class ElementeBridge(panel_base.BaseBridge):
|
|||||||
"font": meta.get("stempel_font", "") or "",
|
"font": meta.get("stempel_font", "") or "",
|
||||||
"bold": bool(meta.get("stempel_bold", False)),
|
"bold": bool(meta.get("stempel_bold", False)),
|
||||||
"italic": bool(meta.get("stempel_italic", False)),
|
"italic": bool(meta.get("stempel_italic", False)),
|
||||||
|
"header": meta.get("stempel_header", "Nutzflächen"),
|
||||||
|
"showScope": bool(meta.get("stempel_show_scope", True)),
|
||||||
|
"showHnf": bool(meta.get("stempel_show_hnf", True)),
|
||||||
|
"showNnf": bool(meta.get("stempel_show_nnf", True)),
|
||||||
|
"showNf": bool(meta.get("stempel_show_nf", True)),
|
||||||
|
"showVf": bool(meta.get("stempel_show_vf", True)),
|
||||||
|
"showFf": bool(meta.get("stempel_show_ff", True)),
|
||||||
|
"showNgf": bool(meta.get("stempel_show_ngf", True)),
|
||||||
|
"showGf": bool(meta.get("stempel_show_gf", True)),
|
||||||
|
"showAgf": bool(meta.get("stempel_show_agf", True)),
|
||||||
|
"showCount": bool(meta.get("stempel_show_count", False)),
|
||||||
|
"showSeparators": bool(meta.get("stempel_show_seps", True)),
|
||||||
|
"stilId": meta.get("stempel_stil_id", ""),
|
||||||
"bilanz": bilanz,
|
"bilanz": bilanz,
|
||||||
})
|
})
|
||||||
elif meta["type"] in ("stuetze_point", "traeger_axis"):
|
elif meta["type"] in ("stuetze_point", "traeger_axis"):
|
||||||
@@ -7025,6 +7214,7 @@ class ElementeBridge(panel_base.BaseBridge):
|
|||||||
for n, m in _get_all_materials(doc).items()],
|
for n, m in _get_all_materials(doc).items()],
|
||||||
"oeffStyles": list_oeff_styles(doc),
|
"oeffStyles": list_oeff_styles(doc),
|
||||||
"raumStempelStile": load_raum_stempel_stile(doc),
|
"raumStempelStile": load_raum_stempel_stile(doc),
|
||||||
|
"stempelStile": load_stempel_stile(doc),
|
||||||
}
|
}
|
||||||
self.send("STATE", payload)
|
self.send("STATE", payload)
|
||||||
# An Properties-Satellite-Window forwarden falls offen
|
# An Properties-Satellite-Window forwarden falls offen
|
||||||
@@ -9054,6 +9244,101 @@ class ElementeBridge(panel_base.BaseBridge):
|
|||||||
stil.get("name"), n_applied))
|
stil.get("name"), n_applied))
|
||||||
self._send_state()
|
self._send_state()
|
||||||
|
|
||||||
|
def _cmd_save_stempel_stil(self, p):
|
||||||
|
"""Speichert einen Stempel-Stil (Layout/Header/Font-Preset).
|
||||||
|
Payload: {id?, name, settings:{header, showScope, show*, font,
|
||||||
|
bold, italic, txtH}, applyToIds?: [stempel_id, ...]}.
|
||||||
|
"""
|
||||||
|
doc = Rhino.RhinoDoc.ActiveDoc
|
||||||
|
if doc is None: return
|
||||||
|
name = (p.get("name") or "").strip()
|
||||||
|
if not name:
|
||||||
|
print("[ELEMENTE] SAVE_STEMPEL_STIL: name leer"); return
|
||||||
|
settings = p.get("settings") or {}
|
||||||
|
sid = (p.get("id") or "").strip() or ("stestil_" + uuid.uuid4().hex[:8])
|
||||||
|
stile = load_stempel_stile(doc)
|
||||||
|
new_stil = {"id": sid, "name": name}
|
||||||
|
for f in _STEMPEL_STIL_FIELDS:
|
||||||
|
if f in settings: new_stil[f] = settings[f]
|
||||||
|
found = False
|
||||||
|
for i, s in enumerate(stile):
|
||||||
|
if s.get("id") == sid:
|
||||||
|
stile[i] = new_stil; found = True; break
|
||||||
|
if not found: stile.append(new_stil)
|
||||||
|
if save_stempel_stile(doc, stile):
|
||||||
|
print("[ELEMENTE] Stempel-Stil '{}' ({}) gespeichert".format(
|
||||||
|
name, sid))
|
||||||
|
# Apply on listed Stempel (nur stil_id schreiben)
|
||||||
|
for eid in (p.get("applyToIds") or []):
|
||||||
|
try:
|
||||||
|
src_obj, _ = _find_source(doc, eid)
|
||||||
|
if src_obj is None: continue
|
||||||
|
attrs = src_obj.Attributes.Duplicate()
|
||||||
|
attrs.SetUserString(_KEY_STEMPEL_STIL_ID, sid)
|
||||||
|
doc.Objects.ModifyAttributes(src_obj.Id, attrs, True)
|
||||||
|
except Exception as ex:
|
||||||
|
print("[ELEMENTE] save-stempel-stil apply-to:", ex)
|
||||||
|
self._send_state()
|
||||||
|
|
||||||
|
def _cmd_delete_stempel_stil(self, p):
|
||||||
|
doc = Rhino.RhinoDoc.ActiveDoc
|
||||||
|
if doc is None: return
|
||||||
|
sid = (p.get("id") or "").strip()
|
||||||
|
if not sid: return
|
||||||
|
stile = load_stempel_stile(doc)
|
||||||
|
stile = [s for s in stile if s.get("id") != sid]
|
||||||
|
if save_stempel_stile(doc, stile):
|
||||||
|
print("[ELEMENTE] Stempel-Stil {} geloescht".format(sid))
|
||||||
|
self._send_state()
|
||||||
|
|
||||||
|
def _cmd_apply_stempel_stil(self, p):
|
||||||
|
"""Wendet einen Stempel-Stil auf Stempel-IDs an. Wenn ids leer →
|
||||||
|
alle aktuell selektierten Stempel."""
|
||||||
|
doc = Rhino.RhinoDoc.ActiveDoc
|
||||||
|
if doc is None: return
|
||||||
|
sid = (p.get("stilId") or "").strip()
|
||||||
|
ids = p.get("ids") or []
|
||||||
|
if not sid: return
|
||||||
|
if not ids:
|
||||||
|
for obj in doc.Objects:
|
||||||
|
try:
|
||||||
|
if obj.IsSelected(False) <= 0: continue
|
||||||
|
m = _read_meta(obj)
|
||||||
|
if m and m.get("type") == "stempel":
|
||||||
|
ids.append(m["id"])
|
||||||
|
except Exception: pass
|
||||||
|
if not ids: return
|
||||||
|
stile = load_stempel_stile(doc)
|
||||||
|
stil = next((s for s in stile if s.get("id") == sid), None)
|
||||||
|
if stil is None:
|
||||||
|
print("[ELEMENTE] APPLY_STEMPEL_STIL: {} nicht gefunden".format(sid))
|
||||||
|
return
|
||||||
|
# Stil-Felder → Patch fuer _update_wall stempel-Branch
|
||||||
|
patch_base = {}
|
||||||
|
for f in _STEMPEL_STIL_FIELDS:
|
||||||
|
if f in stil: patch_base[f] = stil[f]
|
||||||
|
n = 0
|
||||||
|
for eid in ids:
|
||||||
|
try:
|
||||||
|
patch = dict(patch_base); patch["id"] = eid
|
||||||
|
self._update_wall(patch)
|
||||||
|
# stil_id markieren
|
||||||
|
try:
|
||||||
|
src_obj, _ = _find_source(doc, eid)
|
||||||
|
if src_obj is not None:
|
||||||
|
attrs = src_obj.Attributes.Duplicate()
|
||||||
|
attrs.SetUserString(_KEY_STEMPEL_STIL_ID, sid)
|
||||||
|
doc.Objects.ModifyAttributes(src_obj.Id, attrs, True)
|
||||||
|
except Exception: pass
|
||||||
|
n += 1
|
||||||
|
except Exception as ex:
|
||||||
|
print("[ELEMENTE] apply stempel-stil {} -> {}: {}".format(
|
||||||
|
sid, eid, ex))
|
||||||
|
if n > 0:
|
||||||
|
print("[ELEMENTE] Stempel-Stil '{}' auf {} Stempel angewendet".format(
|
||||||
|
stil.get("name"), n))
|
||||||
|
self._send_state()
|
||||||
|
|
||||||
def _cmd_create_symbol(self, p):
|
def _cmd_create_symbol(self, p):
|
||||||
"""Platziert ein Library-Item (symbol/object) im Doc. Interactive
|
"""Platziert ein Library-Item (symbol/object) im Doc. Interactive
|
||||||
GetPoint im aktiven Viewport — User klickt Position.
|
GetPoint im aktiven Viewport — User klickt Position.
|
||||||
@@ -10751,7 +11036,7 @@ class ElementeBridge(panel_base.BaseBridge):
|
|||||||
doc.Views.Redraw()
|
doc.Views.Redraw()
|
||||||
self._send_state()
|
self._send_state()
|
||||||
return
|
return
|
||||||
# Stempel: scope / txtH / font / bold / italic
|
# Stempel: scope / txtH / font / bold / italic + Layout-Custom
|
||||||
if old_meta["type"] == "stempel":
|
if old_meta["type"] == "stempel":
|
||||||
scope = p.get("scope", old_meta.get("stempel_scope", "total"))
|
scope = p.get("scope", old_meta.get("stempel_scope", "total"))
|
||||||
if not (scope == "total" or scope.startswith("geschoss:")):
|
if not (scope == "total" or scope.startswith("geschoss:")):
|
||||||
@@ -10761,12 +11046,47 @@ class ElementeBridge(panel_base.BaseBridge):
|
|||||||
st_font = p.get("font", old_meta.get("stempel_font", "") or "")
|
st_font = p.get("font", old_meta.get("stempel_font", "") or "")
|
||||||
st_bold = bool(p.get("bold", old_meta.get("stempel_bold", False)))
|
st_bold = bool(p.get("bold", old_meta.get("stempel_bold", False)))
|
||||||
st_ital = bool(p.get("italic", old_meta.get("stempel_italic", False)))
|
st_ital = bool(p.get("italic", old_meta.get("stempel_italic", False)))
|
||||||
|
st_header = p.get("header", old_meta.get("stempel_header", "Nutzflächen"))
|
||||||
|
st_show_scope = bool(p.get("showScope",
|
||||||
|
old_meta.get("stempel_show_scope", True)))
|
||||||
|
st_show_hnf = bool(p.get("showHnf",
|
||||||
|
old_meta.get("stempel_show_hnf", True)))
|
||||||
|
st_show_nnf = bool(p.get("showNnf",
|
||||||
|
old_meta.get("stempel_show_nnf", True)))
|
||||||
|
st_show_nf = bool(p.get("showNf",
|
||||||
|
old_meta.get("stempel_show_nf", True)))
|
||||||
|
st_show_vf = bool(p.get("showVf",
|
||||||
|
old_meta.get("stempel_show_vf", True)))
|
||||||
|
st_show_ff = bool(p.get("showFf",
|
||||||
|
old_meta.get("stempel_show_ff", True)))
|
||||||
|
st_show_ngf = bool(p.get("showNgf",
|
||||||
|
old_meta.get("stempel_show_ngf", True)))
|
||||||
|
st_show_gf = bool(p.get("showGf",
|
||||||
|
old_meta.get("stempel_show_gf", True)))
|
||||||
|
st_show_agf = bool(p.get("showAgf",
|
||||||
|
old_meta.get("stempel_show_agf", True)))
|
||||||
|
st_show_count = bool(p.get("showCount",
|
||||||
|
old_meta.get("stempel_show_count", False)))
|
||||||
|
st_show_seps = bool(p.get("showSeparators",
|
||||||
|
old_meta.get("stempel_show_seps", True)))
|
||||||
attrs = axis_obj.Attributes
|
attrs = axis_obj.Attributes
|
||||||
_attach_meta(attrs, wall_id, "stempel",
|
_attach_meta(attrs, wall_id, "stempel",
|
||||||
old_meta.get("geschoss", ""), 0.0, "", "", "mid",
|
old_meta.get("geschoss", ""), 0.0, "", "", "mid",
|
||||||
stempel_scope=scope, stempel_txt_h=st_th,
|
stempel_scope=scope, stempel_txt_h=st_th,
|
||||||
stempel_font=st_font, stempel_bold=st_bold,
|
stempel_font=st_font, stempel_bold=st_bold,
|
||||||
stempel_italic=st_ital)
|
stempel_italic=st_ital,
|
||||||
|
stempel_header=st_header,
|
||||||
|
stempel_show_scope=st_show_scope,
|
||||||
|
stempel_show_hnf=st_show_hnf,
|
||||||
|
stempel_show_nnf=st_show_nnf,
|
||||||
|
stempel_show_nf=st_show_nf,
|
||||||
|
stempel_show_vf=st_show_vf,
|
||||||
|
stempel_show_ff=st_show_ff,
|
||||||
|
stempel_show_ngf=st_show_ngf,
|
||||||
|
stempel_show_gf=st_show_gf,
|
||||||
|
stempel_show_agf=st_show_agf,
|
||||||
|
stempel_show_count=st_show_count,
|
||||||
|
stempel_show_seps=st_show_seps)
|
||||||
axis_obj.Attributes = attrs
|
axis_obj.Attributes = attrs
|
||||||
axis_obj.CommitChanges()
|
axis_obj.CommitChanges()
|
||||||
_save_last(stempel_txt_h=st_th)
|
_save_last(stempel_txt_h=st_th)
|
||||||
@@ -12759,6 +13079,46 @@ def regen_masstab_raeume(doc=None):
|
|||||||
return len(ids)
|
return len(ids)
|
||||||
|
|
||||||
|
|
||||||
|
def _sync_stempel_to_source(doc):
|
||||||
|
"""Spiegelt User-Edits am Stempel-TextEntity (Font/Bold/Italic/TextHeight)
|
||||||
|
auf die UserStrings. Damit ueberleben Oberleiste-/Properties-Aenderungen
|
||||||
|
am Stempel den naechsten Regen — sonst wuerden die meta-Werte beim
|
||||||
|
Re-Render wieder gewinnen. Stempel-Source IST die TextEntity selber."""
|
||||||
|
if doc is None: return
|
||||||
|
for obj in doc.Objects:
|
||||||
|
try:
|
||||||
|
m = _read_meta(obj)
|
||||||
|
if not m or m.get("type") != "stempel": continue
|
||||||
|
te = obj.Geometry
|
||||||
|
if not isinstance(te, rg.TextEntity): continue
|
||||||
|
try: new_h = float(te.TextHeight)
|
||||||
|
except Exception: new_h = float(m.get("stempel_txt_h", 0.20))
|
||||||
|
cur_font = None
|
||||||
|
try: cur_font = te.Font
|
||||||
|
except Exception: pass
|
||||||
|
try: new_face = cur_font.QuartetName if cur_font else ""
|
||||||
|
except Exception: new_face = ""
|
||||||
|
try: new_bold = bool(cur_font.Bold) if cur_font else False
|
||||||
|
except Exception: new_bold = False
|
||||||
|
try: new_ital = bool(cur_font.Italic) if cur_font else False
|
||||||
|
except Exception: new_ital = False
|
||||||
|
old_h = float(m.get("stempel_txt_h", 0.20))
|
||||||
|
old_face = m.get("stempel_font", "") or ""
|
||||||
|
old_bold = bool(m.get("stempel_bold", False))
|
||||||
|
old_ital = bool(m.get("stempel_italic", False))
|
||||||
|
if (abs(new_h - old_h) < 1e-6 and new_face == old_face
|
||||||
|
and new_bold == old_bold and new_ital == old_ital):
|
||||||
|
continue # nichts geaendert
|
||||||
|
attrs = obj.Attributes.Duplicate()
|
||||||
|
attrs.SetUserString(_KEY_STEMPEL_TXT_H, "{:.4f}".format(new_h))
|
||||||
|
attrs.SetUserString(_KEY_STEMPEL_FONT, new_face)
|
||||||
|
attrs.SetUserString(_KEY_STEMPEL_BOLD, "1" if new_bold else "0")
|
||||||
|
attrs.SetUserString(_KEY_STEMPEL_ITAL, "1" if new_ital else "0")
|
||||||
|
doc.Objects.ModifyAttributes(obj.Id, attrs, True)
|
||||||
|
except Exception as ex:
|
||||||
|
print("[ELEMENTE] sync stempel:", ex)
|
||||||
|
|
||||||
|
|
||||||
def _sync_raum_stamps_to_source(doc):
|
def _sync_raum_stamps_to_source(doc):
|
||||||
"""Sync raum_stamp TextEntities → raum_outline Source-UserStrings.
|
"""Sync raum_stamp TextEntities → raum_outline Source-UserStrings.
|
||||||
|
|
||||||
@@ -12959,6 +13319,8 @@ def _on_command_end(sender, e):
|
|||||||
_was_sync = sc.sticky.get(_REGEN_BUSY, False)
|
_was_sync = sc.sticky.get(_REGEN_BUSY, False)
|
||||||
sc.sticky[_REGEN_BUSY] = True
|
sc.sticky[_REGEN_BUSY] = True
|
||||||
try: _sync_raum_stamps_to_source(doc)
|
try: _sync_raum_stamps_to_source(doc)
|
||||||
|
except Exception: pass
|
||||||
|
try: _sync_stempel_to_source(doc)
|
||||||
finally: sc.sticky[_REGEN_BUSY] = _was_sync
|
finally: sc.sticky[_REGEN_BUSY] = _was_sync
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[ELEMENTE] stamp-sync:", ex)
|
print("[ELEMENTE] stamp-sync:", ex)
|
||||||
|
|||||||
+125
-15
@@ -12,6 +12,7 @@ import {
|
|||||||
updateElement, deleteElement, openElementeUebersicht, openElementeProperties,
|
updateElement, deleteElement, openElementeUebersicht, openElementeProperties,
|
||||||
saveOeffStyle, deleteOeffStyle,
|
saveOeffStyle, deleteOeffStyle,
|
||||||
saveRaumStil, deleteRaumStil, applyRaumStil,
|
saveRaumStil, deleteRaumStil, applyRaumStil,
|
||||||
|
saveStempelStil, deleteStempelStil, applyStempelStil,
|
||||||
listLibrary,
|
listLibrary,
|
||||||
} from './lib/rhinoBridge'
|
} from './lib/rhinoBridge'
|
||||||
|
|
||||||
@@ -512,7 +513,7 @@ function NeuesElementSection({ noGeschoss, activeName, elementsCount }) {
|
|||||||
|
|
||||||
// PropertiesView: gemeinsame Komponente, rendert die passende Property-
|
// PropertiesView: gemeinsame Komponente, rendert die passende Property-
|
||||||
// Form je nach Element-Typ. Wiederverwendbar in Inline + Satellite-Window.
|
// Form je nach Element-Typ. Wiederverwendbar in Inline + Satellite-Window.
|
||||||
export function PropertiesView({ selected, geschosse, materials, hatchPatterns, oeffStyles, fonts, raumStempelStile }) {
|
export function PropertiesView({ selected, geschosse, materials, hatchPatterns, oeffStyles, fonts, raumStempelStile, stempelStile }) {
|
||||||
if (!selected) return null
|
if (!selected) return null
|
||||||
const upd = (p) => updateElement(selected.id, p)
|
const upd = (p) => updateElement(selected.id, p)
|
||||||
const del = (label) => () => { if (window.confirm(`${label} löschen?`)) deleteElement(selected.id) }
|
const del = (label) => () => { if (window.confirm(`${label} löschen?`)) deleteElement(selected.id) }
|
||||||
@@ -539,6 +540,7 @@ export function PropertiesView({ selected, geschosse, materials, hatchPatterns,
|
|||||||
onUpdate={upd} onDelete={del('Raum')} />
|
onUpdate={upd} onDelete={del('Raum')} />
|
||||||
if (selected.kind === 'stempel')
|
if (selected.kind === 'stempel')
|
||||||
return <StempelProperties stempel={selected} geschosse={geschosse}
|
return <StempelProperties stempel={selected} geschosse={geschosse}
|
||||||
|
stempelStile={stempelStile || []}
|
||||||
onUpdate={upd} onDelete={del('Stempel')} />
|
onUpdate={upd} onDelete={del('Stempel')} />
|
||||||
|
|
||||||
if (selected.kind === 'aussparung')
|
if (selected.kind === 'aussparung')
|
||||||
@@ -594,7 +596,8 @@ export default function ElementeApp() {
|
|||||||
hatchPatterns={state.hatchPatterns}
|
hatchPatterns={state.hatchPatterns}
|
||||||
fonts={state.fonts || []}
|
fonts={state.fonts || []}
|
||||||
oeffStyles={state.oeffStyles || []}
|
oeffStyles={state.oeffStyles || []}
|
||||||
raumStempelStile={state.raumStempelStile || []} />
|
raumStempelStile={state.raumStempelStile || []}
|
||||||
|
stempelStile={state.stempelStile || []} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<NeuesElementSection
|
<NeuesElementSection
|
||||||
@@ -1168,21 +1171,76 @@ function RaumProperties({ raum, geschosse, onUpdate, onDelete, hatchPatterns, fo
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function StempelProperties({ stempel, geschosse, onUpdate, onDelete }) {
|
function StempelProperties({ stempel, geschosse, stempelStile, onUpdate, onDelete }) {
|
||||||
const scope = stempel.scope || 'total'
|
const scope = stempel.scope || 'total'
|
||||||
const bilanz = stempel.bilanz || {}
|
const bilanz = stempel.bilanz || {}
|
||||||
|
const stilList = stempelStile || []
|
||||||
|
const activeStilId = stempel.stilId || ''
|
||||||
|
const [headerDraft, setHeaderDraft] = useState(stempel.header || 'Nutzflächen')
|
||||||
|
useEffect(() => {
|
||||||
|
setHeaderDraft(stempel.header || 'Nutzflächen')
|
||||||
|
}, [stempel.id, stempel.header])
|
||||||
|
|
||||||
|
// Show-Flags vom Backend (default true ausser showCount)
|
||||||
|
const _show = (k, def = true) =>
|
||||||
|
(stempel[k] !== undefined ? !!stempel[k] : def)
|
||||||
|
|
||||||
|
const handleStilChange = (val) => {
|
||||||
|
if (val === '__save__') {
|
||||||
|
const n = (window.prompt('Name für neuen Stempel-Stil:', 'Stil') || '').trim()
|
||||||
|
if (!n) return
|
||||||
|
saveStempelStil('', n, {
|
||||||
|
header: stempel.header || 'Nutzflächen',
|
||||||
|
showScope: _show('showScope'),
|
||||||
|
showHnf: _show('showHnf'),
|
||||||
|
showNnf: _show('showNnf'),
|
||||||
|
showNf: _show('showNf'),
|
||||||
|
showVf: _show('showVf'),
|
||||||
|
showFf: _show('showFf'),
|
||||||
|
showNgf: _show('showNgf'),
|
||||||
|
showGf: _show('showGf'),
|
||||||
|
showAgf: _show('showAgf'),
|
||||||
|
showCount: _show('showCount', false),
|
||||||
|
showSeparators: _show('showSeparators'),
|
||||||
|
font: stempel.font || '',
|
||||||
|
bold: !!stempel.bold,
|
||||||
|
italic: !!stempel.italic,
|
||||||
|
txtH: stempel.txtH,
|
||||||
|
}, [stempel.id])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (val === '__delete__') {
|
||||||
|
if (activeStilId &&
|
||||||
|
window.confirm(`Stil "${stilList.find(s => s.id === activeStilId)?.name}" löschen?`))
|
||||||
|
deleteStempelStil(activeStilId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Empty ids → Backend nutzt aktuell selektierte Stempel
|
||||||
|
if (val) applyStempelStil(val, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sichtbare Zeilen fuer die Live-Vorschau (nur die mit Werten + Visibility)
|
||||||
const rows = [
|
const rows = [
|
||||||
{ key: 'hnf', label: 'HNF', val: bilanz.hnf },
|
{ key: 'hnf', label: 'HNF', val: bilanz.hnf, on: _show('showHnf') },
|
||||||
{ key: 'nnf', label: 'NNF', val: bilanz.nnf },
|
{ key: 'nnf', label: 'NNF', val: bilanz.nnf, on: _show('showNnf') },
|
||||||
{ key: 'nf', label: 'NF', val: bilanz.nf, accent: true,
|
{ key: 'nf', label: 'NF', val: bilanz.nf, on: _show('showNf'), accent: true,
|
||||||
hint: 'Nutzfläche = HNF + NNF' },
|
hint: 'Nutzfläche = HNF + NNF' },
|
||||||
{ key: 'vf', label: 'VF', val: bilanz.vf },
|
{ key: 'vf', label: 'VF', val: bilanz.vf, on: _show('showVf') },
|
||||||
{ key: 'ff', label: 'FF', val: bilanz.ff },
|
{ key: 'ff', label: 'FF', val: bilanz.ff, on: _show('showFf') },
|
||||||
{ key: 'ngf', label: 'NGF', val: bilanz.ngf,
|
{ key: 'ngf', label: 'NGF', val: bilanz.ngf, on: _show('showNgf'),
|
||||||
hint: 'Nettogeschossfläche = NF + VF + FF' },
|
hint: 'Nettogeschossfläche = NF + VF + FF' },
|
||||||
{ key: 'gf', label: 'GF', val: bilanz.gf },
|
{ key: 'gf', label: 'GF', val: bilanz.gf, on: _show('showGf') },
|
||||||
{ key: 'agf', label: 'AGF', val: bilanz.agf },
|
{ key: 'agf', label: 'AGF', val: bilanz.agf, on: _show('showAgf') },
|
||||||
].filter(r => r.val && r.val > 0)
|
].filter(r => r.on && r.val && r.val > 0)
|
||||||
|
|
||||||
|
const ShowTog = ({ field, label, hint }) => (
|
||||||
|
<BarToggle label={label}
|
||||||
|
icon={_show(field, field === 'showCount' ? false : true) ? 'check_box' : 'check_box_outline_blank'}
|
||||||
|
active={_show(field, field === 'showCount' ? false : true)}
|
||||||
|
onClick={() => onUpdate({ [field]: !_show(field, field === 'showCount' ? false : true) })}
|
||||||
|
title={hint || label} />
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
display: 'flex', flexDirection: 'column', gap: 8,
|
display: 'flex', flexDirection: 'column', gap: 8,
|
||||||
@@ -1202,6 +1260,23 @@ function StempelProperties({ stempel, geschosse, onUpdate, onDelete }) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Stil-Picker — analog Raumstempel-Stile */}
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||||
|
<span style={{ fontSize: 10, color: 'var(--text-secondary)', width: 60 }}>Stil</span>
|
||||||
|
<select value={activeStilId}
|
||||||
|
onChange={(e) => handleStilChange(e.target.value)}
|
||||||
|
style={{ flex: 1, fontSize: 11 }}
|
||||||
|
title="Gespeicherter Stempel-Stil — Klick wendet die Vorlage an">
|
||||||
|
<option value="">— Stil wählen —</option>
|
||||||
|
{stilList.map(s => (
|
||||||
|
<option key={s.id} value={s.id}>{s.name}</option>
|
||||||
|
))}
|
||||||
|
<option disabled>──────────</option>
|
||||||
|
<option value="__save__">+ Aktuelle Settings als Stil speichern…</option>
|
||||||
|
{activeStilId && <option value="__delete__">🗑 Aktiven Stil löschen</option>}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||||
<span style={{ fontSize: 10, color: 'var(--text-secondary)', width: 60 }}>Scope</span>
|
<span style={{ fontSize: 10, color: 'var(--text-secondary)', width: 60 }}>Scope</span>
|
||||||
<select value={scope}
|
<select value={scope}
|
||||||
@@ -1217,6 +1292,42 @@ function StempelProperties({ stempel, geschosse, onUpdate, onDelete }) {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Header-Input — frei editierbar, Default "Nutzflächen" */}
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||||
|
<span style={{ fontSize: 10, color: 'var(--text-secondary)', width: 60 }}>Header</span>
|
||||||
|
<input type="text" value={headerDraft}
|
||||||
|
onChange={(e) => setHeaderDraft(e.target.value)}
|
||||||
|
onBlur={() => {
|
||||||
|
const v = (headerDraft || '').trim()
|
||||||
|
if (v !== (stempel.header || '')) onUpdate({ header: v })
|
||||||
|
}}
|
||||||
|
onKeyDown={(e) => { if (e.key === 'Enter') e.target.blur() }}
|
||||||
|
placeholder="Nutzflächen"
|
||||||
|
style={{ flex: 1, fontSize: 11 }} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Show-Toggles — was im Stempel angezeigt wird */}
|
||||||
|
<div style={{
|
||||||
|
display: 'flex', flexDirection: 'column', gap: 4,
|
||||||
|
paddingTop: 6, borderTop: '1px dashed var(--border)',
|
||||||
|
}}>
|
||||||
|
<span style={{ ...labelXs, marginBottom: 2 }}>Anzeigen im Stempel</span>
|
||||||
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
|
||||||
|
<ShowTog field="showScope" label="Scope" hint="Header-Suffix · Total/Geschoss" />
|
||||||
|
<ShowTog field="showHnf" label="HNF" />
|
||||||
|
<ShowTog field="showNnf" label="NNF" />
|
||||||
|
<ShowTog field="showNf" label="NF" hint="Nutzfläche = HNF + NNF" />
|
||||||
|
<ShowTog field="showVf" label="VF" />
|
||||||
|
<ShowTog field="showFf" label="FF" />
|
||||||
|
<ShowTog field="showNgf" label="NGF" hint="Nettogeschossfläche" />
|
||||||
|
<ShowTog field="showGf" label="GF" />
|
||||||
|
<ShowTog field="showAgf" label="AGF" />
|
||||||
|
<ShowTog field="showCount" label="Anzahl" hint="Anzahl klassifizierter Räume" />
|
||||||
|
<ShowTog field="showSeparators" label="Linien" hint="Trennlinien zwischen Sections" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Live-Vorschau der Bilanz (nur sichtbare Zeilen) */}
|
||||||
<div style={{
|
<div style={{
|
||||||
paddingTop: 6, borderTop: '1px dashed var(--border)',
|
paddingTop: 6, borderTop: '1px dashed var(--border)',
|
||||||
fontSize: 10, fontFamily: 'DM Mono, monospace',
|
fontSize: 10, fontFamily: 'DM Mono, monospace',
|
||||||
@@ -1225,13 +1336,12 @@ function StempelProperties({ stempel, geschosse, onUpdate, onDelete }) {
|
|||||||
<div style={{ fontSize: 9, color: 'var(--text-muted)',
|
<div style={{ fontSize: 9, color: 'var(--text-muted)',
|
||||||
letterSpacing: '0.06em', textTransform: 'uppercase',
|
letterSpacing: '0.06em', textTransform: 'uppercase',
|
||||||
marginBottom: 4 }}>
|
marginBottom: 4 }}>
|
||||||
Bilanz · {bilanz.count || 0} Räume klassifiziert
|
Vorschau · {bilanz.count || 0} Räume klassifiziert
|
||||||
</div>
|
</div>
|
||||||
{rows.length === 0 ? (
|
{rows.length === 0 ? (
|
||||||
<div style={{ fontSize: 10, color: 'var(--text-muted)',
|
<div style={{ fontSize: 10, color: 'var(--text-muted)',
|
||||||
fontStyle: 'italic', padding: '4px 0' }}>
|
fontStyle: 'italic', padding: '4px 0' }}>
|
||||||
Keine klassifizierten Räume im Scope.
|
Nichts anzuzeigen — Räume mit SIA-Tag fehlen oder Felder deaktiviert.
|
||||||
Räume mit SIA-Tag (HNF/NNF/VF/FF/GF/AGF) erscheinen hier.
|
|
||||||
</div>
|
</div>
|
||||||
) : rows.map(r => (
|
) : rows.map(r => (
|
||||||
<div key={r.key} title={r.hint || ''}
|
<div key={r.key} title={r.hint || ''}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export default function ElementePropertiesApp() {
|
|||||||
fonts={state.fonts || []}
|
fonts={state.fonts || []}
|
||||||
oeffStyles={state.oeffStyles || []}
|
oeffStyles={state.oeffStyles || []}
|
||||||
raumStempelStile={state.raumStempelStile || []}
|
raumStempelStile={state.raumStempelStile || []}
|
||||||
|
stempelStile={state.stempelStile || []}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div style={{
|
<div style={{
|
||||||
|
|||||||
@@ -256,6 +256,15 @@ export function reorderRaumStile(ids) { send('REORDER_RAUM_STILE', { ids }) }
|
|||||||
export function duplicateRaumStil(id, newName) {
|
export function duplicateRaumStil(id, newName) {
|
||||||
send('DUPLICATE_RAUM_STIL', { id, newName })
|
send('DUPLICATE_RAUM_STIL', { id, newName })
|
||||||
}
|
}
|
||||||
|
// Stempel-Stile (analog Raumstempel-Stile, eigene Storage pro Doc)
|
||||||
|
export function saveStempelStil(id, name, settings, applyToIds) {
|
||||||
|
send('SAVE_STEMPEL_STIL', { id, name, settings,
|
||||||
|
applyToIds: applyToIds || [] })
|
||||||
|
}
|
||||||
|
export function deleteStempelStil(id) { send('DELETE_STEMPEL_STIL', { id }) }
|
||||||
|
export function applyStempelStil(stilId, ids) {
|
||||||
|
send('APPLY_STEMPEL_STIL', { stilId, ids })
|
||||||
|
}
|
||||||
export function setSectionStyle(enabled, source, color, pattern, scale, rotation,
|
export function setSectionStyle(enabled, source, color, pattern, scale, rotation,
|
||||||
opts = {}) {
|
opts = {}) {
|
||||||
send('SET_SECTION_STYLE', {
|
send('SET_SECTION_STYLE', {
|
||||||
|
|||||||
Reference in New Issue
Block a user