Skip to content

Commit 1fc14f9

Browse files
committed
feat: Adding Playback UI
1 parent bff57a8 commit 1fc14f9

File tree

6 files changed

+556
-375
lines changed

6 files changed

+556
-375
lines changed

docs/examples/_valid_examples.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ files = [
5050
"viz_textblock.py",
5151
"viz_sliders.py",
5252
"viz_button.py",
53+
"viz_playback_panel.py",
5354
]
5455

5556
[animation]
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""
2+
================
3+
PlaybackPanel UI
4+
================
5+
"""
6+
7+
import numpy as np
8+
from fury import actor, window
9+
from fury.ui import PlaybackPanel
10+
11+
###############################################################################
12+
# 1. Create the Scene and a target actor (Rotating Cube)
13+
scene = window.Scene()
14+
15+
centers = np.array([[0, 0, 0]])
16+
colors = np.array([[1, 0.5, 0]])
17+
cube = actor.box(centers, directions=(0, 1, 0), colors=colors, scales=(2, 2, 2))
18+
scene.add(cube)
19+
20+
###############################################################################
21+
# 2. Initialize the PlaybackPanel
22+
23+
playback_ui = PlaybackPanel(position=(50, 50), width=700, loop=True)
24+
playback_ui.final_time = 60.0
25+
scene.add(playback_ui)
26+
27+
state = {"current_time": 0.0, "rotation_speed": 1.0}
28+
29+
30+
def on_progress_changed(t):
31+
state["current_time"] = t
32+
cube.local.rotation = (0, t * 10, 0)
33+
34+
35+
def on_speed_changed(s):
36+
state["rotation_speed"] = s
37+
38+
39+
playback_ui.on_progress_bar_changed = on_progress_changed
40+
playback_ui.on_speed_changed = on_speed_changed
41+
42+
###############################################################################
43+
# 5. Define the Callback
44+
45+
46+
def update_playback_logic(target_actor):
47+
"""Callback to sync animation state with UI."""
48+
if playback_ui._playing:
49+
step = 0.05 * state["rotation_speed"]
50+
state["current_time"] += step
51+
52+
if state["current_time"] > playback_ui.final_time:
53+
if playback_ui._loop:
54+
state["current_time"] = 0
55+
else:
56+
state["current_time"] = playback_ui.final_time
57+
playback_ui.pause()
58+
59+
playback_ui.current_time = state["current_time"]
60+
61+
target_actor.local.rotation = (0, 0, state["current_time"] * 0.01, 1)
62+
63+
64+
###############################################################################
65+
# 6. Start the ShowManager and Register the Callback
66+
67+
show_m = window.ShowManager(
68+
scene=scene, size=(800, 700), title="FURY Playback Panel UI"
69+
)
70+
71+
show_m.register_callback(update_playback_logic, 0.05, True, "PlaybackSync", cube)
72+
73+
show_m.start()

fury/ui/__init__.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ __all__ = [
2323
# "FileMenu2D",
2424
# "DrawShape",
2525
# "DrawPanel",
26-
# "PlaybackPanel",
26+
"PlaybackPanel",
2727
# "Card2D",
2828
# "SpinBox",
2929
"UI",
@@ -48,7 +48,7 @@ __all__ = [
4848
from .containers import Panel2D
4949
from .context import UIContext
5050
from .core import UI, Anchor, Disk2D, Rectangle2D, TextBlock2D
51-
from .elements import LineSlider2D, TextButton2D, TexturedButton2D
51+
from .elements import LineSlider2D, PlaybackPanel, TextButton2D, TexturedButton2D
5252

5353
# from .elements import (
5454
# Card2D,

fury/ui/core.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ def z_order(self, z_order):
301301
raise ValueError("Z-order must be an integer.")
302302

303303
self._z_order = z_order
304+
for child in self._children:
305+
child.z_order = z_order
304306
UIContext.z_order_bounds = z_order
305307

306308
@abc.abstractmethod
@@ -343,6 +345,9 @@ def set_visibility(self, visibility):
343345
for actor in self.actors:
344346
actor.visible = visibility
345347

348+
for child in self._children:
349+
child.set_visibility(visibility)
350+
346351
def handle_events(self, actor):
347352
"""Attach event handlers to the UI object.
348353
@@ -565,9 +570,7 @@ def _setup(self):
565570
Create the plane actor used internally.
566571
"""
567572
geo = plane_geometry(width=1, height=1)
568-
mat = _create_mesh_material(
569-
material="basic", enable_picking=True, flat_shading=True
570-
)
573+
mat = _create_mesh_material(material="basic", alpha_mode="auto")
571574
self.actor = create_mesh(geometry=geo, material=mat)
572575

573576
self.handle_events(self.actor)
@@ -647,6 +650,8 @@ def resize(self, size):
647650
size : (float, float)
648651
Rectangle size (width, height) in pixels.
649652
"""
653+
if tuple(size) == (0, 0):
654+
size = np.array([1, 1])
650655
self.actor.geometry = plane_geometry(width=size[0], height=size[1])
651656
self._update_actors_position()
652657

@@ -762,9 +767,7 @@ def _setup(self):
762767
inner_radius=self.inner_radius, outer_radius=self.outer_radius
763768
)
764769
geo = buffer_to_geometry(positions=positions, indices=indices)
765-
mat = _create_mesh_material(
766-
material="basic", enable_picking=True, flat_shading=True
767-
)
770+
mat = _create_mesh_material(material="basic", alpha_mode="auto")
768771
self.actor = create_mesh(geometry=geo, material=mat)
769772

770773
self.handle_events(self.actor)
@@ -1006,6 +1009,7 @@ def _setup(self):
10061009
markdown=self._message, screen_space=True, anchor="middle-center"
10071010
)
10081011
self.background = Rectangle2D()
1012+
self._children.append(self.background)
10091013
self.handle_events(self.actor)
10101014

10111015
def resize(self, size):
@@ -1040,7 +1044,7 @@ def _get_actors(self):
10401044
list
10411045
List containing the text actor and background actors.
10421046
"""
1043-
return [self.actor] + self.background.actors
1047+
return [self.actor]
10441048

10451049
def get_formatted_text(self, text):
10461050
"""Format the given text with markdown syntax for bold/italic styles.
@@ -1611,7 +1615,8 @@ def _get_actors(self):
16111615
List containing the child actor(s).
16121616
"""
16131617
if self.child:
1614-
if isinstance(self.child, UI):
1615-
return self.child.actors
1616-
return [self.child]
1618+
if not isinstance(self.child, UI):
1619+
return [self.child]
1620+
else:
1621+
self._children.append(self.child)
16171622
return []

0 commit comments

Comments
 (0)