diff --git a/lama_cleaner/app/src/components/Editor/Editor.tsx b/lama_cleaner/app/src/components/Editor/Editor.tsx index c6dd917..d3a6047 100644 --- a/lama_cleaner/app/src/components/Editor/Editor.tsx +++ b/lama_cleaner/app/src/components/Editor/Editor.tsx @@ -106,6 +106,11 @@ export default function Editor(props: EditorProps) { const [sliderPos, setSliderPos] = useState(0) + // redo 相关 + const [redoRenders, setRedoRenders] = useState([]) + const [redoCurLines, setRedoCurLines] = useState([]) + const [redoLineGroups, setRedoLineGroups] = useState([]) + const draw = useCallback( (render: HTMLImageElement, lineGroup: LineGroup) => { if (!context) { @@ -175,6 +180,9 @@ export default function Editor(props: EditorProps) { draw(newRender, []) // Only append new LineGroup after inpainting success setLineGroups(newLineGroups) + + // clear redo stack + resetRedoState() } catch (e: any) { setToastState({ open: true, @@ -303,10 +311,19 @@ export default function Editor(props: EditorProps) { setPanned(false) }, [viewportRef, windowSize, original.width, windowSize.height, minScale]) + const resetRedoState = () => { + setRedoCurLines([]) + setRedoLineGroups([]) + setRedoRenders([]) + } + useEffect(() => { setLineGroups([]) setCurLineGroup([]) setRenders([]) + + resetRedoState() + resetZoom() const imageSizeLimit = Math.max(original.width, original.height) setSizeLimit(imageSizeLimit) @@ -445,28 +462,43 @@ export default function Editor(props: EditorProps) { if (curLineGroup.length === 0) { return } - const newLineGroup = curLineGroup.slice(0, curLineGroup.length - 1) + + const lastLine = curLineGroup.pop()! + const newRedoCurLines = [...redoCurLines, lastLine] + setRedoCurLines(newRedoCurLines) + + const newLineGroup = [...curLineGroup] setCurLineGroup(newLineGroup) drawOnCurrentRender(newLineGroup) - }, [curLineGroup, drawOnCurrentRender]) + }, [curLineGroup, redoCurLines, drawOnCurrentRender]) const undoRender = useCallback(() => { if (!renders.length) { return } - const groups = lineGroups.slice(0, lineGroups.length - 1) - setLineGroups(groups) + // save line Group + const lastLineGroup = lineGroups.pop()! + setRedoLineGroups([...redoLineGroups, lastLineGroup]) + // If render is undo, clear strokes + setRedoCurLines([]) + + setLineGroups([...lineGroups]) setCurLineGroup([]) setIsDraging(false) - const newRenders = renders.slice(0, renders.length - 1) + + // save render + const lastRender = renders.pop()! + setRedoRenders([...redoRenders, lastRender]) + + const newRenders = [...renders] setRenders(newRenders) if (newRenders.length === 0) { draw(original, []) } else { draw(newRenders[newRenders.length - 1], []) } - }, [draw, renders, lineGroups, original]) + }, [draw, renders, redoRenders, redoLineGroups, lineGroups, original]) const undo = () => { if (settings.runInpaintingManually && curLineGroup.length !== 0) { @@ -478,13 +510,15 @@ export default function Editor(props: EditorProps) { // Handle Cmd+Z const undoPredicate = (event: KeyboardEvent) => { - const isCmdZ = (event.metaKey || event.ctrlKey) && event.key === 'z' + const isCmdZ = + (event.metaKey || event.ctrlKey) && !event.shiftKey && event.key === 'z' // Handle tab switch if (event.key === 'Tab') { event.preventDefault() } if (isCmdZ) { event.preventDefault() + console.log('undo') return true } return false @@ -493,6 +527,9 @@ export default function Editor(props: EditorProps) { useKey(undoPredicate, undo, undefined, [undoStroke, undoRender]) const disableUndo = () => { + if (isInpaintingLoading) { + return true + } if (renders.length > 0) { return false } @@ -508,6 +545,80 @@ export default function Editor(props: EditorProps) { return false } + const redoStroke = useCallback(() => { + if (redoCurLines.length === 0) { + return + } + const line = redoCurLines.pop()! + setRedoCurLines([...redoCurLines]) + + const newLineGroup = [...curLineGroup, line] + setCurLineGroup(newLineGroup) + drawOnCurrentRender(newLineGroup) + }, [curLineGroup, redoCurLines, drawOnCurrentRender]) + + const redoRender = useCallback(() => { + if (redoRenders.length === 0) { + return + } + const lineGroup = redoLineGroups.pop()! + setRedoLineGroups([...redoLineGroups]) + + setLineGroups([...lineGroups, lineGroup]) + setCurLineGroup([]) + setIsDraging(false) + + const render = redoRenders.pop()! + const newRenders = [...renders, render] + setRenders(newRenders) + draw(newRenders[newRenders.length - 1], []) + }, [draw, renders, redoRenders, redoLineGroups, lineGroups, original]) + + const redo = () => { + if (settings.runInpaintingManually && redoCurLines.length !== 0) { + redoStroke() + } else { + redoRender() + } + } + + // Handle Cmd+shift+Z + const redoPredicate = (event: KeyboardEvent) => { + const isCmdZ = + (event.metaKey || event.ctrlKey) && event.shiftKey && event.key === 'z' + // Handle tab switch + if (event.key === 'Tab') { + event.preventDefault() + } + if (isCmdZ) { + event.preventDefault() + console.log('redo') + return true + } + return false + } + + useKey(redoPredicate, redo, undefined, [redoStroke, redoRender]) + + const disableRedo = () => { + if (isInpaintingLoading) { + return true + } + if (redoRenders.length > 0) { + return false + } + + if (settings.runInpaintingManually) { + if (redoCurLines.length === 0) { + return true + } + } else if (redoRenders.length === 0) { + return true + } + + return false + } + useKeyPressEvent( 'Tab', ev => { @@ -781,6 +892,27 @@ export default function Editor(props: EditorProps) { onClick={undo} disabled={disableUndo()} /> +