feat(shortcut): h/a/d
This commit is contained in:
@@ -56,6 +56,7 @@ import {
|
||||
import { useTopToolsStore } from "./useTopToolsStore"
|
||||
import { findGroupKey } from "./util"
|
||||
import { safeClone } from "./utils/clone"
|
||||
import { toggleObjectHideByShortcut } from "./utils/objectVisibility"
|
||||
import { labelTypeMap } from "./utils/constants"
|
||||
|
||||
// Splitter component - will need custom implementation or alternative
|
||||
@@ -233,9 +234,11 @@ const LabelPage = ({
|
||||
const {
|
||||
editMode,
|
||||
setEditMode,
|
||||
pressA,
|
||||
setPressA,
|
||||
activeOperation,
|
||||
setActiveOperation,
|
||||
setDrawOption,
|
||||
showObjectList,
|
||||
showGroupList,
|
||||
showTaskList,
|
||||
@@ -1357,6 +1360,12 @@ const LabelPage = ({
|
||||
}, [editMode, setDrawType])
|
||||
|
||||
const { setShift, focusInput } = useKeyEventStore()
|
||||
const drawAction = useKeyboardStore((state) => state.drawAction)
|
||||
const drawShortcutSnapshotRef = useRef<{
|
||||
activeOperation: string
|
||||
drawOption: "default" | "intersect" | "unite"
|
||||
editMode: boolean
|
||||
} | null>(null)
|
||||
|
||||
const handleShortcut = useCallback(
|
||||
(key: string, ctrl: boolean) => {
|
||||
@@ -1376,6 +1385,132 @@ const LabelPage = ({
|
||||
[getOperationSchema, setActiveOperation]
|
||||
)
|
||||
|
||||
const resolveSelectedObjectContext = useCallback(() => {
|
||||
const imageId = useBottomToolsStore.getState().activeImage
|
||||
const selectedIds = useObjectStore.getState().selectedPath[imageId] || []
|
||||
if (selectedIds.length !== 1) return null
|
||||
|
||||
const objectId = selectedIds[0]
|
||||
const imageLabel = useLabelStore.getState().label.get(imageId)
|
||||
if (!imageLabel) return null
|
||||
|
||||
let operationId = ""
|
||||
for (const [categoryId, paths] of imageLabel.entries()) {
|
||||
if (paths.some((path) => path[0] === objectId)) {
|
||||
operationId = categoryId
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!operationId) return null
|
||||
|
||||
const selectedItem = usePaperStore.getState().getItemById(objectId)
|
||||
if (!selectedItem?.data?.type) return null
|
||||
|
||||
return {
|
||||
imageId,
|
||||
objectId,
|
||||
operationId,
|
||||
objectType: selectedItem.data.type as string,
|
||||
}
|
||||
}, [])
|
||||
|
||||
const restoreDrawShortcutSnapshot = useCallback(() => {
|
||||
useKeyboardStore.getState().setDrawAction("none")
|
||||
|
||||
const snapshot = drawShortcutSnapshotRef.current
|
||||
if (!snapshot) return
|
||||
|
||||
setActiveOperation(snapshot.activeOperation)
|
||||
setDrawOption(snapshot.drawOption)
|
||||
setEditMode(snapshot.editMode)
|
||||
drawShortcutSnapshotRef.current = null
|
||||
}, [setActiveOperation, setDrawOption, setEditMode])
|
||||
|
||||
const enterSelectedObjectDrawMode = useCallback(
|
||||
(mode: "add" | "subtract") => {
|
||||
const selectedContext = resolveSelectedObjectContext()
|
||||
if (!selectedContext) {
|
||||
notifications.show({
|
||||
color: "yellow",
|
||||
message: "请先选中单个对象",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
mode === "add" &&
|
||||
!["polygon", "brush"].includes(selectedContext.objectType)
|
||||
) {
|
||||
notifications.show({
|
||||
color: "yellow",
|
||||
message: "新增区域仅支持 polygon/brush 类型对象",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (mode === "subtract" && selectedContext.objectType !== "polygon") {
|
||||
notifications.show({
|
||||
color: "yellow",
|
||||
message: "删除区域仅支持 polygon 类型对象",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!drawShortcutSnapshotRef.current) {
|
||||
const topState = useTopToolsStore.getState()
|
||||
drawShortcutSnapshotRef.current = {
|
||||
activeOperation: topState.activeOperation,
|
||||
drawOption: topState.drawOption,
|
||||
editMode: topState.editMode,
|
||||
}
|
||||
}
|
||||
|
||||
setActiveOperation(selectedContext.operationId)
|
||||
setEditMode(true)
|
||||
setDrawOption("default")
|
||||
useKeyboardStore.getState().setDrawAction(mode)
|
||||
setPressA(true)
|
||||
|
||||
if (!useTopToolsStore.getState().pressA) {
|
||||
notifications.show({
|
||||
color: "yellow",
|
||||
message: "当前对象无法进入区域编辑模式",
|
||||
})
|
||||
restoreDrawShortcutSnapshot()
|
||||
}
|
||||
},
|
||||
[
|
||||
resolveSelectedObjectContext,
|
||||
restoreDrawShortcutSnapshot,
|
||||
setActiveOperation,
|
||||
setDrawOption,
|
||||
setEditMode,
|
||||
setPressA,
|
||||
]
|
||||
)
|
||||
|
||||
const handleToggleHideSelectedObject = useCallback(() => {
|
||||
const selectedContext = resolveSelectedObjectContext()
|
||||
if (!selectedContext) {
|
||||
notifications.show({
|
||||
color: "yellow",
|
||||
message: "请先选中单个对象",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const currentHideStatus =
|
||||
useObjectStore.getState().pathStatus[
|
||||
selectedContext.imageId + selectedContext.objectId
|
||||
]?.HIDE || false
|
||||
toggleObjectHideByShortcut(
|
||||
selectedContext.imageId,
|
||||
selectedContext.operationId,
|
||||
selectedContext.objectId,
|
||||
!currentHideStatus
|
||||
)
|
||||
}, [resolveSelectedObjectContext])
|
||||
|
||||
const handleMergeSelectedObjects = useCallback(() => {
|
||||
const activeImage = useBottomToolsStore.getState().activeImage
|
||||
const selectedIds =
|
||||
@@ -1518,6 +1653,27 @@ const LabelPage = ({
|
||||
|
||||
console.log(e.key)
|
||||
const mode = usePaperStore.getState().mode
|
||||
const lowerKey = e.key.toLowerCase()
|
||||
|
||||
if (e.repeat && ["a", "d", "h"].includes(lowerKey)) return
|
||||
|
||||
if (!e.ctrlKey && !e.metaKey && !e.altKey && lowerKey === "h") {
|
||||
e.preventDefault()
|
||||
handleToggleHideSelectedObject()
|
||||
return
|
||||
}
|
||||
|
||||
if (!e.ctrlKey && !e.metaKey && !e.altKey && lowerKey === "a") {
|
||||
e.preventDefault()
|
||||
enterSelectedObjectDrawMode("add")
|
||||
return
|
||||
}
|
||||
|
||||
if (!e.ctrlKey && !e.metaKey && !e.altKey && lowerKey === "d") {
|
||||
e.preventDefault()
|
||||
enterSelectedObjectDrawMode("subtract")
|
||||
return
|
||||
}
|
||||
|
||||
if (e.altKey && e.key.toLowerCase() === "x") {
|
||||
e.preventDefault()
|
||||
@@ -1561,11 +1717,6 @@ const LabelPage = ({
|
||||
paperContainerRef.current.handleCreatePathGroup()
|
||||
}
|
||||
|
||||
if (e.key === "a") {
|
||||
e.preventDefault()
|
||||
setPressA(true)
|
||||
}
|
||||
|
||||
if (e.key === "Control") {
|
||||
e.preventDefault()
|
||||
useKeyboardStore.getState().setCtrl(true)
|
||||
@@ -1746,19 +1897,27 @@ const LabelPage = ({
|
||||
}
|
||||
}, [
|
||||
editMode,
|
||||
enterSelectedObjectDrawMode,
|
||||
focusInput,
|
||||
getOperationSchema,
|
||||
handleToggleHideSelectedObject,
|
||||
handleMergeSelectedObjects,
|
||||
handleShortcut,
|
||||
isView,
|
||||
projectDetail?.label_type,
|
||||
setEditMode,
|
||||
setGroupScale,
|
||||
setDrawOption,
|
||||
setPressA,
|
||||
setScale,
|
||||
setShift,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
if (drawAction === "none" || pressA) return
|
||||
restoreDrawShortcutSnapshot()
|
||||
}, [drawAction, pressA, restoreDrawShortcutSnapshot])
|
||||
|
||||
const setGlobalLoading = useCallback((flag: boolean) => {
|
||||
setLoading(flag)
|
||||
}, [])
|
||||
@@ -1766,6 +1925,8 @@ const LabelPage = ({
|
||||
// 切换图片时清空复制保存的数组
|
||||
useEffect(() => {
|
||||
useKeyboardStore.getState().setCopyDataIds([])
|
||||
useKeyboardStore.getState().setDrawAction("none")
|
||||
drawShortcutSnapshotRef.current = null
|
||||
}, [activeImage])
|
||||
|
||||
const handleBeforeUnload = (e: any) => {
|
||||
|
||||
Reference in New Issue
Block a user