From 2521b32b07f3da08b52022ed8463c456f8421e3a Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Tue, 12 Dec 2023 13:49:21 +0100 Subject: [PATCH] Add categories and dividers for dropdowns (#2398) --- backend/src/nodes/impl/resize.py | 28 ++-- .../nodes/properties/inputs/generic_inputs.py | 39 ++++- .../inputs/image_dropdown_inputs.py | 7 +- src/common/common-types.ts | 5 + .../components/inputs/DropDownInput.tsx | 3 +- .../components/inputs/elements/Dropdown.tsx | 133 ++++++++++++------ 6 files changed, 156 insertions(+), 59 deletions(-) diff --git a/backend/src/nodes/impl/resize.py b/backend/src/nodes/impl/resize.py index 56e060e71..81e675f02 100644 --- a/backend/src/nodes/impl/resize.py +++ b/backend/src/nodes/impl/resize.py @@ -17,13 +17,13 @@ class ResizeFilter(Enum): CATROM = 3 LANCZOS = 1 - # HERMITE = 5 - # MITCHELL = 6 - # BSPLINE = 7 - # HAMMING = 8 - # HANN = 9 - # LAGRANGE = 10 - # GAUSS = 11 + HERMITE = 5 + MITCHELL = 6 + BSPLINE = 7 + HAMMING = 8 + HANN = 9 + LAGRANGE = 10 + GAUSS = 11 _FILTER_MAP: dict[ResizeFilter, NavtiveResizeFilter] = { @@ -32,13 +32,13 @@ class ResizeFilter(Enum): ResizeFilter.LINEAR: NavtiveResizeFilter.Linear, ResizeFilter.CATROM: NavtiveResizeFilter.CubicCatrom, ResizeFilter.LANCZOS: NavtiveResizeFilter.Lanczos, - # ResizeFilter.HERMITE: NavtiveResizeFilter.Hermite, - # ResizeFilter.MITCHELL: NavtiveResizeFilter.CubicMitchell, - # ResizeFilter.BSPLINE: NavtiveResizeFilter.CubicBSpline, - # ResizeFilter.HAMMING: NavtiveResizeFilter.Hamming, - # ResizeFilter.HANN: NavtiveResizeFilter.Hann, - # ResizeFilter.LAGRANGE: NavtiveResizeFilter.Lagrange, - # ResizeFilter.GAUSS: NavtiveResizeFilter.Gauss, + ResizeFilter.HERMITE: NavtiveResizeFilter.Hermite, + ResizeFilter.MITCHELL: NavtiveResizeFilter.CubicMitchell, + ResizeFilter.BSPLINE: NavtiveResizeFilter.CubicBSpline, + ResizeFilter.HAMMING: NavtiveResizeFilter.Hamming, + ResizeFilter.HANN: NavtiveResizeFilter.Hann, + ResizeFilter.LAGRANGE: NavtiveResizeFilter.Lagrange, + ResizeFilter.GAUSS: NavtiveResizeFilter.Gauss, } diff --git a/backend/src/nodes/properties/inputs/generic_inputs.py b/backend/src/nodes/properties/inputs/generic_inputs.py index c4db2b202..5e604d9fe 100644 --- a/backend/src/nodes/properties/inputs/generic_inputs.py +++ b/backend/src/nodes/properties/inputs/generic_inputs.py @@ -2,6 +2,7 @@ import json import re +from dataclasses import dataclass from enum import Enum from typing import Any, Generic, Literal, TypedDict, TypeVar, Union @@ -51,6 +52,22 @@ class TypedOption(TypedDict): """ +@dataclass +class DropDownGroup: + label: str | None + start_at: str | int | Enum + + @staticmethod + def divider(start_at: str | int | Enum): + return DropDownGroup(None, start_at) + + def to_dict(self): + start_at = self.start_at + if isinstance(start_at, Enum): + start_at = start_at.value + return {"label": self.label, "startAt": start_at} + + class DropDownInput(BaseInput): """Input for a dropdown""" @@ -61,6 +78,7 @@ def __init__( options: list[DropDownOption], default_value: str | int | None = None, preferred_style: DropDownStyle = "dropdown", + groups: list[DropDownGroup] | None = None, associated_type: Any = None, ): super().__init__(input_type, label, kind="dropdown", has_handle=False) @@ -70,6 +88,7 @@ def __init__( default_value if default_value is not None else options[0]["value"] ) self.preferred_style: DropDownStyle = preferred_style + self.groups: list[DropDownGroup] = groups or [] if self.default not in self.accepted_values: logger.error( @@ -87,6 +106,7 @@ def to_dict(self): "options": self.options, "def": self.default, "preferredStyle": self.preferred_style, + "groups": [c.to_dict() for c in self.groups], } def make_optional(self): @@ -157,6 +177,7 @@ def __init__( option_labels: dict[T, str] | None = None, extra_definitions: str | None = None, preferred_style: DropDownStyle = "dropdown", + categories: list[DropDownGroup] | None = None, ): if type_name is None: type_name = enum.__name__ @@ -189,6 +210,7 @@ def __init__( options=options, default_value=default.value if default is not None else None, preferred_style=preferred_style, + groups=categories, ) self.type_definitions = ( @@ -558,6 +580,12 @@ def BlendModeDropdown() -> DropDownInput: option_labels={ BlendMode.ADD: "Linear Dodge (Add)", }, + categories=[ + DropDownGroup.divider(start_at=BlendMode.DARKEN), + DropDownGroup.divider(start_at=BlendMode.LIGHTEN), + DropDownGroup.divider(start_at=BlendMode.OVERLAY), + DropDownGroup.divider(start_at=BlendMode.DIFFERENCE), + ], ) @@ -609,9 +637,9 @@ def TileSizeDropdown( ("BC5_SNORM", "BC5 (8bpp, Signed, 2-channel normal)"), ("BC7_UNORM_SRGB", "BC7 (8bpp, sRGB, 8-bit Alpha)"), ("BC7_UNORM", "BC7 (8bpp, Linear, 8-bit Alpha)"), - ("DXT1", "DXT1 (4bpp, Linear, 1-bit Alpha, Legacy)"), - ("DXT3", "DXT3 (8bpp, Linear, 4-bit Alpha, Legacy)"), - ("DXT5", "DXT5 (8bpp, Linear, 8-bit Alpha, Legacy)"), + ("DXT1", "DXT1 (4bpp, Linear, 1-bit Alpha)"), + ("DXT3", "DXT3 (8bpp, Linear, 4-bit Alpha)"), + ("DXT5", "DXT5 (8bpp, Linear, 8-bit Alpha)"), ("R8G8B8A8_UNORM_SRGB", "RGBA (32bpp, sRGB, 8-bit Alpha)"), ("R8G8B8A8_UNORM", "RGBA (32bpp, Linear, 8-bit Alpha)"), ("B8G8R8A8_UNORM_SRGB", "BGRA (32bpp, sRGB, 8-bit Alpha)"), @@ -631,6 +659,11 @@ def DdsFormatDropdown() -> DropDownInput: label="DDS Format", options=[{"option": title, "value": f} for f, title in SUPPORTED_DDS_FORMATS], associated_type=DDSFormat, + groups=[ + DropDownGroup("Compressed", start_at="BC1_UNORM_SRGB"), + DropDownGroup("Uncompressed", start_at="R8G8B8A8_UNORM_SRGB"), + DropDownGroup("Legacy Compressed", start_at="DXT1"), + ], ) diff --git a/backend/src/nodes/properties/inputs/image_dropdown_inputs.py b/backend/src/nodes/properties/inputs/image_dropdown_inputs.py index d42999ddb..c11a06105 100644 --- a/backend/src/nodes/properties/inputs/image_dropdown_inputs.py +++ b/backend/src/nodes/properties/inputs/image_dropdown_inputs.py @@ -11,7 +11,7 @@ from ...impl.image_utils import BorderType from ...impl.pil_utils import RotationInterpolationMethod from ...impl.resize import ResizeFilter -from .generic_inputs import DropDownInput, EnumInput +from .generic_inputs import DropDownGroup, DropDownInput, EnumInput def ColorSpaceDetectorInput(label: str = "Color Space") -> DropDownInput: @@ -55,10 +55,15 @@ def ResizeFilterInput() -> DropDownInput: return EnumInput( ResizeFilter, label="Interpolation Method", + categories=[ + DropDownGroup("Basic", start_at=ResizeFilter.AUTO), + DropDownGroup("Advanced", start_at=ResizeFilter.HERMITE), + ], option_labels={ ResizeFilter.NEAREST: "Nearest Neighbor", ResizeFilter.BOX: "Area (Box)", ResizeFilter.CATROM: "Cubic", + ResizeFilter.BSPLINE: "B-Spline", }, ) diff --git a/src/common/common-types.ts b/src/common/common-types.ts index f7413a0c7..cc3fabf6c 100644 --- a/src/common/common-types.ts +++ b/src/common/common-types.ts @@ -67,6 +67,10 @@ export interface InputOption { } export type FileInputKind = 'image' | 'pth' | 'pt' | 'video' | 'bin' | 'param' | 'onnx'; export type DropDownStyle = 'dropdown' | 'checkbox' | 'tabs'; +export interface DropdownGroup { + readonly label?: string | null; + readonly startAt: InputSchemaValue; +} export interface GenericInput extends InputBase { readonly kind: 'generic'; @@ -76,6 +80,7 @@ export interface DropDownInput extends InputBase { readonly def: string | number; readonly options: readonly InputOption[]; readonly preferredStyle: DropDownStyle; + readonly groups: readonly DropdownGroup[]; } export interface FileInput extends InputBase { readonly kind: 'file'; diff --git a/src/renderer/components/inputs/DropDownInput.tsx b/src/renderer/components/inputs/DropDownInput.tsx index 7d2bbd7ed..55a574597 100644 --- a/src/renderer/components/inputs/DropDownInput.tsx +++ b/src/renderer/components/inputs/DropDownInput.tsx @@ -8,7 +8,7 @@ import { InputProps } from './props'; type DropDownInputProps = InputProps<'dropdown', string | number>; export const DropDownInput = memo(({ value, setValue, input, isLocked }: DropDownInputProps) => { - const { options, def, label, preferredStyle } = input; + const { options, def, label, preferredStyle, groups } = input; const reset = useCallback(() => setValue(def), [setValue, def]); @@ -46,6 +46,7 @@ export const DropDownInput = memo(({ value, setValue, input, isLocked }: DropDow return ( void; isDisabled?: boolean; options: DropDownInput['options']; + groups?: readonly DropdownGroup[]; } -export const DropDown = memo(({ value, onChange, reset, isDisabled, options }: DropDownProps) => { - // reset invalid values to default - useEffect(() => { - if (value === undefined || options.every((o) => o.value !== value)) { - reset(); - } - }, [value, reset, options]); - - let selection = options.findIndex((o) => o.value === value); - if (selection === -1) selection = 0; - - const handleChange = (event: ChangeEvent) => { - const selectedIndex = Number(event.target.value); - const selectedValue = options[selectedIndex]?.value as InputSchemaValue | undefined; - if (selectedValue === undefined) { - reset(); - } else { - onChange(selectedValue); - } - }; - - return ( - - ); -}); + ); + } + + return ( + + ); + } +);