Skip to content

Commit 012f332

Browse files
committed
NF: Radio button and Checkbox working.
-Tutorial provided for the same. -New icons for checkbox and radio button are incorporated for different states.
1 parent 2037fa1 commit 012f332

6 files changed

Lines changed: 667 additions & 346 deletions

File tree

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
"""
2+
==============================
3+
Checkbox and RadioButton in UI
4+
==============================
5+
6+
This example shows how to use the Checkbox and RadioButton UI elements in FURY.
7+
8+
Both group a small toggle button with a text label for each option and can be
9+
laid out ``"vertical"`` (stacked) or ``"horizontal"`` (side by side):
10+
11+
* A **Checkbox** lets any number of options be checked at the same time.
12+
* A **RadioButton** is mutually exclusive: exactly one option is selected, and
13+
choosing one clears the previous choice.
14+
15+
Here a vertical checkbox toggles the visibility of three colored spheres, and a
16+
horizontal radio button selects the size shared by all of them.
17+
"""
18+
19+
from fury import actor, ui, window
20+
21+
###############################################################################
22+
# 1. Initialize the FURY Scene
23+
scene = window.Scene()
24+
25+
###############################################################################
26+
# 2. Create three colored sphere actors
27+
# We keep them in a dictionary keyed by the same labels we will use for the
28+
# checkbox options.
29+
colors = {
30+
"Red": (1, 0, 0),
31+
"Green": (0, 1, 0),
32+
"Blue": (0, 0, 1),
33+
}
34+
spheres = {}
35+
for i, (name, color) in enumerate(colors.items()):
36+
spheres[name] = actor.sphere(centers=[[i * 3 - 3, 0, 0]], colors=color, radii=1.0)
37+
scene.add(spheres[name])
38+
39+
###############################################################################
40+
# 3. A vertical Checkbox to toggle sphere visibility
41+
# All three options start checked, so every sphere is visible initially. Any
42+
# combination of options can be checked at once.
43+
checkbox = ui.Checkbox(
44+
labels=["Red", "Green", "Blue"],
45+
checked_labels=["Red", "Green", "Blue"],
46+
orientation="vertical",
47+
position=(40, 320),
48+
font_size=20,
49+
)
50+
51+
52+
def toggle_spheres(checkbox_ui):
53+
for name in colors:
54+
spheres[name].visible = name in checkbox_ui.checked_labels
55+
56+
57+
checkbox.on_change = toggle_spheres
58+
59+
###############################################################################
60+
# 4. A horizontal RadioButton to choose the size
61+
# Only one option can be selected at a time. The only difference from the
62+
# checkbox layout is ``orientation="horizontal"``, which lays the options out
63+
# side by side instead of stacked.
64+
size_dict = {
65+
"Small": 0.5,
66+
"Medium": 1.0,
67+
"Large": 1.6,
68+
}
69+
size_radio = ui.RadioButton(
70+
labels=["Small", "Medium", "Large"],
71+
checked_labels=["Medium"],
72+
orientation="horizontal",
73+
position=(40, 40),
74+
font_size=20,
75+
)
76+
77+
78+
def change_size(radio_ui):
79+
scale = size_dict[radio_ui.checked_labels[0]]
80+
for sphere in spheres.values():
81+
sphere.local.scale = (scale, scale, scale)
82+
83+
84+
size_radio.on_change = change_size
85+
86+
###############################################################################
87+
# 5. Add both UI elements to the scene
88+
scene.add(checkbox)
89+
scene.add(size_radio)
90+
91+
###############################################################################
92+
# 6. Setup the ShowManager and start the event loop
93+
showm = window.ShowManager(
94+
scene=scene, size=(800, 600), title="Checkbox and RadioButton Example"
95+
)
96+
showm.start()

