diff --git a/docs/source/examples/02_gui.rst b/docs/source/examples/02_gui.rst index 6b15a2a74..3fa021448 100644 --- a/docs/source/examples/02_gui.rst +++ b/docs/source/examples/02_gui.rst @@ -27,7 +27,7 @@ Examples of basic GUI elements that we can create, read from, and write to. with server.add_gui_folder("Read-only"): gui_counter = server.add_gui_number( "Counter", - initial_value=0, + value=0, disabled=True, ) @@ -36,38 +36,38 @@ Examples of basic GUI elements that we can create, read from, and write to. min=0, max=100, step=1, - initial_value=0, + value=0, disabled=True, ) with server.add_gui_folder("Editable"): gui_vector2 = server.add_gui_vector2( "Position", - initial_value=(0.0, 0.0), + value=(0.0, 0.0), step=0.1, ) gui_vector3 = server.add_gui_vector3( "Size", - initial_value=(1.0, 1.0, 1.0), + value=(1.0, 1.0, 1.0), step=0.25, ) with server.add_gui_folder("Text toggle"): gui_checkbox_hide = server.add_gui_checkbox( "Hide", - initial_value=False, + value=False, ) gui_text = server.add_gui_text( "Text", - initial_value="Hello world", + value="Hello world", ) gui_button = server.add_gui_button("Button") gui_checkbox_disable = server.add_gui_checkbox( "Disable", - initial_value=False, + value=False, ) gui_rgb = server.add_gui_rgb( "Color", - initial_value=(255, 255, 0), + value=(255, 255, 0), ) # Pre-generate a point cloud to send. diff --git a/docs/source/examples/03_gui_callbacks.rst b/docs/source/examples/03_gui_callbacks.rst index 94d1b09ee..e6ba2dabc 100644 --- a/docs/source/examples/03_gui_callbacks.rst +++ b/docs/source/examples/03_gui_callbacks.rst @@ -44,12 +44,12 @@ we get updates. gui_plane.on_update(lambda _: update_plane()) with server.add_gui_folder("Control", expand_by_default=False): - gui_show_frame = server.add_gui_checkbox("Show Frame", initial_value=True) + gui_show_frame = server.add_gui_checkbox("Show Frame", value=True) gui_show_everything = server.add_gui_checkbox( - "Show Everything", initial_value=True + "Show Everything", value=True ) gui_axis = server.add_gui_dropdown("Axis", ("x", "y", "z")) - gui_include_z = server.add_gui_checkbox("Z in dropdown", initial_value=True) + gui_include_z = server.add_gui_checkbox("Z in dropdown", value=True) @gui_include_z.on_update def _(_) -> None: @@ -57,10 +57,10 @@ we get updates. with server.add_gui_folder("Sliders"): gui_location = server.add_gui_slider( - "Location", min=-5.0, max=5.0, step=0.05, initial_value=0.0 + "Location", min=-5.0, max=5.0, step=0.05, value=0.0 ) gui_num_points = server.add_gui_slider( - "# Points", min=1000, max=200_000, step=1000, initial_value=10_000 + "# Points", min=1000, max=200_000, step=1000, value=10_000 ) def draw_frame() -> None: diff --git a/docs/source/examples/04_camera_poses.rst b/docs/source/examples/04_camera_poses.rst index ac5c9127f..34d249719 100644 --- a/docs/source/examples/04_camera_poses.rst +++ b/docs/source/examples/04_camera_poses.rst @@ -31,7 +31,7 @@ Example showing how we can detect new clients and read camera poses from them. print(f"New camera on client {client.client_id}!") # Show the client ID in the GUI. - gui_info = client.add_gui_text("Client ID", initial_value=str(client.client_id)) + gui_info = client.add_gui_text("Client ID", value=str(client.client_id)) gui_info.disabled = True diff --git a/docs/source/examples/07_record3d_visualizer.rst b/docs/source/examples/07_record3d_visualizer.rst index c185fbede..0aaa0038c 100644 --- a/docs/source/examples/07_record3d_visualizer.rst +++ b/docs/source/examples/07_record3d_visualizer.rst @@ -47,14 +47,14 @@ Parse and stream record3d captures. To get the demo data, see ``./assets/downloa min=0, max=num_frames - 1, step=1, - initial_value=0, + value=0, disabled=True, ) gui_next_frame = server.add_gui_button("Next Frame", disabled=True) gui_prev_frame = server.add_gui_button("Prev Frame", disabled=True) gui_playing = server.add_gui_checkbox("Playing", True) gui_framerate = server.add_gui_slider( - "FPS", min=1, max=60, step=0.1, initial_value=loader.fps + "FPS", min=1, max=60, step=0.1, value=loader.fps ) gui_framerate_options = server.add_gui_button_group( "FPS options", ("10", "20", "30", "60") diff --git a/docs/source/examples/08_smplx_visualizer.rst b/docs/source/examples/08_smplx_visualizer.rst index dafc82aee..33bbfc605 100644 --- a/docs/source/examples/08_smplx_visualizer.rst +++ b/docs/source/examples/08_smplx_visualizer.rst @@ -141,9 +141,9 @@ parameters to run this script: # GUI elements: mesh settings + visibility. with tab_group.add_tab("View", viser.Icon.VIEWFINDER): - gui_rgb = server.add_gui_rgb("Color", initial_value=(90, 200, 255)) - gui_wireframe = server.add_gui_checkbox("Wireframe", initial_value=False) - gui_show_controls = server.add_gui_checkbox("Handles", initial_value=False) + gui_rgb = server.add_gui_rgb("Color", value=(90, 200, 255)) + gui_wireframe = server.add_gui_checkbox("Wireframe", value=False) + gui_show_controls = server.add_gui_checkbox("Handles", value=False) @gui_rgb.on_update def _(_): @@ -175,7 +175,7 @@ parameters to run this script: gui_betas = [] for i in range(num_betas): beta = server.add_gui_slider( - f"beta{i}", min=-5.0, max=5.0, step=0.01, initial_value=0.0 + f"beta{i}", min=-5.0, max=5.0, step=0.01, value=0.0 ) gui_betas.append(beta) @@ -210,7 +210,7 @@ parameters to run this script: for i in range(num_body_joints + 1): gui_joint = server.add_gui_vector3( label=smplx.joint_names.JOINT_NAMES[i], - initial_value=(0.0, 0.0, 0.0), + value=(0.0, 0.0, 0.0), step=0.05, ) gui_joints.append(gui_joint) diff --git a/docs/source/examples/09_urdf_visualizer.rst b/docs/source/examples/09_urdf_visualizer.rst index a679113fc..29135a47f 100644 --- a/docs/source/examples/09_urdf_visualizer.rst +++ b/docs/source/examples/09_urdf_visualizer.rst @@ -52,7 +52,7 @@ Examples: min=lower, max=upper, step=1e-3, - initial_value=initial_angle, + value=initial_angle, ) slider.on_update( # When sliders move, we update the URDF configuration. lambda _: urdf.update_cfg(onp.array([gui.value for gui in gui_joints])) diff --git a/docs/source/examples/11_colmap_visualizer.rst b/docs/source/examples/11_colmap_visualizer.rst index dc1da2c0f..930e5f093 100644 --- a/docs/source/examples/11_colmap_visualizer.rst +++ b/docs/source/examples/11_colmap_visualizer.rst @@ -68,16 +68,16 @@ Visualize COLMAP sparse reconstruction outputs. To get demo data, see ``./assets min=1, max=len(points3d), step=1, - initial_value=min(len(points3d), 50_000), + value=min(len(points3d), 50_000), ) gui_frames = server.add_gui_slider( "Max frames", min=1, max=len(images), step=1, - initial_value=min(len(images), 100), + value=min(len(images), 100), ) - gui_point_size = server.add_gui_number("Point size", initial_value=0.05) + gui_point_size = server.add_gui_number("Point size", value=0.05) def visualize_colmap() -> None: """Send all COLMAP elements to viser for visualization. This could be optimized diff --git a/docs/source/examples/12_click_meshes.rst b/docs/source/examples/12_click_meshes.rst index 30ec69e1c..ae2b2846f 100644 --- a/docs/source/examples/12_click_meshes.rst +++ b/docs/source/examples/12_click_meshes.rst @@ -27,13 +27,13 @@ Click on meshes to select them. The index of the last clicked mesh is displayed with server.add_gui_folder("Last clicked"): x_value = server.add_gui_number( label="x", - initial_value=0, + value=0, disabled=True, hint="x coordinate of the last clicked mesh", ) y_value = server.add_gui_number( label="y", - initial_value=0, + value=0, disabled=True, hint="y coordinate of the last clicked mesh", ) diff --git a/docs/source/examples/13_theming.rst b/docs/source/examples/13_theming.rst index c2b0bf868..496784444 100644 --- a/docs/source/examples/13_theming.rst +++ b/docs/source/examples/13_theming.rst @@ -54,16 +54,16 @@ Viser includes support for light theming. gui_theme_code = server.add_gui_markdown("no theme applied yet") # GUI elements for controllable values. - titlebar = server.add_gui_checkbox("Titlebar", initial_value=True) - dark_mode = server.add_gui_checkbox("Dark mode", initial_value=True) - show_logo = server.add_gui_checkbox("Show logo", initial_value=True) - show_share_button = server.add_gui_checkbox("Show share button", initial_value=True) + titlebar = server.add_gui_checkbox("Titlebar", value=True) + dark_mode = server.add_gui_checkbox("Dark mode", value=True) + show_logo = server.add_gui_checkbox("Show logo", value=True) + show_share_button = server.add_gui_checkbox("Show share button", value=True) brand_color = server.add_gui_rgb("Brand color", (230, 180, 30)) control_layout = server.add_gui_dropdown( "Control layout", ("floating", "fixed", "collapsible") ) control_width = server.add_gui_dropdown( - "Control width", ("small", "medium", "large"), initial_value="medium" + "Control width", ("small", "medium", "large"), value="medium" ) synchronize = server.add_gui_button("Apply theme", icon=viser.Icon.CHECK) diff --git a/docs/source/examples/14_markdown.rst b/docs/source/examples/14_markdown.rst index 94f37a4b5..57c978e02 100644 --- a/docs/source/examples/14_markdown.rst +++ b/docs/source/examples/14_markdown.rst @@ -26,7 +26,7 @@ Viser GUI has MDX 2 support. here = Path(__file__).absolute().parent button = server.add_gui_button("Remove blurb") - checkbox = server.add_gui_checkbox("Visibility", initial_value=True) + checkbox = server.add_gui_checkbox("Visibility", value=True) markdown_source = (here / "./assets/mdx_example.mdx").read_text() markdown_blurb = server.add_gui_markdown( diff --git a/docs/source/examples/16_modal.rst b/docs/source/examples/16_modal.rst index 2072ac692..0e3757c51 100644 --- a/docs/source/examples/16_modal.rst +++ b/docs/source/examples/16_modal.rst @@ -30,7 +30,7 @@ Examples of using modals in Viser. gui_title = client.add_gui_text( "Title", - initial_value="My Modal", + value="My Modal", ) modal_button = client.add_gui_button("Show more modals") diff --git a/docs/source/examples/21_set_up_direction.rst b/docs/source/examples/21_set_up_direction.rst index 70ca29bfe..364ee75bb 100644 --- a/docs/source/examples/21_set_up_direction.rst +++ b/docs/source/examples/21_set_up_direction.rst @@ -23,7 +23,7 @@ Set Up Direction server.world_axes.visible = True gui_up = server.add_gui_vector3( "Up Direction", - initial_value=(0.0, 0.0, 1.0), + value=(0.0, 0.0, 1.0), step=0.01, ) diff --git a/examples/02_gui.py b/examples/02_gui.py index 0e7ccc1f2..308f3e8c2 100644 --- a/examples/02_gui.py +++ b/examples/02_gui.py @@ -15,7 +15,7 @@ def main() -> None: with server.add_gui_folder("Read-only"): gui_counter = server.add_gui_number( "Counter", - initial_value=0, + value=0, disabled=True, ) @@ -24,38 +24,38 @@ def main() -> None: min=0, max=100, step=1, - initial_value=0, + value=0, disabled=True, ) with server.add_gui_folder("Editable"): gui_vector2 = server.add_gui_vector2( "Position", - initial_value=(0.0, 0.0), + value=(0.0, 0.0), step=0.1, ) gui_vector3 = server.add_gui_vector3( "Size", - initial_value=(1.0, 1.0, 1.0), + value=(1.0, 1.0, 1.0), step=0.25, ) with server.add_gui_folder("Text toggle"): gui_checkbox_hide = server.add_gui_checkbox( "Hide", - initial_value=False, + value=False, ) gui_text = server.add_gui_text( "Text", - initial_value="Hello world", + value="Hello world", ) gui_button = server.add_gui_button("Button") gui_checkbox_disable = server.add_gui_checkbox( "Disable", - initial_value=False, + value=False, ) gui_rgb = server.add_gui_rgb( "Color", - initial_value=(255, 255, 0), + value=(255, 255, 0), ) # Pre-generate a point cloud to send. diff --git a/examples/03_gui_callbacks.py b/examples/03_gui_callbacks.py index 19baf6825..0c4475830 100644 --- a/examples/03_gui_callbacks.py +++ b/examples/03_gui_callbacks.py @@ -36,12 +36,10 @@ def update_plane() -> None: gui_plane.on_update(lambda _: update_plane()) with server.add_gui_folder("Control", expand_by_default=False): - gui_show_frame = server.add_gui_checkbox("Show Frame", initial_value=True) - gui_show_everything = server.add_gui_checkbox( - "Show Everything", initial_value=True - ) + gui_show_frame = server.add_gui_checkbox("Show Frame", value=True) + gui_show_everything = server.add_gui_checkbox("Show Everything", value=True) gui_axis = server.add_gui_dropdown("Axis", ("x", "y", "z")) - gui_include_z = server.add_gui_checkbox("Z in dropdown", initial_value=True) + gui_include_z = server.add_gui_checkbox("Z in dropdown", value=True) @gui_include_z.on_update def _(_) -> None: @@ -49,10 +47,10 @@ def _(_) -> None: with server.add_gui_folder("Sliders"): gui_location = server.add_gui_slider( - "Location", min=-5.0, max=5.0, step=0.05, initial_value=0.0 + "Location", min=-5.0, max=5.0, step=0.05, value=0.0 ) gui_num_points = server.add_gui_slider( - "# Points", min=1000, max=200_000, step=1000, initial_value=10_000 + "# Points", min=1000, max=200_000, step=1000, value=10_000 ) def draw_frame() -> None: diff --git a/examples/04_camera_poses.py b/examples/04_camera_poses.py index 90b9e4ffb..4ecaf11e7 100644 --- a/examples/04_camera_poses.py +++ b/examples/04_camera_poses.py @@ -21,7 +21,7 @@ def _(_: viser.CameraHandle) -> None: print(f"New camera on client {client.client_id}!") # Show the client ID in the GUI. - gui_info = client.add_gui_text("Client ID", initial_value=str(client.client_id)) + gui_info = client.add_gui_text("Client ID", value=str(client.client_id)) gui_info.disabled = True diff --git a/examples/07_record3d_visualizer.py b/examples/07_record3d_visualizer.py index 9ff5c5d81..612ab02cd 100644 --- a/examples/07_record3d_visualizer.py +++ b/examples/07_record3d_visualizer.py @@ -36,14 +36,14 @@ def main( min=0, max=num_frames - 1, step=1, - initial_value=0, + value=0, disabled=True, ) gui_next_frame = server.add_gui_button("Next Frame", disabled=True) gui_prev_frame = server.add_gui_button("Prev Frame", disabled=True) gui_playing = server.add_gui_checkbox("Playing", True) gui_framerate = server.add_gui_slider( - "FPS", min=1, max=60, step=0.1, initial_value=loader.fps + "FPS", min=1, max=60, step=0.1, value=loader.fps ) gui_framerate_options = server.add_gui_button_group( "FPS options", ("10", "20", "30", "60") diff --git a/examples/08_smplx_visualizer.py b/examples/08_smplx_visualizer.py index 6e9ba6da0..dea575e18 100644 --- a/examples/08_smplx_visualizer.py +++ b/examples/08_smplx_visualizer.py @@ -133,9 +133,9 @@ def make_gui_elements( # GUI elements: mesh settings + visibility. with tab_group.add_tab("View", viser.Icon.VIEWFINDER): - gui_rgb = server.add_gui_rgb("Color", initial_value=(90, 200, 255)) - gui_wireframe = server.add_gui_checkbox("Wireframe", initial_value=False) - gui_show_controls = server.add_gui_checkbox("Handles", initial_value=False) + gui_rgb = server.add_gui_rgb("Color", value=(90, 200, 255)) + gui_wireframe = server.add_gui_checkbox("Wireframe", value=False) + gui_show_controls = server.add_gui_checkbox("Handles", value=False) @gui_rgb.on_update def _(_): @@ -167,7 +167,7 @@ def _(_): gui_betas = [] for i in range(num_betas): beta = server.add_gui_slider( - f"beta{i}", min=-5.0, max=5.0, step=0.01, initial_value=0.0 + f"beta{i}", min=-5.0, max=5.0, step=0.01, value=0.0 ) gui_betas.append(beta) @@ -202,7 +202,7 @@ def _(_): for i in range(num_body_joints + 1): gui_joint = server.add_gui_vector3( label=smplx.joint_names.JOINT_NAMES[i], - initial_value=(0.0, 0.0, 0.0), + value=(0.0, 0.0, 0.0), step=0.05, ) gui_joints.append(gui_joint) diff --git a/examples/09_urdf_visualizer.py b/examples/09_urdf_visualizer.py index 3cb475034..ae423c688 100644 --- a/examples/09_urdf_visualizer.py +++ b/examples/09_urdf_visualizer.py @@ -38,7 +38,7 @@ def main(urdf_path: Path) -> None: min=lower, max=upper, step=1e-3, - initial_value=initial_angle, + value=initial_angle, ) slider.on_update( # When sliders move, we update the URDF configuration. lambda _: urdf.update_cfg(onp.array([gui.value for gui in gui_joints])) diff --git a/examples/11_colmap_visualizer.py b/examples/11_colmap_visualizer.py index f655a17de..d0d1bf306 100644 --- a/examples/11_colmap_visualizer.py +++ b/examples/11_colmap_visualizer.py @@ -57,16 +57,16 @@ def _(event: viser.GuiEvent) -> None: min=1, max=len(points3d), step=1, - initial_value=min(len(points3d), 50_000), + value=min(len(points3d), 50_000), ) gui_frames = server.add_gui_slider( "Max frames", min=1, max=len(images), step=1, - initial_value=min(len(images), 100), + value=min(len(images), 100), ) - gui_point_size = server.add_gui_number("Point size", initial_value=0.05) + gui_point_size = server.add_gui_number("Point size", value=0.05) def visualize_colmap() -> None: """Send all COLMAP elements to viser for visualization. This could be optimized diff --git a/examples/12_click_meshes.py b/examples/12_click_meshes.py index e5d1dcb9f..dee8067c0 100644 --- a/examples/12_click_meshes.py +++ b/examples/12_click_meshes.py @@ -16,13 +16,13 @@ def main() -> None: with server.add_gui_folder("Last clicked"): x_value = server.add_gui_number( label="x", - initial_value=0, + value=0, disabled=True, hint="x coordinate of the last clicked mesh", ) y_value = server.add_gui_number( label="y", - initial_value=0, + value=0, disabled=True, hint="y coordinate of the last clicked mesh", ) diff --git a/examples/13_theming.py b/examples/13_theming.py index 1a7dac6e3..ac3528550 100644 --- a/examples/13_theming.py +++ b/examples/13_theming.py @@ -47,16 +47,16 @@ def main(): gui_theme_code = server.add_gui_markdown("no theme applied yet") # GUI elements for controllable values. - titlebar = server.add_gui_checkbox("Titlebar", initial_value=True) - dark_mode = server.add_gui_checkbox("Dark mode", initial_value=True) - show_logo = server.add_gui_checkbox("Show logo", initial_value=True) - show_share_button = server.add_gui_checkbox("Show share button", initial_value=True) + titlebar = server.add_gui_checkbox("Titlebar", value=True) + dark_mode = server.add_gui_checkbox("Dark mode", value=True) + show_logo = server.add_gui_checkbox("Show logo", value=True) + show_share_button = server.add_gui_checkbox("Show share button", value=True) brand_color = server.add_gui_rgb("Brand color", (230, 180, 30)) control_layout = server.add_gui_dropdown( "Control layout", ("floating", "fixed", "collapsible") ) control_width = server.add_gui_dropdown( - "Control width", ("small", "medium", "large"), initial_value="medium" + "Control width", ("small", "medium", "large"), value="medium" ) synchronize = server.add_gui_button("Apply theme", icon=viser.Icon.CHECK) diff --git a/examples/14_markdown.py b/examples/14_markdown.py index 4d85ac6cc..25c5f8f07 100644 --- a/examples/14_markdown.py +++ b/examples/14_markdown.py @@ -16,7 +16,7 @@ here = Path(__file__).absolute().parent button = server.add_gui_button("Remove blurb") -checkbox = server.add_gui_checkbox("Visibility", initial_value=True) +checkbox = server.add_gui_checkbox("Visibility", value=True) markdown_source = (here / "./assets/mdx_example.mdx").read_text() markdown_blurb = server.add_gui_markdown( diff --git a/examples/16_modal.py b/examples/16_modal.py index 88afc612a..6e7dc21e9 100644 --- a/examples/16_modal.py +++ b/examples/16_modal.py @@ -19,7 +19,7 @@ def _(client: viser.ClientHandle) -> None: gui_title = client.add_gui_text( "Title", - initial_value="My Modal", + value="My Modal", ) modal_button = client.add_gui_button("Show more modals") diff --git a/examples/21_set_up_direction.py b/examples/21_set_up_direction.py index 98c988d8d..cda9fd320 100644 --- a/examples/21_set_up_direction.py +++ b/examples/21_set_up_direction.py @@ -12,7 +12,7 @@ def main() -> None: server.world_axes.visible = True gui_up = server.add_gui_vector3( "Up Direction", - initial_value=(0.0, 0.0, 1.0), + value=(0.0, 0.0, 1.0), step=0.01, ) diff --git a/src/viser/_gui_api.py b/src/viser/_gui_api.py index aa357fa24..509730932 100644 --- a/src/viser/_gui_api.py +++ b/src/viser/_gui_api.py @@ -55,6 +55,35 @@ T = TypeVar("T") +@overload +def _handle_value( + value: Optional[T], initial_value: Optional[T], allow_none: Literal[True] +) -> Optional[T]: + ... + + +@overload +def _handle_value( + value: Optional[T], initial_value: Optional[T], allow_none: bool = ... +) -> T: + ... + + +def _handle_value( + value: Optional[T], initial_value: Optional[T], allow_none: bool = False +): + """ + Handles the deprecated `initial_value` argument for GUI elements. + """ + if initial_value is not None: + assert value is None, "Cannot specify both value and initial_value." + warnings.warn("initial_value is deprecated. Use value instead.") + value = initial_value + if not allow_none: + assert value is not None, "Must specify either value or initial_value." + return value + + def _compute_step(x: Optional[float]) -> float: # type: ignore """For number inputs: compute an increment size from some number. @@ -261,6 +290,7 @@ def add_gui_modal( def add_gui_tab_group( self, order: Optional[float] = None, + visible: bool = True, ) -> GuiTabGroupHandle: """Add a tab group. @@ -280,6 +310,7 @@ def add_gui_tab_group( _gui_api=self, _container_id=self._get_container_id(), _order=order, + _visible=visible, ) def add_gui_markdown( @@ -287,6 +318,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. @@ -294,6 +326,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. @@ -301,7 +334,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, @@ -391,6 +424,8 @@ def add_gui_button_group( disabled: bool = False, hint: Optional[str] = None, order: Optional[float] = None, + *, + value: Optional[TLiteralString] = None, ) -> GuiButtonGroupHandle[TLiteralString]: ... @@ -403,6 +438,8 @@ def add_gui_button_group( disabled: bool = False, hint: Optional[str] = None, order: Optional[float] = None, + *, + value: Optional[TString] = None, ) -> GuiButtonGroupHandle[TString]: ... @@ -414,6 +451,8 @@ def add_gui_button_group( disabled: bool = False, hint: Optional[str] = None, order: Optional[float] = None, + *, + value: Optional[TLiteralString | TString] = None, ) -> GuiButtonGroupHandle[Any]: # Return types are specified in overloads. """Add a button group to the GUI. @@ -428,7 +467,10 @@ def add_gui_button_group( Returns: A handle that can be used to interact with the GUI element. """ - value = options[0] + if value is None: + value = options[0] + else: + assert value in options, "Initial value must be one of the options." id = _make_unique_id() order = _apply_default_order(order) return GuiButtonGroupHandle( @@ -451,26 +493,28 @@ def add_gui_button_group( def add_gui_checkbox( self, label: str, - initial_value: bool, + value: Optional[bool] = None, disabled: bool = False, visible: bool = True, hint: Optional[str] = None, order: Optional[float] = None, + initial_value: Optional[bool] = None, ) -> GuiInputHandle[bool]: """Add a checkbox to the GUI. Args: label: Label to display on the checkbox. - initial_value: Initial value of the checkbox. + value: Initial value of the checkbox. disabled: Whether the checkbox is disabled. visible: Whether the checkbox is visible. hint: Optional hint to display on hover. order: Optional ordering, smallest values will be displayed first. + initial_value: [DEPRECATED] Use `value` instead. Returns: A handle that can be used to interact with the GUI element. """ - value = initial_value + value = _handle_value(value, initial_value) assert isinstance(value, bool) id = _make_unique_id() order = _apply_default_order(order) @@ -491,26 +535,28 @@ def add_gui_checkbox( def add_gui_text( self, label: str, - initial_value: str, + value: Optional[str] = None, disabled: bool = False, visible: bool = True, hint: Optional[str] = None, order: Optional[float] = None, + initial_value: Optional[str] = None, ) -> GuiInputHandle[str]: """Add a text input to the GUI. Args: label: Label to display on the text input. - initial_value: Initial value of the text input. + value: Initial value of the text input. disabled: Whether the text input is disabled. visible: Whether the text input is visible. hint: Optional hint to display on hover. order: Optional ordering, smallest values will be displayed first. + initial_value: [DEPRECATED] Use `value` instead. Returns: A handle that can be used to interact with the GUI element. """ - value = initial_value + value = _handle_value(value, initial_value) assert isinstance(value, str) id = _make_unique_id() order = _apply_default_order(order) @@ -531,7 +577,7 @@ def add_gui_text( def add_gui_number( self, label: str, - initial_value: IntOrFloat, + value: Optional[IntOrFloat] = None, min: Optional[IntOrFloat] = None, max: Optional[IntOrFloat] = None, step: Optional[IntOrFloat] = None, @@ -539,12 +585,13 @@ def add_gui_number( visible: bool = True, hint: Optional[str] = None, order: Optional[float] = None, + initial_value: Optional[IntOrFloat] = None, ) -> GuiInputHandle[IntOrFloat]: """Add a number input to the GUI, with user-specifiable bound and precision parameters. Args: label: Label to display on the number input. - initial_value: Initial value of the number input. + value: Initial value of the number input. min: Optional minimum value of the number input. max: Optional maximum value of the number input. step: Optional step size of the number input. Computed automatically if not @@ -553,11 +600,12 @@ def add_gui_number( visible: Whether the number input is visible. hint: Optional hint to display on hover. order: Optional ordering, smallest values will be displayed first. + initial_value: [DEPRECATED] Use `value` instead. Returns: A handle that can be used to interact with the GUI element. """ - value = initial_value + value = _handle_value(value, initial_value) assert isinstance(value, (int, float)) @@ -600,7 +648,7 @@ def add_gui_number( def add_gui_vector2( self, label: str, - initial_value: Tuple[float, float] | onp.ndarray, + value: Optional[Tuple[float, float] | onp.ndarray] = None, min: Tuple[float, float] | onp.ndarray | None = None, max: Tuple[float, float] | onp.ndarray | None = None, step: Optional[float] = None, @@ -608,12 +656,13 @@ def add_gui_vector2( visible: bool = True, hint: Optional[str] = None, order: Optional[float] = None, + initial_value: Optional[Tuple[float, float] | onp.ndarray] = None, ) -> GuiInputHandle[Tuple[float, float]]: """Add a length-2 vector input to the GUI. Args: label: Label to display on the vector input. - initial_value: Initial value of the vector input. + value: Initial value of the vector input. min: Optional minimum value of the vector input. max: Optional maximum value of the vector input. step: Optional step size of the vector input. Computed automatically if not @@ -621,12 +670,12 @@ def add_gui_vector2( visible: Whether the vector input is visible. hint: Optional hint to display on hover. order: Optional ordering, smallest values will be displayed first. + initial_value: [DEPRECATED] Use `value` instead. Returns: A handle that can be used to interact with the GUI element. """ - value = initial_value - value = cast_vector(value, 2) + _value = cast_vector(_handle_value(value, initial_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() @@ -634,7 +683,7 @@ def add_gui_vector2( if step is None: possible_steps: List[float] = [] - possible_steps.extend([_compute_step(x) for x in 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: @@ -642,14 +691,14 @@ def add_gui_vector2( step = float(onp.min(possible_steps)) return self._create_gui_input( - value, + _value, message=_messages.GuiAddVector2Message( order=order, id=id, label=label, container_id=self._get_container_id(), hint=hint, - value=value, + value=_value, min=min, max=max, step=step, @@ -662,7 +711,7 @@ def add_gui_vector2( def add_gui_vector3( self, label: str, - initial_value: Tuple[float, float, float] | onp.ndarray, + value: Optional[Tuple[float, float, float] | onp.ndarray] = None, min: Tuple[float, float, float] | onp.ndarray | None = None, max: Tuple[float, float, float] | onp.ndarray | None = None, step: Optional[float] = None, @@ -670,12 +719,13 @@ def add_gui_vector3( visible: bool = True, hint: Optional[str] = None, order: Optional[float] = None, + initial_value: Optional[Tuple[float, float, float] | onp.ndarray] = None, ) -> GuiInputHandle[Tuple[float, float, float]]: """Add a length-3 vector input to the GUI. Args: label: Label to display on the vector input. - initial_value: Initial value of the vector input. + value: Initial value of the vector input. min: Optional minimum value of the vector input. max: Optional maximum value of the vector input. step: Optional step size of the vector input. Computed automatically if not @@ -683,12 +733,12 @@ def add_gui_vector3( visible: Whether the vector input is visible. hint: Optional hint to display on hover. order: Optional ordering, smallest values will be displayed first. + initial_value: [DEPRECATED] Use `value` instead. Returns: A handle that can be used to interact with the GUI element. """ - value = initial_value - value = cast_vector(value, 2) + _value = cast_vector(_handle_value(value, initial_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() @@ -696,7 +746,7 @@ def add_gui_vector3( if step is None: possible_steps: List[float] = [] - possible_steps.extend([_compute_step(x) for x in 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: @@ -704,14 +754,14 @@ def add_gui_vector3( step = float(onp.min(possible_steps)) return self._create_gui_input( - value, + _value, message=_messages.GuiAddVector3Message( order=order, id=id, label=label, container_id=self._get_container_id(), hint=hint, - value=value, + value=_value, min=min, max=max, step=step, @@ -727,11 +777,12 @@ def add_gui_dropdown( self, label: str, options: Sequence[TLiteralString], - initial_value: Optional[TLiteralString] = None, + value: Optional[TLiteralString] = None, disabled: bool = False, visible: bool = True, hint: Optional[str] = None, order: Optional[float] = None, + initial_value: Optional[TLiteralString | TString] = None, ) -> GuiDropdownHandle[TLiteralString]: ... @@ -740,11 +791,12 @@ def add_gui_dropdown( self, label: str, options: Sequence[TString], - initial_value: Optional[TString] = None, + value: Optional[TString] = None, disabled: bool = False, visible: bool = True, hint: Optional[str] = None, order: Optional[float] = None, + initial_value: Optional[TLiteralString | TString] = None, ) -> GuiDropdownHandle[TString]: ... @@ -752,41 +804,43 @@ def add_gui_dropdown( self, label: str, options: Sequence[TLiteralString] | Sequence[TString], - initial_value: Optional[TLiteralString | TString] = None, + value: Optional[TLiteralString | TString] = None, disabled: bool = False, visible: bool = True, hint: Optional[str] = None, order: Optional[float] = None, + initial_value: Optional[TLiteralString | TString] = None, ) -> GuiDropdownHandle[Any]: # Output type is specified in overloads. """Add a dropdown to the GUI. Args: label: Label to display on the dropdown. options: Sequence of options to display in the dropdown. - initial_value: Initial value of the dropdown. + value: Initial value of the dropdown. disabled: Whether the dropdown is disabled. visible: Whether the dropdown is visible. hint: Optional hint to display on hover. order: Optional ordering, smallest values will be displayed first. + initial_value: [DEPRECATED] Use `value` instead. Returns: A handle that can be used to interact with the GUI element. """ - value = initial_value - if value is None: - value = options[0] + _value = _handle_value(value, initial_value, allow_none=True) + if _value is None: + _value = options[0] id = _make_unique_id() order = _apply_default_order(order) return GuiDropdownHandle( self._create_gui_input( - value, + _value, message=_messages.GuiAddDropdownMessage( order=order, id=id, label=label, container_id=self._get_container_id(), hint=hint, - value=value, + value=_value, options=tuple(options), disabled=disabled, visible=visible, @@ -801,11 +855,12 @@ def add_gui_slider( min: IntOrFloat, max: IntOrFloat, step: IntOrFloat, - initial_value: IntOrFloat, + value: Optional[IntOrFloat] = None, disabled: bool = False, visible: bool = True, hint: Optional[str] = None, order: Optional[float] = None, + initial_value: Optional[IntOrFloat] = None, ) -> GuiInputHandle[IntOrFloat]: """Add a slider to the GUI. Types of the min, max, step, and initial value should match. @@ -814,27 +869,28 @@ def add_gui_slider( min: Minimum value of the slider. max: Maximum value of the slider. step: Step size of the slider. - initial_value: Initial value of the slider. + value: Initial value of the slider. disabled: Whether the slider is disabled. visible: Whether the slider is visible. hint: Optional hint to display on hover. order: Optional ordering, smallest values will be displayed first. + initial_value: [DEPRECATED] Use `value` instead. Returns: A handle that can be used to interact with the GUI element. """ - value = initial_value + _value: IntOrFloat = _handle_value(value, initial_value) assert max >= min if step > max - min: step = max - min - assert max >= 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(value) is int and ( + if type(_value) is int and ( type(min) is float or type(max) is float or type(step) is float ): - value = float(value) # type: ignore + _value = float(_value) # type: ignore # TODO: as of 6/5/2023, this assert will break something in nerfstudio. (at # least LERF) @@ -844,7 +900,7 @@ def add_gui_slider( id = _make_unique_id() order = _apply_default_order(order) return self._create_gui_input( - value, + _value, message=_messages.GuiAddSliderMessage( order=order, id=id, @@ -854,7 +910,7 @@ def add_gui_slider( min=min, max=max, step=step, - value=value, + value=_value, precision=_compute_precision_digits(step), visible=visible, disabled=disabled, @@ -865,27 +921,29 @@ def add_gui_slider( def add_gui_rgb( self, label: str, - initial_value: Tuple[int, int, int], + value: Optional[Tuple[int, int, int]] = None, disabled: bool = False, visible: bool = True, hint: Optional[str] = None, order: Optional[float] = None, + initial_value: Optional[Tuple[int, int, int]] = None, ) -> GuiInputHandle[Tuple[int, int, int]]: """Add an RGB picker to the GUI. Args: label: Label to display on the RGB picker. - initial_value: Initial value of the RGB picker. + value: Initial value of the RGB picker. disabled: Whether the RGB picker is disabled. visible: Whether the RGB picker is visible. hint: Optional hint to display on hover. order: Optional ordering, smallest values will be displayed first. + initial_value: [DEPRECATED] Use `value` instead. Returns: A handle that can be used to interact with the GUI element. """ - value = initial_value + value = _handle_value(value, initial_value) id = _make_unique_id() order = _apply_default_order(order) return self._create_gui_input( @@ -905,26 +963,28 @@ def add_gui_rgb( def add_gui_rgba( self, label: str, - initial_value: Tuple[int, int, int, int], + value: Optional[Tuple[int, int, int, int]] = None, disabled: bool = False, visible: bool = True, hint: Optional[str] = None, order: Optional[float] = None, + initial_value: Optional[Tuple[int, int, int, int]] = None, ) -> GuiInputHandle[Tuple[int, int, int, int]]: """Add an RGBA picker to the GUI. Args: label: Label to display on the RGBA picker. - initial_value: Initial value of the RGBA picker. + value: Initial value of the RGBA picker. disabled: Whether the RGBA picker is disabled. visible: Whether the RGBA picker is visible. hint: Optional hint to display on hover. order: Optional ordering, smallest values will be displayed first. + initial_value: [DEPRECATED] Use `value` instead. Returns: A handle that can be used to interact with the GUI element. """ - value = initial_value + value = _handle_value(value, initial_value) id = _make_unique_id() order = _apply_default_order(order) return self._create_gui_input( diff --git a/src/viser/_gui_handles.py b/src/viser/_gui_handles.py index 357676f4c..785b9bf4f 100644 --- a/src/viser/_gui_handles.py +++ b/src/viser/_gui_handles.py @@ -309,8 +309,8 @@ def options(self) -> Tuple[StringType, ...]: @options.setter def options(self, options: Iterable[StringType]) -> None: self._impl_options = tuple(options) - if self._impl.initial_value not in self._impl_options: - self._impl.initial_value = self._impl_options[0] + if self._impl.value not in self._impl_options: + self._impl.value = self._impl_options[0] self._impl.gui_api._get_api()._queue( GuiAddDropdownMessage( @@ -319,7 +319,7 @@ def options(self, options: Iterable[StringType]) -> None: label=self._impl.label, container_id=self._impl.container_id, hint=self._impl.hint, - value=self._impl.initial_value, + value=self._impl.value, options=self._impl_options, visible=self._impl.visible, disabled=self._impl.disabled, @@ -339,6 +339,7 @@ class GuiTabGroupHandle: _gui_api: GuiApi _container_id: str # Parent. _order: float + _visible: bool @property def order(self) -> float: @@ -376,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, ) ) @@ -569,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 fabdea20a..fd95d9630 100644 --- a/src/viser/_messages.py +++ b/src/viser/_messages.py @@ -8,10 +8,14 @@ import numpy as onp import numpy.typing as onpt -from typing_extensions import Literal, override +from typing_extensions import Literal, NotRequired, TypedDict, override from . import infra, theme +GuiSliderMark = TypedDict( + "GuiSliderMark", {"value": float, "label": NotRequired[Optional[str]]} +) + class Message(infra.Message): @override @@ -435,6 +439,19 @@ class GuiAddSliderMessage(_GuiAddInputBase): step: Optional[float] value: float precision: int + marks: Optional[Tuple[GuiSliderMark, ...]] = None + + +@dataclasses.dataclass +class GuiAddMultiSliderMessage(_GuiAddInputBase): + min: float + max: float + step: Optional[float] + min_range: Optional[float] + value: Tuple[float, ...] + precision: int + fixed_endpoints: bool = False + marks: Optional[Tuple[GuiSliderMark, ...]] = None @dataclasses.dataclass