Variables of a behavior, the fields of a struct, the ports of a start
or end node and the items of a list could only be added and removed.
Changing their order meant removing and adding them again. Now each of
them is dragged by the mark in front of its row.
- sortBlocks (ui/blockDrag.ts) makes the rows of one column sortable.
A block is every row it covers, so a struct moves with its fields and
a list item with its nested list. The block is dimmed while it is
carried, an accent line shows where it lands, and a scrolled panel
follows the pointer at its edge. Less than 4 px stays a click.
- The arithmetic is pure and lives in ui/sortable.ts: blockGap,
gapLineY, dropSlot and edgeScroll. dropIndex of the tile strip moved
there too, so the reorder maths sits in one file.
- MoveVariableCommand, MoveStructFieldCommand and MovePortCommand
build on the existing MoveCommand. Undo moves back.
- Lists need no command. InlineList replaces the list as a whole, as
it does for every other edit of its items.
- The grip is the kind mark, for a list item its number. Moving only
happens among siblings: a field stays in its struct.
- On a Struct asset the move runs through WithStructTypes. Typed
variables, Pack/Expand ports and split outputs follow the new order.
- Values and edges hang on names, so only the order changes. Nodes
running a behavior read their ports from the start node, the new
order reaches them without a copy.
- Not sortable by design: the variables of a placed object, the fields
of a typed struct (moved on the Struct asset) and the picked ports
of Variables/Properties nodes.
- Test hook __gm.inspectorMark(label) finds the mark of a row.
Tests:
- Gate on melektaus-atx: 235 files, 3572 tests, CHECK EXIT 0 (+9).
- tests/core/reorder.test.ts: a variable, a field two levels deep, a
Struct asset reaching a typed variable and Pack, and start ports
reaching the calling node with edges and result kept.
- e2e 22: ALL PASSED, 39 checks (+4, sum 1739). 22f-iii drags a
variable past a struct of several rows, then a field inside it.
- Counter-probes: dropSlot by top edge instead of middle and a field
move that ignores its path fail 3 unit tests. With sortBlocks
switched off, the three order checks of 22f-iii fail.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reordering shapes by dragging worked well in the vector tab. Pixel
art layers and frames and tilemap layers still used up/down buttons.
All three lists now share one widget built from the shape list.
- SortableList in the UI toolkit, with the drag rules next to it in
src/ui/sortable.ts. A row has an optional thumbnail, a name, a hint
on the right and an eye toggle. Every drop is one undo step.
- The shape list is a thin wrapper around it. shapeRows.ts is gone,
its tests moved to the new rules.
- Pixel art layers show the layer alone on the current frame, frames
show the whole frame. Up/Down, Hide, Earlier and Later are gone.
- Tilemap layers get the eye instead of the checkbox. The per-row
up, down and delete buttons are replaced by Delete layer next to
Add layer.
- A row is selected on release instead of press. Selecting rebuilt
the inspector or tilemap panel and cancelled a drag that started
on a row not yet selected.
Tests:
- ./check.sh: 138 files, 2052 tests, exit 0 (before 137 / 2051).
- GM_STEPS=39,40,47,48 (fresh seed): ALL PASSED, 154 checks.
- 5 new e2e checks. Check total 1264 in the README is computed
(1259 + 5), CI never measured 1259.
- Counter-checks bite: dropMove ignoring reversed fails a unit test,
a tilemap drop not applied fails the drag check, a layer thumbnail
showing all layers fails the thumbnail check.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>