feat(ui): store all stage attrs in nanostores

This commit is contained in:
psychedelicious 2024-06-12 11:57:14 +10:00
parent 2c3ac972e5
commit 154e3e6f64
6 changed files with 55 additions and 24 deletions

View File

@ -1,18 +1,20 @@
import { Box, Flex, Text } from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { useAppSelector } from 'app/store/storeHooks';
import { $stageScale } from 'features/controlLayers/store/controlLayersSlice';
import { $stageAttrs } from 'features/controlLayers/store/controlLayersSlice';
import { round } from 'lodash-es';
import { memo } from 'react';
export const HeadsUpDisplay = memo(() => {
const stageScale = useStore($stageScale);
const stageAttrs = useStore($stageAttrs);
const layerCount = useAppSelector((s) => s.controlLayers.present.layers.length);
const bbox = useAppSelector((s) => s.controlLayers.present.bbox);
return (
<Flex flexDir="column" bg="blackAlpha.400" borderBottomEndRadius="base" p={2} minW={64} gap={2}>
<HUDItem label="Scale" value={round(stageScale, 3)} />
<HUDItem label="Scale" value={round(stageAttrs.scale, 3)} />
<HUDItem label="Stage Pos" value={`${round(stageAttrs.x, 3)}, ${round(stageAttrs.y, 3)}`} />
<HUDItem label="Stage Size" value={`${round(stageAttrs.width, 3)}, ${round(stageAttrs.height, 3)}`} />
<HUDItem label="Layer Count" value={layerCount} />
<HUDItem label="BBox Size" value={`${bbox.width}×${bbox.height}`} />
<HUDItem label="BBox Position" value={`${bbox.x}, ${bbox.y}`} />

View File

@ -26,8 +26,7 @@ import {
$lastMouseDownPos,
$selectedLayer,
$shouldInvertBrushSizeScrollDirection,
$stagePos,
$stageScale,
$stageAttrs,
$tool,
$toolBuffer,
bboxChanged,
@ -89,7 +88,6 @@ const useStageRenderer = (stage: Konva.Stage, container: HTMLDivElement | null,
const lastCursorPos = useStore($lastCursorPos);
const lastMouseDownPos = useStore($lastMouseDownPos);
const isMouseDown = useStore($isMouseDown);
const stageScale = useStore($stageScale);
const isDrawing = useStore($isDrawing);
const brushColor = useAppSelector(selectBrushColor);
const selectedLayer = useAppSelector(selectSelectedLayer);
@ -197,8 +195,7 @@ const useStageRenderer = (stage: Konva.Stage, container: HTMLDivElement | null,
$lastMouseDownPos,
$lastCursorPos,
$lastAddedPoint,
$stageScale,
$stagePos,
$stageAttrs,
$brushSize,
$brushColor,
$brushSpacingPx,
@ -236,6 +233,13 @@ const useStageRenderer = (stage: Konva.Stage, container: HTMLDivElement | null,
const fitStageToContainer = () => {
stage.width(container.offsetWidth);
stage.height(container.offsetHeight);
$stageAttrs.set({
x: stage.x(),
y: stage.y(),
width: stage.width(),
height: stage.height(),
scale: stage.scaleX(),
});
};
const resizeObserver = new ResizeObserver(fitStageToContainer);

View File

@ -1,15 +1,16 @@
import { calculateNewBrushSize } from 'features/canvas/hooks/useCanvasZoom';
import { CANVAS_SCALE_BY, MAX_CANVAS_SCALE, MIN_CANVAS_SCALE } from 'features/canvas/util/constants';
import { getIsMouseDown, getScaledFlooredCursorPosition, snapPosToStage } from 'features/controlLayers/konva/util';
import {
type AddBrushLineArg,
type AddEraserLineArg,
type AddPointToLineArg,
type AddRectShapeArg,
DEFAULT_RGBA_COLOR,
type Layer,
type Tool,
import type {
AddBrushLineArg,
AddEraserLineArg,
AddPointToLineArg,
AddRectShapeArg,
Layer,
StageAttrs,
Tool,
} from 'features/controlLayers/store/types';
import { DEFAULT_RGBA_COLOR } from 'features/controlLayers/store/types';
import type Konva from 'konva';
import type { Vector2d } from 'konva/lib/types';
import { clamp } from 'lodash-es';
@ -27,8 +28,7 @@ type SetStageEventHandlersArg = {
$lastMouseDownPos: WritableAtom<Vector2d | null>;
$lastCursorPos: WritableAtom<Vector2d | null>;
$lastAddedPoint: WritableAtom<Vector2d | null>;
$stageScale: WritableAtom<number>;
$stagePos: WritableAtom<Vector2d>;
$stageAttrs: WritableAtom<StageAttrs>;
$brushColor: WritableAtom<RgbaColor>;
$brushSize: WritableAtom<number>;
$brushSpacingPx: WritableAtom<number>;
@ -93,8 +93,7 @@ export const setStageEventHandlers = ({
$lastMouseDownPos,
$lastCursorPos,
$lastAddedPoint,
$stagePos,
$stageScale,
$stageAttrs,
$brushColor,
$brushSize,
$brushSpacingPx,
@ -333,15 +332,31 @@ export const setStageEventHandlers = ({
stage.scaleX(newScale);
stage.scaleY(newScale);
stage.position(newPos);
$stageScale.set(newScale);
$stagePos.set(newPos);
$stageAttrs.set({ ...newPos, width: stage.width(), height: stage.height(), scale: newScale });
}
});
stage.on('dragmove', () => {
$stageAttrs.set({
x: stage.x(),
y: stage.y(),
width: stage.width(),
height: stage.height(),
scale: stage.scaleX(),
});
});
stage.on('dragend', () => {
// Stage position should always be an integer, else we get fractional pixels which are blurry
stage.x(Math.floor(stage.x()));
stage.y(Math.floor(stage.y()));
$stageAttrs.set({
x: stage.x(),
y: stage.y(),
width: stage.width(),
height: stage.height(),
scale: stage.scaleX(),
});
});
const onKeyDown = (e: KeyboardEvent) => {

View File

@ -13,6 +13,9 @@ export const PREVIEW_RECT_ID = 'preview_layer.rect';
export const PREVIEW_GENERATION_BBOX_GROUP = 'preview_layer.gen_bbox_group';
export const PREVIEW_GENERATION_BBOX_TRANSFORMER = 'preview_layer.gen_bbox_transformer';
export const PREVIEW_GENERATION_BBOX_DUMMY_RECT = 'preview_layer.gen_bbox_dummy_rect';
export const PREVIEW_DOCUMENT_SIZE_GROUP = 'preview_layer.doc_size_group';
export const PREVIEW_DOCUMENT_SIZE_STAGE_RECT = 'preview_layer.doc_size_stage_rect';
export const PREVIEW_DOCUMENT_SIZE_DOCUMENT_RECT = 'preview_layer.doc_size_doc_rect';
// Names for Konva layers and objects (comparable to CSS classes)
export const LAYER_BBOX_NAME = 'layer.bbox';

View File

@ -60,6 +60,7 @@ import type {
RasterLayer,
RegionalGuidanceLayer,
RgbaColor,
StageAttrs,
Tool,
} from './types';
import {
@ -997,8 +998,13 @@ export const $lastCursorPos = atom<Vector2d | null>(null);
export const $isPreviewVisible = atom(true);
export const $lastAddedPoint = atom<Vector2d | null>(null);
export const $isSpaceDown = atom(false);
export const $stageScale = atom<number>(1);
export const $stagePos = atom<Vector2d>({ x: 0, y: 0 });
export const $stageAttrs = atom<StageAttrs>({
x: 0,
y: 0,
width: 0,
height: 0,
scale: 0,
});
// Some nanostores that are manually synced to redux state to provide imperative access
// TODO(psyche): This is a hack, figure out another way to handle this...

View File

@ -272,6 +272,7 @@ export type ControlLayersState = {
bbox: IRect;
};
export type StageAttrs = { x: number; y: number; width: number; height: number; scale: number };
export type AddEraserLineArg = { layerId: string; points: [number, number, number, number] };
export type AddBrushLineArg = AddEraserLineArg & { color: RgbaColor };
export type AddPointToLineArg = { layerId: string; point: [number, number] };