import { makeAutoObservable } from "mobx"; import { state } from "./rootState"; import type { ReactNode } from "react"; import { IconRun, IconTrash, IconPlus, IconCubePlus, IconCubeOff } from '@tabler/icons-react'; export type MenuNodeAction = { id: string; content: ReactNode; tooltip: string; onClick: () => void; } export type MenuNode = { id: string; title: ReactNode; className?: string; actions?: MenuNodeAction[]; onClick?: () => void; selected?: () => boolean; children?: MenuNode[]; } export class MenuState { constructor() { makeAutoObservable(this); } private get editorObjectTypesMenu(): MenuNode[] { const editor = state.worldEditor; const scene = editor.scene; return Object.values(state.world.data.objectTypes) .map((ot) => { const children = Object.values(scene.objects) .filter((o) => o.typeId === ot.id) .map((o, idx) => { const isPlayer = scene.playerObjectId === o.id; const actions: MenuNodeAction[] = []; if (!isPlayer) { actions.push({ id: 'delete-object-instance', content: , tooltip: 'Delete the object', onClick: () => { editor.deleteObject(o.id); }, }); actions.push({ id: 'control-object-instance-by-player', content: , tooltip: 'Mark as player', onClick: () => { scene.playerObjectId = o.id; }, }); } return { id: `o-${o.id}`, title: <> {isPlayer && } {`${ot.name} ${idx + 1}`} , className: isPlayer ? 'player-controlled-object' : undefined, actions, onClick: () => { state.worldEditor.setSelectedObject({ id: o.id, editMode: 'translate' }) }, selected: () => state.worldEditor.selection?.type === 'object' && state.worldEditor.selection?.id === o.id, } as MenuNode; }); return { id: `ot-${ot.id}`, title: `${ot.name} (${children.length ? children.length : 'no'} instance${children.length != 1 ? 's' : ''})`, actions: [ { id: 'create-object-instance', content: , tooltip: 'Create new object instance', onClick: () => { editor.addObjectInstanceAtRandomPosition(ot.id); }, }, { id: 'delete-object-type', content: , tooltip: 'Delete object type', onClick: () => { editor.deleteObjectType(ot.id); }, }, ], onClick: () => { editor.setSelectedObjectType({ id: ot.id, editMode: 'scripts' }) }, selected: () => editor.selection?.type === 'objectType' && editor.selection?.id === ot.id, children, } as MenuNode }); } private get editorMenu(): MenuNode[] { return [ { id: 'editor-scene-menu', title: 'Scene', onClick: () => { state.worldEditor.resetSelection() }, selected: () => !state.worldEditor.selection, children: this.editorObjectTypesMenu, actions: [{ id: 'create-object-type', content: , tooltip: 'Create new object type', onClick: () => { state.worldEditor.addObjectType(); }, }], } ] } public get nodes(): MenuNode[] { return [ ...this.editorMenu, ] } public nodeContainsSelected(node: MenuNode): boolean { return !!(node.selected?.() || node.children?.some((child) => this.nodeContainsSelected(child))); } }