Skip to content

Commit

Permalink
Merge pull request #855 from IshanKamboj/TabBar-position
Browse files Browse the repository at this point in the history
Fix #780 : Added top/bottom for Tabs Bar in Tab Panel UI
  • Loading branch information
skoudoro authored Apr 23, 2024
2 parents 0ff602a + 3d99a0e commit 34e103d
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 6 deletions.
6 changes: 6 additions & 0 deletions docs/examples/viz_tab.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@

tab_ui = ui.TabUI(position=(49, 94), size=(300, 300), nb_tabs=3, draggable=True)

###############################################################################
# We can also define the position of the Tab Bar.
# By default the Tab Bar is positioned at top

tab_ui.tab_bar_pos = 'bottom'

###############################################################################
# Slider Controls for a Cube for Tab Index 0
# ==========================================
Expand Down
1 change: 1 addition & 0 deletions fury/data/files/test_ui_tab_ui_top_position.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"CharEvent": 0, "MouseMoveEvent": 1014, "KeyPressEvent": 0, "KeyReleaseEvent": 0, "LeftButtonPressEvent": 58, "LeftButtonReleaseEvent": 58, "RightButtonPressEvent": 10, "RightButtonReleaseEvent": 10, "MiddleButtonPressEvent": 0, "MiddleButtonReleaseEvent": 0}
Binary file not shown.
23 changes: 19 additions & 4 deletions fury/ui/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
)
from fury.ui.core import UI, Rectangle2D, TextBlock2D
from fury.utils import rotate, set_input

from warnings import warn

