diff --git a/lama_cleaner/app/src/components/Editor/Editor.tsx b/lama_cleaner/app/src/components/Editor/Editor.tsx index 8e6fb00..dd81833 100644 --- a/lama_cleaner/app/src/components/Editor/Editor.tsx +++ b/lama_cleaner/app/src/components/Editor/Editor.tsx @@ -62,6 +62,8 @@ import emitter, { EVENT_CUSTOM_MASK, EVENT_PAINT_BY_EXAMPLE, RERUN_LAST_MASK, + DREAM_BUTTON_MOUSE_ENTER, + DREAM_BUTTON_MOUSE_LEAVE, } from '../../event' import FileSelect from '../FileSelect/FileSelect' import InteractiveSeg from '../InteractiveSeg/InteractiveSeg' @@ -130,15 +132,24 @@ export default function Editor() { ) const [showInteractiveSegModal, setShowInteractiveSegModal] = useState(false) - const [interactiveSegMask, setInteractiveSegMask] = - useState(null) + const [interactiveSegMask, setInteractiveSegMask] = useState< + HTMLImageElement | null | undefined + >(null) // only used while interactive segmentation is on - const [tmpInteractiveSegMask, setTmpInteractiveSegMask] = - useState(null) + const [tmpInteractiveSegMask, setTmpInteractiveSegMask] = useState< + HTMLImageElement | null | undefined + >(null) const [prevInteractiveSegMask, setPrevInteractiveSegMask] = useState< HTMLImageElement | null | undefined >(null) + // 仅用于在 dream button hover 时显示提示 + const [dreamButtonHoverSegMask, setDreamButtonHoverSegMask] = useState< + HTMLImageElement | null | undefined + >(null) + const [dreamButtonHoverLineGroup, setDreamButtonHoverLineGroup] = + useState([]) + const [clicks, setClicks] = useRecoilState(interactiveSegClicksState) const [brushSize, setBrushSize] = useRecoilState(brushSizeState) @@ -202,21 +213,33 @@ export default function Editor() { context.clearRect(0, 0, context.canvas.width, context.canvas.height) context.drawImage(render, 0, 0, imageWidth, imageHeight) - if (isInteractiveSeg && tmpInteractiveSegMask !== null) { + if (isInteractiveSeg && tmpInteractiveSegMask) { context.drawImage(tmpInteractiveSegMask, 0, 0, imageWidth, imageHeight) } - if (!isInteractiveSeg && interactiveSegMask !== null) { + if (!isInteractiveSeg && interactiveSegMask) { context.drawImage(interactiveSegMask, 0, 0, imageWidth, imageHeight) } + if (dreamButtonHoverSegMask) { + context.drawImage( + dreamButtonHoverSegMask, + 0, + 0, + imageWidth, + imageHeight + ) + } drawLines(context, lineGroup) + drawLines(context, dreamButtonHoverLineGroup) }, [ context, isInteractiveSeg, tmpInteractiveSegMask, + dreamButtonHoverSegMask, interactiveSegMask, imageHeight, imageWidth, + dreamButtonHoverLineGroup, ] ) @@ -277,6 +300,7 @@ export default function Editor() { const drawOnCurrentRender = useCallback( (lineGroup: LineGroup) => { + console.log('[drawOnCurrentRender] draw on current render') if (renders.length === 0) { draw(original, lineGroup) } else { @@ -459,6 +483,53 @@ export default function Editor() { prevInteractiveSegMask, ]) + useEffect(() => { + emitter.on(DREAM_BUTTON_MOUSE_ENTER, () => { + // 当前 canvas 上没有手绘 mask 或者 interactiveSegMask 时,显示上一次的 mask + if (!hadDrawSomething() && !interactiveSegMask) { + if (prevInteractiveSegMask) { + setDreamButtonHoverSegMask(prevInteractiveSegMask) + } + let lineGroup2Show: LineGroup = [] + if (redoLineGroups.length !== 0) { + lineGroup2Show = redoLineGroups[redoLineGroups.length - 1] + } else if (lineGroups.length !== 0) { + lineGroup2Show = lineGroups[lineGroups.length - 1] + } + console.log( + `[DREAM_BUTTON_MOUSE_ENTER], prevInteractiveSegMask: ${prevInteractiveSegMask} lineGroup2Show: ${lineGroup2Show.length}` + ) + if (lineGroup2Show) { + setDreamButtonHoverLineGroup(lineGroup2Show) + } + } + }) + return () => { + emitter.off(DREAM_BUTTON_MOUSE_ENTER) + } + }, [ + hadDrawSomething, + interactiveSegMask, + prevInteractiveSegMask, + drawOnCurrentRender, + lineGroups, + redoLineGroups, + ]) + + useEffect(() => { + emitter.on(DREAM_BUTTON_MOUSE_LEAVE, () => { + // 当前 canvas 上没有手绘 mask 或者 interactiveSegMask 时,显示上一次的 mask + if (!hadDrawSomething() && !interactiveSegMask) { + setDreamButtonHoverSegMask(null) + setDreamButtonHoverLineGroup([]) + drawOnCurrentRender([]) + } + }) + return () => { + emitter.off(DREAM_BUTTON_MOUSE_LEAVE) + } + }, [hadDrawSomething, interactiveSegMask, drawOnCurrentRender]) + useEffect(() => { emitter.on(EVENT_CUSTOM_MASK, (data: any) => { // TODO: not work with paint by example @@ -743,7 +814,7 @@ export default function Editor() { setInitialCentered(true) } }, [ - context?.canvas, + // context?.canvas, viewportRef, original, isOriginalLoaded, diff --git a/lama_cleaner/app/src/components/Header/PromptInput.tsx b/lama_cleaner/app/src/components/Header/PromptInput.tsx index 21022e2..0bd2b17 100644 --- a/lama_cleaner/app/src/components/Header/PromptInput.tsx +++ b/lama_cleaner/app/src/components/Header/PromptInput.tsx @@ -1,14 +1,18 @@ import React, { FormEvent, useRef, useState } from 'react' import { useClickAway } from 'react-use' import { useRecoilState, useRecoilValue } from 'recoil' -import emitter, { EVENT_PROMPT } from '../../event' +import emitter, { + DREAM_BUTTON_MOUSE_ENTER, + DREAM_BUTTON_MOUSE_LEAVE, + EVENT_PROMPT, +} from '../../event' import { appState, isInpaintingState, propmtState } from '../../store/Atoms' import Button from '../shared/Button' import TextInput from '../shared/Input' // TODO: show progress in input const PromptInput = () => { - const [app, setAppState] = useRecoilState(appState) + const app = useRecoilValue(appState) const [prompt, setPrompt] = useRecoilState(propmtState) const isInpainting = useRecoilValue(isInpaintingState) const ref = useRef(null) @@ -39,6 +43,14 @@ const PromptInput = () => { } } + const onMouseEnter = () => { + emitter.emit(DREAM_BUTTON_MOUSE_ENTER) + } + + const onMouseLeave = () => { + emitter.emit(DREAM_BUTTON_MOUSE_LEAVE) + } + return (
{ border onClick={handleRepaintClick} disabled={prompt.length === 0 || app.isInpainting} + onMouseEnter={onMouseEnter} + onMouseLeave={onMouseLeave} > Dream diff --git a/lama_cleaner/app/src/components/shared/Button.tsx b/lama_cleaner/app/src/components/shared/Button.tsx index 8126bfa..a2fc170 100644 --- a/lama_cleaner/app/src/components/shared/Button.tsx +++ b/lama_cleaner/app/src/components/shared/Button.tsx @@ -12,6 +12,8 @@ interface ButtonProps { onClick?: () => void onDown?: (ev: PointerEvent) => void onUp?: (ev: PointerEvent) => void + onMouseEnter?: () => void + onMouseLeave?: () => void style?: React.CSSProperties } @@ -27,6 +29,8 @@ const Button: React.FC = props => { onClick, onDown, onUp, + onMouseEnter, + onMouseLeave, style, } = props @@ -42,6 +46,8 @@ const Button: React.FC = props => { style={style} onKeyDown={onKeyDown} onClick={blurOnClick} + onMouseEnter={onMouseEnter} + onMouseLeave={onMouseLeave} onPointerDown={(ev: React.PointerEvent) => { onDown?.(ev.nativeEvent) }} diff --git a/lama_cleaner/app/src/event.ts b/lama_cleaner/app/src/event.ts index ac75816..eab7840 100644 --- a/lama_cleaner/app/src/event.ts +++ b/lama_cleaner/app/src/event.ts @@ -14,6 +14,9 @@ export interface PaintByExampleEventData { export const RERUN_LAST_MASK = 'rerun_last_mask' +export const DREAM_BUTTON_MOUSE_ENTER = 'dream_button_mouse_enter' +export const DREAM_BUTTON_MOUSE_LEAVE = 'dream_btoon_mouse_leave' + const emitter = mitt() export default emitter