Text-Editor: B/I/U sync via queryCommandState + RTF-Reihenfolge fixen
User: B/I/U Toggle-Buttons hinken hinterher oder zeigen invertiert. Im WYSIWYG sieht alles richtig aus aber Rhino zeigt nur die LETZTE gesetzte Schriftart fuer alles. Fix 1 — B/I/U sync: - selectionchange-Listener pollt jetzt queryCommandState fuer bold/italic/underline und syncen das an Toolbar-State - toggleBold/Italic/Underline machen nur noch exec() — kein manuelles setBold(b => !b) mehr (war out-of-sync wenn execCommand wegen fehlender Selection nicht griff) - B/I/U-Button-Highlight reflektiert jetzt die echte Cursor-Position Fix 2 — RTF nimmt nur letzte Schrift: Reihenfolge im _commit war falsch. Vorher: RichText → TextHeight → _apply_font → _apply_align. _apply_font setzt te.Font (Default-Font) NACH dem RichText → schiesst die per-Run-Fonts in der RTF tot. Neue Reihenfolge: 1. PlainText (Initial-Content) 2. TextHeight, Font, Align (Defaults fuer ALLES) 3. RichText (ueberschreibt Defaults pro Run) Plus Font-Tabelle in _runs_to_rtf jetzt mit \fnil\fcharset0 Marker (Rhinos RTF-Parser kann sonst font-Eintraege ignorieren und Default verwenden). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+24
-17
@@ -147,21 +147,13 @@ class TextEditorBridge(panel_base.BaseBridge):
|
|||||||
except Exception: pass
|
except Exception: pass
|
||||||
te.Plane = plane
|
te.Plane = plane
|
||||||
|
|
||||||
# Rich-Text (Phase 2) wenn vorhanden + nicht-trivial, sonst Plain
|
# REIHENFOLGE WICHTIG:
|
||||||
rtf = _runs_to_rtf(
|
# 1. Plain-Text setzen (Initial-Content)
|
||||||
runs,
|
# 2. Default-Font / TextHeight / Align setzen (gilt fuer alles)
|
||||||
st.get("font") or "Helvetica",
|
# 3. RichText setzen (ZULETZT — die per-Run-Format-Codes
|
||||||
base_size_m=float(st.get("size") or 0.2)) if runs else None
|
# ueberschreiben dann die Default-Properties)
|
||||||
applied_rtf = False
|
# Andere Reihenfolge → Defaults schiessen die RTF-Runs weg.
|
||||||
if rtf:
|
te.PlainText = text
|
||||||
try:
|
|
||||||
te.RichText = rtf
|
|
||||||
applied_rtf = True
|
|
||||||
except Exception as ex:
|
|
||||||
print("[TEXT-EDITOR] RichText set fail:", ex)
|
|
||||||
if not applied_rtf:
|
|
||||||
te.PlainText = text
|
|
||||||
|
|
||||||
try: te.TextHeight = float(st.get("size") or 0.2)
|
try: te.TextHeight = float(st.get("size") or 0.2)
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
text_create._apply_font(
|
text_create._apply_font(
|
||||||
@@ -170,6 +162,19 @@ class TextEditorBridge(panel_base.BaseBridge):
|
|||||||
st.get("bold"), st.get("italic"),
|
st.get("bold"), st.get("italic"),
|
||||||
st.get("underline"))
|
st.get("underline"))
|
||||||
text_create._apply_align(te, st.get("align") or "left")
|
text_create._apply_align(te, st.get("align") or "left")
|
||||||
|
|
||||||
|
# RichText (Phase 2) — ZULETZT, ueberschreibt te.Font fuer
|
||||||
|
# alle Runs die eine eigene Schrift haben.
|
||||||
|
rtf = _runs_to_rtf(
|
||||||
|
runs,
|
||||||
|
st.get("font") or "Helvetica",
|
||||||
|
base_size_m=float(st.get("size") or 0.2)) if runs else None
|
||||||
|
if rtf:
|
||||||
|
try:
|
||||||
|
te.RichText = rtf
|
||||||
|
except Exception as ex:
|
||||||
|
print("[TEXT-EDITOR] RichText set fail:", ex)
|
||||||
|
|
||||||
for attr in ("FormatWidth", "TextWidth", "MaskWidth"):
|
for attr in ("FormatWidth", "TextWidth", "MaskWidth"):
|
||||||
try:
|
try:
|
||||||
setattr(te, attr, width); break
|
setattr(te, attr, width); break
|
||||||
@@ -315,10 +320,12 @@ def _runs_to_rtf(runs, default_font, base_size_m=0.20):
|
|||||||
colors.append(rgb)
|
colors.append(rgb)
|
||||||
return len(colors)
|
return len(colors)
|
||||||
|
|
||||||
parts = ["{\\rtf1\\ansi\\deff0"]
|
parts = ["{\\rtf1\\ansi\\ansicpg1252\\deff0"]
|
||||||
parts.append("{\\fonttbl")
|
parts.append("{\\fonttbl")
|
||||||
for i, f in enumerate(fonts):
|
for i, f in enumerate(fonts):
|
||||||
parts.append("{{\\f{} {};}}".format(i, f))
|
# Rhinos RTF-Parser will fnil/fcharset0 — sonst kann es passieren
|
||||||
|
# dass der font-Eintrag ignoriert wird und ein Default verwendet
|
||||||
|
parts.append("{{\\f{}\\fnil\\fcharset0 {};}}".format(i, f))
|
||||||
parts.append("}")
|
parts.append("}")
|
||||||
if colors:
|
if colors:
|
||||||
parts.append("{\\colortbl;")
|
parts.append("{\\colortbl;")
|
||||||
|
|||||||
@@ -237,6 +237,10 @@ export default function TextEditorApp() {
|
|||||||
if (ed.contains(sel.anchorNode)) {
|
if (ed.contains(sel.anchorNode)) {
|
||||||
try { savedRangeRef.current = sel.getRangeAt(0).cloneRange() }
|
try { savedRangeRef.current = sel.getRangeAt(0).cloneRange() }
|
||||||
catch (e) {}
|
catch (e) {}
|
||||||
|
// B/I/U Toolbar-State an die echte Cursor-Position syncen
|
||||||
|
try { setBold(document.queryCommandState('bold')) } catch (e) {}
|
||||||
|
try { setItalic(document.queryCommandState('italic')) } catch (e) {}
|
||||||
|
try { setUnderline(document.queryCommandState('underline')) } catch (e) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
document.addEventListener('selectionchange', onSelChange)
|
document.addEventListener('selectionchange', onSelChange)
|
||||||
@@ -322,9 +326,11 @@ export default function TextEditorApp() {
|
|||||||
fn()
|
fn()
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleBold = () => { setBold(b => !b); exec('bold') }
|
// setState NICHT manuell — der selectionchange-Listener syncen das
|
||||||
const toggleItalic = () => { setItalic(b => !b); exec('italic') }
|
// an die echte queryCommandState-Antwort, sonst hinkt's hinterher.
|
||||||
const toggleUnderline = () => { setUnderline(b => !b); exec('underline') }
|
const toggleBold = () => exec('bold')
|
||||||
|
const toggleItalic = () => exec('italic')
|
||||||
|
const toggleUnderline = () => exec('underline')
|
||||||
const doAlign = (a) => { setAlign(a)
|
const doAlign = (a) => { setAlign(a)
|
||||||
exec(a === 'center' ? 'justifyCenter' : a === 'right' ? 'justifyRight' : 'justifyLeft') }
|
exec(a === 'center' ? 'justifyCenter' : a === 'right' ? 'justifyRight' : 'justifyLeft') }
|
||||||
const doSup = () => exec('superscript')
|
const doSup = () => exec('superscript')
|
||||||
|
|||||||
Reference in New Issue
Block a user