Asset panel: double-click opens the tab, single click only selects (#71)
game-maker / suite (push) Failing after 8m11s
game-maker / suite (push) Failing after 8m11s
One rule for every asset type: a click on an asset row selects it, a double-click (or Enter, or creating it via +) opens its tab. Selection alone still switches tabs only for nodes, frames and template objects. - state.openAsset(id) = select + 'open' event; the editor maps the asset type to its tab via TAB_OF_ASSET. The two special clauses for state machine and shader assets in the selection handler are gone. - Creating via + and importing a texture from the picker open the tab; paste/drop of an image only selects. - 3 unit tests (event order, re-open of a selected asset, selection never fires open), 14 e2e checks in step 4. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
3da0ef1be2
commit
4d9c4982eb
7 files changed
+160
-15
No files matched your search
@@ -88,12 +88,15 @@ export async function assets(t) {
|
||||
`__gm.state.project.assets.push({ id: 'scene2', type: 'scene', name: 'Level 2', props: { backgroundColor: 0x22252c }, objects: [] })`,
|
||||
);
|
||||
const secondScene = await json("__gm.assetRow('scene2')");
|
||||
await evaluate("__gm.showTab('graph')");
|
||||
await sleep(150);
|
||||
await doubleClick(secondScene.x, secondScene.y);
|
||||
check(
|
||||
'double-clicking a scene asset makes it the active scene',
|
||||
(await json('__gm.state.project.activeSceneId')) === 'scene2',
|
||||
await json('__gm.state.project.activeSceneId'),
|
||||
);
|
||||
check('and opens the Scene tab', (await json('__gm.tab()')) === 'scene', await json('__gm.tab()'));
|
||||
const firstScene = await json("__gm.assetRow('scene1')");
|
||||
await doubleClick(firstScene.x, firstScene.y);
|
||||
check(
|
||||
@@ -103,6 +106,72 @@ export async function assets(t) {
|
||||
);
|
||||
await mutate(`__gm.state.project.assets = __gm.state.project.assets.filter((a) => a.id !== 'scene2')`);
|
||||
|
||||
// 4d′. Opening an asset: a click on its row only selects, a double-click opens the tab it
|
||||
// lives in – every type that has one. The fixture lacks four of them; they go in through
|
||||
// the model, empty.
|
||||
await mutate(`__gm.state.project.assets.push(
|
||||
{ id: 'sm-open', type: 'statemachine', name: 'Machine', props: {}, graph: { nodes: [], edges: [] } },
|
||||
{ id: 'tex-open', type: 'texture', name: 'Sheet', props: {}, file: '', width: 0, height: 0, frames: [] },
|
||||
{ id: 'anim-open', type: 'animation', name: 'Walk', props: {}, frames: [] },
|
||||
{ id: 'box-open', type: 'container', name: 'Box', props: {}, objects: [] },
|
||||
)`);
|
||||
const openable = [
|
||||
['mover', 'graph', '__gm.graph.current()'],
|
||||
['sm-open', 'statemachine', '__gm.stateMachine.current()'],
|
||||
['adjust-colors', 'shader', '__gm.shader.current()'],
|
||||
['tex-open', 'texture', '__gm.texture.current()'],
|
||||
['anim-open', 'animation', '__gm.animation.current().assetId'],
|
||||
['box-open', 'container', '__gm.container.current()'],
|
||||
];
|
||||
for (const [id, tab, shown] of openable) {
|
||||
await evaluate("__gm.showTab('scene')");
|
||||
await sleep(150);
|
||||
const row = await json(`__gm.assetRow(${JSON.stringify(id)})`);
|
||||
await click(row.x, row.y);
|
||||
await sleep(500); // past the double-click window, so the next press starts a fresh pair
|
||||
const clicked = {
|
||||
tab: await json('__gm.tab()'),
|
||||
selected: (await json('__gm.state.selection'))?.assetId,
|
||||
};
|
||||
check(
|
||||
`a click on the ${tab} asset selects it and leaves the Scene tab alone`,
|
||||
clicked.tab === 'scene' && clicked.selected === id,
|
||||
JSON.stringify(clicked),
|
||||
);
|
||||
await doubleClick(row.x, row.y);
|
||||
await sleep(300);
|
||||
const opened = { tab: await json('__gm.tab()'), shown: await json(shown) };
|
||||
check(
|
||||
`a double-click opens the ${tab} tab on it`,
|
||||
opened.tab === tab && opened.shown === id,
|
||||
JSON.stringify(opened),
|
||||
);
|
||||
}
|
||||
// Enter goes the same way (`onActivate`), but only once the list holds keyboard focus, which a
|
||||
// click does not give it – so it is not driven here.
|
||||
await evaluate("__gm.showTab('scene')");
|
||||
await sleep(150);
|
||||
await clickText('+');
|
||||
await sleep(200);
|
||||
const entry = await evaluate(`__gm.locate('Behavior', true)`);
|
||||
await click(entry.x, entry.y);
|
||||
await sleep(400);
|
||||
const created = await json(
|
||||
"(__gm.state.project.assets.find((a) => a.type === 'behavior' && !['mover', 'spawner'].includes(a.id)) ?? {}).id ?? ''",
|
||||
);
|
||||
const fresh = { created, tab: await json('__gm.tab()'), shown: await json('__gm.graph.current()') };
|
||||
check(
|
||||
'creating an asset through + opens its tab on the new one',
|
||||
Boolean(created) && fresh.tab === 'graph' && fresh.shown === created,
|
||||
JSON.stringify(fresh),
|
||||
);
|
||||
await undo();
|
||||
await mutate(
|
||||
`__gm.state.project.assets = __gm.state.project.assets.filter((a) => !['sm-open', 'tex-open', 'anim-open', 'box-open'].includes(a.id))`,
|
||||
);
|
||||
await evaluate("__gm.showTab('scene')");
|
||||
await sleep(150);
|
||||
|
||||
// 4e. Asset defaults: the Crate deviates in height (60 against the schema's 100) and colour,
|
||||
// so two rows carry a reset. Rows run Enabled, Width, Height, Color, Texture, so height's
|
||||
// reset is the first on screen and colour's the last.
|
||||
|
||||
Reference in new issue
Block a user