Text-Editor: Toggle "Masstäblich" (AnnotationScaling)

Neuer Pill-Button in Row 3 neben "Zur Kamera": setzt
TextEntity.AnnotationScalingEnabled. Property-Name wird in mehreren
Varianten probiert (Rhino 8 API hat das je nach Build leicht anders
benannt). Zustand wird zusaetzlich als UserString
"dossier_text_scaled" persistiert, sodass open_for_edit den Toggle
auch dann korrekt restored wenn die API-Property nicht gelesen
werden kann.

Default = an (entspricht aktuellem Verhalten: Text skaliert mit der
Annotation-Scale des Layouts).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-21 13:23:30 +02:00
parent 6b3421e7af
commit ae80185064
2 changed files with 38 additions and 1 deletions
+29
View File
@@ -255,6 +255,22 @@ class TextEditorBridge(panel_base.BaseBridge):
te.DrawForward = bool(st.get("horizontalToView")) te.DrawForward = bool(st.get("horizontalToView"))
except Exception: pass except Exception: pass
# 6. Annotation-Scaling (Masstaeblich) — Rhino 8 hat das pro
# Annotation-Objekt. Property-Name variiert je nach Build,
# deshalb mehrere Varianten versuchen.
scale_flag = bool(st.get("scaleWithModel", True))
applied_scale = None
for prop in ("AnnotationScalingEnabled",
"IsAnnotationScalingEnabled",
"ModelSpaceScalingEnabled"):
try:
setattr(te, prop, scale_flag)
applied_scale = prop
break
except Exception: pass
if applied_scale is None:
print("[TEXT-EDITOR] AnnotationScaling-Property nicht gefunden")
attrs = Rhino.DocObjects.ObjectAttributes() attrs = Rhino.DocObjects.ObjectAttributes()
col = st.get("color") # [r,g,b] oder None col = st.get("color") # [r,g,b] oder None
if col is not None and len(col) >= 3: if col is not None and len(col) >= 3:
@@ -265,6 +281,7 @@ class TextEditorBridge(panel_base.BaseBridge):
except Exception as ex: except Exception as ex:
print("[TEXT-EDITOR] color:", ex) print("[TEXT-EDITOR] color:", ex)
attrs.SetUserString("dossier_text", "1") attrs.SetUserString("dossier_text", "1")
attrs.SetUserString("dossier_text_scaled", "1" if scale_flag else "0")
# Runs als JSON persistieren — beim Re-Open kann der Editor # Runs als JSON persistieren — beim Re-Open kann der Editor
# die ganze Struktur (Fonts/Sizes/Styles pro Segment) wieder # die ganze Struktur (Fonts/Sizes/Styles pro Segment) wieder
# herstellen statt nur PlainText zu zeigen. # herstellen statt nur PlainText zu zeigen.
@@ -513,6 +530,18 @@ def open_for_edit(obj):
settings["align"] = "right" settings["align"] = "right"
else: settings["align"] = "left" else: settings["align"] = "left"
except Exception: pass except Exception: pass
try:
flag = obj.Attributes.GetUserString("dossier_text_scaled")
if flag in ("0", "1"):
settings["scaleWithModel"] = (flag == "1")
else:
for prop in ("AnnotationScalingEnabled",
"IsAnnotationScalingEnabled",
"ModelSpaceScalingEnabled"):
if hasattr(te, prop):
settings["scaleWithModel"] = bool(getattr(te, prop))
break
except Exception: pass
try: try:
v = te.TextVerticalAlignment v = te.TextVerticalAlignment
VA = Rhino.DocObjects.TextVerticalAlignment VA = Rhino.DocObjects.TextVerticalAlignment
+9 -1
View File
@@ -248,6 +248,7 @@ export default function TextEditorApp() {
const [horizontalToView, setHorizontalToView] = useState(false) const [horizontalToView, setHorizontalToView] = useState(false)
const [rotation, setRotation] = useState(0) const [rotation, setRotation] = useState(0)
const [valign, setVAlign] = useState('top') // top | middle | bottom const [valign, setVAlign] = useState('top') // top | middle | bottom
const [scaleWithModel, setScaleWithModel] = useState(true)
const [maskType, setMaskType] = useState('none') // none | viewport | solid const [maskType, setMaskType] = useState('none') // none | viewport | solid
const [maskColor, setMaskColor] = useState([255, 255, 255]) const [maskColor, setMaskColor] = useState([255, 255, 255])
const [maskMargin, setMaskMargin] = useState(0) const [maskMargin, setMaskMargin] = useState(0)
@@ -328,6 +329,7 @@ export default function TextEditorApp() {
if (s.underline != null) setUnderline(!!s.underline) if (s.underline != null) setUnderline(!!s.underline)
if (s.align) setAlign(s.align) if (s.align) setAlign(s.align)
if (s.valign) setVAlign(s.valign) if (s.valign) setVAlign(s.valign)
if (s.scaleWithModel != null) setScaleWithModel(!!s.scaleWithModel)
if (s.maskType) setMaskType(s.maskType) if (s.maskType) setMaskType(s.maskType)
if (Array.isArray(s.maskColor)) setMaskColor(s.maskColor) if (Array.isArray(s.maskColor)) setMaskColor(s.maskColor)
// Bei Edit-Mode: bestehenden Text in den Editor laden. Wenn Runs // Bei Edit-Mode: bestehenden Text in den Editor laden. Wenn Runs
@@ -467,7 +469,7 @@ export default function TextEditorApp() {
runs, runs,
settings: { settings: {
font, size, bold, italic, underline, align, valign, color, font, size, bold, italic, underline, align, valign, color,
frame, horizontalToView, rotation, frame, horizontalToView, rotation, scaleWithModel,
maskType, maskColor, maskMargin, maskType, maskColor, maskMargin,
}, },
}) })
@@ -659,6 +661,12 @@ export default function TextEditorApp() {
<Icon name="screen_rotation" size={13} /> <Icon name="screen_rotation" size={13} />
<span style={{ fontSize: 10 }}>Zur Kamera</span> <span style={{ fontSize: 10 }}>Zur Kamera</span>
</Pill> </Pill>
<Pill active={scaleWithModel}
onClick={() => setScaleWithModel(b => !b)}
title="Text skaliert sich mit dem Massstab (Annotation Scaling). Aus = absolute Modellhöhe.">
<Icon name="zoom_out_map" size={13} />
<span style={{ fontSize: 10 }}>Masstäblich</span>
</Pill>
<div style={{ position: 'relative' }}> <div style={{ position: 'relative' }}>
<Pill onClick={() => setSymbolsOpen(o => !o)} <Pill onClick={() => setSymbolsOpen(o => !o)}
active={symbolsOpen} active={symbolsOpen}