Skip to content

Fix layout-save crash; add screen-alignment buttons and drag-snap UX (auto-snap, zone spanning, sticky right-click cancel) - #86

Open
haylax wants to merge 3 commits into
rohanrhu:mainfrom
haylax:feat/snap-align-enhancements
Open

Fix layout-save crash; add screen-alignment buttons and drag-snap UX (auto-snap, zone spanning, sticky right-click cancel)#86
haylax wants to merge 3 commits into
rohanrhu:mainfrom
haylax:feat/snap-align-enhancements

Conversation

@haylax

@haylax haylax commented Jun 29, 2026

Copy link
Copy Markdown

This branch bundles one bug fix and three opt-in UX features. Each is in its own commit.

1. Fix crash when saving a zone layout

UserLayout.reArrange() force-unwrapped both the section number ($0.number!) and the matching section window (.first(where:)!). When section configs and live section windows fell out of sync (e.g. after adding/removing a section), the unwrap hit nil and the app crashed with SIGTRAP on Save. Made it tolerant using the same guard-let pattern already used in LayoutWindow.onSave().

2. Screen-alignment buttons in the zone editor

Adds an AlignmentPreset enum + AlignmentButton (SF Symbols) and a new row in the per-section editor. Unlike the existing PositioningPreset buttons (which also resize), these keep the section's current size and only reposition it relative to the screen: left / center / right and top / middle / bottom. Lets you size a zone freely, then align it without changing its dimensions.

3. Drag-snap UX (all toggleable in Preferences)

  • Auto-snap while dragging (snapWhileDragging, default on): the layout activates automatically when a drag starts, no key required. Holding the snap key (default Shift) temporarily suppresses snapping instead of activating it.
  • Zone spanning (enableZoneSpanning + spanKey, default Command): hold the span key while dragging over multiple zones to accumulate them, then drop to snap the window to their bounding-box union. (Grid layouts already span natively.)
  • Sticky right-click cancel: snapWithRightClick already toggled snapping mid-drag, but auto-snap re-activated it on the next mouse move. A snapSuppressedForDrag flag now keeps snapping off for the rest of the drag once cancelled.

All new behavior is gated behind settings and defaults preserve a familiar experience for existing users where reasonable.

🤖 Generated with Claude Code

haylax and others added 3 commits June 29, 2026 12:48
UserLayout.reArrange() force-unwrapped both the section number
(`$0.number!`) and the matching section window
(`.first(where:)!`). When the section configs and live section
windows fell out of sync (e.g. after adding/removing a section),
the unwrap hit nil and the app crashed with SIGTRAP on Save.

Make it tolerant, matching the existing guard-let pattern already
used in LayoutWindow.onSave(): sort with `?? Int.max` and skip
configs that have no matching window instead of force-unwrapping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds an AlignmentPreset enum + AlignmentButton (SF Symbols
align.horizontal.* / align.vertical.*) and a new row of buttons in
the per-section editor (EditorSectionView).

Unlike the existing PositioningPreset buttons, which also resize the
section, these keep the section's current size and only reposition it
relative to the screen: align left / center / right and top / middle /
bottom. This lets you size a zone freely, then align it without
changing its dimensions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three related window-drag snapping improvements, all toggleable in
Preferences:

- Auto-snap while dragging (snapWhileDragging, default on): the layout
  activates automatically when a window drag starts, no key required.
  Holding the snap key (default Shift) temporarily suppresses snapping
  instead of activating it (inverted logic in monitorShortcuts).

- Zone spanning (enableZoneSpanning, default on; spanKey, default
  Command): hold the span key while dragging over multiple zones to
  accumulate them, and drop to snap the window to their bounding-box
  union. Implemented in Macsy.swift via spannedSectionWindows plus
  isSpanKeyPressed/spannedAXRect/applyZoneSpanHighlight, accumulation in
  onWindowMoved and union snapping in handleZoneMouseUp. (Grid layouts
  already span natively.)

- Sticky right-click cancel: snapWithRightClick already toggled snapping
  mid-drag, but auto-snap re-activated it on the next mouse move. A
  snapSuppressedForDrag flag now keeps snapping off for the rest of the
  drag once cancelled, reset at drag start/end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rohanrhu

Copy link
Copy Markdown
Owner

Thanks. I'll merge with next update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants