2025-10-14 23:31:09 +08:00
|
|
|
import { useState, useEffect } from 'react';
|
|
|
|
|
import { Entity } from '@esengine/ecs-framework';
|
|
|
|
|
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
|
2025-10-14 23:56:54 +08:00
|
|
|
import { useLocale } from '../hooks/useLocale';
|
2025-10-14 23:31:09 +08:00
|
|
|
import '../styles/SceneHierarchy.css';
|
|
|
|
|
|
|
|
|
|
interface SceneHierarchyProps {
|
|
|
|
|
entityStore: EntityStoreService;
|
|
|
|
|
messageHub: MessageHub;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function SceneHierarchy({ entityStore, messageHub }: SceneHierarchyProps) {
|
|
|
|
|
const [entities, setEntities] = useState<Entity[]>([]);
|
|
|
|
|
const [selectedId, setSelectedId] = useState<number | null>(null);
|
2025-10-14 23:56:54 +08:00
|
|
|
const { t } = useLocale();
|
2025-10-14 23:31:09 +08:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const updateEntities = () => {
|
|
|
|
|
setEntities(entityStore.getRootEntities());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSelection = (data: { entity: Entity | null }) => {
|
|
|
|
|
setSelectedId(data.entity?.id ?? null);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
updateEntities();
|
|
|
|
|
|
|
|
|
|
const unsubAdd = messageHub.subscribe('entity:added', updateEntities);
|
|
|
|
|
const unsubRemove = messageHub.subscribe('entity:removed', updateEntities);
|
|
|
|
|
const unsubClear = messageHub.subscribe('entities:cleared', updateEntities);
|
|
|
|
|
const unsubSelect = messageHub.subscribe('entity:selected', handleSelection);
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
unsubAdd();
|
|
|
|
|
unsubRemove();
|
|
|
|
|
unsubClear();
|
|
|
|
|
unsubSelect();
|
|
|
|
|
};
|
|
|
|
|
}, [entityStore, messageHub]);
|
|
|
|
|
|
|
|
|
|
const handleEntityClick = (entity: Entity) => {
|
|
|
|
|
entityStore.selectEntity(entity);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="scene-hierarchy">
|
|
|
|
|
<div className="hierarchy-header">
|
2025-10-14 23:56:54 +08:00
|
|
|
<h3>{t('hierarchy.title')}</h3>
|
2025-10-14 23:31:09 +08:00
|
|
|
</div>
|
|
|
|
|
<div className="hierarchy-content">
|
|
|
|
|
{entities.length === 0 ? (
|
2025-10-14 23:56:54 +08:00
|
|
|
<div className="empty-state">{t('hierarchy.empty')}</div>
|
2025-10-14 23:31:09 +08:00
|
|
|
) : (
|
|
|
|
|
<ul className="entity-list">
|
|
|
|
|
{entities.map(entity => (
|
|
|
|
|
<li
|
|
|
|
|
key={entity.id}
|
|
|
|
|
className={`entity-item ${selectedId === entity.id ? 'selected' : ''}`}
|
|
|
|
|
onClick={() => handleEntityClick(entity)}
|
|
|
|
|
>
|
|
|
|
|
<span className="entity-icon">📦</span>
|
|
|
|
|
<span className="entity-name">Entity {entity.id}</span>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|