From 9e5a01564a5ec98618835ff49c80dc05831a4f76 Mon Sep 17 00:00:00 2001
From: Jonas Kulhanek
Date: Mon, 29 Jan 2024 14:14:04 +0100
Subject: [PATCH] Refac components
---
src/viser/_gui_api.py | 157 ++--
src/viser/_gui_handles.py | 7 +-
src/viser/_messages.py | 31 +-
.../client/src/ControlPanel/Generated.tsx | 765 ++----------------
.../src/ControlPanel/GuiComponentContext.tsx | 18 +
.../client/src/ControlPanel/GuiState.tsx | 25 +-
src/viser/client/src/WebsocketInterface.tsx | 7 +-
src/viser/client/src/WebsocketMessages.tsx | 79 +-
src/viser/client/src/components/Button.tsx | 69 ++
.../client/src/components/ButtonGroup.tsx | 40 +
src/viser/client/src/components/Checkbox.tsx | 49 ++
src/viser/client/src/components/Dropdown.tsx | 36 +
src/viser/client/src/components/Folder.tsx | 77 ++
src/viser/client/src/components/Markdown.tsx | 18 +
.../client/src/components/NumberInput.tsx | 36 +
src/viser/client/src/components/Rgb.tsx | 28 +
src/viser/client/src/components/Rgba.tsx | 27 +
src/viser/client/src/components/Slider.tsx | 91 +++
src/viser/client/src/components/TabGroup.tsx | 56 ++
src/viser/client/src/components/TextInput.tsx | 28 +
src/viser/client/src/components/Vector2.tsx | 23 +
src/viser/client/src/components/Vector3.tsx | 23 +
src/viser/client/src/components/common.tsx | 147 ++++
src/viser/client/src/components/utils.tsx | 32 +
24 files changed, 1039 insertions(+), 830 deletions(-)
create mode 100644 src/viser/client/src/ControlPanel/GuiComponentContext.tsx
create mode 100644 src/viser/client/src/components/Button.tsx
create mode 100644 src/viser/client/src/components/ButtonGroup.tsx
create mode 100644 src/viser/client/src/components/Checkbox.tsx
create mode 100644 src/viser/client/src/components/Dropdown.tsx
create mode 100644 src/viser/client/src/components/Folder.tsx
create mode 100644 src/viser/client/src/components/Markdown.tsx
create mode 100644 src/viser/client/src/components/NumberInput.tsx
create mode 100644 src/viser/client/src/components/Rgb.tsx
create mode 100644 src/viser/client/src/components/Rgba.tsx
create mode 100644 src/viser/client/src/components/Slider.tsx
create mode 100644 src/viser/client/src/components/TabGroup.tsx
create mode 100644 src/viser/client/src/components/TextInput.tsx
create mode 100644 src/viser/client/src/components/Vector2.tsx
create mode 100644 src/viser/client/src/components/Vector3.tsx
create mode 100644 src/viser/client/src/components/common.tsx
create mode 100644 src/viser/client/src/components/utils.tsx
diff --git a/src/viser/_gui_api.py b/src/viser/_gui_api.py
index 53e0f46b5..9a8f7f4fc 100644
--- a/src/viser/_gui_api.py
+++ b/src/viser/_gui_api.py
@@ -196,6 +196,7 @@ def add_gui_folder(
label: str,
order: Optional[float] = None,
expand_by_default: bool = True,
+ visible: bool = True,
) -> GuiFolderHandle:
"""Add a folder, and return a handle that can be used to populate it.
@@ -204,6 +205,7 @@ def add_gui_folder(
order: Optional ordering, smallest values will be displayed first.
expand_by_default: Open the folder by default. Set to False to collapse it by
default.
+ visible: Whether the component is visible.
Returns:
A handle that can be used as a context to populate the folder.
@@ -217,6 +219,7 @@ def add_gui_folder(
label=label,
container_id=self._get_container_id(),
expand_by_default=expand_by_default,
+ visible=visible,
)
)
return GuiFolderHandle(
@@ -258,11 +261,13 @@ def add_gui_modal(
def add_gui_tab_group(
self,
order: Optional[float] = None,
+ visible: bool = True,
) -> GuiTabGroupHandle:
"""Add a tab group.
Args:
order: Optional ordering, smallest values will be displayed first.
+ visible: Whether the component is visible.
Returns:
A handle that can be used as a context to populate the tab group.
@@ -277,6 +282,7 @@ def add_gui_tab_group(
_gui_api=self,
_container_id=self._get_container_id(),
_order=order,
+ _visible=visible,
)
def add_gui_markdown(
@@ -284,6 +290,7 @@ def add_gui_markdown(
content: str,
image_root: Optional[Path] = None,
order: Optional[float] = None,
+ visible: bool = True,
) -> GuiMarkdownHandle:
"""Add markdown to the GUI.
@@ -291,6 +298,7 @@ def add_gui_markdown(
content: Markdown content to display.
image_root: Optional root directory to resolve relative image paths.
order: Optional ordering, smallest values will be displayed first.
+ visible: Whether the component is visible.
Returns:
A handle that can be used to interact with the GUI element.
@@ -298,7 +306,7 @@ def add_gui_markdown(
handle = GuiMarkdownHandle(
_gui_api=self,
_id=_make_unique_id(),
- _visible=True,
+ _visible=visible,
_container_id=self._get_container_id(),
_order=_apply_default_order(order),
_image_root=image_root,
@@ -357,19 +365,19 @@ def add_gui_button(
order = _apply_default_order(order)
return GuiButtonHandle(
self._create_gui_input(
- initial_value=False,
+ value=False,
message=_messages.GuiAddButtonMessage(
order=order,
id=id,
label=label,
container_id=self._get_container_id(),
hint=hint,
- initial_value=False,
+ value=False,
color=color,
icon_base64=None if icon is None else base64_from_icon(icon),
+ disabled=disabled,
+ visible=visible,
),
- disabled=disabled,
- visible=visible,
is_button=True,
)._impl
)
@@ -425,23 +433,23 @@ def add_gui_button_group(
Returns:
A handle that can be used to interact with the GUI element.
"""
- initial_value = options[0]
+ value = options[0]
id = _make_unique_id()
order = _apply_default_order(order)
return GuiButtonGroupHandle(
self._create_gui_input(
- initial_value,
+ value,
message=_messages.GuiAddButtonGroupMessage(
order=order,
id=id,
label=label,
container_id=self._get_container_id(),
hint=hint,
- initial_value=initial_value,
+ value=value,
options=tuple(options),
+ disabled=disabled,
+ visible=visible,
),
- disabled=disabled,
- visible=visible,
)._impl,
)
@@ -467,21 +475,22 @@ def add_gui_checkbox(
Returns:
A handle that can be used to interact with the GUI element.
"""
- assert isinstance(initial_value, bool)
+ value = initial_value
+ assert isinstance(value, bool)
id = _make_unique_id()
order = _apply_default_order(order)
return self._create_gui_input(
- initial_value,
+ value,
message=_messages.GuiAddCheckboxMessage(
order=order,
id=id,
label=label,
container_id=self._get_container_id(),
hint=hint,
- initial_value=initial_value,
+ value=value,
+ disabled=disabled,
+ visible=visible,
),
- disabled=disabled,
- visible=visible,
)
def add_gui_text(
@@ -506,21 +515,22 @@ def add_gui_text(
Returns:
A handle that can be used to interact with the GUI element.
"""
- assert isinstance(initial_value, str)
+ value = initial_value
+ assert isinstance(value, str)
id = _make_unique_id()
order = _apply_default_order(order)
return self._create_gui_input(
- initial_value,
+ value,
message=_messages.GuiAddTextMessage(
order=order,
id=id,
label=label,
container_id=self._get_container_id(),
hint=hint,
- initial_value=initial_value,
+ value=value,
+ disabled=disabled,
+ visible=visible,
),
- disabled=disabled,
- visible=visible,
)
def add_gui_number(
@@ -552,8 +562,9 @@ def add_gui_number(
Returns:
A handle that can be used to interact with the GUI element.
"""
+ value = initial_value
- assert isinstance(initial_value, (int, float))
+ assert isinstance(value, (int, float))
if step is None:
# It's ok that `step` is always a float, even if the value is an integer,
@@ -561,7 +572,7 @@ def add_gui_number(
step = float( # type: ignore
onp.min(
[
- _compute_step(initial_value),
+ _compute_step(value),
_compute_step(min),
_compute_step(max),
]
@@ -573,21 +584,21 @@ def add_gui_number(
id = _make_unique_id()
order = _apply_default_order(order)
return self._create_gui_input(
- initial_value=initial_value,
+ value,
message=_messages.GuiAddNumberMessage(
order=order,
id=id,
label=label,
container_id=self._get_container_id(),
hint=hint,
- initial_value=initial_value,
+ value=value,
min=min,
max=max,
precision=_compute_precision_digits(step),
step=step,
+ disabled=disabled,
+ visible=visible,
),
- disabled=disabled,
- visible=visible,
is_button=False,
)
@@ -619,7 +630,8 @@ def add_gui_vector2(
Returns:
A handle that can be used to interact with the GUI element.
"""
- initial_value = cast_vector(initial_value, 2)
+ value = initial_value
+ value = cast_vector(value, 2)
min = cast_vector(min, 2) if min is not None else None
max = cast_vector(max, 2) if max is not None else None
id = _make_unique_id()
@@ -627,7 +639,7 @@ def add_gui_vector2(
if step is None:
possible_steps: List[float] = []
- possible_steps.extend([_compute_step(x) for x in initial_value])
+ possible_steps.extend([_compute_step(x) for x in value])
if min is not None:
possible_steps.extend([_compute_step(x) for x in min])
if max is not None:
@@ -635,21 +647,21 @@ def add_gui_vector2(
step = float(onp.min(possible_steps))
return self._create_gui_input(
- initial_value,
+ value,
message=_messages.GuiAddVector2Message(
order=order,
id=id,
label=label,
container_id=self._get_container_id(),
hint=hint,
- initial_value=initial_value,
+ value=value,
min=min,
max=max,
step=step,
precision=_compute_precision_digits(step),
+ disabled=disabled,
+ visible=visible,
),
- disabled=disabled,
- visible=visible,
)
def add_gui_vector3(
@@ -680,7 +692,8 @@ def add_gui_vector3(
Returns:
A handle that can be used to interact with the GUI element.
"""
- initial_value = cast_vector(initial_value, 2)
+ value = initial_value
+ value = cast_vector(value, 2)
min = cast_vector(min, 3) if min is not None else None
max = cast_vector(max, 3) if max is not None else None
id = _make_unique_id()
@@ -688,7 +701,7 @@ def add_gui_vector3(
if step is None:
possible_steps: List[float] = []
- possible_steps.extend([_compute_step(x) for x in initial_value])
+ possible_steps.extend([_compute_step(x) for x in value])
if min is not None:
possible_steps.extend([_compute_step(x) for x in min])
if max is not None:
@@ -696,21 +709,21 @@ def add_gui_vector3(
step = float(onp.min(possible_steps))
return self._create_gui_input(
- initial_value,
+ value,
message=_messages.GuiAddVector3Message(
order=order,
id=id,
label=label,
container_id=self._get_container_id(),
hint=hint,
- initial_value=initial_value,
+ value=value,
min=min,
max=max,
step=step,
precision=_compute_precision_digits(step),
+ disabled=disabled,
+ visible=visible,
),
- disabled=disabled,
- visible=visible,
)
# See add_gui_dropdown for notes on overloads.
@@ -764,24 +777,25 @@ def add_gui_dropdown(
Returns:
A handle that can be used to interact with the GUI element.
"""
- if initial_value is None:
- initial_value = options[0]
+ value = initial_value
+ if value is None:
+ value = options[0]
id = _make_unique_id()
order = _apply_default_order(order)
return GuiDropdownHandle(
self._create_gui_input(
- initial_value,
+ value,
message=_messages.GuiAddDropdownMessage(
order=order,
id=id,
label=label,
container_id=self._get_container_id(),
hint=hint,
- initial_value=initial_value,
+ value=value,
options=tuple(options),
+ disabled=disabled,
+ visible=visible,
),
- disabled=disabled,
- visible=visible,
)._impl,
_impl_options=tuple(options),
)
@@ -814,27 +828,28 @@ def add_gui_slider(
Returns:
A handle that can be used to interact with the GUI element.
"""
+ value: IntOrFloat = initial_value
assert max >= min
if step > max - min:
step = max - min
- assert max >= initial_value >= min
+ assert max >= value >= min
# GUI callbacks cast incoming values to match the type of the initial value. If
# the min, max, or step is a float, we should cast to a float.
- if type(initial_value) is int and (
+ if type(value) is int and (
type(min) is float or type(max) is float or type(step) is float
):
- initial_value = float(initial_value) # type: ignore
+ value = float(value) # type: ignore
# TODO: as of 6/5/2023, this assert will break something in nerfstudio. (at
# least LERF)
#
- # assert type(min) == type(max) == type(step) == type(initial_value)
+ # assert type(min) == type(max) == type(step) == type(value)
id = _make_unique_id()
order = _apply_default_order(order)
return self._create_gui_input(
- initial_value=initial_value,
+ value,
message=_messages.GuiAddSliderMessage(
order=order,
id=id,
@@ -844,11 +859,11 @@ def add_gui_slider(
min=min,
max=max,
step=step,
- initial_value=initial_value,
+ value=value,
precision=_compute_precision_digits(step),
+ visible=visible,
+ disabled=disabled,
),
- disabled=disabled,
- visible=visible,
is_button=False,
)
@@ -875,20 +890,21 @@ def add_gui_rgb(
A handle that can be used to interact with the GUI element.
"""
+ value = initial_value
id = _make_unique_id()
order = _apply_default_order(order)
return self._create_gui_input(
- initial_value,
+ value,
message=_messages.GuiAddRgbMessage(
order=order,
id=id,
label=label,
container_id=self._get_container_id(),
hint=hint,
- initial_value=initial_value,
+ value=value,
+ disabled=disabled,
+ visible=visible,
),
- disabled=disabled,
- visible=visible,
)
def add_gui_rgba(
@@ -913,28 +929,27 @@ def add_gui_rgba(
Returns:
A handle that can be used to interact with the GUI element.
"""
+ value = initial_value
id = _make_unique_id()
order = _apply_default_order(order)
return self._create_gui_input(
- initial_value,
+ value,
message=_messages.GuiAddRgbaMessage(
order=order,
id=id,
label=label,
container_id=self._get_container_id(),
hint=hint,
- initial_value=initial_value,
+ value=value,
+ disabled=disabled,
+ visible=visible,
),
- disabled=disabled,
- visible=visible,
)
def _create_gui_input(
self,
- initial_value: T,
+ value: T,
message: _messages._GuiAddInputBase,
- disabled: bool,
- visible: bool,
is_button: bool = False,
) -> GuiInputHandle[T]:
"""Private helper for adding a simple GUI element."""
@@ -945,19 +960,19 @@ def _create_gui_input(
# Construct handle.
handle_state = _GuiHandleState(
label=message.label,
- typ=type(initial_value),
+ typ=type(value),
gui_api=self,
- value=initial_value,
+ value=value,
+ initial_value=value,
update_timestamp=time.time(),
container_id=self._get_container_id(),
update_cb=[],
is_button=is_button,
sync_cb=None,
- disabled=False,
- visible=True,
+ disabled=message.disabled,
+ visible=message.visible,
id=message.id,
order=message.order,
- initial_value=initial_value,
hint=message.hint,
)
@@ -974,10 +989,4 @@ def sync_other_clients(client_id: ClientId, value: Any) -> None:
handle = GuiInputHandle(handle_state)
- # Set the disabled/visible fields. These will queue messages under-the-hood.
- if disabled:
- handle.disabled = disabled
- if not visible:
- handle.visible = visible
-
return handle
diff --git a/src/viser/_gui_handles.py b/src/viser/_gui_handles.py
index f150ae604..aae704412 100644
--- a/src/viser/_gui_handles.py
+++ b/src/viser/_gui_handles.py
@@ -319,8 +319,10 @@ def options(self, options: Iterable[StringType]) -> None:
label=self._impl.label,
container_id=self._impl.container_id,
hint=self._impl.hint,
- initial_value=self._impl.initial_value,
+ value=self._impl.initial_value,
options=self._impl_options,
+ visible=self._impl.visible,
+ disabled=self._impl.disabled,
)
)
@@ -337,6 +339,7 @@ class GuiTabGroupHandle:
_gui_api: GuiApi
_container_id: str # Parent.
_order: float
+ _visible: bool
@property
def order(self) -> float:
@@ -374,6 +377,7 @@ def _sync_with_client(self) -> None:
tab_labels=tuple(self._labels),
tab_icons_base64=tuple(self._icons_base64),
tab_container_ids=tuple(tab._id for tab in self._tabs),
+ visible=self._visible,
)
)
@@ -567,6 +571,7 @@ def content(self, content: str) -> None:
id=self._id,
markdown=_parse_markdown(content, self._image_root),
container_id=self._container_id,
+ visible=self._visible,
)
)
diff --git a/src/viser/_messages.py b/src/viser/_messages.py
index 9cf8cd411..fabdea20a 100644
--- a/src/viser/_messages.py
+++ b/src/viser/_messages.py
@@ -353,6 +353,7 @@ class GuiAddFolderMessage(Message):
label: str
container_id: str
expand_by_default: bool
+ visible: bool
@dataclasses.dataclass
@@ -361,6 +362,7 @@ class GuiAddMarkdownMessage(Message):
id: str
markdown: str
container_id: str
+ visible: bool
@dataclasses.dataclass
@@ -371,6 +373,7 @@ class GuiAddTabGroupMessage(Message):
tab_labels: Tuple[str, ...]
tab_icons_base64: Tuple[Union[str, None], ...]
tab_container_ids: Tuple[str, ...]
+ visible: bool
@dataclasses.dataclass
@@ -382,7 +385,9 @@ class _GuiAddInputBase(Message):
label: str
container_id: str
hint: Optional[str]
- initial_value: Any
+ value: Any
+ visible: bool
+ disabled: bool
@dataclasses.dataclass
@@ -399,9 +404,9 @@ class GuiCloseModalMessage(Message):
@dataclasses.dataclass
class GuiAddButtonMessage(_GuiAddInputBase):
- # All GUI elements currently need an `initial_value` field.
+ # All GUI elements currently need an `value` field.
# This makes our job on the frontend easier.
- initial_value: bool
+ value: bool
color: Optional[
Literal[
"dark",
@@ -428,13 +433,13 @@ class GuiAddSliderMessage(_GuiAddInputBase):
min: float
max: float
step: Optional[float]
- initial_value: float
+ value: float
precision: int
@dataclasses.dataclass
class GuiAddNumberMessage(_GuiAddInputBase):
- initial_value: float
+ value: float
precision: int
step: float
min: Optional[float]
@@ -443,22 +448,22 @@ class GuiAddNumberMessage(_GuiAddInputBase):
@dataclasses.dataclass
class GuiAddRgbMessage(_GuiAddInputBase):
- initial_value: Tuple[int, int, int]
+ value: Tuple[int, int, int]
@dataclasses.dataclass
class GuiAddRgbaMessage(_GuiAddInputBase):
- initial_value: Tuple[int, int, int, int]
+ value: Tuple[int, int, int, int]
@dataclasses.dataclass
class GuiAddCheckboxMessage(_GuiAddInputBase):
- initial_value: bool
+ value: bool
@dataclasses.dataclass
class GuiAddVector2Message(_GuiAddInputBase):
- initial_value: Tuple[float, float]
+ value: Tuple[float, float]
min: Optional[Tuple[float, float]]
max: Optional[Tuple[float, float]]
step: float
@@ -467,7 +472,7 @@ class GuiAddVector2Message(_GuiAddInputBase):
@dataclasses.dataclass
class GuiAddVector3Message(_GuiAddInputBase):
- initial_value: Tuple[float, float, float]
+ value: Tuple[float, float, float]
min: Optional[Tuple[float, float, float]]
max: Optional[Tuple[float, float, float]]
step: float
@@ -476,18 +481,18 @@ class GuiAddVector3Message(_GuiAddInputBase):
@dataclasses.dataclass
class GuiAddTextMessage(_GuiAddInputBase):
- initial_value: str
+ value: str
@dataclasses.dataclass
class GuiAddDropdownMessage(_GuiAddInputBase):
- initial_value: str
+ value: str
options: Tuple[str, ...]
@dataclasses.dataclass
class GuiAddButtonGroupMessage(_GuiAddInputBase):
- initial_value: str
+ value: str
options: Tuple[str, ...]
diff --git a/src/viser/client/src/ControlPanel/Generated.tsx b/src/viser/client/src/ControlPanel/Generated.tsx
index 9419eb2a1..6e12c131f 100644
--- a/src/viser/client/src/ControlPanel/Generated.tsx
+++ b/src/viser/client/src/ControlPanel/Generated.tsx
@@ -1,50 +1,30 @@
-import {
- GuiAddFolderMessage,
- GuiAddTabGroupMessage,
-} from "../WebsocketMessages";
-import { ViewerContext, ViewerContextContents } from "../App";
+import { ViewerContext } from "../App";
import { makeThrottledMessageSender } from "../WebsocketFunctions";
-import { computeRelativeLuminance } from "./GuiState";
-import {
- Collapse,
- Image,
- Paper,
- Tabs,
- TabsValue,
- useMantineTheme,
-} from "@mantine/core";
+import { GuiConfig } from "./GuiState";
+import { GuiComponentContext } from "./GuiComponentContext";
import {
Box,
- Button,
- Checkbox,
- ColorInput,
- Flex,
- NumberInput,
- Select,
- Slider,
- Text,
- TextInput,
- Tooltip,
} from "@mantine/core";
import React from "react";
-import Markdown from "../Markdown";
-import { ErrorBoundary } from "react-error-boundary";
-import { useDisclosure } from "@mantine/hooks";
-import { IconChevronDown, IconChevronUp } from "@tabler/icons-react";
-
-/** Root of generated inputs. */
-export default function GeneratedGuiContainer({
- // We need to take viewer as input in drei's elements, where contexts break.
- containerId,
- viewer,
- folderDepth,
-}: {
- containerId: string;
- viewer?: ViewerContextContents;
- folderDepth?: number;
-}) {
- if (viewer === undefined) viewer = React.useContext(ViewerContext)!;
+import ButtonComponent from "../components/Button";
+import SliderComponent from "../components/Slider";
+import NumberInputComponent from "../components/NumberInput";
+import TextInputComponent from "../components/TextInput";
+import CheckboxComponent from "../components/Checkbox";
+import Vector2Component from "../components/Vector2";
+import Vector3Component from "../components/Vector3";
+import DropdownComponent from "../components/Dropdown";
+import RgbComponent from "../components/Rgb";
+import RgbaComponent from "../components/Rgba";
+import ButtonGroupComponent from "../components/ButtonGroup";
+import MarkdownComponent from "../components/Markdown";
+import TabGroupComponent from "../components/TabGroup";
+import FolderComponent from "../components/Folder";
+
+
+function GuiContainer({ containerId }: { containerId: string }) {
+ const viewer = React.useContext(ViewerContext)!;
const guiIdSet =
viewer.useGui((state) => state.guiIdSetFromContainerId[containerId]) ?? {};
@@ -54,685 +34,84 @@ export default function GeneratedGuiContainer({
const guiOrderFromId = viewer!.useGui((state) => state.guiOrderFromId);
if (guiIdSet === undefined) return null;
- const guiIdOrderPairArray = guiIdArray.map((id) => ({
+ let guiIdOrderPairArray = guiIdArray.map((id) => ({
id: id,
order: guiOrderFromId[id],
}));
+ let pb = undefined;
+ guiIdOrderPairArray = guiIdOrderPairArray.sort((a, b) => a.order - b.order);
+ const inputProps = viewer.useGui((state) => guiIdOrderPairArray.map(pair => state.guiConfigFromId[pair.id]));
+ const lastProps = inputProps && inputProps[inputProps.length - 1];
+
+ // Done to match the old behaviour. Is it still needed?
+ if (lastProps !== undefined && lastProps.type === "GuiAddFolderMessage") {
+ pb = "0.125em";
+ }
const out = (
-
- {guiIdOrderPairArray
- .sort((a, b) => a.order - b.order)
- .map((pair, index) => (
-
- ))}
+
+ {inputProps.map((conf) => )}
);
return out;
}
-/** A single generated GUI element. */
-function GeneratedInput({
- id,
- viewer,
- folderDepth,
- last,
-}: {
- id: string;
- viewer?: ViewerContextContents;
- folderDepth: number;
- last: boolean;
-}) {
- // Handle GUI input types.
- if (viewer === undefined) viewer = React.useContext(ViewerContext)!;
- const conf = viewer.useGui((state) => state.guiConfigFromId[id]);
-
- // Handle nested containers.
- if (conf.type == "GuiAddFolderMessage")
- return (
-
-
-
- );
- if (conf.type == "GuiAddTabGroupMessage")
- return ;
- if (conf.type == "GuiAddMarkdownMessage") {
- let { visible } =
- viewer.useGui((state) => state.guiAttributeFromId[conf.id]) || {};
- visible = visible ?? true;
- if (!visible) return <>>;
- return (
-
- Markdown Failed to Render}
- >
- {conf.markdown}
-
-
- );
- }
-
+/** Root of generated inputs. */
+export default function GeneratedGuiContainer({ containerId }: { containerId: string; }) {
+ const viewer = React.useContext(ViewerContext)!;
const messageSender = makeThrottledMessageSender(viewer.websocketRef, 50);
- function updateValue(value: any) {
- setGuiValue(conf.id, value);
- messageSender({ type: "GuiUpdateMessage", id: conf.id, value: value });
+ function setValue(id: string, value: any) {
+ setGuiValue(id, value);
+ messageSender({ type: "GuiUpdateMessage", id: id, value: value });
}
const setGuiValue = viewer.useGui((state) => state.setGuiValue);
- const value =
- viewer.useGui((state) => state.guiValueFromId[conf.id]) ??
- conf.initial_value;
- const theme = useMantineTheme();
+ return
+
+
- let { visible, disabled } =
- viewer.useGui((state) => state.guiAttributeFromId[conf.id]) || {};
-
- visible = visible ?? true;
- disabled = disabled ?? false;
-
- if (!visible) return <>>;
-
- let inputColor =
- computeRelativeLuminance(theme.fn.primaryColor()) > 50.0
- ? theme.colors.gray[9]
- : theme.white;
+}
- let labeled = true;
- let input = null;
+/** A single generated GUI element. */
+function GeneratedInput(conf: GuiConfig) {
switch (conf.type) {
+ case "GuiAddFolderMessage":
+ return ;
+ case "GuiAddTabGroupMessage":
+ return ;
+ case "GuiAddMarkdownMessage":
+ return ;
case "GuiAddButtonMessage":
- labeled = false;
- if (conf.color !== null) {
- inputColor =
- computeRelativeLuminance(
- theme.colors[conf.color][theme.fn.primaryShade()],
- ) > 50.0
- ? theme.colors.gray[9]
- : theme.white;
- }
-
- input = (
-
- );
- break;
+ return ;
case "GuiAddSliderMessage":
- input = (
-
-
- ({
- thumb: {
- background: theme.fn.primaryColor(),
- borderRadius: "0.1em",
- height: "0.75em",
- width: "0.625em",
- },
- })}
- pt="0.2em"
- showLabelOnHover={false}
- min={conf.min}
- max={conf.max}
- step={conf.step ?? undefined}
- precision={conf.precision}
- value={value}
- onChange={updateValue}
- marks={[{ value: conf.min }, { value: conf.max }]}
- disabled={disabled}
- />
-
- {parseInt(conf.min.toFixed(6))}
- {parseInt(conf.max.toFixed(6))}
-
-
- {
- // Ignore empty values.
- newValue !== "" && updateValue(newValue);
- }}
- size="xs"
- min={conf.min}
- max={conf.max}
- hideControls
- step={conf.step ?? undefined}
- precision={conf.precision}
- sx={{ width: "3rem" }}
- styles={{
- input: {
- padding: "0.375em",
- letterSpacing: "-0.5px",
- minHeight: "1.875em",
- height: "1.875em",
- },
- }}
- ml="xs"
- />
-
- );
- break;
+ return ;
case "GuiAddNumberMessage":
- input = (
- {
- // Ignore empty values.
- newValue !== "" && updateValue(newValue);
- }}
- styles={{
- input: {
- minHeight: "1.625rem",
- height: "1.625rem",
- },
- }}
- disabled={disabled}
- stepHoldDelay={500}
- stepHoldInterval={(t) => Math.max(1000 / t ** 2, 25)}
- />
- );
- break;
+ return ;
case "GuiAddTextMessage":
- input = (
- {
- updateValue(value.target.value);
- }}
- styles={{
- input: {
- minHeight: "1.625rem",
- height: "1.625rem",
- padding: "0 0.5em",
- },
- }}
- disabled={disabled}
- />
- );
- break;
+ return ;
case "GuiAddCheckboxMessage":
- input = (
- {
- updateValue(value.target.checked);
- }}
- disabled={disabled}
- styles={{
- icon: {
- color: inputColor + " !important",
- },
- }}
- />
- );
- break;
+ return ;
case "GuiAddVector2Message":
- input = (
-
- );
- break;
+ return ;
case "GuiAddVector3Message":
- input = (
-
- );
- break;
+ return ;
case "GuiAddDropdownMessage":
- input = (
-