Skip to content

Commit 26702b5

Browse files
feat(ui): tweak layouts, use react conventions, disabled state
1 parent 2d65e45 commit 26702b5

File tree

3 files changed

+86
-48
lines changed

3 files changed

+86
-48
lines changed

invokeai/frontend/web/src/features/controlLayers/components/RasterLayer/RasterLayerAdjustmentsPanel.tsx

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Button, ButtonGroup, Flex, IconButton, Switch, Text } from '@invoke-ai/ui-library';
2+
import { createSelector } from '@reduxjs/toolkit';
23
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
34
import { RasterLayerCurvesAdjustmentsEditor } from 'features/controlLayers/components/RasterLayer/RasterLayerCurvesAdjustmentsEditor';
45
import { RasterLayerSimpleAdjustmentsEditor } from 'features/controlLayers/components/RasterLayer/RasterLayerSimpleAdjustmentsEditor';
@@ -10,36 +11,40 @@ import {
1011
rasterLayerAdjustmentsSet,
1112
rasterLayerAdjustmentsSimpleUpdated,
1213
} from 'features/controlLayers/store/canvasSlice';
13-
import { selectEntity } from 'features/controlLayers/store/selectors';
14+
import { selectCanvasSlice, selectEntity } from 'features/controlLayers/store/selectors';
1415
import { makeDefaultRasterLayerAdjustments } from 'features/controlLayers/store/util';
15-
import React, { memo, useCallback } from 'react';
16+
import React, { memo, useCallback, useMemo } from 'react';
1617
import { useTranslation } from 'react-i18next';
1718
import { PiArrowCounterClockwiseBold, PiCaretDownBold, PiCheckBold, PiTrashBold } from 'react-icons/pi';
1819

