Wiresheet: keep off-sheet input knobs on the sheet

A box with a link arriving from another sheet draws a knob on its left
edge. Tidy Layout moves the first column one grid step in when any of its
boxes has one, and dragging and arrow nudges stop such a box one step
inside the margin, so the knob never sits out in the grey.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-18 15:34:27 +03:00
co-authored by Claude Opus 5.5
parent 0d5e5115d9
commit 0dddea53f8
3 changed files with 48 additions and 6 deletions
+36
View File
@@ -154,6 +154,36 @@ def suggest_box_width_for_grid(width, grid_size):
return proposed
def offsheet_input_comps(components):
"""The components with a link arriving from off this sheet, drawn as a knob on
their left edge."""
root = app_state.xml_root_element
links_elem = root.find("links") if root is not None else None
if links_elem is None:
return set()
comp_by_path = {get_component_path(comp, root): comp for comp in components}
found = set()
for link in links_elem.findall("link"):
from_ref, to_ref = link.get("from", ""), link.get("to", "")
if "." not in from_ref or "." not in to_ref:
continue
dst = comp_by_path.get(to_ref.rsplit(".", 1)[0])
if dst is not None and from_ref.rsplit(".", 1)[0] not in comp_by_path:
found.add(dst)
return found
def box_left_limits(tags, margin, step):
"""Left-most x each box on the open sheet may be moved to, keyed by canvas tag.
The margin, or one step further in for a box with an off-sheet input, so its knob
stays on the sheet rather than out in the grey margin.
"""
knobbed = offsheet_input_comps(list(app_state.canvas_comp_map.values()))
return {tag: margin + step if app_state.canvas_comp_map.get(tag) in knobbed
else margin for tag in tags}
def layout_margin(grid_size=None):
"""The top/left edge offset a box may not encroach on, snapped onto the grid."""
if grid_size is None:
@@ -1575,6 +1605,10 @@ def plan_columns(columns, column_keys, demand, scale, wires=()):
# Column x positions depend only on widths and wire lanes, so they come first.
column_x = []
cursor_x = margin # the left-most column clears the canvas edge by the margin
if count and any(item.get("knob_in") for item in columns[column_keys[0]]):
# One step further in, so a knob on a first-column box's left edge stays on
# the sheet instead of out in the margin.
cursor_x = snap_up(margin + app_state.GRID_SIZE, scale)
for index, grid_x in enumerate(column_keys):
column_x.append(cursor_x)
gap = column_gap_for(demand.get(index, 0))
@@ -1868,6 +1902,7 @@ def build_layout_items(components):
linked_slot_index = build_linked_slot_index()
pairs = sheet_link_pairs(components)
on_sheet = {comp for src, _, dst, _ in pairs for comp in (src, dst)}
knobbed = offsheet_input_comps(components)
linked = []
loose = []
@@ -1880,6 +1915,7 @@ def build_layout_items(components):
"comp": comp, "meta": meta_val,
"grid_x": grid_x, "grid_y": grid_y,
"width": width, "height": height,
"knob_in": comp in knobbed,
# Where each slot's wire meets the box, as painted by draw_component_box.
"slot_offsets": {
raw_name: HEADER_HEIGHT + row * SLOT_ROW_HEIGHT + SLOT_ROW_HEIGHT // 2