From e659beb51207e148e313eb8461323c2b518b7135 Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Fri, 3 Apr 2026 00:55:13 +0200 Subject: [PATCH] Add delete functionality for scene items in App.tsx --- src/app/App.tsx | 336 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 239 insertions(+), 97 deletions(-) diff --git a/src/app/App.tsx b/src/app/App.tsx index b45fc5e9..dbad37f7 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -10,9 +10,12 @@ import { } from "react"; import { createCreateBoxBrushCommand } from "../commands/create-box-brush-command"; +import { createDeleteBoxBrushCommand } from "../commands/delete-box-brush-command"; +import { createDeleteEntityCommand } from "../commands/delete-entity-command"; import { createImportAudioAssetCommand } from "../commands/import-audio-asset-command"; import { createImportBackgroundImageAssetCommand } from "../commands/import-background-image-asset-command"; import { createImportModelAssetCommand } from "../commands/import-model-asset-command"; +import { createDeleteModelInstanceCommand } from "../commands/delete-model-instance-command"; import { createMoveBoxBrushCommand } from "../commands/move-box-brush-command"; import { createResizeBoxBrushCommand } from "../commands/resize-box-brush-command"; import { createSetBoxBrushFaceMaterialCommand } from "../commands/set-box-brush-face-material-command"; @@ -1266,6 +1269,25 @@ export function App({ store, initialStatusMessage }: AppProps) { return; } + const isDeletionKey = event.key === "Delete" || event.key === "Backspace"; + const isDeleteShortcut = !event.altKey && !event.ctrlKey && !event.metaKey && (event.code === "KeyX" || isDeletionKey); + + if (addMenuPosition !== null) { + if (isDeletionKey) { + event.preventDefault(); + } + return; + } + + if (isDeleteShortcut && editorState.toolMode !== "create") { + const deleted = handleDeleteSelectedSceneItem(); + + if (deleted || isDeletionKey) { + event.preventDefault(); + } + return; + } + if ( event.code !== "NumpadComma" && !(event.key === "," && event.location === globalThis.KeyboardEvent.DOM_KEY_LOCATION_NUMPAD) @@ -1295,7 +1317,7 @@ export function App({ store, initialStatusMessage }: AppProps) { window.removeEventListener("pointermove", handleWindowPointerMove); window.removeEventListener("keydown", handleWindowKeyDown); }; - }, [activePanelId, addMenuPosition, editorState.selection, editorState.toolMode, brushList.length, entityList.length]); + }, [activePanelId, addMenuPosition, brushList.length, editorState.selection, editorState.toolMode, entityList.length, handleDeleteSelectedSceneItem]); const applySceneName = () => { const normalizedName = sceneNameDraft.trim() || "Untitled Scene"; @@ -2036,6 +2058,86 @@ export function App({ store, initialStatusMessage }: AppProps) { } }; + const confirmDeleteSceneItem = (label: string) => + globalThis.window.confirm(`Delete ${label}?\n\nThis can be undone with Undo.`); + + const handleDeleteBrush = (brushId: string) => { + const label = getBrushLabelById(brushId, brushList); + + if (!confirmDeleteSceneItem(label)) { + return false; + } + + try { + store.executeCommand(createDeleteBoxBrushCommand(brushId)); + setStatusMessage(`Deleted ${label}.`); + return true; + } catch (error) { + setStatusMessage(getErrorMessage(error)); + return false; + } + }; + + const handleDeleteEntity = (entityId: string) => { + const label = getEntityDisplayLabelById(entityId, editorState.document.entities, editorState.document.assets); + + if (!confirmDeleteSceneItem(label)) { + return false; + } + + try { + store.executeCommand(createDeleteEntityCommand(entityId)); + setStatusMessage(`Deleted ${label}.`); + return true; + } catch (error) { + setStatusMessage(getErrorMessage(error)); + return false; + } + }; + + const handleDeleteModelInstance = (modelInstanceId: string) => { + const label = getModelInstanceDisplayLabelById( + modelInstanceId, + editorState.document.modelInstances, + editorState.document.assets + ); + + if (!confirmDeleteSceneItem(label)) { + return false; + } + + try { + store.executeCommand(createDeleteModelInstanceCommand(modelInstanceId)); + setStatusMessage(`Deleted ${label}.`); + return true; + } catch (error) { + setStatusMessage(getErrorMessage(error)); + return false; + } + }; + + const handleDeleteSelectedSceneItem = () => { + const selectedBrushId = getSingleSelectedBrushId(editorState.selection); + + if (selectedBrushId !== null) { + return handleDeleteBrush(selectedBrushId); + } + + const selectedEntityId = getSingleSelectedEntityId(editorState.selection); + + if (selectedEntityId !== null) { + return handleDeleteEntity(selectedEntityId); + } + + const selectedModelInstanceId = getSingleSelectedModelInstanceId(editorState.selection); + + if (selectedModelInstanceId !== null) { + return handleDeleteModelInstance(selectedModelInstanceId); + } + + return false; + }; + const updateInteractionLinkTrigger = (link: InteractionLink, trigger: InteractionTriggerKind) => { const sourceEntity = getInteractionSourceEntityForLink(link); @@ -3911,6 +4013,16 @@ export function App({ store, initialStatusMessage }: AppProps) {
+ @@ -3997,53 +4109,67 @@ export function App({ store, initialStatusMessage }: AppProps) {
Use Add > Box and click in the viewport to create the first brush.
) : (
- {brushList.map((brush, brushIndex) => ( -
- + {brushList.map((brush, brushIndex) => { + const label = getBrushLabel(brush, brushIndex); - {selectedBrush?.id !== brush.id ? null : ( - - )} -
- ))} + return ( +
+
+ + +
+ + {selectedBrush?.id !== brush.id ? null : ( + + )} +
+ ); + })}
)}
@@ -4055,31 +4181,45 @@ export function App({ store, initialStatusMessage }: AppProps) { ) : (
{modelInstanceDisplayList.map(({ modelInstance, label }) => ( - +
+ + +
+
))}
)} @@ -4087,49 +4227,51 @@ export function App({ store, initialStatusMessage }: AppProps) {
Entities
-
- -
{entityDisplayList.length === 0 ?
No entities authored yet.
: null} {entityDisplayList.length === 0 ? null : (
{entityDisplayList.map(({ entity, label }) => ( - +
+ + +
+
))}
)}