Skip to content

Commit

Permalink
Merge pull request #1117 from saroad2/add_optionscontainer_abilities
Browse files Browse the repository at this point in the history
Add optionscontainer abilities
  • Loading branch information
freakboy3742 authored Nov 29, 2020
2 parents caa0e10 + d0c3974 commit d0ebd61
Show file tree
Hide file tree
Showing 8 changed files with 393 additions and 71 deletions.
39 changes: 37 additions & 2 deletions examples/optioncontainer/optioncontainer/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ def on_remove_option(self, button):
except toga.OptionContainer.OptionException as e:
self.main_window.info_dialog('Oops', str(e))

def set_next_tab(self, widget):
if self.optioncontainer.current_tab.index < len(self.optioncontainer.content) - 1:
self.optioncontainer.current_tab += 1

def set_previous_tab(self, widget):
if self.optioncontainer.current_tab.index > 0:
self.optioncontainer.current_tab -= 1

def on_select_tab(self, widget, option):
self.selected_label.text = "Tab {} has been chosen: {}".format(
option.index, option.label,
)

def startup(self):
# Set up main window
self.main_window = toga.MainWindow(title=self.name)
Expand Down Expand Up @@ -101,7 +114,11 @@ def startup(self):
children=[box_select, box_actions]
)

self.optioncontainer = toga.OptionContainer(style=Pack(padding_bottom=20))
self.selected_label = toga.Label("")
self.optioncontainer = toga.OptionContainer(
on_select=self.on_select_tab,
style=Pack(padding_bottom=20)
)
self._create_options()

btn_add = toga.Button('Add Option', on_press=self.on_add_option)
Expand All @@ -115,7 +132,8 @@ def startup(self):
children=[
box_general_actions,
box_container_actions,
self.optioncontainer
self.selected_label,
self.optioncontainer,
],
style=Pack(
flex=1,
Expand All @@ -124,6 +142,23 @@ def startup(self):
)
)

self.commands.add(
toga.Command(
self.set_next_tab,
"Next tab",
shortcut=toga.Key.MOD_1 + toga.Key.RIGHT,
group=toga.Group.COMMANDS,
order=1
),
toga.Command(
self.set_previous_tab,
"Previous tab",
shortcut=toga.Key.MOD_1 + toga.Key.LEFT,
group=toga.Group.COMMANDS,
order=1
)
)

# Add the content on the main window
self.main_window.content = outer_box

Expand Down
45 changes: 33 additions & 12 deletions src/cocoa/toga_cocoa/widgets/optioncontainer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from toga_cocoa.libs import NSObject, NSTabView, NSTabViewItem, at, objc_method
from toga_cocoa.libs import NSObject, NSTabView, NSTabViewItem, objc_method
from toga_cocoa.window import CocoaViewport

from .base import Widget
Expand All @@ -7,9 +7,12 @@
class TogaTabViewDelegate(NSObject):
@objc_method
def tabView_didSelectTabViewItem_(self, view, item) -> None:
index = at(item.identifier).longValue
if self.interface.on_select:
self.interface.on_select(self.interface, option=self.interface.content[index])
index = view.indexOfTabViewItem(view.selectedTabViewItem)
self.interface.on_select(
self.interface,
option=self.interface.content[index]
)


class OptionContainer(Widget):
Expand All @@ -20,6 +23,12 @@ def create(self):
self.delegate._impl = self
self.native.delegate = self.delegate

# Cocoa doesn't provide an explicit (public) API for tracking
# tab enabled/disabled status; it's handled by the delegate returning
# if a specific tab should be enabled/disabled. Keep the set set of
# currently disabled tabs for reference purposes.
self._disabled_tabs = set()

# Add the layout constraints
self.add_constraints()

Expand All @@ -35,7 +44,7 @@ def add_content(self, label, widget):
for child in widget.interface.children:
child._impl.container = widget

item = NSTabViewItem.alloc().initWithIdentifier(len(self.interface.content) - 1)
item = NSTabViewItem.alloc().init()
item.label = label

