Panel-Konsistenz: Gestaltung context-aware + Tabellen-Cleanup
Gestaltung: - Backend detektiert geometryKind (curve / curveOpen / 3d / mixed), ignoriert DOSSIER-Source-Curves (wand_axis etc.) damit die Klassifikation einer Wand-Selektion (Axis + Volume) als reines 3D durchgeht. - UI zeigt sektion-spezifische Section-Heads: 2D-Curve → Fill+Pen, 3D-Solid → Section Style+Boundary. Section Style + Fill nutzen jetzt einen gemeinsamen HatchEditor (gleiche Controls). - _set_section_style schreibt per-Object SectionHatchIndex/Scale/ Rotation/Color via _try_set_attr-Multifallback. - Selection-Summary liest dieselben Properties zurueck. - ColorBar als Pill (borderRadius 999) statt eckig. - "Attribute"-Header oben raus (war alt + redundant). Ebenen / Zeichnungsebenen: - Aktive Zeile wieder als Pill (borderRadius 999) — aber ohne Margin/Shift, Inhalt springt nicht. Kein bold-text-change mehr. - Linker borderLeft komplett raus — vorher leere graue Spalte am Panel-Rand sichtbar. - Inhalt mehr nach links (Padding 8/6 statt 12). - Zeilen-minHeight 24, kompaktere Icons. - EbenenSettings: Ebene-Picker auf BarCombo. - GeschossManager: Gebaeudehoehe-Zeile raus, Stift→Settings-Icon. ElementeApp: - Alle btn-contained/btn-outlined → BarToggle (Wand-Aufbau, Raum- Align, Treppe-Lage/Modus, Oeffnung-Ref/Rahmen/Fluegel/Glas, AutoOverride). - ReferenzSelector → BarToggle. - "Neues Element"-Container ohne Box-Border, Header-Slot beherbergt Projektuebersicht-Pill statt label. - Property-Labels (UK/OK/Dicke/...) von text-muted auf text-secondary (war zu blass). - Gruener Accent-Border um Properties-Containern → normaler border. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -853,6 +853,18 @@ def _selection_summary(doc):
|
||||
fill_scales = set()
|
||||
fill_rots = set()
|
||||
has_closed_curves = False
|
||||
# Section-Style (3D)
|
||||
sec_enabled = set()
|
||||
sec_sources = set()
|
||||
sec_colors = set()
|
||||
sec_patterns = set()
|
||||
sec_scales = set()
|
||||
sec_rots = set()
|
||||
# Geometry-Kind-Klassifikation: 'curve' (closed planar 2D), 'curveOpen'
|
||||
# (offene Kurve), '3d' (Brep/Extrusion/Mesh — Volumen mit Schnittflaeche),
|
||||
# 'other'. Aggregiert ueber alle Selektions-Objekte zu kind=
|
||||
# 'curve' / '3d' / 'mixed' / 'other'.
|
||||
geometry_kinds = set()
|
||||
|
||||
for obj in objs:
|
||||
a = obj.Attributes
|
||||
@@ -895,6 +907,72 @@ def _selection_summary(doc):
|
||||
nm = _safe_layer_label(doc, layer, a.LayerIndex)
|
||||
layer_names.add(nm)
|
||||
|
||||
# Geometry-Klassifikation. DOSSIER-Source-Curves (wand_axis,
|
||||
# decke_outline, ...) sind Meta-Geometrie und keine User-facing
|
||||
# Form — fuer den Section/Fill-Entscheid ignorieren. Dann wird
|
||||
# eine Wand-Selektion (Achse + Volume) als reines 3D klassifiziert.
|
||||
g = obj.Geometry
|
||||
is_3d = isinstance(g, (rg.Brep, rg.Extrusion, rg.Mesh, rg.SubD))
|
||||
dossier_type = ""
|
||||
try: dossier_type = a.GetUserString("dossier_element_type") or ""
|
||||
except Exception: pass
|
||||
is_dossier_source = dossier_type.endswith(("_axis", "_outline", "_point"))
|
||||
if isinstance(g, rg.Curve) and not is_dossier_source:
|
||||
geometry_kinds.add('curve' if (g.IsClosed and g.IsPlanar()) else 'curveOpen')
|
||||
elif is_3d:
|
||||
geometry_kinds.add('3d')
|
||||
elif isinstance(g, rg.Curve) and is_dossier_source:
|
||||
pass # ignorieren — Volume zaehlt fuer die Klassifikation
|
||||
else:
|
||||
geometry_kinds.add('other')
|
||||
|
||||
# Section-Style aus Object-Attributes lesen (Rhino 8, mit Fallbacks
|
||||
# fuer Property-Namen die je nach Build variieren).
|
||||
if is_3d:
|
||||
src_attr = None
|
||||
try:
|
||||
src_attr = getattr(a, "SectionAttributesSource", None)
|
||||
except Exception: src_attr = None
|
||||
if src_attr is not None:
|
||||
try:
|
||||
src_name = str(src_attr).lower()
|
||||
if "layer" in src_name: sec_sources.add("layer")
|
||||
elif "object" in src_name: sec_sources.add("object")
|
||||
except Exception: pass
|
||||
# Hatch-Index/Scale/Rotation
|
||||
hidx = None
|
||||
for n in ("SectionHatchIndex", "HatchPatternIndex"):
|
||||
if hasattr(a, n):
|
||||
try:
|
||||
v = getattr(a, n)
|
||||
if v is not None: hidx = int(v); break
|
||||
except Exception: pass
|
||||
if hidx is not None and hidx >= 0 and hidx < doc.HatchPatterns.Count:
|
||||
sec_enabled.add(True)
|
||||
try: sec_patterns.add(doc.HatchPatterns[hidx].Name)
|
||||
except Exception: pass
|
||||
elif hidx == -1:
|
||||
sec_enabled.add(False)
|
||||
for n, target in (
|
||||
(("SectionHatchScale", "HatchPatternScale"), sec_scales),
|
||||
(("SectionHatchRotation", "HatchPatternRotation"), sec_rots),
|
||||
):
|
||||
for nn in n:
|
||||
if hasattr(a, nn):
|
||||
try:
|
||||
v = float(getattr(a, nn))
|
||||
target.add(round(v, 4)
|
||||
if target is sec_scales
|
||||
else round(math.degrees(v), 2))
|
||||
break
|
||||
except Exception: pass
|
||||
for n in ("SectionFillColor", "SectionHatchColor", "HatchColor"):
|
||||
if hasattr(a, n):
|
||||
try:
|
||||
c = _color_to_hex(getattr(a, n))
|
||||
if c: sec_colors.add(c); break
|
||||
except Exception: pass
|
||||
|
||||
# Fuellung
|
||||
if _is_closed_planar_curve(obj.Geometry):
|
||||
has_closed_curves = True
|
||||
@@ -987,6 +1065,18 @@ def _selection_summary(doc):
|
||||
"layerLinetype": single(layer_lts),
|
||||
"layerName": single(layer_names),
|
||||
"canFill": has_closed_curves,
|
||||
# Section-Style (3D)
|
||||
"sectionEnabled": single(sec_enabled),
|
||||
"sectionSource": single(sec_sources),
|
||||
"sectionColor": single(sec_colors),
|
||||
"sectionPattern": single(sec_patterns),
|
||||
"sectionScale": single(sec_scales),
|
||||
"sectionRotation": single(sec_rots),
|
||||
# geometryKind: 'curve' | 'curveOpen' | '3d' | 'mixed' | 'other'
|
||||
"geometryKind": (
|
||||
'mixed' if len(geometry_kinds & {'curve', 'curveOpen', '3d'}) > 1
|
||||
else (next(iter(geometry_kinds)) if len(geometry_kinds) == 1 else 'other')
|
||||
),
|
||||
"fillEnabled": single(fill_enabled),
|
||||
"fillColor": single(fill_colors),
|
||||
"fillSource": single(fill_sources),
|
||||
@@ -1061,6 +1151,15 @@ class GestaltungBridge(panel_base.BaseBridge):
|
||||
p.get("scale"),
|
||||
p.get("rotation"),
|
||||
)
|
||||
elif t == "SET_SECTION_STYLE":
|
||||
self._set_section_style(
|
||||
bool(p.get("enabled")),
|
||||
p.get("source", "object"),
|
||||
p.get("color"),
|
||||
p.get("pattern"),
|
||||
p.get("scale"),
|
||||
p.get("rotation"),
|
||||
)
|
||||
|
||||
def _send_selection(self):
|
||||
doc = Rhino.RhinoDoc.ActiveDoc
|
||||
@@ -1376,6 +1475,79 @@ class GestaltungBridge(panel_base.BaseBridge):
|
||||
doc.Views.Redraw()
|
||||
self._send_selection()
|
||||
|
||||
# ---- SectionStyle (per-Object, Rhino 8) -------------------------------
|
||||
|
||||
def _set_section_style(self, enabled, source, color_hex,
|
||||
pattern_name=None, scale=None, rotation_deg=None):
|
||||
"""Setzt Per-Object SectionStyle-Properties auf die selektierten
|
||||
3D-Objekte. Rhino 8 expone diese Properties auf ObjectAttributes
|
||||
unter teils variierenden Namen — wir versuchen die bekannten."""
|
||||
doc = Rhino.RhinoDoc.ActiveDoc
|
||||
objs = list(doc.Objects.GetSelectedObjects(False, False))
|
||||
is_layer_source = (source == "layer")
|
||||
|
||||
# Hatch-Pattern-Index ermitteln
|
||||
pat_idx = -1
|
||||
if pattern_name and pattern_name not in ("None", ""):
|
||||
try: pat_idx = doc.HatchPatterns.Find(pattern_name, True)
|
||||
except Exception: pat_idx = -1
|
||||
if pat_idx < 0 and pattern_name not in ("None", ""):
|
||||
try: pat_idx = doc.HatchPatterns.Find("Solid", True)
|
||||
except Exception: pat_idx = -1
|
||||
|
||||
col = _hex_to_color(color_hex) if color_hex else None
|
||||
scale_v = float(scale) if scale is not None else 1.0
|
||||
rot_rad = math.radians(float(rotation_deg)) if rotation_deg is not None else 0.0
|
||||
|
||||
def _try_set_attr(a, names, value):
|
||||
for n in names:
|
||||
if hasattr(a, n):
|
||||
try:
|
||||
setattr(a, n, value)
|
||||
return n
|
||||
except Exception: pass
|
||||
return None
|
||||
|
||||
n_ok = 0
|
||||
for obj in objs:
|
||||
geom = obj.Geometry
|
||||
if not isinstance(geom, (rg.Brep, rg.Extrusion, rg.Mesh, rg.SubD)):
|
||||
continue
|
||||
a = obj.Attributes.Duplicate()
|
||||
|
||||
# Source: FromLayer vs FromObject — verschiedene Enum-Namen
|
||||
if is_layer_source:
|
||||
# Versuche SectionAttributesSource auf FromLayer
|
||||
_try_set_attr(a, ("SectionAttributesSource",),
|
||||
Rhino.DocObjects.SectionAttributesSource.FromLayer
|
||||
if hasattr(Rhino.DocObjects, "SectionAttributesSource") else 0)
|
||||
else:
|
||||
_try_set_attr(a, ("SectionAttributesSource",),
|
||||
Rhino.DocObjects.SectionAttributesSource.FromObject
|
||||
if hasattr(Rhino.DocObjects, "SectionAttributesSource") else 1)
|
||||
|
||||
if not enabled or pattern_name == "None":
|
||||
# Hatch-Index auf -1 = keine Fuellung
|
||||
_try_set_attr(a, ("SectionHatchIndex", "HatchPatternIndex"), -1)
|
||||
else:
|
||||
if pat_idx >= 0:
|
||||
_try_set_attr(a, ("SectionHatchIndex", "HatchPatternIndex"), pat_idx)
|
||||
_try_set_attr(a, ("SectionHatchScale", "HatchPatternScale"), scale_v)
|
||||
_try_set_attr(a, ("SectionHatchRotation", "HatchPatternRotation"), rot_rad)
|
||||
if col is not None:
|
||||
_try_set_attr(a, ("SectionFillColor", "SectionHatchColor",
|
||||
"HatchColor"), col)
|
||||
|
||||
try:
|
||||
doc.Objects.ModifyAttributes(obj, a, True)
|
||||
n_ok += 1
|
||||
except Exception as ex:
|
||||
print("[GESTALTUNG] SectionStyle ModifyAttributes:", ex)
|
||||
|
||||
print("[GESTALTUNG] SectionStyle auf {} Objekt(e) appliziert".format(n_ok))
|
||||
doc.Views.Redraw()
|
||||
self._send_selection()
|
||||
|
||||
|
||||
# --- Selection-Events ----------------------------------------------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user