Filter entities

This commit is contained in:
Simon Lübeß
2024-11-17 19:57:31 +01:00
parent 080861ed4a
commit e1e91089ca
2 changed files with 103 additions and 71 deletions
@@ -2,7 +2,7 @@
import {MenuBar, MenuItem} from "../Components/Menu.tsx"; import {MenuBar, MenuItem} from "../Components/Menu.tsx";
import "./EntityHierarchyWindow.css"; import "./EntityHierarchyWindow.css";
import {MouseEvent, MouseEventHandler, ReactElement, useEffect} from "react"; import {MouseEvent, MouseEventHandler, ReactElement, useEffect, useState} from "react";
import IconVisible from "../assets/Icons/AntDesign/eye-visible.svg"; import IconVisible from "../assets/Icons/AntDesign/eye-visible.svg";
import IconInvisible from "../assets/Icons/AntDesign/eye-invisible.svg"; import IconInvisible from "../assets/Icons/AntDesign/eye-invisible.svg";
@@ -12,23 +12,35 @@ import {EngineGlue} from "../EngineGlue";
import {enableMapSet} from "immer" import {enableMapSet} from "immer"
import {Entity, EntityId} from "../Entity.ts"; import {Entity, EntityId} from "../Entity.ts";
import * as sea from "node:sea";
enableMapSet() enableMapSet()
type EntityMap = { type EntityMap = {
selectedIds: Set<EntityId>; selectedIds: Set<EntityId>;
[id: EntityId]: Entity; entities: Map<EntityId, Entity>;
//[id: EntityId]: Entity;
}; };
const entityHierarchy: EntityMap = { const entityHierarchy: EntityMap = {
selectedIds: new Set<EntityId>(), selectedIds: new Set<EntityId>(),
// 0 is hardcoded to be the root. The editor must provide this "pseudo"-entity. entities: new Map<EntityId, Entity>([
0: new Entity("Root", 0, []) [0, new Entity("Root", 0, [1, 2])],
[1, new Entity("Entity 1", 1, [])],
[2, new Entity("Entity 2", 2, [3])],
[3, new Entity("Entity 3 in 2", 3, [])]
])
// // 0 is hardcoded to be the root. The editor must provide this "pseudo"-entity.
// 0: new Entity("Root", 0, [1, 2]),
// 1: new Entity("Entity 1", 1, []),
// 2: new Entity("Entity 2", 2, [3]),
// 3: new Entity("Entity 3 in 2", 3, [])
}; };
export default function EntityHierarchyWindow(props: IDockviewPanelProps) export default function EntityHierarchyWindow(props: IDockviewPanelProps)
{ {
const [entities, updateEntities] = useImmer(entityHierarchy); const [entities, updateEntities] = useImmer(entityHierarchy);
const [filterText, setFilterText] = useState("");
useEffect(() => { useEffect(() => {
EngineGlue.onUpdateEntities = (entities: Entity[]) => { EngineGlue.onUpdateEntities = (entities: Entity[]) => {
@@ -42,12 +54,14 @@ export default function EntityHierarchyWindow(props: IDockviewPanelProps)
if (entity.name === "undefined") if (entity.name === "undefined")
{ {
delete draft[entity.id]; draft.entities.delete(entity.id);
//delete draft[entity.id];
draft.selectedIds.delete(entity.id); draft.selectedIds.delete(entity.id);
} }
else else
{ {
draft[entity.id] = entity; draft.entities.set(entity.id, entity);
//draft[entity.id] = entity;
} }
} }
} }
@@ -67,43 +81,15 @@ export default function EntityHierarchyWindow(props: IDockviewPanelProps)
return ( return (
<> <>
<MenuBar> <EntityMenuBar searchString={filterText} onFilterTextChanged={setFilterText} />
<MenuItem text="Create"> <EntityTree items={entities} updateItems={updateEntities} entityFilter={filterText}/>
<MenuItem text="Empty Entity" onClick={window.EngineGlue.onClickCreateEmptyEntity}/>
<MenuItem text="Parent Entity">
<MenuItem text="Test 1 (lang)">
<MenuItem text="Du">
<MenuItem text="Übertreibst">
<MenuItem text="Völlig"/>
<MenuItem text="Du Hund!"/>
</MenuItem>
</MenuItem>
</MenuItem>
<MenuItem text="Test 2">
<MenuItem text="Ach komm,"/>
</MenuItem>
<MenuItem text="Test 3">
<MenuItem text="Hör auf!"/>
</MenuItem>
</MenuItem>
<MenuItem text="Child Entity"/>
</MenuItem>
<MenuItem text="Delete">
<MenuItem text="Selected"/>
<MenuItem text="All"/>
</MenuItem>
<MenuItem text="Copy">
</MenuItem>
<input className="filterEntities" placeholder="Filter entities..."/>
</MenuBar>
<EntityTree items={entities} updateItems={updateEntities}/>
</> </>
); );
} }
function EntityTreeItem({item, allEntities, updateEntities}: { function EntityTreeItem({item, allEntities, updateEntities, showAsTree}: {
item: Entity, item: Entity,
allEntities: EntityMap, updateEntities: Updater<EntityMap>}) : ReactElement allEntities: EntityMap, updateEntities: Updater<EntityMap>, showAsTree: boolean}) : ReactElement
{ {
//const [isOpen, setOpen] = useState(false); //const [isOpen, setOpen] = useState(false);
@@ -148,16 +134,16 @@ function EntityTreeItem({item, allEntities, updateEntities}: {
</div> </div>
{ {
item.children.length > 0 && showAsTree && item.children.length > 0 &&
<ul> <ul>
{ {
item.children.map((childId) => { item.children.map((childId) => {
const entity: Entity = allEntities[childId]; const entity = allEntities.entities.get(childId);
if (entity === undefined) if (entity === undefined)
return; return;
return <EntityTreeItem key={entity.id} item={entity} allEntities={allEntities} updateEntities={updateEntities}/>; return <EntityTreeItem key={entity.id} item={entity} allEntities={allEntities} updateEntities={updateEntities} showAsTree={showAsTree}/>;
}) })
} }
</ul> </ul>
@@ -170,7 +156,12 @@ function VisibilityToggle({item, onClick, updateEntities} : {item: Entity, onCli
function clickHandler(event: MouseEvent) function clickHandler(event: MouseEvent)
{ {
updateEntities(draft => { updateEntities(draft => {
draft[item.id].visible = !item.visible; const entity = draft.entities.get(item.id)
if (entity !== undefined)
{
entity.visible = !item.visible;
}
}); });
console.log("Clickidy" + item.visible); console.log("Clickidy" + item.visible);
@@ -187,20 +178,77 @@ function VisibilityToggle({item, onClick, updateEntities} : {item: Entity, onCli
); );
} }
function EntityTree({items, updateItems}: { items: EntityMap, updateItems: Updater<EntityMap> }) function EntityTree({items, updateItems, entityFilter}: { items: EntityMap, updateItems: Updater<EntityMap>, entityFilter: string })
{
const rootEntity = items.entities.get(0);
if (entityFilter.length == 0)
{ {
return ( return (
<ul className="tree-view"> <ul className="tree-view">
{ {
items[0].children.map((childId) => { rootEntity && rootEntity.children.map((childId) => {
const entity: Entity = items[childId]; const entity = items.entities.get(childId);
if (entity === undefined) if (entity === undefined)
return; return;
return <EntityTreeItem key={entity.id} item={entity} allEntities={items} updateEntities={updateItems} />; return <EntityTreeItem key={entity.id} item={entity} allEntities={items} updateEntities={updateItems} showAsTree={true} />;
}) })
} }
</ul> </ul>
); );
} }
else
{
return (
<ul className="tree-view">
{
Array.from(items.entities).filter(([, entity]) => {
return entity.name.indexOf(entityFilter) != -1
}).map(([, entity]) => {
return <EntityTreeItem key={entity.id} item={entity} allEntities={items}
updateEntities={updateItems} showAsTree={false}/>;
})
}
</ul>
);
}
}
function EntityMenuBar({searchString, onFilterTextChanged}: {
searchString: string,
onFilterTextChanged: (s: string) => void
})
{
return <MenuBar>
<MenuItem text="Create">
<MenuItem text="Empty Entity" onClick={window.EngineGlue.onClickCreateEmptyEntity}/>
<MenuItem text="Parent Entity">
<MenuItem text="Test 1 (lang)">
<MenuItem text="Du">
<MenuItem text="Übertreibst">
<MenuItem text="Völlig"/>
<MenuItem text="Du Hund!"/>
</MenuItem>
</MenuItem>
</MenuItem>
<MenuItem text="Test 2">
<MenuItem text="Ach komm,"/>
</MenuItem>
<MenuItem text="Test 3">
<MenuItem text="Hör auf!"/>
</MenuItem>
</MenuItem>
<MenuItem text="Child Entity"/>
</MenuItem>
<MenuItem text="Delete">
<MenuItem text="Selected"/>
<MenuItem text="All"/>
</MenuItem>
<MenuItem text="Copy">
</MenuItem>
<input className="filterEntities" placeholder="Filter entities..." content={searchString}
onChange={(e) => onFilterTextChanged(e.target.value)}/>
</MenuBar>;
}
@@ -118,22 +118,6 @@ abstract class UltralightWindow
{ {
CopyToImmediateTexture(); CopyToImmediateTexture();
CopyToBackBuffer(); CopyToBackBuffer();
if (Input.IsKeyPressing(Key.A))
{
ULString str = ulCreateString("window.updateEntities([])");
ULString exception = null;
ulViewEvaluateScript(_view, str, &exception);
if (exception != null && ulStringGetLength(exception) != 0)
{
StringView ex = StringView(ulStringGetData(exception), ulStringGetLength(exception));
Log.EngineLogger.Error($"Failed to evaluate script: {ex}");
}
ulDestroyString(str);
}
} }
private void CreateTexture() private void CreateTexture()