Add Page Editor toolbar toggles and widen the default window
Edit mode, snap to grid and the widgets/properties pane are now toggles on the main toolbar while the Page Editor is open. Outside edit mode the page and the property sheet are read-only; drags snap to the 10px grid when snapping is on. The default window grows by the right pane's width so the canvas is not squeezed when the pane shows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+47
-3
@@ -574,6 +574,10 @@ class OxWidgetPropertiesPanel:
|
||||
self.repaint = repaint
|
||||
self.comp = None
|
||||
self.rows = []
|
||||
# Off until the Page Editor's edit mode is switched on: every field is then shown
|
||||
# but none of them takes input, and no write reaches `commit`.
|
||||
self.editable = False
|
||||
self._controls = [] # (widget, state when editable) for every input on the sheet
|
||||
self.frame = ttk.Frame(parent)
|
||||
|
||||
self._name_font = tkfont.Font(family="Segoe UI", size=9)
|
||||
@@ -637,6 +641,7 @@ class OxWidgetPropertiesPanel:
|
||||
for child in self._sheet.winfo_children():
|
||||
child.destroy()
|
||||
self.rows = []
|
||||
self._controls = []
|
||||
self._status_var.set("")
|
||||
|
||||
if self.comp is None:
|
||||
@@ -649,9 +654,36 @@ class OxWidgetPropertiesPanel:
|
||||
|
||||
for grid_row, prop in enumerate(build_props(self.comp)):
|
||||
self.rows.append(self._build_row(grid_row, prop))
|
||||
self._apply_editable()
|
||||
self.reload()
|
||||
self._canvas.yview_moveto(0)
|
||||
|
||||
def set_editable(self, editable):
|
||||
"""Edit mode on or off: the fields take input, or only show their values."""
|
||||
self.editable = editable
|
||||
self._apply_editable()
|
||||
|
||||
def _apply_editable(self):
|
||||
for widget, editable_state in self._controls:
|
||||
state = editable_state if self.editable else "disabled"
|
||||
# Combobox first: it is an Entry too, and "readonly" would still let it pick.
|
||||
if isinstance(widget, ttk.Combobox):
|
||||
widget.configure(state=state)
|
||||
elif isinstance(widget, tk.Entry):
|
||||
widget.configure(state="normal" if self.editable else "readonly")
|
||||
else:
|
||||
widget.state(["!disabled"] if self.editable else ["disabled"])
|
||||
if self.comp is not None:
|
||||
self._status_var.set("" if self.editable else
|
||||
"View mode — switch on edit mode (✏) to change values.")
|
||||
|
||||
def _guarded(self, command):
|
||||
"""`command`, run only while the sheet is editable."""
|
||||
def run(*args):
|
||||
if self.editable:
|
||||
return command(*args)
|
||||
return run
|
||||
|
||||
def flush_edits(self):
|
||||
"""Commits a typed value still sitting in its field.
|
||||
|
||||
@@ -695,7 +727,9 @@ class OxWidgetPropertiesPanel:
|
||||
return label
|
||||
|
||||
def _dots(self, cell, command):
|
||||
ttk.Button(cell, text="…", width=3, command=command).pack(side=tk.RIGHT, padx=1)
|
||||
button = ttk.Button(cell, text="…", width=3, command=self._guarded(command))
|
||||
button.pack(side=tk.RIGHT, padx=1)
|
||||
self._controls.append((button, None))
|
||||
|
||||
def _build_readonly(self, cell, row):
|
||||
self._value_label(cell, row, READONLY_FG)
|
||||
@@ -712,6 +746,10 @@ class OxWidgetPropertiesPanel:
|
||||
|
||||
def commit(_event=None):
|
||||
text = var.get()
|
||||
if not self.editable:
|
||||
if text != row["loaded"]:
|
||||
var.set(row["loaded"])
|
||||
return
|
||||
if text != row["loaded"]:
|
||||
# Taken as loaded first: the write repaints, and the repaint must not
|
||||
# find this same edit still pending and commit it a second time.
|
||||
@@ -739,6 +777,7 @@ class OxWidgetPropertiesPanel:
|
||||
highlightbackground=SHEET_BG)
|
||||
entry.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=2, pady=1)
|
||||
self._bind_commit(entry, row)
|
||||
self._controls.append((entry, None))
|
||||
|
||||
def _build_image(self, cell, row):
|
||||
combo = ttk.Combobox(cell, textvariable=row["var"], font=self._name_font,
|
||||
@@ -746,6 +785,7 @@ class OxWidgetPropertiesPanel:
|
||||
combo.pack(fill=tk.BOTH, expand=True, padx=1)
|
||||
commit = self._bind_commit(combo, row)
|
||||
combo.bind("<<ComboboxSelected>>", commit)
|
||||
self._controls.append((combo, "normal"))
|
||||
|
||||
def _build_choice(self, cell, row):
|
||||
prop, var = row["prop"], row["var"]
|
||||
@@ -759,6 +799,7 @@ class OxWidgetPropertiesPanel:
|
||||
|
||||
combo.bind("<<ComboboxSelected>>", selected)
|
||||
row["load"] = lambda: var.set(prop.read())
|
||||
self._controls.append((combo, "readonly"))
|
||||
|
||||
def _build_colour(self, cell, row):
|
||||
prop, var = row["prop"], row["var"]
|
||||
@@ -781,14 +822,14 @@ class OxWidgetPropertiesPanel:
|
||||
|
||||
self._dots(cell, choose)
|
||||
self._value_label(cell, row, READONLY_FG)
|
||||
swatch.bind("<Button-1>", choose)
|
||||
swatch.bind("<Button-1>", self._guarded(choose))
|
||||
row["load"] = load
|
||||
|
||||
def _build_dialog(self, cell, row):
|
||||
opener = getattr(self, f"_open_{row['prop'].dialog}_dialog")
|
||||
self._dots(cell, opener)
|
||||
label = self._value_label(cell, row)
|
||||
label.bind("<Double-Button-1>", lambda e: opener())
|
||||
label.bind("<Double-Button-1>", self._guarded(lambda e: opener()))
|
||||
row["load"] = lambda: row["var"].set(row["prop"].read())
|
||||
|
||||
def _build_link(self, cell, row):
|
||||
@@ -815,6 +856,9 @@ class OxWidgetPropertiesPanel:
|
||||
# ── writing ───────────────────────────────────────────────────
|
||||
|
||||
def _write(self, row, text):
|
||||
if not self.editable:
|
||||
row["load"]()
|
||||
return
|
||||
values, error = row["prop"].write(text)
|
||||
if error:
|
||||
self._status_var.set(f"{row['prop'].label}: {error}")
|
||||
|
||||
Reference in New Issue
Block a user