mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 21:01:52 +00:00
Basic Entity hierarchy sync
This commit is contained in:
@@ -9,5 +9,5 @@ StartupObject = "EditorUI.Program"
|
||||
BuildKind = "StaticLib"
|
||||
BuildCommandsOnCompile = "IfFilesChanged"
|
||||
BuildCommandsOnRun = "IfFilesChanged"
|
||||
PreBuildCmds = ["npm run build"]
|
||||
PreBuildCmds = ["npm run build:debug"]
|
||||
PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist\")"]
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"build:debug": "tsc -b && vite --config vite.config.debug.ts build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
align-items: center;
|
||||
|
||||
--menu-item-height: 2em;
|
||||
--menu-item-height: 1.5em;
|
||||
}
|
||||
|
||||
/* Remove indentation from lists for menu */
|
||||
@@ -25,7 +25,7 @@
|
||||
.menu-item
|
||||
{
|
||||
/* Doesn't change our position, but does something to it, so that
|
||||
following absolutes are absolute to us? */
|
||||
following absolutes are relative to us? */
|
||||
position: relative;
|
||||
height: var(--menu-item-height);
|
||||
}
|
||||
@@ -105,6 +105,7 @@
|
||||
background-color: var(--menu-bar-background-color-click);
|
||||
list-style: none;
|
||||
z-index: 10;
|
||||
height: min-content;
|
||||
}
|
||||
|
||||
/* Show submenu */
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
export interface IEngineGlue {
|
||||
import { Entity } from "./Entity.ts";
|
||||
|
||||
export interface IEngineGlue
|
||||
{
|
||||
// Titlebar Events
|
||||
handleClickCloseWindow(): void;
|
||||
handleClickMaximizeWindow(): void;
|
||||
@@ -9,6 +12,9 @@
|
||||
handleHoverNonClientArea(hover: boolean): void;
|
||||
|
||||
onClickCreateEmptyEntity(): void;
|
||||
|
||||
requestEntityHierarchyUpdate(): void;
|
||||
onUpdateEntities?: (entities: Entity[]) => void;
|
||||
}
|
||||
|
||||
function logNotImplemented(functionName: string)
|
||||
@@ -54,19 +60,38 @@ class DevEngineGlue implements IEngineGlue {
|
||||
{
|
||||
logNotImplemented("onClickCreateEmptyEntity");
|
||||
}
|
||||
|
||||
requestEntityHierarchyUpdate(): void
|
||||
{
|
||||
logNotImplemented("requestEntityHierarchyUpdate");
|
||||
}
|
||||
|
||||
private callFromEngine_updateEntities(entities: Entity[]): void
|
||||
{
|
||||
console.log("Yeah!")
|
||||
|
||||
if (EngineGlue.onUpdateEntities)
|
||||
{
|
||||
EngineGlue.onUpdateEntities(entities);
|
||||
}
|
||||
else
|
||||
{
|
||||
logNotImplemented("onUpdateEntities");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Globales Objekt deklarieren
|
||||
declare global {
|
||||
interface Window {
|
||||
declare global
|
||||
{
|
||||
interface Window
|
||||
{
|
||||
EngineGlue: IEngineGlue;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialisierung: DevEngineGlue als Fallback setzen wenn noch kein EngineGlue existiert
|
||||
if (typeof window.EngineGlue === 'undefined') {
|
||||
if (typeof window.EngineGlue === 'undefined')
|
||||
{
|
||||
window.EngineGlue = new DevEngineGlue();
|
||||
}
|
||||
|
||||
// Export für einfacheren Zugriff in der Anwendung
|
||||
export const EngineGlue: IEngineGlue = window.EngineGlue;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
export type EntityId = number;
|
||||
|
||||
export class Entity
|
||||
{
|
||||
name: string;
|
||||
id: EntityId;
|
||||
visible: boolean = true;
|
||||
children: EntityId[];
|
||||
|
||||
constructor(name: string, key: number, children: EntityId[] = [])
|
||||
{
|
||||
this.name = name;
|
||||
this.id = key;
|
||||
this.children = children;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
import {MenuBar, MenuItem} from "../Components/Menu.tsx";
|
||||
|
||||
import "./EntityHierarchyWindow.css";
|
||||
import {MouseEventHandler, ReactElement, MouseEvent} from "react";
|
||||
import {MouseEvent, MouseEventHandler, ReactElement, useEffect} from "react";
|
||||
|
||||
import IconVisible from "../assets/Icons/AntDesign/eye-visible.svg";
|
||||
import IconInvisible from "../assets/Icons/AntDesign/eye-invisible.svg";
|
||||
@@ -10,47 +10,61 @@ import {Updater, useImmer} from "use-immer";
|
||||
|
||||
import {EngineGlue} from "../EngineGlue";
|
||||
|
||||
type EntityId = number;
|
||||
import {enableMapSet} from "immer"
|
||||
import {Entity, EntityId} from "../Entity.ts";
|
||||
|
||||
class Entity
|
||||
{
|
||||
name: string;
|
||||
id: EntityId;
|
||||
visible: boolean = true;
|
||||
children: EntityId[];
|
||||
|
||||
constructor(name: string, key: number, children: EntityId[] = [])
|
||||
{
|
||||
this.name = name;
|
||||
this.id = key;
|
||||
this.children = children;
|
||||
}
|
||||
}
|
||||
enableMapSet()
|
||||
|
||||
type EntityMap = {
|
||||
selectedIds: EntityId[];
|
||||
selectedIds: Set<EntityId>;
|
||||
[id: EntityId]: Entity;
|
||||
};
|
||||
|
||||
const entityHierarchy: EntityMap = {
|
||||
selectedIds: [],
|
||||
|
||||
0: new Entity("Entity Root", 0, [1, 4]),
|
||||
1: new Entity("Entity Entity 1", 1, [2, 3]),
|
||||
2: new Entity("Entity Entity 1.1", 2),
|
||||
3: new Entity("Entity Entity 1.2", 3),
|
||||
4: new Entity("Entity Entity 2", 4, [5, 6]),
|
||||
5: new Entity("Entity Entity 2.1", 5),
|
||||
6: new Entity("Entity Entity 2.2", 6, [7]),
|
||||
7: new Entity("Entity Entity 2.2.1", 7, [8, 9]),
|
||||
8: new Entity("Entity Entity 2.2.1.1", 8),
|
||||
9: new Entity("Entity Entity 2.2.1.2", 9)
|
||||
selectedIds: new Set<EntityId>(),
|
||||
// 0 is hardcoded to be the root. The editor must provide this "pseudo"-entity.
|
||||
0: new Entity("Root", 0, [])
|
||||
};
|
||||
|
||||
export default function EntityHierarchyWindow(props: IDockviewPanelProps)
|
||||
{
|
||||
const [entities, updateEntities] = useImmer(entityHierarchy);
|
||||
|
||||
useEffect(() => {
|
||||
EngineGlue.onUpdateEntities = (entities: Entity[]) => {
|
||||
updateEntities(draft => {
|
||||
try
|
||||
{
|
||||
for (const entity of entities)
|
||||
{
|
||||
// console.log(`${entity.id}: "${entity.name ?? "deleted"}",
|
||||
// ${entity.visible ? "Visible" : "Invisible"}, ${entity.children.length} Children: [${entity.children}]`)
|
||||
|
||||
if (entity.name === "undefined")
|
||||
{
|
||||
delete draft[entity.id];
|
||||
draft.selectedIds.delete(entity.id);
|
||||
}
|
||||
else
|
||||
{
|
||||
draft[entity.id] = entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
console.log(`Failed to update entities: ${e}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
EngineGlue.requestEntityHierarchyUpdate();
|
||||
|
||||
return () => {
|
||||
delete EngineGlue.onUpdateEntities;
|
||||
};
|
||||
}, [updateEntities]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuBar>
|
||||
@@ -83,7 +97,6 @@ export default function EntityHierarchyWindow(props: IDockviewPanelProps)
|
||||
<input className="filterEntities" placeholder="Filter entities..."/>
|
||||
</MenuBar>
|
||||
<EntityTree items={entities} updateItems={updateEntities}/>
|
||||
<button className="title-bar__button close" onClick={EngineGlue.handleClickCloseWindow}>🗙</button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -94,7 +107,7 @@ function EntityTreeItem({item, allEntities, updateEntities}: {
|
||||
{
|
||||
//const [isOpen, setOpen] = useState(false);
|
||||
|
||||
const isSelected = allEntities.selectedIds.includes(item.id);
|
||||
const isSelected = allEntities.selectedIds.has(item.id);
|
||||
//const isVisible = allEntities[item.id].visible;
|
||||
|
||||
function handleClick(event: MouseEvent)
|
||||
@@ -103,11 +116,11 @@ function EntityTreeItem({item, allEntities, updateEntities}: {
|
||||
updateEntities(draft => {
|
||||
if (isSelected)
|
||||
{
|
||||
draft.selectedIds = allEntities.selectedIds.filter((id) => {return id != item.id});
|
||||
draft.selectedIds.delete(item.id);
|
||||
}
|
||||
else
|
||||
{
|
||||
draft.selectedIds.push(item.id);
|
||||
draft.selectedIds.add(item.id);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -180,9 +193,12 @@ function EntityTree({items, updateItems}: { items: EntityMap, updateItems: Updat
|
||||
<ul className="tree-view">
|
||||
{
|
||||
items[0].children.map((childId) => {
|
||||
const entity: Entity = items[childId];
|
||||
const entity: Entity = items[childId];
|
||||
|
||||
return <EntityTreeItem key={entity.id} item={entity} allEntities={items} updateEntities={updateItems} />;
|
||||
if (entity === undefined)
|
||||
return;
|
||||
|
||||
return <EntityTreeItem key={entity.id} item={entity} allEntities={items} updateEntities={updateItems} />;
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
{
|
||||
display: flex;
|
||||
grid-area: title;
|
||||
height: 3em;
|
||||
height: 2em;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const isDebug = mode === 'debug'
|
||||
|
||||
return {
|
||||
plugins: [react()],
|
||||
base: "./",
|
||||
build: {
|
||||
target: "es2015",
|
||||
minify: false,
|
||||
terserOptions: undefined,
|
||||
rollupOptions: {
|
||||
preserveModules: true,
|
||||
output: {
|
||||
dir: 'dist',
|
||||
entryFileNames: '[name].js',
|
||||
chunkFileNames: '[name].js',
|
||||
assetFileNames: '[name].[ext]'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user