Lists duplicate, rename and edit values right in their rows
Name, opacity and Z each sat in a separate field below or beside
the list. You had to select a row first and then look elsewhere to
change it. Duplicating was a separate button or not possible at all.
Now the row itself carries everything.
- SortableList gets three optional callbacks. onDuplicate shows a
copy button between the eye and the delete button. onRename opens
a text field on double click, Enter or a click outside commits,
Esc cancels, an empty name is ignored. value puts a NumberField
into the row.
- Dragging on the number changes the value and never moves the row.
A whole drag is one undo step, the canvas follows live.
- Copy and delete only show on the hovered and the selected row.
Their space stays reserved, so nothing jumps on hover.
- Pixel layers: copy right above with the same pixels on all
frames, rename, opacity in percent. The Name and Opacity fields
below the list are gone.
- Pixel frames: copy right after, replaces the Duplicate button.
- Tilemap layers: copy with cells, Z and visibility, rename, Z in
the row. The Name and Z fields in the panel are gone.
- Vector shapes: copy at the same place and select it, rename.
- New in core: DuplicateVectorShapeCommand,
DuplicateTilemapLayerCommand, withLayerDuplicated and copyName
("X copy", "X copy 2"). copyName lives in src/core/util/names.ts
because the model never imports from commands/.
Findings:
- Double clicking a shape that is not selected yet only selects it.
The first click moves the list up, so the second click misses the
name. Module 47 selects the row first.
Tests:
- ./check.sh: 138 files, 2055 tests, CHECK EXIT 0 (before 2052).
- GM_STEPS=47,48 (fresh, twice): ALL PASSED, 91 checks (before 86).
- GM_STEPS=39,40,47,48: module 40 green, 47 died on the rename
check, which was a test fault and is fixed.
- Counter probes: a constant copyName fails the shape and pixel
layer tests. A dead copy hit fails the copy check in 47.
- Check total 1272 in README and wiki, computed (1266 + 6).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ae0247d86f
commit
bbbf34109b
19 files changed
+747
-153
No files matched your search
@@ -7,11 +7,13 @@ import {
|
||||
import { AddTilePictureCommand } from '../../src/core/commands/tileCommands';
|
||||
import {
|
||||
AddTilemapLayerCommand,
|
||||
DuplicateTilemapLayerCommand,
|
||||
MoveTilemapLayerCommand,
|
||||
PaintTilesCommand,
|
||||
RemoveTilemapLayerCommand,
|
||||
RenameTilemapLayerCommand,
|
||||
SetTilemapLayerHiddenCommand,
|
||||
SetTilemapLayerZCommand,
|
||||
} from '../../src/core/commands/tilemapCommands';
|
||||
import type { TilemapAsset } from '../../src/core/model/Asset';
|
||||
import { isPlaceableType } from '../../src/core/model/AssetTypes';
|
||||
@@ -319,6 +321,25 @@ describe('the layers of a tilemap', () => {
|
||||
expect(f.assetOf().layers.map((l) => l.name)).toEqual(['Layer 1', 'Roofs']);
|
||||
});
|
||||
|
||||
it('duplicates a layer right above it, with its cells, its z and a name of its own', () => {
|
||||
const f = makeTilemap();
|
||||
f.paint([{ x: 1, y: 1 }]);
|
||||
f.stack.execute(new SetTilemapLayerZCommand(f.tilemapId, f.layerId(), 3));
|
||||
f.stack.execute(new AddTilemapLayerCommand(f.tilemapId));
|
||||
const copy = new DuplicateTilemapLayerCommand(f.tilemapId, f.layerId());
|
||||
f.stack.execute(copy);
|
||||
const layers = f.assetOf().layers;
|
||||
expect(layers.map((l) => l.name)).toEqual(['Layer 1', 'Layer 1 copy', 'Layer 2']);
|
||||
expect(layers[1]).toMatchObject({ id: copy.layerId, z: 3, cells: layers[0]!.cells });
|
||||
// Cells of its own: painting on the copy leaves the original alone.
|
||||
f.stack.execute(new PaintTilesCommand(f.tilemapId, copy.layerId, [{ x: 1, y: 1, tileId: '' }]));
|
||||
expect(f.assetOf().layers[0]!.cells[cellKey(1, 1)]).toBeTruthy();
|
||||
|
||||
f.stack.undo();
|
||||
f.stack.undo();
|
||||
expect(f.assetOf().layers.map((l) => l.name)).toEqual(['Layer 1', 'Layer 2']);
|
||||
});
|
||||
|
||||
it('renames a layer without the spaces around it, refuses a blank name and undoes to the old one', () => {
|
||||
const f = makeTilemap();
|
||||
f.stack.execute(new RenameTilemapLayerCommand(f.tilemapId, f.layerId(), ' Ground '));
|
||||
|
||||
Reference in new issue
Block a user