class Panel2D(UI):
"""A 2D UI Panel.
Expand Down Expand Up @@ -640,6 +640,7 @@ def __init__(
inactive_color=(0.5, 0.5, 0.5),
draggable=False,
startup_tab_id=None,
tab_bar_pos="top",
):
"""Init class instance.
Expand All @@ -661,7 +662,8 @@ def __init__(
startup_tab_id : int, optional
Tab to be activated and uncollapsed on startup.
by default None is activated/ all collapsed.
tab_bar_pos : str, optional
Position of the Tab Bar in the panel
"""
self.tabs = []
self.nb_tabs = nb_tabs
Expand All @@ -672,6 +674,7 @@ def __init__(
self.inactive_color = inactive_color
self.active_tab_idx = startup_tab_id
self.collapsed = True
self.tab_bar_pos = tab_bar_pos

super(TabUI, self).__init__()
self.position = position
Expand Down Expand Up @@ -737,8 +740,15 @@ def _get_size(self):
def update_tabs(self):
"""Update position, size and callbacks for tab panels."""
self.tab_panel_size = (self.size[0] // self.nb_tabs, int(0.1 * self.size[1]))
if self.tab_bar_pos.lower() not in ['top', 'bottom']:
warn("tab_bar_pos can only have value top/bottom")
self.tab_bar_pos = "top"

if self.tab_bar_pos.lower() == "top":
tab_panel_pos = [0.0, 0.9]
elif self.tab_bar_pos.lower() == "bottom":
tab_panel_pos = [0.0, 0.0]

tab_panel_pos = [0.0, 0.9]
for tab_panel in self.tabs:
tab_panel.resize(self.tab_panel_size)
tab_panel.content_panel.position = self.position
Expand Down Expand Up @@ -776,7 +786,12 @@ def update_tabs(self):

tab_panel.content_panel.resize(self.content_size)
self.parent_panel.add_element(tab_panel, tab_panel_pos)
self.parent_panel.add_element(tab_panel.content_panel, (0.0, 0.0))
if self.tab_bar_pos.lower() == "top":
self.parent_panel.add_element(tab_panel.content_panel,
(0.0, 0.0))
elif self.tab_bar_pos.lower() == "bottom":
self.parent_panel.add_element(tab_panel.content_panel,
(0.0, 0.1))
tab_panel_pos[0] += 1 / self.nb_tabs

def select_tab_callback(self, iren, _obj, _tab_comp):
Expand Down
114 changes: 112 additions & 2 deletions fury/ui/tests/test_containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ def test_ui_tab_ui(interactive=False):
npt.assert_equal(tab_ui.tabs[1].title_italic, True)
npt.assert_equal(tab_ui.tabs[2].title_italic, False)

tab_ui.add_element(0, ui.Checkbox(['Option 1', 'Option 2']), (0.5, 0.5))
tab_ui.add_element(0, ui.Checkbox(['Option 1', 'Option 2']),
(0.5, 0.5))
tab_ui.add_element(1, ui.LineSlider2D(), (0.0, 0.5))
tab_ui.add_element(2, ui.TextBlock2D(), (0.5, 0.5))

Expand Down Expand Up @@ -345,7 +346,8 @@ def tab_change(tab_ui):
event_counter.monitor(tab_ui)

current_size = (800, 800)
show_manager = window.ShowManager(size=current_size, title='Tab UI Test')
show_manager = window.ShowManager(size=current_size,
title='Tab UI Test')
show_manager.scene.add(tab_ui)

if interactive:
Expand All @@ -360,3 +362,111 @@ def tab_change(tab_ui):
npt.assert_equal(0, tab_ui.active_tab_idx)
npt.assert_equal(11, next(changes))
npt.assert_equal(5, next(collapses))


def test_ui_tab_ui_position(interactive=False):
filename = 'test_ui_tab_ui_top_position'
recording_filename = pjoin(DATA_DIR, filename + '.log.gz')
expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json')

tab_ui_top = ui.TabUI(
position=(50, 50), size=(300, 300), nb_tabs=3, draggable=True,
tab_bar_pos='top')

tab_ui_top.tabs[0].title = 'Tab 1'
tab_ui_top.tabs[1].title = 'Tab 2'
tab_ui_top.tabs[2].title = 'Tab 3'

tab_ui_top.add_element(0, ui.Checkbox(['Option 1', 'Option 2']),
(0.5, 0.5))
tab_ui_top.add_element(1, ui.LineSlider2D(), (0.0, 0.5))
tab_ui_top.add_element(2, ui.TextBlock2D(), (0.5, 0.5))

npt.assert_equal('Tab 1', tab_ui_top.tabs[0].title)
npt.assert_equal('Tab 2', tab_ui_top.tabs[1].title)
npt.assert_equal('Tab 3', tab_ui_top.tabs[2].title)

npt.assert_equal(3, tab_ui_top.nb_tabs)

npt.assert_equal((50, 50), tab_ui_top.position)
npt.assert_equal((300, 300), tab_ui_top.size)

with npt.assert_raises(IndexError):
tab_ui_top.add_element(3, ui.TextBlock2D(), (0.5, 0.5, 0.5))

with npt.assert_raises(IndexError):
tab_ui_top.remove_element(3, ui.TextBlock2D())

with npt.assert_raises(IndexError):
tab_ui_top.update_element(3, ui.TextBlock2D(), (0.5, 0.5, 0.5))

tab_ui_bottom = ui.TabUI(
position=(350, 50), size=(300, 300), nb_tabs=3, draggable=True,
tab_bar_pos='bottom')

tab_ui_bottom.tabs[0].title = 'Tab 1'
tab_ui_bottom.tabs[1].title = 'Tab 2'
tab_ui_bottom.tabs[2].title = 'Tab 3'

tab_ui_bottom.add_element(0, ui.Checkbox(['Option 1', 'Option 2']),
(0.5, 0.5))
tab_ui_bottom.add_element(1, ui.LineSlider2D(), (0.0, 0.5))
tab_ui_bottom.add_element(2, ui.TextBlock2D(), (0.5, 0.5))

npt.assert_equal('Tab 1', tab_ui_bottom.tabs[0].title)
npt.assert_equal('Tab 2', tab_ui_bottom.tabs[1].title)
npt.assert_equal('Tab 3', tab_ui_bottom.tabs[2].title)

npt.assert_equal(3, tab_ui_bottom.nb_tabs)

npt.assert_equal((350, 50), tab_ui_bottom.position)
npt.assert_equal((300, 300), tab_ui_bottom.size)

with npt.assert_raises(IndexError):
tab_ui_bottom.add_element(3, ui.TextBlock2D(), (0.5, 0.5, 0.5))

with npt.assert_raises(IndexError):
tab_ui_bottom.remove_element(3, ui.TextBlock2D())

with npt.assert_raises(IndexError):
tab_ui_bottom.update_element(3, ui.TextBlock2D(), (0.5, 0.5, 0.5))

collapses = itertools.count()
changes = itertools.count()

def collapse(tab_ui_top):
if tab_ui_top.collapsed or tab_ui_bottom.collapsed:
next(collapses)

def tab_change(tab_ui_top):
next(changes)

tab_ui_top.on_change = tab_change
tab_ui_top.on_collapse = collapse

tab_ui_bottom.on_change = tab_change
tab_ui_bottom.on_collapse = collapse

event_counter = EventCounter()
event_counter.monitor(tab_ui_top)
event_counter.monitor(tab_ui_bottom)

current_size = (800, 800)
show_manager = window.ShowManager(size=current_size,
title='Tab UI Test')
show_manager.scene.add(tab_ui_top)
show_manager.scene.add(tab_ui_bottom)

if interactive:
show_manager.record_events_to_file(recording_filename)
print(list(event_counter.events_counts.items()))
event_counter.save(expected_events_counts_filename)
else:
show_manager.play_events_from_file(recording_filename)
expected = EventCounter.load(expected_events_counts_filename)
event_counter.check_counts(expected)

npt.assert_equal(0, tab_ui_top.active_tab_idx)
npt.assert_equal(0, tab_ui_bottom.active_tab_idx)
npt.assert_equal(14, next(changes))
npt.assert_equal(5, next(collapses))

0 comments on commit 34e103d

Please sign in to comment.