Lists add and delete items right in the list header and rows
The layer, frame and shape lists still had their add and delete buttons scattered below the list, each in its own layout. They now live in the shared SortableList, so every list works the same way. - SortableList gets an optional header with the title on the left and a + on the right, plus an optional x per row next to the eye. - The keepOne option hides the x on the last remaining row, so a pixel art image and a tilemap always keep one layer. - Pixel art layers and frames and tilemap layers use header, + and x. Only Merge down and Duplicate stay below the lists. - Vector art shapes get the x but no +. Add shape stays below the list and Delete shapes stays for a multi-selection. - The section headings in the pixel art column use the same style as the list titles and the inspector. Findings: - The wait loop added to check 47i for #196 only waited for the right half of the shape. If the texture landed between the two reads, the left half was still blue and the check failed. It now waits for both halves. Tests: - ./check.sh: 138 files, 2052 tests, exit 0. - GM_STEPS=39,40,47,48 (fresh): ALL PASSED, 156 checks (was 154). - GM_STEPS=47,48 (fresh, final): ALL PASSED, 86 checks. - Two new e2e checks: x on a shape (47) and x on a frame (48). The tilemap check in 40 now uses the x instead of Delete layer. - Counter-check: with the x not reporting to its owner, exactly the two new checks fail. - Check total 1266 in README and wiki is computed (1264 + 2). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5b9b57fd19
commit
ae0247d86f
11 files changed
+264
-100
No files matched your search
@@ -371,6 +371,20 @@ export async function vectorArt(t) {
|
||||
JSON.stringify({ added: added.length, selected: await json('__gm.vectorArt.selected()') }),
|
||||
);
|
||||
|
||||
// The cross on its row takes that shape out again, and the selection with it.
|
||||
const cross = await json(`__gm.vectorArt.shapeRemoveAt(${JSON.stringify(added.at(-1))})`);
|
||||
if (cross) await click(cross.x, cross.y);
|
||||
await settle();
|
||||
const afterCross = await shapeIds();
|
||||
check(
|
||||
'the cross on a shape row removes that shape and nothing else',
|
||||
cross !== null &&
|
||||
afterCross.length === before47e &&
|
||||
!afterCross.includes(added.at(-1)) &&
|
||||
(await json('__gm.vectorArt.selected()')) === '',
|
||||
JSON.stringify({ cross, afterCross, selected: await json('__gm.vectorArt.selected()') }),
|
||||
);
|
||||
|
||||
// 47f (stage 5). The way a user takes, which the blocks before took by hand: the asset is made
|
||||
// from the + menu, its row opens the tab, and a sprite wears the drawing through its
|
||||
// Texture row – the picture picker of #185, which until here only unit tests had seen.
|
||||
@@ -848,7 +862,10 @@ export async function vectorArt(t) {
|
||||
// out and in, a canvas of the old editor used to swallow the news (#196).
|
||||
let leftHalf = await tabPixel(60, 100);
|
||||
let rightHalf = await tabPixel(196, 100);
|
||||
for (let waited = 0; waited < 3000 && colourDistance(rightHalf, HALVES_RIGHT) >= 20; waited += 100) {
|
||||
// Both halves, or the picture may land between the two reads and leave the left one stale.
|
||||
const landed = () =>
|
||||
colourDistance(leftHalf, HALVES_LEFT) < 20 && colourDistance(rightHalf, HALVES_RIGHT) < 20;
|
||||
for (let waited = 0; waited < 3000 && !landed(); waited += 100) {
|
||||
await sleep(100);
|
||||
leftHalf = await tabPixel(60, 100);
|
||||
rightHalf = await tabPixel(196, 100);
|
||||
|
||||
Reference in new issue
Block a user