diff --git a/src/commands/delete-box-brush-command.ts b/src/commands/delete-box-brush-command.ts new file mode 100644 index 00000000..56b75155 --- /dev/null +++ b/src/commands/delete-box-brush-command.ts @@ -0,0 +1,78 @@ +import { createOpaqueId } from "../core/ids"; +import type { EditorSelection } from "../core/selection"; +import type { ToolMode } from "../core/tool-mode"; +import { cloneBoxBrush, type BoxBrush } from "../document/brushes"; + +import { cloneSelectionForCommand, removeBrush } from "./brush-command-helpers"; +import type { EditorCommand } from "./command"; + +function selectionIncludesBrush(selection: EditorSelection, brushId: string): boolean { + return ( + (selection.kind === "brushes" && selection.ids.includes(brushId)) || + (selection.kind === "brushFace" && selection.brushId === brushId) + ); +} + +export function createDeleteBoxBrushCommand(brushId: string): EditorCommand { + let previousBrush: BoxBrush | null = null; + let previousSelection: EditorSelection | null = null; + let previousToolMode: ToolMode | null = null; + + return { + id: createOpaqueId("command"), + label: "Delete box brush", + execute(context) { + const currentDocument = context.getDocument(); + const currentBrush = currentDocument.brushes[brushId]; + + if (currentBrush === undefined) { + throw new Error(`Box brush ${brushId} does not exist.`); + } + + if (previousBrush === null) { + previousBrush = cloneBoxBrush(currentBrush); + } + + if (previousSelection === null) { + previousSelection = cloneSelectionForCommand(context.getSelection()); + } + + if (previousToolMode === null) { + previousToolMode = context.getToolMode(); + } + + context.setDocument(removeBrush(currentDocument, brushId)); + + if (selectionIncludesBrush(context.getSelection(), brushId)) { + context.setSelection({ + kind: "none" + }); + } + + context.setToolMode("select"); + }, + undo(context) { + if (previousBrush === null) { + return; + } + + const currentDocument = context.getDocument(); + + context.setDocument({ + ...currentDocument, + brushes: { + ...currentDocument.brushes, + [previousBrush.id]: cloneBoxBrush(previousBrush) + } + }); + + if (previousSelection !== null) { + context.setSelection(previousSelection); + } + + if (previousToolMode !== null) { + context.setToolMode(previousToolMode); + } + } + }; +} diff --git a/src/commands/delete-entity-command.ts b/src/commands/delete-entity-command.ts new file mode 100644 index 00000000..ede9ff98 --- /dev/null +++ b/src/commands/delete-entity-command.ts @@ -0,0 +1,82 @@ +import { createOpaqueId } from "../core/ids"; +import { cloneEditorSelection, type EditorSelection } from "../core/selection"; +import type { ToolMode } from "../core/tool-mode"; +import { cloneEntityInstance, type EntityInstance } from "../entities/entity-instances"; + +import type { EditorCommand } from "./command"; + +function selectionIncludesEntity(selection: EditorSelection, entityId: string): boolean { + return selection.kind === "entities" && selection.ids.includes(entityId); +} + +export function createDeleteEntityCommand(entityId: string): EditorCommand { + let previousEntity: EntityInstance | null = null; + let previousSelection: EditorSelection | null = null; + let previousToolMode: ToolMode | null = null; + + return { + id: createOpaqueId("command"), + label: "Delete entity", + execute(context) { + const currentDocument = context.getDocument(); + const currentEntity = currentDocument.entities[entityId]; + + if (currentEntity === undefined) { + throw new Error(`Entity ${entityId} does not exist.`); + } + + if (previousEntity === null) { + previousEntity = cloneEntityInstance(currentEntity); + } + + if (previousSelection === null) { + previousSelection = cloneEditorSelection(context.getSelection()); + } + + if (previousToolMode === null) { + previousToolMode = context.getToolMode(); + } + + const nextEntities = { + ...currentDocument.entities + }; + delete nextEntities[entityId]; + + context.setDocument({ + ...currentDocument, + entities: nextEntities + }); + + if (selectionIncludesEntity(context.getSelection(), entityId)) { + context.setSelection({ + kind: "none" + }); + } + + context.setToolMode("select"); + }, + undo(context) { + if (previousEntity === null) { + return; + } + + const currentDocument = context.getDocument(); + + context.setDocument({ + ...currentDocument, + entities: { + ...currentDocument.entities, + [previousEntity.id]: cloneEntityInstance(previousEntity) + } + }); + + if (previousSelection !== null) { + context.setSelection(previousSelection); + } + + if (previousToolMode !== null) { + context.setToolMode(previousToolMode); + } + } + }; +} diff --git a/src/commands/delete-model-instance-command.ts b/src/commands/delete-model-instance-command.ts new file mode 100644 index 00000000..5d1f5517 --- /dev/null +++ b/src/commands/delete-model-instance-command.ts @@ -0,0 +1,82 @@ +import { createOpaqueId } from "../core/ids"; +import { cloneEditorSelection, type EditorSelection } from "../core/selection"; +import type { ToolMode } from "../core/tool-mode"; +import { cloneModelInstance, type ModelInstance } from "../assets/model-instances"; + +import type { EditorCommand } from "./command"; + +function selectionIncludesModelInstance(selection: EditorSelection, modelInstanceId: string): boolean { + return selection.kind === "modelInstances" && selection.ids.includes(modelInstanceId); +} + +export function createDeleteModelInstanceCommand(modelInstanceId: string): EditorCommand { + let previousModelInstance: ModelInstance | null = null; + let previousSelection: EditorSelection | null = null; + let previousToolMode: ToolMode | null = null; + + return { + id: createOpaqueId("command"), + label: "Delete model instance", + execute(context) { + const currentDocument = context.getDocument(); + const currentModelInstance = currentDocument.modelInstances[modelInstanceId]; + + if (currentModelInstance === undefined) { + throw new Error(`Model instance ${modelInstanceId} does not exist.`); + } + + if (previousModelInstance === null) { + previousModelInstance = cloneModelInstance(currentModelInstance); + } + + if (previousSelection === null) { + previousSelection = cloneEditorSelection(context.getSelection()); + } + + if (previousToolMode === null) { + previousToolMode = context.getToolMode(); + } + + const nextModelInstances = { + ...currentDocument.modelInstances + }; + delete nextModelInstances[modelInstanceId]; + + context.setDocument({ + ...currentDocument, + modelInstances: nextModelInstances + }); + + if (selectionIncludesModelInstance(context.getSelection(), modelInstanceId)) { + context.setSelection({ + kind: "none" + }); + } + + context.setToolMode("select"); + }, + undo(context) { + if (previousModelInstance === null) { + return; + } + + const currentDocument = context.getDocument(); + + context.setDocument({ + ...currentDocument, + modelInstances: { + ...currentDocument.modelInstances, + [previousModelInstance.id]: cloneModelInstance(previousModelInstance) + } + }); + + if (previousSelection !== null) { + context.setSelection(previousSelection); + } + + if (previousToolMode !== null) { + context.setToolMode(previousToolMode); + } + } + }; +}