121 lines
5.4 KiB
TypeScript
121 lines
5.4 KiB
TypeScript
/**
|
||
* Which tilemap the painting panel and the scene view's brush work on (#142): exactly one placed
|
||
* map, selected in the active scene. Everything else – nothing, two objects, the asset itself, a
|
||
* map in a scene that is not showing – leaves nothing to paint.
|
||
*/
|
||
import { describe, expect, it } from 'vitest';
|
||
import { CreateAssetCommand } from '../../src/core/commands/assetCommands';
|
||
import { PlaceAssetCommand } from '../../src/core/commands/sceneObjectCommands';
|
||
import { createEmptyProject } from '../../src/core/model/Project';
|
||
import { chooseTool, holdPick, paintedTilemap, pickTile } from '../../src/editor/panels/TilemapPanel';
|
||
import { EditorState, objectSelection } from '../../src/editor/state';
|
||
|
||
function setup() {
|
||
const state = new EditorState();
|
||
state.loadProject(createEmptyProject('p', 'P'), 1);
|
||
const create = (type: 'tilemap' | 'sprite' | 'scene', name: string) => {
|
||
const command = new CreateAssetCommand(type, name);
|
||
expect(state.execute(command)).toBe(true);
|
||
return command.asset.id;
|
||
};
|
||
// The first scene there is becomes the active one by itself.
|
||
const sceneId = create('scene', 'Main');
|
||
expect(state.activeScene?.id).toBe(sceneId);
|
||
const place = (holderId: string, assetId: string) => {
|
||
const command = new PlaceAssetCommand(holderId, assetId, { x: 0, y: 0 });
|
||
expect(state.execute(command)).toBe(true);
|
||
return command.objectId;
|
||
};
|
||
const tilemapId = create('tilemap', 'Ground');
|
||
return { state, sceneId, tilemapId, create, place };
|
||
}
|
||
|
||
describe('the painted tilemap', () => {
|
||
it('is the one placed map selected in the active scene', () => {
|
||
const { state, sceneId, tilemapId, place } = setup();
|
||
const map = place(sceneId, tilemapId);
|
||
state.select(objectSelection(sceneId, [map]));
|
||
expect(paintedTilemap(state)).toMatchObject({ objectId: map, asset: { id: tilemapId } });
|
||
});
|
||
|
||
it('is none without a selection, for another object and for the asset itself', () => {
|
||
const { state, sceneId, tilemapId, create, place } = setup();
|
||
expect(paintedTilemap(state)).toBeNull();
|
||
const sprite = place(sceneId, create('sprite', 'Box'));
|
||
state.select(objectSelection(sceneId, [sprite]));
|
||
expect(paintedTilemap(state)).toBeNull();
|
||
state.select({ kind: 'asset', assetId: tilemapId });
|
||
expect(paintedTilemap(state)).toBeNull();
|
||
});
|
||
|
||
it('is none while a second object is selected with it, map or not', () => {
|
||
const { state, sceneId, tilemapId, create, place } = setup();
|
||
const map = place(sceneId, tilemapId);
|
||
const other = place(sceneId, tilemapId);
|
||
const sprite = place(sceneId, create('sprite', 'Box'));
|
||
state.select(objectSelection(sceneId, [map, other], map));
|
||
expect(paintedTilemap(state)).toBeNull();
|
||
state.select(objectSelection(sceneId, [map, sprite], map));
|
||
expect(paintedTilemap(state)).toBeNull();
|
||
state.select(objectSelection(sceneId, [map]));
|
||
expect(paintedTilemap(state)?.objectId).toBe(map);
|
||
});
|
||
|
||
it('picks with the Pick tool and hands the tile to the painting tool before it (#133)', () => {
|
||
const { state, sceneId, tilemapId, place } = setup();
|
||
state.select(objectSelection(sceneId, [place(sceneId, tilemapId)]));
|
||
chooseTool(state, 'rect');
|
||
chooseTool(state, 'pick');
|
||
pickTile(state, 'grass');
|
||
expect(state.tilemapPaint).toMatchObject({ tool: 'rect', tileId: 'grass' });
|
||
// From a tool that does not paint with a tile, the pick goes to the brush.
|
||
chooseTool(state, 'erase');
|
||
chooseTool(state, 'pick');
|
||
pickTile(state, 'wall');
|
||
expect(state.tilemapPaint).toMatchObject({ tool: 'brush', tileId: 'wall' });
|
||
});
|
||
|
||
it('picks while Alt is held and goes back to the tool before it on release', () => {
|
||
const { state, sceneId, tilemapId, place } = setup();
|
||
state.select(objectSelection(sceneId, [place(sceneId, tilemapId)]));
|
||
chooseTool(state, 'fill');
|
||
expect(holdPick(state, true)).toBe(true);
|
||
expect(state.tilemapPaint.tool).toBe('pick');
|
||
pickTile(state, 'grass');
|
||
expect(state.tilemapPaint).toMatchObject({ tool: 'pick', tileId: 'grass' });
|
||
expect(holdPick(state, false)).toBe(true);
|
||
expect(state.tilemapPaint).toMatchObject({ tool: 'fill', tileId: 'grass' });
|
||
// Held from Select, too: the release brings Select back.
|
||
chooseTool(state, 'select');
|
||
holdPick(state, true);
|
||
holdPick(state, false);
|
||
expect(state.tilemapPaint.tool).toBe('select');
|
||
});
|
||
|
||
it('leaves Alt alone without a map, and a tool chosen while holding it stays', () => {
|
||
const { state, sceneId, tilemapId, place } = setup();
|
||
expect(holdPick(state, true)).toBe(false);
|
||
expect(state.tilemapPaint.tool).toBe('select');
|
||
const map = place(sceneId, tilemapId);
|
||
state.select(objectSelection(sceneId, [map]));
|
||
chooseTool(state, 'brush');
|
||
holdPick(state, true);
|
||
chooseTool(state, 'rect');
|
||
expect(holdPick(state, false)).toBe(false);
|
||
expect(state.tilemapPaint.tool).toBe('rect');
|
||
// Released after the map was deselected: nothing to paint on, so Select.
|
||
holdPick(state, true);
|
||
state.select(null);
|
||
holdPick(state, false);
|
||
expect(state.tilemapPaint.tool).toBe('select');
|
||
});
|
||
|
||
it('is none for a map in a scene that is not the one showing', () => {
|
||
const { state, tilemapId, create, place } = setup();
|
||
const otherScene = create('scene', 'Elsewhere');
|
||
const map = place(otherScene, tilemapId);
|
||
state.select(objectSelection(otherScene, [map]));
|
||
expect(paintedTilemap(state)).toBeNull();
|
||
});
|
||
});
|