# Turn the autoresizing mask on the widget widget
Expand All @@ -61,17 +70,23 @@ def set_on_select(self, handler):

def set_option_enabled(self, index, enabled):
tabview = self.native.tabViewItemAtIndex(index)
if not enabled and tabview == self.native.selectedTabViewItem:
# Don't allow disable a selected tab
raise self.interface.OptionException(
'Currently selected option cannot be disabled'
)

if enabled:
try:
self._disabled_tabs.remove(index)
except KeyError:
pass
else:
if tabview == self.native.selectedTabViewItem:
# Don't allow disable a selected tab
raise self.interface.OptionException(
'Currently selected option cannot be disabled'
)

self._disabled_tabs.add(index)
tabview._setTabEnabled(enabled)

def is_option_enabled(self, index):
tabview = self.native.tabViewItemAtIndex(index)
return tabview._isTabEnabled()
return index not in self._disabled_tabs

def set_option_label(self, index, value):
tabview = self.native.tabViewItemAtIndex(index)
Expand All @@ -80,3 +95,9 @@ def set_option_label(self, index, value):
def get_option_label(self, index):
tabview = self.native.tabViewItemAtIndex(index)
return tabview.label

def get_current_tab_index(self):
return self.native.indexOfTabViewItem(self.native.selectedTabViewItem)

def set_current_tab_index(self, current_tab_index):
self.native.selectTabViewItemAtIndex(current_tab_index)
185 changes: 170 additions & 15 deletions src/core/tests/widgets/test_optioncontainer.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from unittest import mock

import toga
import toga_dummy
from toga_dummy.utils import TestCase, TestStyle
Expand All @@ -7,31 +9,184 @@ class OptionContainerTests(TestCase):
def setUp(self):
super().setUp()

self.op_container = toga.OptionContainer(style=TestStyle(), factory=toga_dummy.factory)
self.on_select = mock.Mock()
self.op_container = toga.OptionContainer(
style=TestStyle(),
factory=toga_dummy.factory,
on_select=self.on_select
)
self.widget = toga.Box(style=TestStyle(), factory=toga_dummy.factory)
self.label2, self.widget2 = "Widget 2", toga.Box(
style=TestStyle(), factory=toga_dummy.factory
)
self.label3, self.widget3 = "Widget 3", toga.Box(
style=TestStyle(), factory=toga_dummy.factory
)
self.label = 'New Container'
self.op_container.add(self.label, self.widget)

def assert_tab(self, tab, index, label, widget, enabled):
self.assertEqual(tab.index, index)
self.assertEqual(tab.label, label)
self.assertEqual(tab._interface, self.op_container)
self.assertEqual(tab.enabled, enabled)

def add_widgets(self):
self.op_container.add(self.label2, self.widget2)
self.op_container.add(self.label3, self.widget3)

def test_on_select(self):
self.assertEqual(self.op_container.on_select._raw, self.on_select)

def test_widget_created(self):
self.assertEqual(self.op_container._impl.interface, self.op_container)
self.assertActionPerformed(self.op_container, 'create OptionContainer')

def test_adding_container_invokes_add_content(self):
widget = toga.Box(style=TestStyle(), factory=toga_dummy.factory)
label = 'New Container'
self.assertActionPerformedWith(
self.op_container, 'add content', label=self.label, widget=self.widget._impl
)

self.op_container.add(label, widget)
self.assertActionPerformedWith(self.op_container, 'add content', label=label, widget=widget._impl)

self.assertActionPerformedWith(widget, 'set bounds', x=0, y=0, width=0, height=0)
self.assertActionPerformedWith(
self.widget, 'set bounds', x=0, y=0, width=0, height=0
)

def test_widget_refresh_sublayouts(self):
widget = toga.Box(style=TestStyle(), factory=toga_dummy.factory)
label = 'New Container'

self.op_container.add(label, widget)
self.assertActionPerformedWith(self.op_container, 'add content', label=label, widget=widget._impl)
self.assertActionPerformedWith(widget, 'set bounds', x=0, y=0, width=0, height=0)