1920
export const RasterLayerAdjustmentsPanel = memo(() => {
2021
const dispatch = useAppDispatch();
2122
const entityIdentifier = useEntityIdentifierContext<'raster_layer'>();
2223
const canvasManager = useCanvasManager();
23-
const layer = useAppSelector((s) => selectEntity(s.canvas.present, entityIdentifier));
24+
const selectAdjustments = useMemo(() => {
25+
return createSelector(selectCanvasSlice, (canvas) => selectEntity(canvas, entityIdentifier)?.adjustments);
26+
}, [entityIdentifier]);
27+
28+
const adjustments = useAppSelector(selectAdjustments);
2429
const { t } = useTranslation();
2530

26-
const hasAdjustments = Boolean(layer?.adjustments);
27-
const enabled = Boolean(layer?.adjustments?.enabled);
28-
const collapsed = Boolean(layer?.adjustments?.collapsed);
29-
const mode = layer?.adjustments?.mode ?? 'simple';
31+
const hasAdjustments = Boolean(adjustments);
32+
const enabled = Boolean(adjustments?.enabled);
33+
const collapsed = Boolean(adjustments?.collapsed);
34+
const mode = adjustments?.mode ?? 'simple';
3035

3136
const onToggleEnabled = useCallback(
3237
(e: React.ChangeEvent<HTMLInputElement>) => {
3338
const v = e.target.checked;
34-
const current = layer?.adjustments ?? makeDefaultRasterLayerAdjustments(mode);
39+
const current = adjustments ?? makeDefaultRasterLayerAdjustments(mode);
3540
dispatch(
3641
rasterLayerAdjustmentsSet({
3742
entityIdentifier,
3843
adjustments: { ...current, enabled: v },
3944
})
4045
);
4146
},
42-
[dispatch, entityIdentifier, layer?.adjustments, mode]
47+
[dispatch, entityIdentifier, adjustments, mode]
4348
);
4449

4550
const onReset = useCallback(() => {
@@ -73,29 +78,29 @@ export const RasterLayerAdjustmentsPanel = memo(() => {
7378
}, [dispatch, entityIdentifier]);
7479

7580
const onToggleCollapsed = useCallback(() => {
76-
const current = layer?.adjustments ?? makeDefaultRasterLayerAdjustments(mode);
81+
const current = adjustments ?? makeDefaultRasterLayerAdjustments(mode);
7782
dispatch(
7883
rasterLayerAdjustmentsSet({
7984
entityIdentifier,
8085
adjustments: { ...current, collapsed: !collapsed },
8186
})
8287
);
83-
}, [dispatch, entityIdentifier, collapsed, layer?.adjustments, mode]);
88+
}, [dispatch, entityIdentifier, collapsed, adjustments, mode]);
8489

8590
const onSetMode = useCallback(
8691
(nextMode: 'simple' | 'curves') => {
8792
if (nextMode === mode) {
8893
return;
8994
}
90-
const current = layer?.adjustments ?? makeDefaultRasterLayerAdjustments(nextMode);
95+
const current = adjustments ?? makeDefaultRasterLayerAdjustments(nextMode);
9196
dispatch(
9297
rasterLayerAdjustmentsSet({
9398
entityIdentifier,
9499
adjustments: { ...current, mode: nextMode },
95100
})
96101
);
97102
},
98-
[dispatch, entityIdentifier, layer?.adjustments, mode]
103+
[dispatch, entityIdentifier, adjustments, mode]
99104
);
100105

101106
// Memoized click handlers to avoid inline arrow functions in JSX
@@ -125,7 +130,7 @@ export const RasterLayerAdjustmentsPanel = memo(() => {
125130

126131
return (
127132
<>
128-
<Flex px={4} alignItems="center" gap={3} mt={2} mb={2}>
133+
<Flex p={2} alignItems="center" gap={2}>
129134
<IconButton
130135
aria-label={collapsed ? t('controlLayers.adjustments.expand') : t('controlLayers.adjustments.collapse')}
131136
size="sm"
@@ -141,18 +146,10 @@ export const RasterLayerAdjustmentsPanel = memo(() => {
141146
Adjustments
142147
</Text>
143148
<ButtonGroup size="sm" isAttached variant="outline">
144-
<Button
145-
onClick={onClickModeSimple}
146-
isActive={mode === 'simple'}
147-
colorScheme={mode === 'simple' ? 'invokeBlue' : undefined}
148-
>
149+
<Button onClick={onClickModeSimple} colorScheme={mode === 'simple' ? 'invokeBlue' : undefined}>
149150
{t('controlLayers.adjustments.simple')}
150151
</Button>
151-
<Button
152-
onClick={onClickModeCurves}
153-
isActive={mode === 'curves'}
154-
colorScheme={mode === 'curves' ? 'invokeBlue' : undefined}
155-
>
152+
<Button onClick={onClickModeCurves} colorScheme={mode === 'curves' ? 'invokeBlue' : undefined}>
156153
{t('controlLayers.adjustments.curves')}
157154
</Button>
158155
</ButtonGroup>
@@ -161,7 +158,7 @@ export const RasterLayerAdjustmentsPanel = memo(() => {
161158
aria-label={t('controlLayers.adjustments.cancel')}
162159
size="md"
163160
onClick={onCancel}
164-
isDisabled={!layer?.adjustments}
161+
isDisabled={!adjustments}
165162
colorScheme="red"
166163
icon={<PiTrashBold />}
167164
variant="ghost"
@@ -170,15 +167,15 @@ export const RasterLayerAdjustmentsPanel = memo(() => {
170167
aria-label={t('controlLayers.adjustments.reset')}
171168
size="md"
172169
onClick={onReset}
173-
isDisabled={!layer?.adjustments}
170+
isDisabled={!adjustments}
174171
icon={<PiArrowCounterClockwiseBold />}
175172
variant="ghost"
176173
/>
177174
<IconButton
178175
aria-label={t('controlLayers.adjustments.finish')}
179176
size="md"
180177
onClick={onFinish}
181-
isDisabled={!layer?.adjustments}
178+
isDisabled={!adjustments}
182179
colorScheme="green"
183180
icon={<PiCheckBold />}
184181
variant="ghost"

invokeai/frontend/web/src/features/controlLayers/components/RasterLayer/RasterLayerCurvesAdjustmentsEditor.tsx

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Box, Flex, Text } from '@invoke-ai/ui-library';
1+
import { Box, Flex, IconButton, Text } from '@invoke-ai/ui-library';
22
import { createSelector } from '@reduxjs/toolkit';
33
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
44
import { useEntityAdapterContext } from 'features/controlLayers/contexts/EntityAdapterContext';
@@ -7,6 +7,7 @@ import { rasterLayerAdjustmentsCurvesUpdated } from 'features/controlLayers/stor
77
import { selectCanvasSlice, selectEntity } from 'features/controlLayers/store/selectors';
88
import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
99
import { useTranslation } from 'react-i18next';
10+
import { PiArrowCounterClockwiseBold } from 'react-icons/pi';
1011

1112
const DEFAULT_POINTS: Array<[number, number]> = [
1213
[0, 0],
@@ -397,21 +398,33 @@ const CurveGraph = memo(function CurveGraph(props: CurveGraphProps) {
397398
return () => ro.disconnect();
398399
}, [draw]);
399400

400-
const canvasStyle = useMemo<React.CSSProperties>(() => CANVAS_STYLE, []);
401+
const resetPoints = useCallback(() => {
402+
setLocalPoints(sortPoints(DEFAULT_POINTS));
403+
commit(DEFAULT_POINTS);
404+
}, [commit]);
401405

402406
return (
403-
<Flex flexDir="column" gap={4}>
404-
<Text fontSize="sm" color={channelColor[channel]}>
405-
{title}
406-
</Text>
407+
<Flex flexDir="column" gap={2}>
408+
<Flex justifyContent="space-between">
409+
<Text fontSize="sm" color={channelColor[channel]} fontWeight="semibold">
410+
{title}
411+
</Text>
412+
<IconButton
413+
icon={<PiArrowCounterClockwiseBold />}
414+
aria-label="Reset"
415+
size="sm"
416+
variant="link"
417+
onClick={resetPoints}
418+
/>
419+
</Flex>
407420
<canvas
408421
ref={canvasRef}
409422
onPointerDown={handlePointerDown}
410423
onPointerMove={handlePointerMove}
411424
onPointerUp={handlePointerUp}
412425
onPointerCancel={handlePointerCancel}
413426
onDoubleClick={handleDoubleClick}
414-
style={canvasStyle}
427+
style={CANVAS_STYLE}
415428
/>
416429
</Flex>
417430
);
@@ -427,6 +440,13 @@ export const RasterLayerCurvesAdjustmentsEditor = memo(() => {
427440
[entityIdentifier]
428441
);
429442
const layer = useAppSelector(selectLayer);
443+
const selectIsDisabled = useMemo(() => {
444+
return createSelector(
445+
selectCanvasSlice,
446+
(canvas) => selectEntity(canvas, entityIdentifier)?.adjustments?.enabled !== true
447+
);
448+
}, [entityIdentifier]);
449+
const isDisabled = useAppSelector(selectIsDisabled);
430450

431451
const [histMaster, setHistMaster] = useState<number[] | null>(null);
432452
const [histR, setHistR] = useState<number[] | null>(null);
@@ -502,7 +522,14 @@ export const RasterLayerCurvesAdjustmentsEditor = memo(() => {
502522
const onChangeB = useCallback((pts: Array<[number, number]>) => onChangePoints('b', pts), [onChangePoints]);
503523

504524
return (
505-
<Flex direction="column" gap={2} style={{ paddingLeft: 8, paddingRight: 8, paddingBottom: 10 }}>
525+
<Flex
526+
direction="column"
527+
gap={2}
528+
px={3}
529+
pb={3}
530+
opacity={isDisabled ? 0.3 : 1}
531+
pointerEvents={isDisabled ? 'none' : 'auto'}
532+
>
506533
<Box display="grid" gridTemplateColumns="repeat(2, minmax(0, 1fr))" gap={4}>
507534
<CurveGraph
508535
title={t('controlLayers.adjustments.master')}

invokeai/frontend/web/src/features/controlLayers/components/RasterLayer/RasterLayerSimpleAdjustmentsEditor.tsx

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
2+
import { createSelector } from '@reduxjs/toolkit';
23
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
34
import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext';
45
import { rasterLayerAdjustmentsSimpleUpdated } from 'features/controlLayers/store/canvasSlice';
5-
import { selectEntity } from 'features/controlLayers/store/selectors';
6-
import React, { memo, useCallback } from 'react';
6+
import { selectCanvasSlice, selectEntity } from 'features/controlLayers/store/selectors';
7+
import React, { memo, useCallback, useMemo } from 'react';
78
import { useTranslation } from 'react-i18next';
89

910
type AdjustmentSliderRowProps = {
@@ -25,20 +26,33 @@ const AdjustmentSliderRow = ({ label, value, onChange, min = -1, max = 1, step =
2526
</FormControl>
2627
);
2728

29+
const DEFAULT_SIMPLE_ADJUSTMENTS = {
30+
brightness: 0,
31+
contrast: 0,
32+
saturation: 0,
33+
temperature: 0,
34+
tint: 0,
35+
sharpness: 0,
36+
};
37+
2838
export const RasterLayerSimpleAdjustmentsEditor = memo(() => {
2939
const dispatch = useAppDispatch();
3040
const entityIdentifier = useEntityIdentifierContext<'raster_layer'>();
3141
const { t } = useTranslation();
32-
const layer = useAppSelector((s) => selectEntity(s.canvas.present, entityIdentifier));
33-
34-
const simple = layer?.adjustments?.simple ?? {
35-
brightness: 0,
36-
contrast: 0,
37-
saturation: 0,
38-
temperature: 0,
39-
tint: 0,
40-
sharpness: 0,
41-
};
42+
const selectSimpleAdjustments = useMemo(() => {
43+
return createSelector(
44+
selectCanvasSlice,
45+
(canvas) => selectEntity(canvas, entityIdentifier)?.adjustments?.simple ?? DEFAULT_SIMPLE_ADJUSTMENTS
46+
);
47+
}, [entityIdentifier]);
48+
const simple = useAppSelector(selectSimpleAdjustments);
49+
const selectIsDisabled = useMemo(() => {
50+
return createSelector(
51+
selectCanvasSlice,
52+
(canvas) => selectEntity(canvas, entityIdentifier)?.adjustments?.enabled !== true
53+
);
54+
}, [entityIdentifier]);
55+
const isDisabled = useAppSelector(selectIsDisabled);
4256

4357
const onBrightness = useCallback(
4458
(v: number) => dispatch(rasterLayerAdjustmentsSimpleUpdated({ entityIdentifier, simple: { brightness: v } })),
@@ -66,7 +80,7 @@ export const RasterLayerSimpleAdjustmentsEditor = memo(() => {
6680
);
6781

6882
return (
69-
<Flex px={8} direction="column">
83+
<Flex px={3} pb={2} direction="column" opacity={isDisabled ? 0.3 : 1} pointerEvents={isDisabled ? 'none' : 'auto'}>
7084
<AdjustmentSliderRow
7185
label={t('controlLayers.adjustments.brightness')}
7286
value={simple.brightness}

0 commit comments

Comments
 (0)