#! python 3 # -*- coding: utf-8 -*- """ text_editor.py React-WYSIWYG-Editor in Satellite-WebView (Topmost). User picked Frame in create_text(), dann oeffnet sich dieser Editor neben dem Frame. TextEditorBridge haelt Frame-Daten + Settings, auf COMMIT erstellt es die TextEntity und schliesst das Fenster. """ import os import sys import Rhino import Rhino.Geometry as rg import scriptcontext as sc _HERE = os.path.dirname(os.path.abspath(__file__)) if _HERE not in sys.path: sys.path.insert(0, _HERE) import panel_base import text_create class TextEditorBridge(panel_base.BaseBridge): def __init__(self, frame_data, settings, fonts): panel_base.BaseBridge.__init__(self, "text_editor") self._frame = frame_data # (origin, width, height, p1, p2) self._initial_settings = settings self._fonts = fonts self._form_ref = None def set_form(self, form): self._form_ref = form def _on_ready(self): self.send("INIT", { "settings": self._initial_settings, "fonts": self._fonts, }) def handle(self, data): if not isinstance(data, dict): return t = data.get("type", "") p = data.get("payload") or {} if t == "READY": self._on_ready() elif t == "COMMIT": self._commit(p) try: self._form_ref.Close() except Exception: pass elif t == "CANCEL": try: self._form_ref.Close() except Exception: pass def _commit(self, payload): import System doc = Rhino.RhinoDoc.ActiveDoc if doc is None or self._frame is None: return text = (payload.get("text") or "").strip() if not text: return st = payload.get("settings") or {} origin, width, height, _p1, _p2 = self._frame try: te = rg.TextEntity() te.Plane = rg.Plane(origin, rg.Vector3d.ZAxis) te.PlainText = text try: te.TextHeight = float(st.get("size") or 0.2) except Exception: pass text_create._apply_font( te, st.get("font") or "Helvetica", st.get("bold"), st.get("italic"), st.get("underline")) text_create._apply_align(te, st.get("align") or "left") for attr in ("FormatWidth", "TextWidth", "MaskWidth"): try: setattr(te, attr, width); break except Exception: pass try: te.TextIsWrapped = True except Exception: try: te.TextWrap = True except Exception: pass attrs = Rhino.DocObjects.ObjectAttributes() col = st.get("color") # [r,g,b] oder None if col is not None and len(col) >= 3: try: attrs.ColorSource = Rhino.DocObjects.ObjectColorSource.ColorFromObject attrs.ObjectColor = System.Drawing.Color.FromArgb( int(col[0]), int(col[1]), int(col[2])) except Exception as ex: print("[TEXT-EDITOR] color:", ex) attrs.SetUserString("dossier_text", "1") doc.Objects.AddText(te, attrs) doc.Views.Redraw() # Defaults speichern (ohne color) text_create.save_settings(doc, { "font": st.get("font"), "size": st.get("size"), "bold": st.get("bold"), "italic": st.get("italic"), "underline": st.get("underline"), "align": st.get("align"), }) except Exception as ex: print("[TEXT-EDITOR] commit:", ex) def open_with_frame(p1, p2, origin, width, height): """Aufgerufen aus text_create.create_text() nach Frame-Pick. Oeffnet das React-WYSIWYG-Editor-Fenster (Topmost) neben dem Frame. Non-blocking — Bridge handlet die Eingabe + erstellt TextEntity bei COMMIT. """ doc = Rhino.RhinoDoc.ActiveDoc settings = text_create.load_settings(doc) fonts = text_create.available_fonts() bridge = TextEditorBridge((origin, width, height, p1, p2), settings, fonts) sc.sticky["text_editor_bridge"] = bridge form = panel_base.open_satellite_window( "text_editor", title="Dossier Text", size=(640, 480), bridge=bridge, topmost=True) if form is not None: bridge.set_form(form)