fury/data/fetcher.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,12 @@ def fetch_gltf(*, name=None, mode="glTF"):
523523
"resize.png",
524524
"selection-pressed.png",
525525
"selection.png",
526+
"checkbox.png",
527+
"checkbox-selected.png",
528+
"checkbox-pressed.png",
529+
"checkbox-pressed-selected.png",
530+
"circle-selected.png",
531+
"circle-pressed-selected.png",
526532
],
527533
[
528534
"circle-pressed.png",
@@ -541,6 +547,12 @@ def fetch_gltf(*, name=None, mode="glTF"):
541547
"resize.png",
542548
"selection-pressed.png",
543549
"selection.png",
550+
"checkbox.png",
551+
"checkbox-selected.png",
552+
"checkbox-pressed.png",
553+
"checkbox-pressed-selected.png",
554+
"circle-selected.png",
555+
"circle-pressed-selected.png",
544556
],
545557
sha_list=[
546558
"CD859F244DF1BA719C65C869C3FAF6B8563ABF82F457730ADBFBD7CA72DDB7BC",
@@ -559,6 +571,12 @@ def fetch_gltf(*, name=None, mode="glTF"):
559571
"A2D850CDBA8F332DA9CD7B7C9459CBDA587C18AF0D3C12CA68D6E6A864EF54BB",
560572
"54618FDC4589F0A039D531C07A110ED9BC57A256BB15A3B5429CF60E950887C3",
561573
"CD573F5E4BF4A91A3B21F6124A95FFB3C036F926F8FEC1FD0180F5D27D8F48C0",
574+
"E6F755AC6808AE5FA36E1AFBBF9697D678CF38B4C3D1A60CF80A9F2185B8BC12",
575+
"D56ED6C2120E1DEE73DDCF9D4E3BC6B6197D8AF3379A96EF69A971B617DEE3BE",
576+
"3C0B5295645A832085CF24F2974BAAABF0162F07596BA631C7830E58D6C7043B",
577+
"78D1E7FAD2C48D9BAC04A14B0064F9E798EF046DDF4EFE0FD77E5A5F89A414A5",
578+
"440FB425205FB2ACD4B18780EC167E8B2469284BB51DF5D0298284FFC56A791F",
579+
"09F1C25FBA15673C63288F2814490CFBA48D97598640836E44D2F9965B273167",
562580
],
563581
doc="Download the new icons for DrawPanel",
564582
)

fury/ui/__init__.pyi

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ __all__ = [
1515
"LineDoubleSlider2D",
1616
"RingSlider2D",
1717
"RangeSlider",
18-
# "Checkbox",
18+
"Checkbox",
1919
# "Option",
20-
# "RadioButton",
20+
"RadioButton",
2121
"ComboBox2D",
2222
"ListBox2D",
2323
"ListBoxItem2D",
@@ -51,12 +51,14 @@ from .context import UIContext
5151
from .core import UI, Anchor, Disk2D, Rectangle2D, TextBlock2D
5252
from .elements import (
5353
Card2D,
54+
Checkbox,
5455
ComboBox2D,
5556
LineDoubleSlider2D,
5657
LineSlider2D,
5758
ListBox2D,
5859
ListBoxItem2D,
5960
PlaybackPanel,
61+
RadioButton,
6062
RangeSlider,
6163
RingSlider2D,
6264
TextBox2D,

fury/ui/core.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,11 +1771,14 @@ def resolve_state_key(self, available_keys):
17711771
"""
17721772
Determine the current visual state key based on priority.
17731773
1774-
The priority order is:
1775-
1. 'disabled' (if not enabled)
1776-
2. 'pressed' (if is_pressed or toggled is True)
1777-
3. 'hover' (if is_hovered)
1778-
4. 'default'
1774+
Two schemes are supported, chosen by the keys the subclass provides:
1775+
1776+
* One-dimensional (default): ``'disabled'`` > ``'pressed'`` (when
1777+
``is_pressed`` or ``toggled``) > ``'hover'`` > ``'default'``.
1778+
* Two-dimensional toggle icons: when a ``'selected'`` key is present,
1779+
the selected dimension (``toggled``) is combined with interaction
1780+
feedback, yielding ``'default'``, ``'selected'``, ``'pressed'`` or
1781+
``'pressed-selected'``. This suits checkbox/radio state icons.
17791782
17801783
Parameters
17811784
----------
@@ -1790,6 +1793,16 @@ def resolve_state_key(self, available_keys):
17901793
if not self.enabled:
17911794
return "disabled" if "disabled" in available_keys else "default"
17921795

1796+
# Two-dimensional toggle icons: selected state x interaction feedback.
1797+
if "selected" in available_keys:
1798+
selected = self.is_toggle and self.toggled
1799+
active = self.is_pressed or self.is_hovered
1800+
if active and selected and "pressed-selected" in available_keys:
1801+
return "pressed-selected"
1802+
if active and not selected and "pressed" in available_keys:
1803+
return "pressed"
1804+
return "selected" if selected else "default"
1805+
17931806
is_active = self.is_pressed or (self.is_toggle and self.toggled)
17941807

17951808
if is_active and "pressed" in available_keys:

0 commit comments

Comments
 (0)