From 54d362afe7fefca27a769708eb03b8e340968400 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 19 Nov 2024 15:43:56 -0600 Subject: [PATCH 1/2] feat(ui): change reset canvas button to new session menu --- invokeai/frontend/web/public/locales/en.json | 2 +- .../components/Toolbar/CanvasToolbar.tsx | 4 +-- .../CanvasToolbarNewSessionMenuButton.tsx | 35 +++++++++++++++++++ .../CanvasToolbarResetCanvasButton.tsx | 30 ---------------- 4 files changed, 38 insertions(+), 33 deletions(-) create mode 100644 invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarNewSessionMenuButton.tsx delete mode 100644 invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarResetCanvasButton.tsx diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 4ac3e2f199d..c885af9afe5 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1676,7 +1676,7 @@ "mergingLayers": "Merging layers", "clearHistory": "Clear History", "bboxOverlay": "Show Bbox Overlay", - "resetCanvas": "Reset Canvas", + "newSession": "New Session", "clearCaches": "Clear Caches", "recalculateRects": "Recalculate Rects", "clipToBbox": "Clip Strokes to Bbox", diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbar.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbar.tsx index e8dcf7bb263..c2c4b5451f8 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbar.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbar.tsx @@ -4,8 +4,8 @@ import { CanvasSettingsPopover } from 'features/controlLayers/components/Setting import { ToolColorPicker } from 'features/controlLayers/components/Tool/ToolFillColorPicker'; import { ToolSettings } from 'features/controlLayers/components/Tool/ToolSettings'; import { CanvasToolbarFitBboxToLayersButton } from 'features/controlLayers/components/Toolbar/CanvasToolbarFitBboxToLayersButton'; +import { CanvasToolbarNewSessionMenuButton } from 'features/controlLayers/components/Toolbar/CanvasToolbarNewSessionMenuButton'; import { CanvasToolbarRedoButton } from 'features/controlLayers/components/Toolbar/CanvasToolbarRedoButton'; -import { CanvasToolbarResetCanvasButton } from 'features/controlLayers/components/Toolbar/CanvasToolbarResetCanvasButton'; import { CanvasToolbarResetViewButton } from 'features/controlLayers/components/Toolbar/CanvasToolbarResetViewButton'; import { CanvasToolbarSaveToGalleryButton } from 'features/controlLayers/components/Toolbar/CanvasToolbarSaveToGalleryButton'; import { CanvasToolbarScale } from 'features/controlLayers/components/Toolbar/CanvasToolbarScale'; @@ -43,7 +43,7 @@ export const CanvasToolbar = memo(() => { - + diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarNewSessionMenuButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarNewSessionMenuButton.tsx new file mode 100644 index 00000000000..efc87d3ff01 --- /dev/null +++ b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarNewSessionMenuButton.tsx @@ -0,0 +1,35 @@ +import { IconButton, Menu, MenuButton, MenuItem, MenuList } from '@invoke-ai/ui-library'; +import { + useNewCanvasSession, + useNewGallerySession, +} from 'features/controlLayers/components/NewSessionConfirmationAlertDialog'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { PiFilePlusBold, PiImageBold, PiPaintBrushBold } from 'react-icons/pi'; + +export const CanvasToolbarNewSessionMenuButton = memo(() => { + const { t } = useTranslation(); + const { newGallerySessionWithDialog } = useNewGallerySession(); + const { newCanvasSessionWithDialog } = useNewCanvasSession(); + return ( + + } + variant="link" + alignSelf="stretch" + /> + + } onClick={newGallerySessionWithDialog}> + {t('controlLayers.newGallerySession')} + + } onClick={newCanvasSessionWithDialog}> + {t('controlLayers.newCanvasSession')} + + + + ); +}); + +CanvasToolbarNewSessionMenuButton.displayName = 'CanvasToolbarNewSessionMenuButton'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarResetCanvasButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarResetCanvasButton.tsx deleted file mode 100644 index 08e9326c69a..00000000000 --- a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarResetCanvasButton.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { IconButton } from '@invoke-ai/ui-library'; -import { useAppDispatch } from 'app/store/storeHooks'; -import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; -import { canvasReset } from 'features/controlLayers/store/actions'; -import { memo, useCallback } from 'react'; -import { useTranslation } from 'react-i18next'; -import { PiEmptyBold } from 'react-icons/pi'; - -export const CanvasToolbarResetCanvasButton = memo(() => { - const { t } = useTranslation(); - const dispatch = useAppDispatch(); - const canvasManager = useCanvasManager(); - const onClick = useCallback(() => { - dispatch(canvasReset()); - canvasManager.stage.fitLayersToStage(); - }, [canvasManager.stage, dispatch]); - return ( - } - variant="link" - alignSelf="stretch" - /> - ); -}); - -CanvasToolbarResetCanvasButton.displayName = 'CanvasToolbarResetCanvasButton'; From f1e7ee92a31c76c46dcac25d8fdc5723c1eccf93 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 19 Nov 2024 15:49:09 -0600 Subject: [PATCH 2/2] feat(ui): add actions for reset canvas layers / generation settings to session menus --- invokeai/frontend/web/public/locales/en.json | 2 + .../common/components/SessionMenuItems.tsx | 42 +++++++++++++++++++ .../CanvasToolbarNewSessionMenuButton.tsx | 18 ++------ .../controlLayers/store/paramsSlice.ts | 30 +++++++------ .../components/QueueActionsMenuButton.tsx | 25 ++--------- 5 files changed, 68 insertions(+), 49 deletions(-) create mode 100644 invokeai/frontend/web/src/common/components/SessionMenuItems.tsx diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index c885af9afe5..8b679897138 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1787,6 +1787,8 @@ "newGallerySessionDesc": "This will clear the canvas and all settings except for your model selection. Generations will be sent to the gallery.", "newCanvasSession": "New Canvas Session", "newCanvasSessionDesc": "This will clear the canvas and all settings except for your model selection. Generations will be staged on the canvas.", + "resetCanvasLayers": "Reset Canvas Layers", + "resetGenerationSettings": "Reset Generation Settings", "replaceCurrent": "Replace Current", "controlLayerEmptyState": "Upload an image, drag an image from the gallery onto this layer, or draw on the canvas to get started.", "controlMode": { diff --git a/invokeai/frontend/web/src/common/components/SessionMenuItems.tsx b/invokeai/frontend/web/src/common/components/SessionMenuItems.tsx new file mode 100644 index 00000000000..0f931b17c44 --- /dev/null +++ b/invokeai/frontend/web/src/common/components/SessionMenuItems.tsx @@ -0,0 +1,42 @@ +import { MenuItem } from '@invoke-ai/ui-library'; +import { useAppDispatch } from 'app/store/storeHooks'; +import { + useNewCanvasSession, + useNewGallerySession, +} from 'features/controlLayers/components/NewSessionConfirmationAlertDialog'; +import { canvasReset } from 'features/controlLayers/store/actions'; +import { paramsReset } from 'features/controlLayers/store/paramsSlice'; +import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import { PiArrowsCounterClockwiseBold, PiFilePlusBold } from 'react-icons/pi'; + +export const SessionMenuItems = memo(() => { + const { t } = useTranslation(); + const dispatch = useAppDispatch(); + const { newGallerySessionWithDialog } = useNewGallerySession(); + const { newCanvasSessionWithDialog } = useNewCanvasSession(); + const resetCanvasLayers = useCallback(() => { + dispatch(canvasReset()); + }, [dispatch]); + const resetGenerationSettings = useCallback(() => { + dispatch(paramsReset()); + }, [dispatch]); + return ( + <> + } onClick={newGallerySessionWithDialog}> + {t('controlLayers.newGallerySession')} + + } onClick={newCanvasSessionWithDialog}> + {t('controlLayers.newCanvasSession')} + + } onClick={resetCanvasLayers}> + {t('controlLayers.resetCanvasLayers')} + + } onClick={resetGenerationSettings}> + {t('controlLayers.resetGenerationSettings')} + + + ); +}); + +SessionMenuItems.displayName = 'SessionMenuItems'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarNewSessionMenuButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarNewSessionMenuButton.tsx index efc87d3ff01..a55c768f9fe 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarNewSessionMenuButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarNewSessionMenuButton.tsx @@ -1,16 +1,11 @@ -import { IconButton, Menu, MenuButton, MenuItem, MenuList } from '@invoke-ai/ui-library'; -import { - useNewCanvasSession, - useNewGallerySession, -} from 'features/controlLayers/components/NewSessionConfirmationAlertDialog'; +import { IconButton, Menu, MenuButton, MenuList } from '@invoke-ai/ui-library'; +import { SessionMenuItems } from 'common/components/SessionMenuItems'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; -import { PiFilePlusBold, PiImageBold, PiPaintBrushBold } from 'react-icons/pi'; +import { PiFilePlusBold } from 'react-icons/pi'; export const CanvasToolbarNewSessionMenuButton = memo(() => { const { t } = useTranslation(); - const { newGallerySessionWithDialog } = useNewGallerySession(); - const { newCanvasSessionWithDialog } = useNewCanvasSession(); return ( { alignSelf="stretch" /> - } onClick={newGallerySessionWithDialog}> - {t('controlLayers.newGallerySession')} - - } onClick={newCanvasSessionWithDialog}> - {t('controlLayers.newCanvasSession')} - + ); diff --git a/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts b/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts index f70dc697d3a..582419a247e 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts @@ -273,24 +273,27 @@ export const paramsSlice = createSlice({ setCanvasCoherenceMinDenoise: (state, action: PayloadAction) => { state.canvasCoherenceMinDenoise = action.payload; }, + paramsReset: (state) => resetState(state), }, extraReducers(builder) { - builder.addMatcher(newSessionRequested, (state) => { - // When a new session is requested, we need to keep the current model selections, plus dependent state - // like VAE precision. Everything else gets reset to default. - const newState = deepClone(initialState); - newState.model = state.model; - newState.vae = state.vae; - newState.fluxVAE = state.fluxVAE; - newState.vaePrecision = state.vaePrecision; - newState.t5EncoderModel = state.t5EncoderModel; - newState.clipEmbedModel = state.clipEmbedModel; - newState.refinerModel = state.refinerModel; - return newState; - }); + builder.addMatcher(newSessionRequested, (state) => resetState(state)); }, }); +const resetState = (state: ParamsState): ParamsState => { + // When a new session is requested, we need to keep the current model selections, plus dependent state + // like VAE precision. Everything else gets reset to default. + const newState = deepClone(initialState); + newState.model = state.model; + newState.vae = state.vae; + newState.fluxVAE = state.fluxVAE; + newState.vaePrecision = state.vaePrecision; + newState.t5EncoderModel = state.t5EncoderModel; + newState.clipEmbedModel = state.clipEmbedModel; + newState.refinerModel = state.refinerModel; + return newState; +}; + export const { setInfillMethod, setInfillTileSize, @@ -334,6 +337,7 @@ export const { setRefinerNegativeAestheticScore, setRefinerStart, modelChanged, + paramsReset, } = paramsSlice.actions; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ diff --git a/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx b/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx index 1ae76eec4b7..e4ed61b5653 100644 --- a/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx +++ b/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx @@ -1,9 +1,6 @@ import { IconButton, Menu, MenuButton, MenuGroup, MenuItem, MenuList } from '@invoke-ai/ui-library'; import { useAppDispatch } from 'app/store/storeHooks'; -import { - useNewCanvasSession, - useNewGallerySession, -} from 'features/controlLayers/components/NewSessionConfirmationAlertDialog'; +import { SessionMenuItems } from 'common/components/SessionMenuItems'; import { useClearQueue } from 'features/queue/components/ClearQueueConfirmationAlertDialog'; import { QueueCountBadge } from 'features/queue/components/QueueCountBadge'; import { usePauseProcessor } from 'features/queue/hooks/usePauseProcessor'; @@ -12,16 +9,7 @@ import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { setActiveTab } from 'features/ui/store/uiSlice'; import { memo, useCallback, useRef } from 'react'; import { useTranslation } from 'react-i18next'; -import { - PiImageBold, - PiListBold, - PiPaintBrushBold, - PiPauseFill, - PiPlayFill, - PiQueueBold, - PiTrashSimpleBold, - PiXBold, -} from 'react-icons/pi'; +import { PiListBold, PiPauseFill, PiPlayFill, PiQueueBold, PiTrashSimpleBold, PiXBold } from 'react-icons/pi'; export const QueueActionsMenuButton = memo(() => { const ref = useRef(null); @@ -29,8 +17,6 @@ export const QueueActionsMenuButton = memo(() => { const { t } = useTranslation(); const isPauseEnabled = useFeatureStatus('pauseQueue'); const isResumeEnabled = useFeatureStatus('resumeQueue'); - const { newGallerySessionWithDialog } = useNewGallerySession(); - const { newCanvasSessionWithDialog } = useNewCanvasSession(); const clearQueue = useClearQueue(); const { resumeProcessor, @@ -52,12 +38,7 @@ export const QueueActionsMenuButton = memo(() => { } /> - } onClick={newGallerySessionWithDialog}> - {t('controlLayers.newGallerySession')} - - } onClick={newCanvasSessionWithDialog}> - {t('controlLayers.newCanvasSession')} - +