The assets and scene objects panels in the left column are split by a draggable splitter that keeps its ratio when the window is resized
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
33a7b1b63e
commit
55bfa7521a
4 files changed
+54
-4
No files matched your search
@@ -38,7 +38,7 @@ npm run build # writes dist/ and regenerates index.html; the folder is wh
|
|||||||
The browser suite and the three example games need a machine with a GPU:
|
The browser suite and the three example games need a machine with a GPU:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # the editor, 1006 checks (GM_STEPS=20 for one step)
|
node tools/seed-e2e.mjs && node tools/e2e.mjs # the editor, 1009 checks (GM_STEPS=20 for one step)
|
||||||
node tools/seed-jumprun.mjs && node tools/smoke-jumprun.mjs
|
node tools/seed-jumprun.mjs && node tools/smoke-jumprun.mjs
|
||||||
node tools/seed-tetris.mjs && node tools/smoke-tetris.mjs
|
node tools/seed-tetris.mjs && node tools/smoke-tetris.mjs
|
||||||
node tools/seed-actor.mjs && node tools/smoke-actor.mjs
|
node tools/seed-actor.mjs && node tools/smoke-actor.mjs
|
||||||
|
|||||||
+20
-3
@@ -115,6 +115,8 @@ const MAX_RIGHT_WIDTH = 600;
|
|||||||
// The floor is the console's own header: dragged all the way shut it stays visible to drag open.
|
// The floor is the console's own header: dragged all the way shut it stays visible to drag open.
|
||||||
const MIN_CONSOLE_HEIGHT = Panel.HEADER_HEIGHT;
|
const MIN_CONSOLE_HEIGHT = Panel.HEADER_HEIGHT;
|
||||||
const MAX_CONSOLE_HEIGHT = 600;
|
const MAX_CONSOLE_HEIGHT = 600;
|
||||||
|
// Either panel of the left column keeps at least its header, for the same reason as the console.
|
||||||
|
const MIN_PANEL_HEIGHT = Panel.HEADER_HEIGHT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Composes toolbar, panels, viewports and graph editor into the one application that edits and
|
* Composes toolbar, panels, viewports and graph editor into the one application that edits and
|
||||||
@@ -151,6 +153,8 @@ export class Editor implements PlayHost {
|
|||||||
readonly leftSplitter = new Splitter('x');
|
readonly leftSplitter = new Splitter('x');
|
||||||
readonly rightSplitter = new Splitter('x');
|
readonly rightSplitter = new Splitter('x');
|
||||||
readonly consoleSplitter = new Splitter('y');
|
readonly consoleSplitter = new Splitter('y');
|
||||||
|
/** Between the asset panel and the scene objects below it. */
|
||||||
|
readonly columnSplitter = new Splitter('y');
|
||||||
private readonly workspace: HStack;
|
private readonly workspace: HStack;
|
||||||
private readonly centre: VStack;
|
private readonly centre: VStack;
|
||||||
private readonly tabs: TabStrip<TabId>;
|
private readonly tabs: TabStrip<TabId>;
|
||||||
@@ -165,6 +169,8 @@ export class Editor implements PlayHost {
|
|||||||
private leftWidth = 250;
|
private leftWidth = 250;
|
||||||
private rightWidth = 350;
|
private rightWidth = 350;
|
||||||
private consoleHeight = 300;
|
private consoleHeight = 300;
|
||||||
|
/** The asset panel's part of the left column's height; the scene objects get the rest. */
|
||||||
|
private assetsShare = 0.5;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
app: Application,
|
app: Application,
|
||||||
@@ -219,11 +225,22 @@ export class Editor implements PlayHost {
|
|||||||
root.add(this.toolbar);
|
root.add(this.toolbar);
|
||||||
|
|
||||||
this.workspace = new HStack();
|
this.workspace = new HStack();
|
||||||
this.leftColumn = new VStack({ gap: 1 });
|
this.leftColumn = new VStack();
|
||||||
this.assets = new AssetPanel(state, textures, fonts, sounds);
|
this.assets = new AssetPanel(state, textures, fonts, sounds);
|
||||||
this.leftColumn.add(this.assets, 1);
|
this.leftColumn.add(this.assets, this.assetsShare);
|
||||||
installFileImport(app.canvas, { state, textures, fonts, sounds });
|
installFileImport(app.canvas, { state, textures, fonts, sounds });
|
||||||
this.leftColumn.add(this.hierarchy, 1);
|
this.leftColumn.add(this.columnSplitter);
|
||||||
|
this.leftColumn.add(this.hierarchy, 1 - this.assetsShare);
|
||||||
|
// A share rather than a height, so a taller or shorter window keeps the split the user chose.
|
||||||
|
this.columnSplitter.onDrag = (delta) => {
|
||||||
|
const room = this.leftColumn.h - Splitter.THICKNESS;
|
||||||
|
if (room <= 0) return;
|
||||||
|
const floor = Math.min(0.5, MIN_PANEL_HEIGHT / room);
|
||||||
|
this.assetsShare = clamp(this.assetsShare + delta / room, floor, 1 - floor);
|
||||||
|
this.assets.flex = this.assetsShare;
|
||||||
|
this.hierarchy.flex = 1 - this.assetsShare;
|
||||||
|
this.leftColumn.relayout();
|
||||||
|
};
|
||||||
|
|
||||||
this.centre = new VStack();
|
this.centre = new VStack();
|
||||||
this.tabs = new TabStrip<TabId>(
|
this.tabs = new TabStrip<TabId>(
|
||||||
|
|||||||
@@ -264,6 +264,12 @@ export function installDebugHook(app: Application, state: EditorState, editor: E
|
|||||||
tabRow: () => editor.tabRow(),
|
tabRow: () => editor.tabRow(),
|
||||||
/** The dividers left and right of the centre column – dragging them narrows the tab row. */
|
/** The dividers left and right of the centre column – dragging them narrows the tab row. */
|
||||||
panelSplitters: () => ({ left: centreOf(editor.leftSplitter), right: centreOf(editor.rightSplitter) }),
|
panelSplitters: () => ({ left: centreOf(editor.leftSplitter), right: centreOf(editor.rightSplitter) }),
|
||||||
|
/** The left column: asset panel on top, scene objects below, and the divider between them. */
|
||||||
|
leftColumn: () => ({
|
||||||
|
assets: rectOf(editor.assets),
|
||||||
|
objects: rectOf(editor.hierarchy),
|
||||||
|
splitter: centreOf(editor.columnSplitter),
|
||||||
|
}),
|
||||||
viewportCenter: () => centreOf(viewport),
|
viewportCenter: () => centreOf(viewport),
|
||||||
/** Pans the Scene tab to a world point – a step's own lane, away from what earlier steps left. */
|
/** Pans the Scene tab to a world point – a step's own lane, away from what earlier steps left. */
|
||||||
lookAt: (x: number, y: number) => viewport.lookAt(x, y),
|
lookAt: (x: number, y: number) => viewport.lookAt(x, y),
|
||||||
|
|||||||
@@ -108,6 +108,33 @@ export async function overflow(t) {
|
|||||||
JSON.stringify({ hidden: back.hidden, narrow: narrow.hidden }),
|
JSON.stringify({ hidden: back.hidden, narrow: narrow.hidden }),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 14b-iii. The divider between asset panel and scene objects moves the height from one to the
|
||||||
|
// other, and dragged shut either keeps its header to grab it by again.
|
||||||
|
const column = () => json('__gm.leftColumn()');
|
||||||
|
const near = (a, b) => Math.abs(a - b) <= 1;
|
||||||
|
const start = await column();
|
||||||
|
await drag(start.splitter.x, start.splitter.y, start.splitter.x, start.splitter.y + 80, { steps: 6 });
|
||||||
|
const lower = await column();
|
||||||
|
check(
|
||||||
|
'dragging the left column’s divider down gives the assets 80 px the scene objects lose',
|
||||||
|
near(lower.assets.h, start.assets.h + 80) && near(lower.objects.h, start.objects.h - 80),
|
||||||
|
JSON.stringify({ start, lower }),
|
||||||
|
);
|
||||||
|
await drag(lower.splitter.x, lower.splitter.y, lower.splitter.x, lower.splitter.y - 2000, { steps: 10 });
|
||||||
|
const shut = await column();
|
||||||
|
check(
|
||||||
|
'dragged all the way up the asset panel stops at its header',
|
||||||
|
near(shut.assets.h, 30) && shut.objects.y > shut.assets.y,
|
||||||
|
JSON.stringify(shut),
|
||||||
|
);
|
||||||
|
await drag(shut.splitter.x, shut.splitter.y, shut.splitter.x, start.splitter.y, { steps: 10 });
|
||||||
|
const restored = await column();
|
||||||
|
check(
|
||||||
|
'and dragged back it returns to the split it started with',
|
||||||
|
near(restored.assets.h, start.assets.h) && near(restored.objects.h, start.objects.h),
|
||||||
|
JSON.stringify({ start, restored }),
|
||||||
|
);
|
||||||
|
|
||||||
// 14c. Every tab, because each one owns a different set of controls.
|
// 14c. Every tab, because each one owns a different set of controls.
|
||||||
for (const tab of ['scene', 'graph', 'texture', 'game', 'container', 'list', 'particles']) {
|
for (const tab of ['scene', 'graph', 'texture', 'game', 'container', 'list', 'particles']) {
|
||||||
await showTab(tab);
|
await showTab(tab);
|
||||||
|
|||||||
Reference in new issue
Block a user