# Clear event log to verify new set bounds for refresh
self.reset_event_log()

self.op_container.refresh_sublayouts()
self.assertActionPerformedWith(widget, 'set bounds', x=0, y=0, width=0, height=0)
self.assertActionPerformedWith(
self.widget, 'set bounds', x=0, y=0, width=0, height=0
)

def test_set_current_tab_as_index(self):
self.add_widgets()
self.op_container.current_tab = 1
self.assert_tab(
self.op_container.current_tab,
index=1,
label=self.label2,
widget=self.widget2,
enabled=True,
)

def test_set_current_tab_as_label(self):
self.add_widgets()
self.op_container.current_tab = self.label3
self.assert_tab(
self.op_container.current_tab,
index=2,
label=self.label3,
widget=self.widget3,
enabled=True,
)

def test_set_current_tab_as_tab(self):
self.add_widgets()
self.op_container.current_tab = self.op_container.content[1]
self.assert_tab(
self.op_container.current_tab,
index=1,
label=self.label2,
widget=self.widget2,
enabled=True,
)

def test_current_tab_increment(self):
self.add_widgets()
self.op_container.current_tab = 1
self.op_container.current_tab += 1
self.assert_tab(
self.op_container.current_tab,
index=2,
label=self.label3,
widget=self.widget3,
enabled=True,
)

def test_set_current_tab_as_label_raises_an_error(self):
self.add_widgets()

def set_label():
self.op_container.current_tab = "I do not exist!"

self.assertRaises(ValueError, set_label)

def test_current_tab_string_increment_raises_an_error(self):
self.add_widgets()

def set_label():
self.op_container.current_tab += "I do not exist!"

self.assertRaises(ValueError, set_label)

def test_current_tab_string_decrement_raises_an_error(self):
self.add_widgets()

def set_label():
self.op_container.current_tab -= "I do not exist!"

self.assertRaises(ValueError, set_label)

def test_current_tab_decrement(self):
self.add_widgets()
self.op_container.current_tab = 1
self.op_container.current_tab -= 1
self.assert_tab(
self.op_container.current_tab,
index=0,
label=self.label,
widget=self.widget,
enabled=True,
)

def test_disable_tab(self):
self.op_container.current_tab.enabled = False
self.assertEqual(self.op_container.current_tab.enabled, False)

def test_content_repr(self):
self.add_widgets()
self.assertEqual(
(
"OptionList([OptionItem(title=New Container), "
"OptionItem(title=Widget 2), "
"OptionItem(title=Widget 3)])"
),
repr(self.op_container.content)
)

def test_add_tabs(self):
self.add_widgets()
self.assertEqual(len(self.op_container.content), 3)
self.assertEqual(self.op_container.content[0]._widget, self.widget)
self.assertEqual(self.op_container.content[1]._widget, self.widget2)
self.assertEqual(self.op_container.content[2]._widget, self.widget3)

def test_remove_tab(self):
self.add_widgets()
self.op_container.remove(1)
self.assertEqual(len(self.op_container.content), 2)
self.assertEqual(self.op_container.content[0]._widget, self.widget)
self.assertEqual(self.op_container.content[1]._widget, self.widget3)

def test_set_content_in_constructor(self):
new_container = toga.OptionContainer(
style=TestStyle(),
factory=toga_dummy.factory,
content=[
(self.label, self.widget),
(self.label2, self.widget2),
(self.label3, self.widget3),
]
)
self.assertEqual(len(new_container.content), 3)
self.assertEqual(new_container.content[0]._widget, self.widget)
self.assertEqual(new_container.content[1]._widget, self.widget2)
self.assertEqual(new_container.content[2]._widget, self.widget3)

def test_set_window(self):
window = mock.Mock()
self.op_container.window = window
for item in self.op_container.content:
self.assertEqual(item._widget.window, window)
Loading

0 comments on commit d0ebd61

Please sign in to comment.