tidy(ui): tool components & translations

This commit is contained in:
psychedelicious 2024-08-15 20:52:51 +10:00
parent 97c966b04f
commit c172657324
16 changed files with 93 additions and 87 deletions

View File

@ -1697,7 +1697,17 @@
"objects_other": "{{count}} objects",
"filter": "Filter",
"convertToControlLayer": "Convert to Control Layer",
"convertToRasterLayer": "Convert to Raster Layer"
"convertToRasterLayer": "Convert to Raster Layer",
"tool": {
"brush": "Brush",
"eraser": "Eraser",
"rectangle": "Rectangle",
"bbox": "Bbox",
"move": "Move",
"view": "View",
"transform": "Transform",
"eyeDropper": "Eye Dropper"
}
},
"upscaling": {
"upscale": "Upscale",

View File

@ -2,14 +2,14 @@
import { Flex, Switch } from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { useAppSelector } from 'app/store/storeHooks';
import { BrushWidth } from 'features/controlLayers/components/BrushWidth';
import { CanvasResetViewButton } from 'features/controlLayers/components/CanvasResetViewButton';
import { CanvasScale } from 'features/controlLayers/components/CanvasScale';
import ControlLayersSettingsPopover from 'features/controlLayers/components/ControlLayersSettingsPopover';
import { EraserWidth } from 'features/controlLayers/components/EraserWidth';
import { FillColorPicker } from 'features/controlLayers/components/FillColorPicker';
import { ResetCanvasButton } from 'features/controlLayers/components/ResetCanvasButton';
import { ToolChooser } from 'features/controlLayers/components/ToolChooser';
import { ToolBrushWidth } from 'features/controlLayers/components/Tool/ToolBrushWidth';
import { ToolChooser } from 'features/controlLayers/components/Tool/ToolChooser';
import { ToolEraserWidth } from 'features/controlLayers/components/Tool/ToolEraserWidth';
import { ToolFillColorPicker } from 'features/controlLayers/components/Tool/ToolFillColorPicker';
import { UndoRedoButtonGroup } from 'features/controlLayers/components/UndoRedoButtonGroup';
import { $canvasManager } from 'features/controlLayers/konva/CanvasManager';
import { ToggleProgressButton } from 'features/gallery/components/ImageViewer/ToggleProgressButton';
@ -42,15 +42,15 @@ export const ControlLayersToolbar = memo(() => {
</Flex>
</Flex>
<Flex flex={1} gap={2} justifyContent="center" alignItems="center">
{tool === 'brush' && <BrushWidth />}
{tool === 'eraser' && <EraserWidth />}
{tool === 'brush' && <ToolBrushWidth />}
{tool === 'eraser' && <ToolEraserWidth />}
</Flex>
<CanvasScale />
<CanvasResetViewButton />
<Switch onChange={onChangeDebugging}>debug</Switch>
<Flex flex={1} justifyContent="center">
<Flex gap={2} marginInlineStart="auto" alignItems="center">
<FillColorPicker />
<ToolFillColorPicker />
<UndoRedoButtonGroup />
<ControlLayersSettingsPopover />
<ResetCanvasButton />

View File

@ -6,7 +6,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { PiBoundingBoxBold } from 'react-icons/pi';
export const BboxToolButton = memo(() => {
export const ToolBboxButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const isDisabled = useAppSelector((s) => s.canvasV2.session.isStaging || s.canvasV2.tool.isTransforming);
@ -20,8 +20,8 @@ export const BboxToolButton = memo(() => {
return (
<IconButton
aria-label={`${t('controlLayers.bbox')} (Q)`}
tooltip={`${t('controlLayers.bbox')} (Q)`}
aria-label={`${t('controlLayers.tool.bbox')} (Q)`}
tooltip={`${t('controlLayers.tool.bbox')} (Q)`}
icon={<PiBoundingBoxBold />}
colorScheme={isSelected ? 'invokeBlue' : 'base'}
variant="outline"
@ -31,4 +31,4 @@ export const BboxToolButton = memo(() => {
);
});
BboxToolButton.displayName = 'BboxToolButton';
ToolBboxButton.displayName = 'ToolBboxButton';

View File

@ -7,7 +7,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { PiPaintBrushBold } from 'react-icons/pi';
export const BrushToolButton = memo(() => {
export const ToolBrushButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'brush');
@ -26,8 +26,8 @@ export const BrushToolButton = memo(() => {
return (
<IconButton
aria-label={`${t('unifiedCanvas.brush')} (B)`}
tooltip={`${t('unifiedCanvas.brush')} (B)`}
aria-label={`${t('controlLayers.tool.brush')} (B)`}
tooltip={`${t('controlLayers.tool.brush')} (B)`}
icon={<PiPaintBrushBold />}
colorScheme={isSelected ? 'invokeBlue' : 'base'}
variant="outline"
@ -37,4 +37,4 @@ export const BrushToolButton = memo(() => {
);
});
BrushToolButton.displayName = 'BrushToolButton';
ToolBrushButton.displayName = 'ToolBrushButton';

View File

@ -17,7 +17,7 @@ import { useTranslation } from 'react-i18next';
const marks = [0, 100, 200, 300];
const formatPx = (v: number | string) => `${v} px`;
export const BrushWidth = memo(() => {
export const ToolBrushWidth = memo(() => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const width = useAppSelector((s) => s.canvasV2.tool.brush.width);
@ -53,4 +53,4 @@ export const BrushWidth = memo(() => {
);
});
BrushWidth.displayName = 'BrushSize';
ToolBrushWidth.displayName = 'ToolBrushWidth';

View File

@ -0,0 +1,34 @@
import { ButtonGroup } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { ToolBboxButton } from 'features/controlLayers/components/Tool/ToolBboxButton';
import { ToolBrushButton } from 'features/controlLayers/components/Tool/ToolBrushButton';
import { ToolEyeDropperButton } from 'features/controlLayers/components/Tool/ToolEyeDropperButton';
import { ToolMoveButton } from 'features/controlLayers/components/Tool/ToolMoveButton';
import { ToolRectButton } from 'features/controlLayers/components/Tool/ToolRectButton';
import { useCanvasDeleteLayerHotkey } from 'features/controlLayers/hooks/useCanvasDeleteLayerHotkey';
import { useCanvasResetLayerHotkey } from 'features/controlLayers/hooks/useCanvasResetLayerHotkey';
import { ToolEraserButton } from './ToolEraserButton';
import { ToolTransformButton } from './ToolTransformButton';
import { ToolViewButton } from './ToolViewButton';
export const ToolChooser: React.FC = () => {
useCanvasResetLayerHotkey();
useCanvasDeleteLayerHotkey();
const isTransforming = useAppSelector((s) => s.canvasV2.tool.isTransforming);
return (
<>
<ButtonGroup isAttached isDisabled={isTransforming}>
<ToolBrushButton />
<ToolEraserButton />
<ToolRectButton />
<ToolMoveButton />
<ToolViewButton />
<ToolBboxButton />
<ToolEyeDropperButton />
</ButtonGroup>
<ToolTransformButton />
</>
);
};

View File

@ -7,7 +7,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { PiEraserBold } from 'react-icons/pi';
export const EraserToolButton = memo(() => {
export const ToolEraserButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'eraser');
@ -26,8 +26,8 @@ export const EraserToolButton = memo(() => {
return (
<IconButton
aria-label={`${t('unifiedCanvas.eraser')} (E)`}
tooltip={`${t('unifiedCanvas.eraser')} (E)`}
aria-label={`${t('controlLayers.tool.eraser')} (E)`}
tooltip={`${t('controlLayers.tool.eraser')} (E)`}
icon={<PiEraserBold />}
colorScheme={isSelected ? 'invokeBlue' : 'base'}
variant="outline"
@ -37,4 +37,4 @@ export const EraserToolButton = memo(() => {
);
});
EraserToolButton.displayName = 'EraserToolButton';
ToolEraserButton.displayName = 'ToolEraserButton';

View File

@ -17,7 +17,7 @@ import { useTranslation } from 'react-i18next';
const marks = [0, 100, 200, 300];
const formatPx = (v: number | string) => `${v} px`;
export const EraserWidth = memo(() => {
export const ToolEraserWidth = memo(() => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const width = useAppSelector((s) => s.canvasV2.tool.eraser.width);
@ -53,4 +53,4 @@ export const EraserWidth = memo(() => {
);
});
EraserWidth.displayName = 'EraserWidth';
ToolEraserWidth.displayName = 'ToolEraserWidth';

View File

@ -20,8 +20,8 @@ export const ToolEyeDropperButton = memo(() => {
return (
<IconButton
aria-label={`${t('controlLayers.eyeDropper')} (I)`}
tooltip={`${t('controlLayers.eyeDropper')} (I)`}
aria-label={`${t('controlLayers.tool.eyeDropper')} (I)`}
tooltip={`${t('controlLayers.tool.eyeDropper')} (I)`}
icon={<PiEyedropperBold />}
colorScheme={isSelected ? 'invokeBlue' : 'base'}
variant="outline"

View File

@ -7,7 +7,7 @@ import type { RgbaColor } from 'features/controlLayers/store/types';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
export const FillColorPicker = memo(() => {
export const ToolFillColorPicker = memo(() => {
const { t } = useTranslation();
const fill = useAppSelector((s) => s.canvasV2.tool.fill);
const dispatch = useAppDispatch();
@ -41,4 +41,4 @@ export const FillColorPicker = memo(() => {
);
});
FillColorPicker.displayName = 'BrushColorPicker';
ToolFillColorPicker.displayName = 'ToolFillColorPicker';

View File

@ -6,7 +6,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { PiCursorBold } from 'react-icons/pi';
export const MoveToolButton = memo(() => {
export const ToolMoveButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'move');
@ -22,8 +22,8 @@ export const MoveToolButton = memo(() => {
return (
<IconButton
aria-label={`${t('unifiedCanvas.move')} (V)`}
tooltip={`${t('unifiedCanvas.move')} (V)`}
aria-label={`${t('controlLayers.tool.move')} (V)`}
tooltip={`${t('controlLayers.tool.move')} (V)`}
icon={<PiCursorBold />}
colorScheme={isSelected ? 'invokeBlue' : 'base'}
variant="outline"
@ -33,4 +33,4 @@ export const MoveToolButton = memo(() => {
);
});
MoveToolButton.displayName = 'MoveToolButton';
ToolMoveButton.displayName = 'ToolMoveButton';

View File

@ -7,7 +7,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { PiRectangleBold } from 'react-icons/pi';
export const RectToolButton = memo(() => {
export const ToolRectButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'rect');
@ -26,8 +26,8 @@ export const RectToolButton = memo(() => {
return (
<IconButton
aria-label={`${t('controlLayers.rectangle')} (U)`}
tooltip={`${t('controlLayers.rectangle')} (U)`}
aria-label={`${t('controlLayers.tool.rectangle')} (U)`}
tooltip={`${t('controlLayers.tool.rectangle')} (U)`}
icon={<PiRectangleBold />}
colorScheme={isSelected ? 'invokeBlue' : 'base'}
variant="outline"
@ -37,4 +37,4 @@ export const RectToolButton = memo(() => {
);
});
RectToolButton.displayName = 'RectToolButton';
ToolRectButton.displayName = 'ToolRectButton';

View File

@ -8,7 +8,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { PiResizeBold } from 'react-icons/pi';
export const TransformToolButton = memo(() => {
export const ToolTransformButton = memo(() => {
const { t } = useTranslation();
const canvasManager = useStore($canvasManager);
const transformingEntity = useStore($transformingEntity);
@ -50,8 +50,8 @@ export const TransformToolButton = memo(() => {
return (
<IconButton
aria-label={`${t('unifiedCanvas.transform')} (Ctrl+T)`}
tooltip={`${t('unifiedCanvas.transform')} (Ctrl+T)`}
aria-label={`${t('controlLayers.tool.transform')} (Ctrl+T)`}
tooltip={`${t('controlLayers.tool.transform')} (Ctrl+T)`}
icon={<PiResizeBold />}
variant="solid"
onClick={onTransform}
@ -60,4 +60,4 @@ export const TransformToolButton = memo(() => {
);
});
TransformToolButton.displayName = 'TransformToolButton';
ToolTransformButton.displayName = 'ToolTransformButton';

View File

@ -6,7 +6,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { PiHandBold } from 'react-icons/pi';
export const ViewToolButton = memo(() => {
export const ToolViewButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'view');
@ -19,8 +19,8 @@ export const ViewToolButton = memo(() => {
return (
<IconButton
aria-label={`${t('unifiedCanvas.view')} (H)`}
tooltip={`${t('unifiedCanvas.view')} (H)`}
aria-label={`${t('controlLayers.tool.view')} (H)`}
tooltip={`${t('controlLayers.tool.view')} (H)`}
icon={<PiHandBold />}
colorScheme={isSelected ? 'invokeBlue' : 'base'}
variant="outline"
@ -30,4 +30,4 @@ export const ViewToolButton = memo(() => {
);
});
ViewToolButton.displayName = 'ViewToolButton';
ToolViewButton.displayName = 'ToolViewButton';

View File

@ -1,33 +0,0 @@
import { ButtonGroup } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { BboxToolButton } from 'features/controlLayers/components/BboxToolButton';
import { BrushToolButton } from 'features/controlLayers/components/BrushToolButton';
import { EraserToolButton } from 'features/controlLayers/components/EraserToolButton';
import { MoveToolButton } from 'features/controlLayers/components/MoveToolButton';
import { RectToolButton } from 'features/controlLayers/components/RectToolButton';
import { ToolEyeDropperButton } from 'features/controlLayers/components/ToolEyeDropperButton';
import { TransformToolButton } from 'features/controlLayers/components/TransformToolButton';
import { ViewToolButton } from 'features/controlLayers/components/ViewToolButton';
import { useCanvasDeleteLayerHotkey } from 'features/controlLayers/hooks/useCanvasDeleteLayerHotkey';
import { useCanvasResetLayerHotkey } from 'features/controlLayers/hooks/useCanvasResetLayerHotkey';
export const ToolChooser: React.FC = () => {
useCanvasResetLayerHotkey();
useCanvasDeleteLayerHotkey();
const isTransforming = useAppSelector((s) => s.canvasV2.tool.isTransforming);
return (
<>
<ButtonGroup isAttached isDisabled={isTransforming}>
<BrushToolButton />
<EraserToolButton />
<RectToolButton />
<MoveToolButton />
<ViewToolButton />
<BboxToolButton />
<ToolEyeDropperButton />
</ButtonGroup>
<TransformToolButton />
</>
);
};

View File

@ -8,6 +8,7 @@ import {
BRUSH_ERASER_BORDER_WIDTH,
} from 'features/controlLayers/konva/constants';
import { alignCoordForTool, getPrefixedId } from 'features/controlLayers/konva/util';
import type { Tool } from 'features/controlLayers/store/types';
import { isDrawableEntity } from 'features/controlLayers/store/types';
import Konva from 'konva';
import type { Logger } from 'roarr';
@ -175,7 +176,7 @@ export class CanvasTool {
});
};
setToolVisibility = (tool: 'brush' | 'eraser' | 'eyeDropper' | 'none') => {
setToolVisibility = (tool: Tool) => {
this.konva.brush.group.visible(tool === 'brush');
this.konva.eraser.group.visible(tool === 'eraser');
this.konva.eyeDropper.group.visible(tool === 'eyeDropper');
@ -252,9 +253,6 @@ export class CanvasTool {
y: cursorPos.y,
radius: radius + BRUSH_ERASER_BORDER_WIDTH / scale,
});
this.scaleTool();
this.setToolVisibility('brush');
} else if (cursorPos && tool === 'eraser') {
const alignedCursorPos = alignCoordForTool(cursorPos, toolState.eraser.width);
@ -277,9 +275,6 @@ export class CanvasTool {
y: cursorPos.y,
radius: radius + BRUSH_ERASER_BORDER_WIDTH / scale,
});
this.scaleTool();
this.setToolVisibility('eraser');
} else if (cursorPos && colorUnderCursor) {
this.konva.eyeDropper.fillCircle.setAttrs({
x: cursorPos.x,
@ -290,10 +285,10 @@ export class CanvasTool {
x: cursorPos.x,
y: cursorPos.y,
});
this.setToolVisibility('eyeDropper');
} else {
this.setToolVisibility('none');
}
this.scaleTool();
this.setToolVisibility(tool);
}
}