Add scene creation and active scene switching commands

This commit is contained in:
2026-04-11 03:46:53 +02:00
parent f1ab5f8282
commit a6bb276678
3 changed files with 119 additions and 1 deletions

View File

@@ -1,10 +1,12 @@
import type { EditorSelection } from "../core/selection";
import type { ToolMode } from "../core/tool-mode";
import type { SceneDocument } from "../document/scene-document";
import type { ProjectDocument, SceneDocument } from "../document/scene-document";
export interface CommandContext {
getDocument(): SceneDocument;
setDocument(document: SceneDocument): void;
getProjectDocument(): ProjectDocument;
setProjectDocument(document: ProjectDocument): void;
getSelection(): EditorSelection;
setSelection(selection: EditorSelection): void;
getToolMode(): ToolMode;

View File

@@ -0,0 +1,68 @@
import { createOpaqueId } from "../core/ids";
import { createEmptyProjectScene } from "../document/scene-document";
import type { EditorCommand } from "./command";
function createUniqueSceneName(existingNames: string[]): string {
const normalizedNames = new Set(
existingNames.map((name) => name.trim().toLowerCase())
);
let suffix = existingNames.length + 1;
while (normalizedNames.has(`scene ${suffix}`)) {
suffix += 1;
}
return `Scene ${suffix}`;
}
export function createCreateSceneCommand(): EditorCommand {
const createdSceneId = createOpaqueId("scene");
let createdSceneName: string | null = null;
let previousProjectDocumentSerialized: string | null = null;
return {
id: createOpaqueId("command"),
label: "Create scene",
execute(context) {
const currentProjectDocument = context.getProjectDocument();
if (previousProjectDocumentSerialized === null) {
previousProjectDocumentSerialized = JSON.stringify(currentProjectDocument);
}
if (createdSceneName === null) {
createdSceneName = createUniqueSceneName(
Object.values(currentProjectDocument.scenes).map((scene) => scene.name)
);
}
context.setProjectDocument({
...currentProjectDocument,
activeSceneId: createdSceneId,
scenes: {
...currentProjectDocument.scenes,
[createdSceneId]: createEmptyProjectScene({
id: createdSceneId,
name: createdSceneName
})
}
});
context.setSelection({ kind: "none" });
context.setToolMode("select");
},
undo(context) {
if (previousProjectDocumentSerialized === null) {
return;
}
context.setProjectDocument(
JSON.parse(previousProjectDocumentSerialized) as ReturnType<
typeof context.getProjectDocument
>
);
context.setSelection({ kind: "none" });
context.setToolMode("select");
}
};
}

View File

@@ -0,0 +1,48 @@
import { createOpaqueId } from "../core/ids";
import type { EditorCommand } from "./command";
export function createSetActiveSceneCommand(nextSceneId: string): EditorCommand {
let previousSceneId: string | null = null;
return {
id: createOpaqueId("command"),
label: "Switch active scene",
execute(context) {
const currentProjectDocument = context.getProjectDocument();
if (currentProjectDocument.scenes[nextSceneId] === undefined) {
throw new Error(`Cannot activate missing scene ${nextSceneId}.`);
}
if (previousSceneId === null) {
previousSceneId = currentProjectDocument.activeSceneId;
}
context.setProjectDocument({
...currentProjectDocument,
activeSceneId: nextSceneId
});
context.setSelection({ kind: "none" });
context.setToolMode("select");
},
undo(context) {
if (previousSceneId === null) {
return;
}
const currentProjectDocument = context.getProjectDocument();
if (currentProjectDocument.scenes[previousSceneId] === undefined) {
throw new Error(`Cannot restore missing scene ${previousSceneId}.`);
}
context.setProjectDocument({
...currentProjectDocument,
activeSceneId: previousSceneId
});
context.setSelection({ kind: "none" });
context.setToolMode("select");
}
};
}