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:
+1
-1
@@ -8,7 +8,7 @@ so later rebinding would only ever be seen by the module that did it.
|
|||||||
import configparser
|
import configparser
|
||||||
import os
|
import os
|
||||||
|
|
||||||
VERSION = "0.0.0.180"
|
VERSION = "0.0.0.181"
|
||||||
PROPERTIES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "editor.properties")
|
PROPERTIES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "editor.properties")
|
||||||
DEFAULT_GRID_SIZE = 10
|
DEFAULT_GRID_SIZE = 10
|
||||||
DEFAULT_ADD_TIMESTAMP = True
|
DEFAULT_ADD_TIMESTAMP = True
|
||||||
|
|||||||
@@ -2135,14 +2135,17 @@ def on_canvas_drag(event):
|
|||||||
dy = cy - app_state.drag_data["y"]
|
dy = cy - app_state.drag_data["y"]
|
||||||
xs = [entry["origin"][0] for entry in group]
|
xs = [entry["origin"][0] for entry in group]
|
||||||
ys = [entry["origin"][1] for entry in group]
|
ys = [entry["origin"][1] for entry in group]
|
||||||
dx = min(limit - max(xs), max(margin - min(xs), dx))
|
# A box with an off-sheet input stops a step further in, keeping its knob on the sheet.
|
||||||
|
left = wiresheet.box_left_limits([entry["tag"] for entry in group], margin, step)
|
||||||
|
dx = min(limit - max(xs),
|
||||||
|
max(max(left[e["tag"]] - e["origin"][0] for e in group), dx))
|
||||||
dy = min(limit - max(ys), max(margin - min(ys), dy))
|
dy = min(limit - max(ys), max(margin - min(ys), dy))
|
||||||
|
|
||||||
shifted = False
|
shifted = False
|
||||||
for entry in group:
|
for entry in group:
|
||||||
# Land each box on a step every step of the way.
|
# Land each box on a step every step of the way.
|
||||||
start_x, start_y = entry["origin"]
|
start_x, start_y = entry["origin"]
|
||||||
target_x = min(limit, max(margin, round((start_x + dx) / step) * step))
|
target_x = min(limit, max(left[entry["tag"]], round((start_x + dx) / step) * step))
|
||||||
target_y = min(limit, max(margin, round((start_y + dy) / step) * step))
|
target_y = min(limit, max(margin, round((start_y + dy) / step) * step))
|
||||||
origin = wiresheet.get_box_origin(entry["tag"])
|
origin = wiresheet.get_box_origin(entry["tag"])
|
||||||
if origin is None:
|
if origin is None:
|
||||||
@@ -2178,6 +2181,7 @@ def on_canvas_release(event):
|
|||||||
|
|
||||||
changes = []
|
changes = []
|
||||||
failed = []
|
failed = []
|
||||||
|
left = wiresheet.box_left_limits([entry["tag"] for entry in group], margin, step)
|
||||||
for entry in group:
|
for entry in group:
|
||||||
group_tag = entry["tag"]
|
group_tag = entry["tag"]
|
||||||
origin = wiresheet.get_box_origin(group_tag)
|
origin = wiresheet.get_box_origin(group_tag)
|
||||||
@@ -2185,7 +2189,7 @@ def on_canvas_release(event):
|
|||||||
continue
|
continue
|
||||||
current_x, current_y = origin
|
current_x, current_y = origin
|
||||||
|
|
||||||
snapped_x = min(limit, max(margin, round(current_x / step) * step))
|
snapped_x = min(limit, max(left[group_tag], round(current_x / step) * step))
|
||||||
snapped_y = min(limit, max(margin, round(current_y / step) * step))
|
snapped_y = min(limit, max(margin, round(current_y / step) * step))
|
||||||
|
|
||||||
shift_x = snapped_x - current_x
|
shift_x = snapped_x - current_x
|
||||||
@@ -2255,9 +2259,11 @@ def nudge_selected_boxes(dx, dy):
|
|||||||
origins = {t: wiresheet.get_box_origin(t) for t in tags}
|
origins = {t: wiresheet.get_box_origin(t) for t in tags}
|
||||||
if any(o is None for o in origins.values()):
|
if any(o is None for o in origins.values()):
|
||||||
return "break"
|
return "break"
|
||||||
# The group stops as one at the margin strip and the sheet's far edge.
|
# The group stops as one at the margin strip and the sheet's far edge; a box with an
|
||||||
|
# off-sheet input stops a step further in, keeping its knob on the sheet.
|
||||||
|
left = wiresheet.box_left_limits(tags, margin, step)
|
||||||
shift_x = min(limit - max(o[0] for o in origins.values()),
|
shift_x = min(limit - max(o[0] for o in origins.values()),
|
||||||
max(margin - min(o[0] for o in origins.values()), dx * step))
|
max(max(left[t] - o[0] for t, o in origins.items()), dx * step))
|
||||||
shift_y = min(limit - max(o[1] for o in origins.values()),
|
shift_y = min(limit - max(o[1] for o in origins.values()),
|
||||||
max(margin - min(o[1] for o in origins.values()), dy * step))
|
max(margin - min(o[1] for o in origins.values()), dy * step))
|
||||||
if not shift_x and not shift_y:
|
if not shift_x and not shift_y:
|
||||||
|
|||||||
@@ -154,6 +154,36 @@ def suggest_box_width_for_grid(width, grid_size):
|
|||||||
return proposed
|
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):
|
def layout_margin(grid_size=None):
|
||||||
"""The top/left edge offset a box may not encroach on, snapped onto the grid."""
|
"""The top/left edge offset a box may not encroach on, snapped onto the grid."""
|
||||||
if grid_size is None:
|
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 positions depend only on widths and wire lanes, so they come first.
|
||||||
column_x = []
|
column_x = []
|
||||||
cursor_x = margin # the left-most column clears the canvas edge by the margin
|
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):
|
for index, grid_x in enumerate(column_keys):
|
||||||
column_x.append(cursor_x)
|
column_x.append(cursor_x)
|
||||||
gap = column_gap_for(demand.get(index, 0))
|
gap = column_gap_for(demand.get(index, 0))
|
||||||
@@ -1868,6 +1902,7 @@ def build_layout_items(components):
|
|||||||
linked_slot_index = build_linked_slot_index()
|
linked_slot_index = build_linked_slot_index()
|
||||||
pairs = sheet_link_pairs(components)
|
pairs = sheet_link_pairs(components)
|
||||||
on_sheet = {comp for src, _, dst, _ in pairs for comp in (src, dst)}
|
on_sheet = {comp for src, _, dst, _ in pairs for comp in (src, dst)}
|
||||||
|
knobbed = offsheet_input_comps(components)
|
||||||
|
|
||||||
linked = []
|
linked = []
|
||||||
loose = []
|
loose = []
|
||||||
@@ -1880,6 +1915,7 @@ def build_layout_items(components):
|
|||||||
"comp": comp, "meta": meta_val,
|
"comp": comp, "meta": meta_val,
|
||||||
"grid_x": grid_x, "grid_y": grid_y,
|
"grid_x": grid_x, "grid_y": grid_y,
|
||||||
"width": width, "height": height,
|
"width": width, "height": height,
|
||||||
|
"knob_in": comp in knobbed,
|
||||||
# Where each slot's wire meets the box, as painted by draw_component_box.
|
# Where each slot's wire meets the box, as painted by draw_component_box.
|
||||||
"slot_offsets": {
|
"slot_offsets": {
|
||||||
raw_name: HEADER_HEIGHT + row * SLOT_ROW_HEIGHT + SLOT_ROW_HEIGHT // 2
|
raw_name: HEADER_HEIGHT + row * SLOT_ROW_HEIGHT + SLOT_ROW_HEIGHT // 2
|
||||||
|
|||||||
Reference in New Issue
Block a user