2025-11-18 14:46:51 +08:00
|
|
|
import { useCallback } from 'react';
|
2025-11-03 21:22:16 +08:00
|
|
|
import { ask } from '@tauri-apps/plugin-dialog';
|
2025-11-18 14:46:51 +08:00
|
|
|
import { BehaviorTreeNode } from '../stores';
|
2025-11-03 21:22:16 +08:00
|
|
|
|
|
|
|
|
interface UseEditorHandlersParams {
|
|
|
|
|
isDraggingNode: boolean;
|
|
|
|
|
selectedNodeIds: string[];
|
|
|
|
|
setSelectedNodeIds: (ids: string[]) => void;
|
|
|
|
|
resetView: () => void;
|
2025-11-18 14:46:51 +08:00
|
|
|
resetTree: () => void;
|
2025-11-03 21:22:16 +08:00
|
|
|
triggerForceUpdate: () => void;
|
|
|
|
|
onNodeSelect?: (node: BehaviorTreeNode) => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useEditorHandlers(params: UseEditorHandlersParams) {
|
|
|
|
|
const {
|
|
|
|
|
isDraggingNode,
|
|
|
|
|
selectedNodeIds,
|
|
|
|
|
setSelectedNodeIds,
|
|
|
|
|
resetView,
|
2025-11-18 14:46:51 +08:00
|
|
|
resetTree,
|
2025-11-03 21:22:16 +08:00
|
|
|
triggerForceUpdate,
|
2025-11-18 14:46:51 +08:00
|
|
|
onNodeSelect
|
2025-11-03 21:22:16 +08:00
|
|
|
} = params;
|
|
|
|
|
|
2025-11-18 14:46:51 +08:00
|
|
|
const handleNodeClick = useCallback((e: React.MouseEvent, node: BehaviorTreeNode) => {
|
|
|
|
|
// 阻止事件冒泡,避免触发画布的点击事件
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
2025-11-03 21:22:16 +08:00
|
|
|
if (isDraggingNode) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (e.ctrlKey || e.metaKey) {
|
|
|
|
|
if (selectedNodeIds.includes(node.id)) {
|
|
|
|
|
setSelectedNodeIds(selectedNodeIds.filter((id: string) => id !== node.id));
|
|
|
|
|
} else {
|
|
|
|
|
setSelectedNodeIds([...selectedNodeIds, node.id]);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
setSelectedNodeIds([node.id]);
|
|
|
|
|
}
|
|
|
|
|
onNodeSelect?.(node);
|
2025-11-18 14:46:51 +08:00
|
|
|
}, [isDraggingNode, selectedNodeIds, setSelectedNodeIds, onNodeSelect]);
|
2025-11-03 21:22:16 +08:00
|
|
|
|
2025-11-18 14:46:51 +08:00
|
|
|
const handleResetView = useCallback(() => {
|
2025-11-03 21:22:16 +08:00
|
|
|
resetView();
|
|
|
|
|
requestAnimationFrame(() => {
|
|
|
|
|
triggerForceUpdate();
|
|
|
|
|
});
|
2025-11-18 14:46:51 +08:00
|
|
|
}, [resetView, triggerForceUpdate]);
|
2025-11-03 21:22:16 +08:00
|
|
|
|
2025-11-18 14:46:51 +08:00
|
|
|
const handleClearCanvas = useCallback(async () => {
|
2025-11-03 21:22:16 +08:00
|
|
|
const confirmed = await ask('确定要清空画布吗?此操作不可撤销。', {
|
|
|
|
|
title: '清空画布',
|
|
|
|
|
kind: 'warning'
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (confirmed) {
|
2025-11-18 14:46:51 +08:00
|
|
|
resetTree();
|
2025-11-03 21:22:16 +08:00
|
|
|
setSelectedNodeIds([]);
|
|
|
|
|
}
|
2025-11-18 14:46:51 +08:00
|
|
|
}, [resetTree, setSelectedNodeIds]);
|
2025-11-03 21:22:16 +08:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
handleNodeClick,
|
|
|
|
|
handleResetView,
|
|
|
|
|
handleClearCanvas
|
|
|
|
|
};
|
|
|
|
|
}
|