support search node

This commit is contained in:
codetypes committed 2024-04-26 09:37:49 +08:00
1 parent 7dbea171bb
commit 82d1d89311
6 files changed
+112 -8

No files matched your search

+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "behavior3editor",
"version": "1.1.2",
"version": "1.1.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "behavior3editor",
"version": "1.1.2",
"version": "1.1.3",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "behavior3editor",
"version": "1.1.2",
"version": "1.1.3",
"main": "dist-electron/main/index.js",
"description": "行为树编辑器",
"author": "zhandouxiaojiji & codetypes",
+104 -2
View File
@@ -10,17 +10,19 @@ import * as b3util from "@/misc/b3util";
import { message } from "@/misc/hooks";
import { Hotkey, isHotkeyPressed, isMacos, useHotkeys } from "@/misc/keys";
import Path from "@/misc/path";
import { ArrowDownOutlined, ArrowUpOutlined, CloseOutlined } from "@ant-design/icons";
import G6, { G6GraphEvent, Item, TreeGraph } from "@antv/g6";
import { dialog } from "@electron/remote";
import { useSize } from "ahooks";
import { Dropdown, Flex, FlexProps, MenuProps } from "antd";
import { Button, Dropdown, Flex, FlexProps, Input, MenuProps } from "antd";
import { clipboard } from "electron";
import * as fs from "fs";
import React, { FC, useCallback, useEffect, useMemo, useRef } from "react";
import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { FiDelete } from "react-icons/fi";
import { IoMdReturnLeft } from "react-icons/io";
import { mergeRefs } from "react-merge-refs";
import { useDebounceCallback } from "usehooks-ts";
import "./register-node";
export interface EditorProps extends React.HTMLAttributes<HTMLElement> {
@@ -36,11 +38,27 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
open: useWorkspace((state) => state.open),
workdir: useWorkspace((state) => state.workdir),
};
const [results, setResults] = useState<string[]>([]);
const [resultIndex, setResultIndex] = useState(0);
const [showingSearch, setShowingSearch] = useState(false);
const graphRef = useRef(null);
const sizeRef = useRef(null);
const editorSize = useSize(sizeRef);
const { t } = useTranslation();
const onSearchChange = useDebounceCallback((filter: string) => {
const ids = filterNodes(filter, findDataById("1"));
setResults(ids);
setResultIndex(0);
if (ids.length > 0) {
editor.graph.focusItem(ids[0]);
selectNode(ids[0]);
}
if (filter.length == 0) {
restoreViewport();
}
}, 200);
const onChange = () => {
if (!editor.unsave) {
editor.unsave = true;
@@ -93,6 +111,17 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
return editor.graph.findDataById(id) as TreeGraphData;
};
const filterNodes = (str: string, node: TreeGraphData | null, ids?: string[]): string[] => {
ids ||= [];
if (node && str) {
if (node.name.toLocaleLowerCase().indexOf(str) >= 0) {
ids.push(node.id);
}
node.children?.forEach((child: TreeGraphData) => filterNodes(str, child, ids));
}
return ids;
};
const isAncestor = (ancestor: TreeGraphData, node: TreeGraphData): boolean => {
if (ancestor.id === node.parent) {
return true;
@@ -761,6 +790,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
Hotkey.Delete,
Hotkey.Enter,
Hotkey.Backspace,
Hotkey.SearchNode,
],
(event) => {
event.preventDefault();
@@ -778,6 +808,8 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
createNode();
} else if (isHotkeyPressed(Hotkey.Delete) || isHotkeyPressed(Hotkey.Backspace)) {
deleteNode();
} else if (isHotkeyPressed(Hotkey.SearchNode)) {
setShowingSearch(true);
}
}
);
@@ -967,6 +999,76 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
tabIndex={-1}
style={{ maxWidth: "inherit", maxHeight: "inherit" }}
>
{showingSearch && (
<Flex
style={{
position: "absolute",
marginTop: "10px",
marginLeft: "10px",
backgroundColor: "#161b22",
padding: "4px 10px 4px 10px",
borderRadius: "4px",
borderLeft: "4px solid #f78166",
boxShadow: "0 0 8px 2px #0000005c",
alignItems: "center",
}}
>
<Input
autoFocus
allowClear
size="small"
style={{ borderRadius: "2px" }}
onChange={(e) => onSearchChange(e.currentTarget.value)}
/>
<div style={{ padding: "0 10px 0 5px" }}>
{results.length ? `${resultIndex + 1}/${results.length}` : ""}
</div>
<Button
icon={<ArrowDownOutlined />}
type="text"
size="small"
style={{ width: "30px" }}
disabled={results.length == 0}
onClick={() => {
if (results.length > 0) {
const idx = (resultIndex + 1) % results.length;
setResultIndex(idx);
editor.graph.focusItem(results[idx]);
selectNode(results[idx]);
}
}}
/>
<Button
icon={<ArrowUpOutlined />}
type="text"
size="small"
style={{ width: "30px" }}
disabled={results.length == 0}
onClick={() => {
if (results.length > 0) {
const idx = (resultIndex + results.length - 1) % results.length;
setResultIndex(idx);
console.log(idx, results[idx]);
editor.graph.focusItem(results[idx]);
selectNode(results[idx]);
}
}}
/>
<Button
icon={<CloseOutlined />}
type="text"
size="small"
style={{ width: "30px" }}
onClick={() => {
setShowingSearch(false);
setResults([]);
setResultIndex(0);
keysRef.current?.focus();
}}
/>
</Flex>
)}
<Dropdown menu={{ items: menuItems, onClick }} trigger={["contextMenu"]}>
<div tabIndex={-1} style={{ width: "100%", height: "100%" }} ref={graphRef} />
</Dropdown>
+2 -2
View File
@@ -44,7 +44,7 @@ export const Workspace: FC = () => {
const { width = 0, height = 0 } = useWindowSize();
const keysRef = useHotkeys<HTMLDivElement>(
[Hotkey.Save, Hotkey.CloseEditor, Hotkey.Search, Hotkey.Build],
[Hotkey.Save, Hotkey.CloseEditor, Hotkey.SearchTree, Hotkey.Build],
(event) => {
if (isHotkeyPressed(Hotkey.Save)) {
event.preventDefault();
@@ -58,7 +58,7 @@ export const Workspace: FC = () => {
workspace.close(workspace.editing.path);
}
}
} else if (isHotkeyPressed(Hotkey.Search)) {
} else if (isHotkeyPressed(Hotkey.SearchTree)) {
event.preventDefault();
workspace.onShowingSearch(true);
} else if (isHotkeyPressed(Hotkey.Build)) {
+1
View File
@@ -32,6 +32,7 @@ export type EditEvent =
| "rename"
| "updateTree"
| "updateNode"
| "searchNode"
| "editSubtree"
| "saveAsSubtree";
+2 -1
View File
@@ -57,7 +57,8 @@ export const Hotkey = {
Redo: isMacos ? hotkey("shift+ctrl+z") : hotkey("ctrl+y"),
Replace: hotkey("shift+ctrl+v"),
Save: hotkey("ctrl+s"),
Search: hotkey("ctrl+p"),
SearchTree: hotkey("ctrl+p"),
SearchNode: hotkey("ctrl+f"),
Undo: hotkey("ctrl+z"),
};