Tidy Layout as signal flow; fixed-size wiresheet; signed Sox int writes

- Tidy Layout lays linked boxes out left to right by signal flow, in as few
  columns as the longest chain allows; feedback loops are cut where they run
  backwards, and sources sit just before the boxes they feed.
- Boxes with no link on the open sheet go to the bottom of the first column,
  alphabetically.
- A box that wires skipping its column would cross is pushed down below them.
- The wiresheet is fixed at meta's 255-step reach; outside it is light grey.
  Dragging keeps a box's top-left corner on the sheet.
- Sox write_i4 wraps to signed, so meta with x >= 128 reaches the device.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-18 10:15:22 +03:00
co-authored by Claude Opus 5.5
parent 160f65c95e
commit b3d96d96b6
5 changed files with 321 additions and 92 deletions
+17 -29
View File
@@ -933,7 +933,7 @@ def do_tidy_layout(event=None):
multiplier = app_state.meta_scale // app_state.GRID_SIZE
if moved == 0:
messagebox.showinfo("Tidy Layout", "Nothing to move — no boxes overlap.")
messagebox.showinfo("Tidy Layout", "Nothing to move — the sheet is already tidy.")
elif clamped:
messagebox.showwarning(
"Tidy Layout",
@@ -991,14 +991,8 @@ def zoom_to(level, anchor=None):
if after == before:
return
# Scroll the repainted sheet back under the held point. The scrollregion starts at
# the origin, so its far corner is the span the view fractions are measured against.
region = str(canvas.cget("scrollregion")).split()
if len(region) == 4:
span_x = float(region[2]) or 1.0
span_y = float(region[3]) or 1.0
canvas.xview_moveto(max(0.0, (sheet_x * after - anchor[0]) / span_x))
canvas.yview_moveto(max(0.0, (sheet_y * after - anchor[1]) / span_y))
# Scroll the repainted sheet back under the held point.
wiresheet.scroll_view_to(sheet_x * after - anchor[0], sheet_y * after - anchor[1])
def do_zoom_in(event=None):
@@ -1054,12 +1048,8 @@ def do_zoom_fit(event=None):
applied = wiresheet.set_zoom(level)
update_zoom_label()
region = str(canvas.cget("scrollregion")).split()
if len(region) == 4:
span_x = float(region[2]) or 1.0
span_y = float(region[3]) or 1.0
canvas.xview_moveto(max(0.0, (bounds[0] * applied - wiresheet.FIT_PADDING) / span_x))
canvas.yview_moveto(max(0.0, (bounds[1] * applied - wiresheet.FIT_PADDING) / span_y))
wiresheet.scroll_view_to(bounds[0] * applied - wiresheet.FIT_PADDING,
bounds[1] * applied - wiresheet.FIT_PADDING)
return "break"
@@ -1256,16 +1246,11 @@ def scroll_canvas_to(tag):
"""Scrolls the sheet so the tagged items sit in the middle of the view."""
canvas = app_state.canvas
box = canvas.bbox(tag)
region = str(canvas.cget("scrollregion")).split()
if box is None or len(region) != 4:
if box is None:
return
span_x = float(region[2]) or 1.0
span_y = float(region[3]) or 1.0
middle_x = (box[0] + box[2]) / 2 - canvas.winfo_width() / 2
middle_y = (box[1] + box[3]) / 2 - canvas.winfo_height() / 2
canvas.xview_moveto(max(0.0, middle_x / span_x))
canvas.yview_moveto(max(0.0, middle_y / span_y))
wiresheet.scroll_view_to((box[0] + box[2]) / 2 - canvas.winfo_width() / 2,
(box[1] + box[3]) / 2 - canvas.winfo_height() / 2)
def select_link_element(link_elem):
@@ -2111,8 +2096,10 @@ def on_canvas_drag(event):
# out of the margin strip along the top and left canvas edges.
wanted_x = box_x + (cx - app_state.drag_data["x"])
wanted_y = app_state.drag_data["box_y"] + (cy - app_state.drag_data["y"])
target_x = max(margin, round(wanted_x / step) * step)
target_y = max(margin, round(wanted_y / step) * step)
# The box's corner also stays on the sheet, the furthest meta can store it.
limit = wiresheet.META_COORD_MAX * step
target_x = min(limit, max(margin, round(wanted_x / step) * step))
target_y = min(limit, max(margin, round(wanted_y / step) * step))
shift_x = target_x - origin[0]
shift_y = target_y - origin[1]
@@ -2137,8 +2124,9 @@ def on_canvas_release(event):
current_x, current_y = origin
margin = wiresheet.layout_margin(app_state.meta_scale) * app_state.zoom
snapped_x = max(margin, round(current_x / step) * step)
snapped_y = max(margin, round(current_y / step) * step)
limit = wiresheet.META_COORD_MAX * step
snapped_x = min(limit, max(margin, round(current_x / step) * step))
snapped_y = min(limit, max(margin, round(current_y / step) * step))
shift_x = snapped_x - current_x
shift_y = snapped_y - current_y
@@ -3755,11 +3743,11 @@ canvas_hscroll.pack(side=tk.BOTTOM, fill=tk.X)
canvas = tk.Canvas(
frame_editor,
bg="white",
bg=wiresheet.OFF_SHEET_COLOUR,
highlightthickness=0,
xscrollcommand=canvas_hscroll.set,
yscrollcommand=canvas_vscroll.set,
scrollregion=(0, 0, 2000, 2000),
scrollregion=(0, 0, *wiresheet.sheet_extent()),
)
app_state.canvas = canvas
canvas.pack(fill=tk.BOTH, expand=True)