Text-Editor zurueck auf Dialog.ShowModal (chromeloses Form ging nicht)
User: Frame wird gezeichnet aber Editor erscheint nicht — kann nicht schreiben. Eto.Form mit WindowStyle.None + Form.Show() funktioniert auf Mac WebKit/Rhino-Build nicht zuverlaessig (kein Render oder hinter Rhino- Window). Fix: Eto.Dialog mit ShowModal — laeuft proven auf Mac+Windows. Dialog hat normale Chrome (Title-Bar, OK/Cancel-Buttons) aber wird neben dem gepickten Frame positioniert (via vp.WorldToScreen + view.ScreenRectangle → Dialog.Location 20px rechts vom Frame). Tradeoff zu "inline im Viewport": Dialog hat Rahmen, aber ist sichtbar und funktional. Workflow: pick Frame → Dialog poppt neben Frame mit TextArea + OK/Cancel + Cmd/Ctrl+Enter Shortcut + Esc-Abbruch. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+70
-47
@@ -198,40 +198,47 @@ def _prompt_for_text(default=""):
|
|||||||
|
|
||||||
|
|
||||||
def _inline_editor(p1, p2, initial=""):
|
def _inline_editor(p1, p2, initial=""):
|
||||||
"""Inline-Editor: chromeloses Eto.Form ueber dem gepickten Frame im
|
"""Editor-Dialog mit Multi-Line-TextArea, positioniert NEBEN dem
|
||||||
Viewport positioniert. Cmd+Enter / Ctrl+Enter = commit, Esc = abbrechen.
|
gepickten Frame (statt zentriert). Eto.Dialog.ShowModal — reliable
|
||||||
Returns Text-String oder None."""
|
auf Mac/Win. Returns Text-String oder None."""
|
||||||
import Eto.Forms as forms
|
import Eto.Forms as forms
|
||||||
import Eto.Drawing as drawing
|
import Eto.Drawing as drawing
|
||||||
|
|
||||||
|
# Frame-Position im Screen ermitteln (fuer Dialog-Positionierung)
|
||||||
|
sx = sy = None
|
||||||
|
sw = max(360, 280)
|
||||||
|
sh = max(180, 150)
|
||||||
try:
|
try:
|
||||||
view = Rhino.RhinoDoc.ActiveDoc.Views.ActiveView
|
view = Rhino.RhinoDoc.ActiveDoc.Views.ActiveView
|
||||||
vp = view.ActiveViewport
|
vp = view.ActiveViewport
|
||||||
# WorldToScreen → (bool, int_x, int_y) viewport-lokale Pixel
|
|
||||||
ok1, x1, y1 = vp.WorldToScreen(p1)
|
ok1, x1, y1 = vp.WorldToScreen(p1)
|
||||||
ok2, x2, y2 = vp.WorldToScreen(p2)
|
ok2, x2, y2 = vp.WorldToScreen(p2)
|
||||||
view_rect = view.ScreenRectangle # absolute Viewport-Position
|
if ok1 and ok2:
|
||||||
|
view_rect = view.ScreenRectangle
|
||||||
|
fx = view_rect.X + min(x1, x2)
|
||||||
|
fy = view_rect.Y + min(y1, y2)
|
||||||
|
fw = abs(x2 - x1); fh = abs(y2 - y1)
|
||||||
|
# Dialog rechts neben dem Frame platzieren (oder darunter wenn
|
||||||
|
# rechts kein Platz). Falls Frame klein, Dialog hat eigene Min-
|
||||||
|
# Groesse.
|
||||||
|
sx = int(fx + fw + 20)
|
||||||
|
sy = int(fy)
|
||||||
|
sw = max(360, fw)
|
||||||
|
sh = max(180, fh)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[TEXT] viewport-coords:", ex)
|
print("[TEXT] viewport-coords:", ex)
|
||||||
return None
|
|
||||||
if not (ok1 and ok2):
|
|
||||||
return None
|
|
||||||
# Frame-Rect in absoluten Screen-Pixeln
|
|
||||||
sx = view_rect.X + min(x1, x2)
|
|
||||||
sy = view_rect.Y + min(y1, y2)
|
|
||||||
sw = max(60, abs(x2 - x1))
|
|
||||||
sh = max(28, abs(y2 - y1))
|
|
||||||
|
|
||||||
form = forms.Form()
|
dlg = forms.Dialog()
|
||||||
try: form.WindowStyle = forms.WindowStyle.None_
|
dlg.Title = "Text einfuegen"
|
||||||
except Exception:
|
dlg.Resizable = True
|
||||||
try: form.WindowStyle = getattr(forms.WindowStyle, "None")
|
dlg.Padding = drawing.Padding(8)
|
||||||
|
try: dlg.MinimumSize = drawing.Size(360, 180)
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
try: form.Topmost = True
|
try: dlg.ClientSize = drawing.Size(int(sw), int(sh))
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
form.Resizable = False
|
# Position neben dem Frame (falls verfuegbar)
|
||||||
form.ClientSize = drawing.Size(int(sw), int(sh))
|
if sx is not None and sy is not None:
|
||||||
try:
|
try: dlg.Location = drawing.Point(sx, sy)
|
||||||
form.Location = drawing.Point(int(sx), int(sy))
|
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
|
|
||||||
ta = forms.TextArea()
|
ta = forms.TextArea()
|
||||||
@@ -241,12 +248,26 @@ def _inline_editor(p1, p2, initial=""):
|
|||||||
ta.Text = initial or ""
|
ta.Text = initial or ""
|
||||||
try: ta.Font = drawing.Font("Helvetica", 13)
|
try: ta.Font = drawing.Font("Helvetica", 13)
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
try: ta.BackgroundColor = drawing.Color.FromArgb(245, 245, 245)
|
|
||||||
except Exception: pass
|
|
||||||
ta.ShowBorder = False
|
|
||||||
|
|
||||||
result = {"text": None, "committed": False}
|
result = {"text": None, "committed": False}
|
||||||
|
|
||||||
|
ok_btn = forms.Button()
|
||||||
|
ok_btn.Text = "Einfuegen"
|
||||||
|
cancel_btn = forms.Button()
|
||||||
|
cancel_btn.Text = "Abbrechen"
|
||||||
|
|
||||||
|
def on_ok(s, e):
|
||||||
|
result["text"] = ta.Text or ""
|
||||||
|
result["committed"] = True
|
||||||
|
try: dlg.Close()
|
||||||
|
except Exception: pass
|
||||||
|
def on_cancel(s, e):
|
||||||
|
try: dlg.Close()
|
||||||
|
except Exception: pass
|
||||||
|
ok_btn.Click += on_ok
|
||||||
|
cancel_btn.Click += on_cancel
|
||||||
|
|
||||||
|
# Cmd/Ctrl+Enter Shortcut im TextArea
|
||||||
def on_keydown(sender, e):
|
def on_keydown(sender, e):
|
||||||
try:
|
try:
|
||||||
is_cmd = (e.Modifiers == forms.Keys.Application or
|
is_cmd = (e.Modifiers == forms.Keys.Application or
|
||||||
@@ -254,34 +275,36 @@ def _inline_editor(p1, p2, initial=""):
|
|||||||
except Exception:
|
except Exception:
|
||||||
is_cmd = False
|
is_cmd = False
|
||||||
if e.Key == forms.Keys.Enter and is_cmd:
|
if e.Key == forms.Keys.Enter and is_cmd:
|
||||||
result["text"] = ta.Text or ""
|
on_ok(sender, e); e.Handled = True
|
||||||
result["committed"] = True
|
|
||||||
try: form.Close()
|
|
||||||
except Exception: pass
|
|
||||||
e.Handled = True
|
|
||||||
elif e.Key == forms.Keys.Escape:
|
elif e.Key == forms.Keys.Escape:
|
||||||
try: form.Close()
|
on_cancel(sender, e); e.Handled = True
|
||||||
except Exception: pass
|
|
||||||
e.Handled = True
|
|
||||||
|
|
||||||
ta.KeyDown += on_keydown
|
ta.KeyDown += on_keydown
|
||||||
form.Content = ta
|
|
||||||
|
|
||||||
try: form.Show()
|
layout = forms.DynamicLayout()
|
||||||
except Exception as ex:
|
layout.Spacing = drawing.Size(6, 6)
|
||||||
print("[TEXT] inline editor show:", ex)
|
layout.BeginVertical()
|
||||||
return None
|
layout.AddRow(ta)
|
||||||
try: ta.Focus()
|
layout.EndVertical()
|
||||||
|
layout.BeginVertical()
|
||||||
|
layout.BeginHorizontal()
|
||||||
|
layout.Add(None, True, False)
|
||||||
|
layout.Add(cancel_btn)
|
||||||
|
layout.Add(ok_btn)
|
||||||
|
layout.EndHorizontal()
|
||||||
|
layout.EndVertical()
|
||||||
|
dlg.Content = layout
|
||||||
|
try:
|
||||||
|
dlg.DefaultButton = ok_btn
|
||||||
|
dlg.AbortButton = cancel_btn
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
|
|
||||||
# Warten bis User Esc oder Cmd+Enter drueckt
|
|
||||||
while True:
|
|
||||||
try:
|
try:
|
||||||
if form.Closed: break
|
parent = Rhino.UI.RhinoEtoApp.MainWindow
|
||||||
except Exception:
|
if parent is not None: dlg.ShowModal(parent)
|
||||||
break
|
else: dlg.ShowModal()
|
||||||
try: Rhino.RhinoApp.Wait()
|
except Exception as ex:
|
||||||
except Exception: break
|
print("[TEXT] dialog show:", ex)
|
||||||
|
return None
|
||||||
|
|
||||||
if not result["committed"]: return None
|
if not result["committed"]: return None
|
||||||
return (result["text"] or "").strip() or None
|
return (result["text"] or "").strip() or None
|
||||||
|
|||||||
Reference in New Issue
Block a user