From 3059ba3bca1e91a37e7e6b8d54fdda8669f563e4 Mon Sep 17 00:00:00 2001 From: Ignacio Cabeza Date: Sat, 21 Mar 2020 12:22:09 +0800 Subject: [PATCH 01/12] enable/disable tab in optionContainer (wip) Signed-off-by: Ignacio Cabeza --- src/cocoa/toga_cocoa/widgets/optioncontainer.py | 4 ++++ src/core/toga/widgets/optioncontainer.py | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/cocoa/toga_cocoa/widgets/optioncontainer.py b/src/cocoa/toga_cocoa/widgets/optioncontainer.py index bca24a8f93..c8254b5084 100644 --- a/src/cocoa/toga_cocoa/widgets/optioncontainer.py +++ b/src/cocoa/toga_cocoa/widgets/optioncontainer.py @@ -50,3 +50,7 @@ def add_content(self, label, widget): def set_on_select(self, handler): pass + + def set_option_enabled(self, index, enabled): + tabview = self.native.tabViewItemAtIndex(index) + tabview._setTabEnabled(enabled) diff --git a/src/core/toga/widgets/optioncontainer.py b/src/core/toga/widgets/optioncontainer.py index 4e626ffdbe..2dffa68966 100644 --- a/src/core/toga/widgets/optioncontainer.py +++ b/src/core/toga/widgets/optioncontainer.py @@ -84,3 +84,6 @@ def on_select(self, handler): """ self._on_select = wrapped_handler(self, handler) self._impl.set_on_select(self._on_select) + + def set_option_enabled(self, index, enabled=True): + self._impl.set_option_enabled(index, enabled) From bba51b9922f36dc484eeaec427e62ac3b17db8a5 Mon Sep 17 00:00:00 2001 From: Ignacio Cabeza Date: Sat, 4 Apr 2020 12:06:42 +0800 Subject: [PATCH 02/12] first working implementation --- examples/optioncontainer/README.rst | 12 ++++ .../optioncontainer/__init__.py | 9 +++ .../optioncontainer/__main__.py | 4 ++ .../optioncontainer/optioncontainer/app.py | 72 +++++++++++++++++++ .../optioncontainer/resources/README | 1 + examples/optioncontainer/pyproject.toml | 44 ++++++++++++ 6 files changed, 142 insertions(+) create mode 100644 examples/optioncontainer/README.rst create mode 100644 examples/optioncontainer/optioncontainer/__init__.py create mode 100644 examples/optioncontainer/optioncontainer/__main__.py create mode 100644 examples/optioncontainer/optioncontainer/app.py create mode 100644 examples/optioncontainer/optioncontainer/resources/README create mode 100644 examples/optioncontainer/pyproject.toml diff --git a/examples/optioncontainer/README.rst b/examples/optioncontainer/README.rst new file mode 100644 index 0000000000..04b0f5769f --- /dev/null +++ b/examples/optioncontainer/README.rst @@ -0,0 +1,12 @@ +Option Container Example +======================== + +Test app for the Option Container Example widget. + +Quickstart +~~~~~~~~~~ + +To run this example: + + $ pip install toga + $ python -m optioncontainer diff --git a/examples/optioncontainer/optioncontainer/__init__.py b/examples/optioncontainer/optioncontainer/__init__.py new file mode 100644 index 0000000000..5de825baaa --- /dev/null +++ b/examples/optioncontainer/optioncontainer/__init__.py @@ -0,0 +1,9 @@ +# Examples of valid version strings +# __version__ = '1.2.3.dev1' # Development release 1 +# __version__ = '1.2.3a1' # Alpha Release 1 +# __version__ = '1.2.3b1' # Beta Release 1 +# __version__ = '1.2.3rc1' # RC Release 1 +# __version__ = '1.2.3' # Final Release +# __version__ = '1.2.3.post1' # Post Release 1 + +__version__ = '0.0.1' diff --git a/examples/optioncontainer/optioncontainer/__main__.py b/examples/optioncontainer/optioncontainer/__main__.py new file mode 100644 index 0000000000..5877b9b83e --- /dev/null +++ b/examples/optioncontainer/optioncontainer/__main__.py @@ -0,0 +1,4 @@ +from optioncontainer.app import main + +if __name__ == '__main__': + main().main_loop() diff --git a/examples/optioncontainer/optioncontainer/app.py b/examples/optioncontainer/optioncontainer/app.py new file mode 100644 index 0000000000..28a0d7ce08 --- /dev/null +++ b/examples/optioncontainer/optioncontainer/app.py @@ -0,0 +1,72 @@ +import toga +from toga.style import Pack +from toga.constants import COLUMN + + +class ExampleOptionContainerApp(toga.App): + + def on_enable1(self, button): + self.optioncontainer.content[0].enabled = not self.optioncontainer.content[0].enabled + + def on_enable2(self, button): + self.optioncontainer.content[1].enabled = not self.optioncontainer.content[1].enabled + + def on_change_label(self, button): + self.optioncontainer.content[1].label = 'Now I have another label!' + + def on_remove(self, button): + self.optioncontainer.remove(2) + + def startup(self): + # Set up main window + self.main_window = toga.MainWindow(title=self.name) + + self.optioncontainer = toga.OptionContainer() + + btn_toggle_1 = toga.Button('Toggle Enabled Option 1', on_press=self.on_enable1) + btn_toggle_2 = toga.Button('Toggle Enabled Option 2', on_press=self.on_enable2) + btn_change_label = toga.Button('Change Label in Option 2', on_press=self.on_change_label) + btn_remove_option = toga.Button('Remove Tab', on_press=self.on_remove) + + label_box1 = toga.Label('This is Box 1 ') + label_box2 = toga.Label('This is Box 2 ') + label_box3 = toga.Label('This is Box 3 ') + + box1 = toga.Box(children=[label_box1]) + box2 = toga.Box(children=[label_box2]) + box3 = toga.Box(children=[label_box3]) + + self.optioncontainer.add('Option1', box1) + self.optioncontainer.add('Option2', box2) + self.optioncontainer.add('Option3', box3) + + # Outermost box + outer_box = toga.Box( + children=[ + btn_toggle_1, btn_toggle_2, + btn_change_label, btn_remove_option, + self.optioncontainer + ], + style=Pack( + flex=1, + direction=COLUMN, + padding=10, + width=500, + height=300 + ) + ) + + # Add the content on the main window + self.main_window.content = outer_box + + # Show the main window + self.main_window.show() + + +def main(): + return ExampleOptionContainerApp('Option Container Example', 'org.beeware.widgets.optioncontainer') + + +if __name__ == '__main__': + app = main() + app.main_loop() diff --git a/examples/optioncontainer/optioncontainer/resources/README b/examples/optioncontainer/optioncontainer/resources/README new file mode 100644 index 0000000000..246d0829ed --- /dev/null +++ b/examples/optioncontainer/optioncontainer/resources/README @@ -0,0 +1 @@ +Put any icons or images in this directory. \ No newline at end of file diff --git a/examples/optioncontainer/pyproject.toml b/examples/optioncontainer/pyproject.toml new file mode 100644 index 0000000000..3d7045a30b --- /dev/null +++ b/examples/optioncontainer/pyproject.toml @@ -0,0 +1,44 @@ +[build-system] +requires = ["briefcase"] + +[tool.briefcase] +project_name = "Option Container Example" +bundle = "org.beeware" +version = "0.3.0.dev20" +url = "https://beeware.org" +license = "BSD license" +author = 'Tiberius Yak' +author_email = "tiberius@beeware.org" + +[tool.briefcase.app.optioncontainer] +formal_name = "Option Container Example" +description = "A testing app" +sources = ['optioncontainer'] +requires = [] + + +[tool.briefcase.app.optioncontainer.macOS] +requires = [ + 'toga-cocoa', +] + +[tool.briefcase.app.optioncontainer.linux] +requires = [ + 'toga-gtk', +] + +[tool.briefcase.app.optioncontainer.windows] +requires = [ + 'toga-winforms', +] + +# Mobile deployments +[tool.briefcase.app.optioncontainer.iOS] +requires = [ + 'toga-iOS', +] + +[tool.briefcase.app.optioncontainer.android] +requires = [ + 'toga-android', +] From b7a26201118d0e6528610c59b13e1a61e9b21cb5 Mon Sep 17 00:00:00 2001 From: Ignacio Cabeza Date: Sat, 4 Apr 2020 12:11:19 +0800 Subject: [PATCH 03/12] added the actual code of the implementation and not just the exxample Signed-off-by: Ignacio Cabeza --- .../toga_cocoa/widgets/optioncontainer.py | 8 ++ src/core/toga/widgets/optioncontainer.py | 79 +++++++++++++++++-- 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/src/cocoa/toga_cocoa/widgets/optioncontainer.py b/src/cocoa/toga_cocoa/widgets/optioncontainer.py index c8254b5084..d195a49e96 100644 --- a/src/cocoa/toga_cocoa/widgets/optioncontainer.py +++ b/src/cocoa/toga_cocoa/widgets/optioncontainer.py @@ -48,9 +48,17 @@ def add_content(self, label, widget): item.view = widget.native self.native.addTabViewItem(item) + def remove_content(self, index): + tabview = self.native.tabViewItemAtIndex(index) + self.native.removeTabViewItem(tabview) + def set_on_select(self, handler): pass def set_option_enabled(self, index, enabled): tabview = self.native.tabViewItemAtIndex(index) tabview._setTabEnabled(enabled) + + def set_label(self, index, value): + tabview = self.native.tabViewItemAtIndex(index) + tabview.label = value diff --git a/src/core/toga/widgets/optioncontainer.py b/src/core/toga/widgets/optioncontainer.py index 2dffa68966..180309725f 100644 --- a/src/core/toga/widgets/optioncontainer.py +++ b/src/core/toga/widgets/optioncontainer.py @@ -3,6 +3,63 @@ from .base import Widget +class OptionItem: + def __init__(self, container, label, widget, enabled): + self._container = container + self._index = len(container) + self._label = label + self._widget = widget + self._enabled = enabled + + @property + def enabled(self): + return self._enabled + + @enabled.setter + def enabled(self, value): + self._enabled = value + self._container.interface._impl.set_option_enabled(self._index, value) + + @property + def label(self): + return self._label + + @label.setter + def label(self, value): + self._label = value + self._container.interface._impl.set_label(self._index, value) + + def refresh(self): + self._widget.refresh() + + +class OptionList: + + def __init__(self, interface): + self.interface = interface + self._options = [] + + def __setitem__(self, index, option): + option.index = index + self._options[index] = option + + def __getitem__(self, index): + return self._options[index] + + def __delitem__(self, key): + del self._options[key] + + def __iter__(self): + return iter(self._options) + + def __len__(self): + return len(self._options) + + def append(self, label, widget, enabled=True): + option = OptionItem(self, label, widget, enabled) + self._options.append(option) + + class OptionContainer(Widget): """ The option container widget. @@ -21,7 +78,7 @@ def __init__(self, id=None, style=None, content=None, on_select=None, factory=No self._impl = self.factory.OptionContainer(interface=self) self.on_select = on_select - self._content = [] + self._content = OptionList(self) if content: for label, widget in content: self.add(label, widget) @@ -56,10 +113,25 @@ def add(self, label, widget): widget.app = self.app widget.window = self.window - self._content.append(widget) + self._content.append(label, widget) self._impl.add_content(label, widget._impl) widget.refresh() + def remove(self, index): + + disabled_siblings = not any( + [ + opt.enabled for opt in self._content + if opt != self._content[index] + ] + ) + + if len(self._content) == 1 or disabled_siblings: + return + else: + self._impl.remove_content(index) + del self._content[index] + def refresh_sublayouts(self): """Refresh the layout and appearance of this widget.""" for widget in self._content: @@ -84,6 +156,3 @@ def on_select(self, handler): """ self._on_select = wrapped_handler(self, handler) self._impl.set_on_select(self._on_select) - - def set_option_enabled(self, index, enabled=True): - self._impl.set_option_enabled(index, enabled) From f7c38d1e64bdae115e994a47354b2b2ced71bbd9 Mon Sep 17 00:00:00 2001 From: Ignacio Cabeza Date: Wed, 15 Apr 2020 18:21:06 +0800 Subject: [PATCH 04/12] changes after code review --- .../optioncontainer/optioncontainer/app.py | 25 ++++---- src/core/toga/widgets/optioncontainer.py | 62 ++++++++++++++++--- 2 files changed, 63 insertions(+), 24 deletions(-) diff --git a/examples/optioncontainer/optioncontainer/app.py b/examples/optioncontainer/optioncontainer/app.py index 28a0d7ce08..743146ab5e 100644 --- a/examples/optioncontainer/optioncontainer/app.py +++ b/examples/optioncontainer/optioncontainer/app.py @@ -5,17 +5,14 @@ class ExampleOptionContainerApp(toga.App): - def on_enable1(self, button): + def on_enable(self, button): self.optioncontainer.content[0].enabled = not self.optioncontainer.content[0].enabled - def on_enable2(self, button): - self.optioncontainer.content[1].enabled = not self.optioncontainer.content[1].enabled - def on_change_label(self, button): - self.optioncontainer.content[1].label = 'Now I have another label!' + self.optioncontainer.content[0].label = 'Now I have another label!' def on_remove(self, button): - self.optioncontainer.remove(2) + self.optioncontainer.remove(0) def startup(self): # Set up main window @@ -23,14 +20,14 @@ def startup(self): self.optioncontainer = toga.OptionContainer() - btn_toggle_1 = toga.Button('Toggle Enabled Option 1', on_press=self.on_enable1) - btn_toggle_2 = toga.Button('Toggle Enabled Option 2', on_press=self.on_enable2) - btn_change_label = toga.Button('Change Label in Option 2', on_press=self.on_change_label) - btn_remove_option = toga.Button('Remove Tab', on_press=self.on_remove) + style_btn = Pack(padding_bottom=2) + btn_toggle_1 = toga.Button('Toggle enabled first option', on_press=self.on_enable, style=style_btn) + btn_change_label = toga.Button('Change label in first option', on_press=self.on_change_label, style=style_btn) + btn_remove_option = toga.Button('Remove first tab', on_press=self.on_remove, style=style_btn) - label_box1 = toga.Label('This is Box 1 ') - label_box2 = toga.Label('This is Box 2 ') - label_box3 = toga.Label('This is Box 3 ') + label_box1 = toga.Label('This is Box 1 ', style=Pack(padding=10)) + label_box2 = toga.Label('This is Box 2 ', style=Pack(padding=10)) + label_box3 = toga.Label('This is Box 3 ', style=Pack(padding=10)) box1 = toga.Box(children=[label_box1]) box2 = toga.Box(children=[label_box2]) @@ -43,7 +40,7 @@ def startup(self): # Outermost box outer_box = toga.Box( children=[ - btn_toggle_1, btn_toggle_2, + btn_toggle_1, btn_change_label, btn_remove_option, self.optioncontainer ], diff --git a/src/core/toga/widgets/optioncontainer.py b/src/core/toga/widgets/optioncontainer.py index 180309725f..fb3736075d 100644 --- a/src/core/toga/widgets/optioncontainer.py +++ b/src/core/toga/widgets/optioncontainer.py @@ -4,13 +4,29 @@ class OptionItem: - def __init__(self, container, label, widget, enabled): - self._container = container - self._index = len(container) + def __init__(self, label, widget, enabled): + self._interface = None + self._index = None self._label = label self._widget = widget self._enabled = enabled + @property + def interface(self): + return self._interface + + @interface.setter + def interface(self, interface): + self._interface = interface + + @property + def index(self): + return self._index + + @index.setter + def index(self, index): + self._index = index + @property def enabled(self): return self._enabled @@ -18,7 +34,7 @@ def enabled(self): @enabled.setter def enabled(self, value): self._enabled = value - self._container.interface._impl.set_option_enabled(self._index, value) + self._interface._impl.set_option_enabled(self._index, value) @property def label(self): @@ -27,7 +43,7 @@ def label(self): @label.setter def label(self, value): self._label = value - self._container.interface._impl.set_label(self._index, value) + self._interface._impl.set_label(self._index, value) def refresh(self): self._widget.refresh() @@ -39,15 +55,26 @@ def __init__(self, interface): self.interface = interface self._options = [] + def __repr__(self): + repr_list = ', '.join([ + '{}(title={})'.format( + option.__class__.__name__, + option.label) + for option in self + ]) + return '[{}]'.format(repr_list) + def __setitem__(self, index, option): option.index = index + option.interface = self.inteface self._options[index] = option def __getitem__(self, index): return self._options[index] - def __delitem__(self, key): - del self._options[key] + def __delitem__(self, index): + del self._options[index] + self._update_indices() def __iter__(self): return iter(self._options) @@ -56,8 +83,21 @@ def __len__(self): return len(self._options) def append(self, label, widget, enabled=True): - option = OptionItem(self, label, widget, enabled) - self._options.append(option) + self._insert(len(self), label, widget, enabled) + + def insert(self, index, label, widget, enabled=True): + self._insert(index, label, widget, enabled) + + def _insert(self, index, label, widget, enabled=True): + option = OptionItem(label, widget, enabled) + option.interface = self.interface + self._options.insert(index, option) + self._update_indices() + + def _update_indices(self): + # ensure that all option have a corrrect index + for i, option in enumerate(self._options): + option.index = i class OptionContainer(Widget): @@ -118,7 +158,6 @@ def add(self, label, widget): widget.refresh() def remove(self, index): - disabled_siblings = not any( [ opt.enabled for opt in self._content @@ -127,6 +166,9 @@ def remove(self, index): ) if len(self._content) == 1 or disabled_siblings: + # if sibling options are disabled or there is + # only one tab in the option container, don't allow + # remove tab. return else: self._impl.remove_content(index) From 7c391692180e626b3560585e2c7dd4d310b7ed74 Mon Sep 17 00:00:00 2001 From: Ignacio Cabeza Date: Fri, 24 Apr 2020 18:25:30 +0800 Subject: [PATCH 05/12] fixes, changes in example app and small fix in selection widget --- .../optioncontainer/optioncontainer/app.py | 97 +++++++++++++------ .../toga_cocoa/widgets/optioncontainer.py | 25 ++++- src/cocoa/toga_cocoa/widgets/selection.py | 2 +- src/core/toga/widgets/optioncontainer.py | 65 +++++-------- .../toga_dummy/widgets/optioncontainer.py | 15 +++ 5 files changed, 130 insertions(+), 74 deletions(-) diff --git a/examples/optioncontainer/optioncontainer/app.py b/examples/optioncontainer/optioncontainer/app.py index 743146ab5e..246cb541d9 100644 --- a/examples/optioncontainer/optioncontainer/app.py +++ b/examples/optioncontainer/optioncontainer/app.py @@ -1,30 +1,11 @@ import toga from toga.style import Pack -from toga.constants import COLUMN +from toga.constants import COLUMN, ROW class ExampleOptionContainerApp(toga.App): - def on_enable(self, button): - self.optioncontainer.content[0].enabled = not self.optioncontainer.content[0].enabled - - def on_change_label(self, button): - self.optioncontainer.content[0].label = 'Now I have another label!' - - def on_remove(self, button): - self.optioncontainer.remove(0) - - def startup(self): - # Set up main window - self.main_window = toga.MainWindow(title=self.name) - - self.optioncontainer = toga.OptionContainer() - - style_btn = Pack(padding_bottom=2) - btn_toggle_1 = toga.Button('Toggle enabled first option', on_press=self.on_enable, style=style_btn) - btn_change_label = toga.Button('Change label in first option', on_press=self.on_change_label, style=style_btn) - btn_remove_option = toga.Button('Remove first tab', on_press=self.on_remove, style=style_btn) - + def _create_options(self): label_box1 = toga.Label('This is Box 1 ', style=Pack(padding=10)) label_box2 = toga.Label('This is Box 2 ', style=Pack(padding=10)) label_box3 = toga.Label('This is Box 3 ', style=Pack(padding=10)) @@ -36,20 +17,80 @@ def startup(self): self.optioncontainer.add('Option1', box1) self.optioncontainer.add('Option2', box2) self.optioncontainer.add('Option3', box3) + self._refresh_select() + + def _remove_all(self): + while len(self.optioncontainer.content) > 0: + self.optioncontainer.remove(0) + + def _refresh_select(self): + items = [] + for i in range(len(self.optioncontainer.content)): + items.append(str(i)) + self.select_option.items = items + + def on_add_option(self, button): + self.optioncontainer.add('Option', toga.Box()) + self._refresh_select() + + def on_enable(self, button): + index = int(self.select_option.value) + self.optioncontainer.content[index].enabled = not self.optioncontainer.content[index].enabled + + def on_change_title(self, button): + index = int(self.select_option.value) + self.optioncontainer.content[index].label = self.input_change_title.value + + def on_remove(self, button): + index = int(self.select_option.value) + del self.optioncontainer.content[index] + self._refresh_select() + + def on_reset_optioncontainer(self, button): + self._remove_all() + self._create_options() + + def startup(self): + # Set up main window + self.main_window = toga.MainWindow(title=self.name) + + # styles + style_flex = Pack(flex=1, padding=5) + style_row = Pack(direction=ROW, flex=1) + style_select = Pack(direction=ROW, flex=1, padding_right=10) + style_col = Pack(direction=COLUMN, flex=1) + + # select + label_select = toga.Label('Select an Option position:', style=style_flex) + self.select_option = toga.Selection(style=style_flex) + # buttons + btn_remove = toga.Button('Remove', on_press=self.on_remove, style=style_flex) + btn_enabled = toga.Button('Toggle enabled', on_press=self.on_enable, style=style_flex) + # change label + self.input_change_title = toga.TextInput(style=style_flex) + btn_change_title = toga.Button('Change title', on_press=self.on_change_title, + style=style_flex) + + box_select = toga.Box(style=style_select, children=[label_select, self.select_option]) + box_actions_col1 = toga.Box(style=style_row, children=[btn_remove, btn_enabled]) + box_actions_col2 = toga.Box(style=style_row, children=[self.input_change_title, btn_change_title]) + box_actions = toga.Box(style=style_col, children=[box_actions_col1, box_actions_col2]) + box_container_actions = toga.Box(style=style_row, children=[box_select, box_actions]) + + self.optioncontainer = toga.OptionContainer(style=Pack(padding_bottom=20)) + self._create_options() + + btn_reset = toga.Button('Reset demo', on_press=self.on_reset_optioncontainer) + btn_add = toga.Button('Add Option', on_press=self.on_add_option) + box_general_actions = toga.Box(style=Pack(padding_bottom=10), children=[btn_reset, btn_add]) # Outermost box outer_box = toga.Box( - children=[ - btn_toggle_1, - btn_change_label, btn_remove_option, - self.optioncontainer - ], + children=[box_general_actions, box_container_actions, self.optioncontainer], style=Pack( flex=1, direction=COLUMN, padding=10, - width=500, - height=300 ) ) diff --git a/src/cocoa/toga_cocoa/widgets/optioncontainer.py b/src/cocoa/toga_cocoa/widgets/optioncontainer.py index d195a49e96..35daeb0ce5 100644 --- a/src/cocoa/toga_cocoa/widgets/optioncontainer.py +++ b/src/cocoa/toga_cocoa/widgets/optioncontainer.py @@ -1,6 +1,11 @@ from rubicon.objc import at -from toga_cocoa.libs import * +from toga_cocoa.libs import ( + NSObject, + objc_method, + NSTabView, + NSTabViewItem +) from toga_cocoa.window import CocoaViewport from .base import Widget @@ -49,16 +54,30 @@ def add_content(self, label, widget): self.native.addTabViewItem(item) def remove_content(self, index): - tabview = self.native.tabViewItemAtIndex(index) - self.native.removeTabViewItem(tabview) + try: + tabview = self.native.tabViewItemAtIndex(index) + self.native.removeTabViewItem(tabview) + except Exception as e: + print(e) def set_on_select(self, handler): pass def set_option_enabled(self, index, enabled): tabview = self.native.tabViewItemAtIndex(index) + if not enabled and tabview == self.native.selectedTabViewItem: + # Don't allow to disable selected tab + raise Exception('Disable selected Option is not allowed') tabview._setTabEnabled(enabled) + def is_enabled(self, index): + tabview = self.native.tabViewItemAtIndex(index) + return tabview._isTabEnabled() + def set_label(self, index, value): tabview = self.native.tabViewItemAtIndex(index) tabview.label = value + + def get_label(self, index): + tabview = self.native.tabViewItemAtIndex(index) + return tabview.label diff --git a/src/cocoa/toga_cocoa/widgets/selection.py b/src/cocoa/toga_cocoa/widgets/selection.py index 1feed0732b..3e6b96e099 100644 --- a/src/cocoa/toga_cocoa/widgets/selection.py +++ b/src/cocoa/toga_cocoa/widgets/selection.py @@ -38,7 +38,7 @@ def select_item(self, item): self.native.selectItemWithTitle(item) def get_selected_item(self): - return self.native.titleOfSelectedItem + return str(self.native.titleOfSelectedItem) def set_on_select(self, handler): pass diff --git a/src/core/toga/widgets/optioncontainer.py b/src/core/toga/widgets/optioncontainer.py index fb3736075d..69b86fd2e3 100644 --- a/src/core/toga/widgets/optioncontainer.py +++ b/src/core/toga/widgets/optioncontainer.py @@ -4,12 +4,10 @@ class OptionItem: - def __init__(self, label, widget, enabled): + def __init__(self, widget): self._interface = None self._index = None - self._label = label self._widget = widget - self._enabled = enabled @property def interface(self): @@ -18,6 +16,7 @@ def interface(self): @interface.setter def interface(self, interface): self._interface = interface + self.refresh() @property def index(self): @@ -29,54 +28,55 @@ def index(self, index): @property def enabled(self): - return self._enabled + return self._interface._impl.is_enabled(self.index) @enabled.setter - def enabled(self, value): - self._enabled = value - self._interface._impl.set_option_enabled(self._index, value) + def enabled(self, enabled): + self._interface._impl.set_option_enabled(self.index, enabled) @property def label(self): - return self._label + return self._interface._impl.get_label(self.index) @label.setter def label(self, value): - self._label = value - self._interface._impl.set_label(self._index, value) + self._interface._impl.set_label(self.index, value) def refresh(self): self._widget.refresh() class OptionList: - def __init__(self, interface): self.interface = interface self._options = [] def __repr__(self): - repr_list = ', '.join([ + repr_optionlist = '{}([{}])' + repr_items = ', '.join([ '{}(title={})'.format( option.__class__.__name__, option.label) for option in self ]) - return '[{}]'.format(repr_list) + return repr_optionlist.format(self.__class__.__name__, repr_items) def __setitem__(self, index, option): - option.index = index - option.interface = self.inteface self._options[index] = option def __getitem__(self, index): + # sync options index attr + self._options[index].index = index return self._options[index] def __delitem__(self, index): + self.interface._impl.remove_content(index) del self._options[index] - self._update_indices() def __iter__(self): + for i, option in enumerate(self._options): + # sync options index attr + option.index = i return iter(self._options) def __len__(self): @@ -89,15 +89,12 @@ def insert(self, index, label, widget, enabled=True): self._insert(index, label, widget, enabled) def _insert(self, index, label, widget, enabled=True): - option = OptionItem(label, widget, enabled) - option.interface = self.interface + self.interface._impl.add_content(label, widget._impl) + option = OptionItem(widget) self._options.insert(index, option) - self._update_indices() - - def _update_indices(self): - # ensure that all option have a corrrect index - for i, option in enumerate(self._options): - option.index = i + self[index].interface = self.interface + self[index].label = label + self[index].enabled = enabled class OptionContainer(Widget): @@ -130,7 +127,7 @@ def content(self): """ The sub layouts of the `SplitContainer`. Returns: - A ``list`` of :class:`toga.Widget`. Each element of the list + A OptionList ``list`` of :class:`toga.OptionItem`. Each element of the list is a sub layout of the `SplitContainer` Raises: @@ -154,25 +151,9 @@ def add(self, label, widget): widget.window = self.window self._content.append(label, widget) - self._impl.add_content(label, widget._impl) - widget.refresh() def remove(self, index): - disabled_siblings = not any( - [ - opt.enabled for opt in self._content - if opt != self._content[index] - ] - ) - - if len(self._content) == 1 or disabled_siblings: - # if sibling options are disabled or there is - # only one tab in the option container, don't allow - # remove tab. - return - else: - self._impl.remove_content(index) - del self._content[index] + del self._content[index] def refresh_sublayouts(self): """Refresh the layout and appearance of this widget.""" diff --git a/src/dummy/toga_dummy/widgets/optioncontainer.py b/src/dummy/toga_dummy/widgets/optioncontainer.py index b558eaf788..a5ef905ed0 100644 --- a/src/dummy/toga_dummy/widgets/optioncontainer.py +++ b/src/dummy/toga_dummy/widgets/optioncontainer.py @@ -8,5 +8,20 @@ def create(self): def add_content(self, label, widget): self._action('add content', label=label, widget=widget) + def remove_content(self, index): + self._action('remove content', index=index) + def set_on_select(self, handler): self._set_value('on_select', handler) + + def set_option_enabled(self, index, enabled): + self._action('set option enabled', index=index) + + def is_enabled(self, index): + self._action('is enabled', index=index) + + def set_label(self, index, value): + self._action('set option label', index=index, value=value) + + def get_label(self, index): + self._action('get label', index=index) From 3e814b0ab1c9ca016b2be65d3f85b756b9363889 Mon Sep 17 00:00:00 2001 From: Ignacio Cabeza Date: Tue, 28 Apr 2020 18:34:16 +0800 Subject: [PATCH 06/12] improve edge cases handling exceptions and rename methods for consistency --- .../toga_cocoa/widgets/optioncontainer.py | 28 +++++++++++++------ src/core/toga/widgets/optioncontainer.py | 6 ++-- .../toga_dummy/widgets/optioncontainer.py | 6 ++-- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/cocoa/toga_cocoa/widgets/optioncontainer.py b/src/cocoa/toga_cocoa/widgets/optioncontainer.py index 35daeb0ce5..95d81b68fc 100644 --- a/src/cocoa/toga_cocoa/widgets/optioncontainer.py +++ b/src/cocoa/toga_cocoa/widgets/optioncontainer.py @@ -11,6 +11,10 @@ from .base import Widget +class OptionException(ValueError): + pass + + class TogaTabViewDelegate(NSObject): @objc_method def tabView_didSelectTabViewItem_(self, view, item) -> None: @@ -54,11 +58,12 @@ def add_content(self, label, widget): self.native.addTabViewItem(item) def remove_content(self, index): - try: - tabview = self.native.tabViewItemAtIndex(index) - self.native.removeTabViewItem(tabview) - except Exception as e: - print(e) + if self.native.numberOfTabViewItem == 1: + # don't allow remove if there is one tab left + raise OptionException('Option cannot be deleted because there is only one left') + + tabview = self.native.tabViewItemAtIndex(index) + self.native.removeTabViewItem(tabview) def set_on_select(self, handler): pass @@ -67,17 +72,22 @@ def set_option_enabled(self, index, enabled): tabview = self.native.tabViewItemAtIndex(index) if not enabled and tabview == self.native.selectedTabViewItem: # Don't allow to disable selected tab - raise Exception('Disable selected Option is not allowed') + raise OptionException('Selected Option cannot be disabled') + + if self.native.numberOfTabViewItem == 1: + # don't allow disable if there is one tab left + raise OptionException('Option cannot be disabled because there is only one left') + tabview._setTabEnabled(enabled) - def is_enabled(self, index): + def is_option_enabled(self, index): tabview = self.native.tabViewItemAtIndex(index) return tabview._isTabEnabled() - def set_label(self, index, value): + def set_option_label(self, index, value): tabview = self.native.tabViewItemAtIndex(index) tabview.label = value - def get_label(self, index): + def get_option_label(self, index): tabview = self.native.tabViewItemAtIndex(index) return tabview.label diff --git a/src/core/toga/widgets/optioncontainer.py b/src/core/toga/widgets/optioncontainer.py index 69b86fd2e3..5d9cb4fabc 100644 --- a/src/core/toga/widgets/optioncontainer.py +++ b/src/core/toga/widgets/optioncontainer.py @@ -28,7 +28,7 @@ def index(self, index): @property def enabled(self): - return self._interface._impl.is_enabled(self.index) + return self._interface._impl.is_option_enabled(self.index) @enabled.setter def enabled(self, enabled): @@ -36,11 +36,11 @@ def enabled(self, enabled): @property def label(self): - return self._interface._impl.get_label(self.index) + return self._interface._impl.get_option_label(self.index) @label.setter def label(self, value): - self._interface._impl.set_label(self.index, value) + self._interface._impl.set_option_label(self.index, value) def refresh(self): self._widget.refresh() diff --git a/src/dummy/toga_dummy/widgets/optioncontainer.py b/src/dummy/toga_dummy/widgets/optioncontainer.py index a5ef905ed0..d63a6acfcd 100644 --- a/src/dummy/toga_dummy/widgets/optioncontainer.py +++ b/src/dummy/toga_dummy/widgets/optioncontainer.py @@ -17,11 +17,11 @@ def set_on_select(self, handler): def set_option_enabled(self, index, enabled): self._action('set option enabled', index=index) - def is_enabled(self, index): + def is_option_enabled(self, index): self._action('is enabled', index=index) - def set_label(self, index, value): + def set_option_label(self, index, value): self._action('set option label', index=index, value=value) - def get_label(self, index): + def get_option_label(self, index): self._action('get label', index=index) From d3e03cf570c46443f19d616a1ea0ec5fc2c37acb Mon Sep 17 00:00:00 2001 From: Ignacio Cabeza Date: Wed, 29 Apr 2020 07:27:33 +0800 Subject: [PATCH 07/12] fix gtk tests --- src/gtk/toga_gtk/widgets/optioncontainer.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/gtk/toga_gtk/widgets/optioncontainer.py b/src/gtk/toga_gtk/widgets/optioncontainer.py index f39042da23..85ca30ee9a 100644 --- a/src/gtk/toga_gtk/widgets/optioncontainer.py +++ b/src/gtk/toga_gtk/widgets/optioncontainer.py @@ -21,3 +21,18 @@ def add_content(self, label, widget): def set_on_select(self, handler): # No special handling required pass + + def remove_content(self, index): + return NotImplementedError + + def set_option_enabled(self, index, enabled): + return NotImplementedError + + def is_option_enabled(self, index): + return NotImplementedError + + def set_option_label(self, index, value): + return NotImplementedError + + def get_option_label(self, index): + return NotImplementedError From 9263958d92dd9856e86742f5a118bfe29ddd609e Mon Sep 17 00:00:00 2001 From: Ignacio Cabeza Date: Wed, 29 Apr 2020 17:43:19 +0800 Subject: [PATCH 08/12] fixed gtk not_implemented, changed OptionException messages, fixed typo and fixed disable condition --- src/cocoa/toga_cocoa/widgets/optioncontainer.py | 8 ++++---- src/gtk/toga_gtk/widgets/optioncontainer.py | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cocoa/toga_cocoa/widgets/optioncontainer.py b/src/cocoa/toga_cocoa/widgets/optioncontainer.py index 95d81b68fc..dfd4b29eb0 100644 --- a/src/cocoa/toga_cocoa/widgets/optioncontainer.py +++ b/src/cocoa/toga_cocoa/widgets/optioncontainer.py @@ -60,7 +60,7 @@ def add_content(self, label, widget): def remove_content(self, index): if self.native.numberOfTabViewItem == 1: # don't allow remove if there is one tab left - raise OptionException('Option cannot be deleted because there is only one left') + raise OptionException('Cannot remove last remaining option') tabview = self.native.tabViewItemAtIndex(index) self.native.removeTabViewItem(tabview) @@ -72,11 +72,11 @@ def set_option_enabled(self, index, enabled): tabview = self.native.tabViewItemAtIndex(index) if not enabled and tabview == self.native.selectedTabViewItem: # Don't allow to disable selected tab - raise OptionException('Selected Option cannot be disabled') + raise OptionException('Currently selected option cannot be disabled') - if self.native.numberOfTabViewItem == 1: + if not enabled and self.native.numberOfTabViewItems == 1: # don't allow disable if there is one tab left - raise OptionException('Option cannot be disabled because there is only one left') + raise OptionException('Cannot disable last remaining option') tabview._setTabEnabled(enabled) diff --git a/src/gtk/toga_gtk/widgets/optioncontainer.py b/src/gtk/toga_gtk/widgets/optioncontainer.py index 85ca30ee9a..4100aef40c 100644 --- a/src/gtk/toga_gtk/widgets/optioncontainer.py +++ b/src/gtk/toga_gtk/widgets/optioncontainer.py @@ -23,16 +23,16 @@ def set_on_select(self, handler): pass def remove_content(self, index): - return NotImplementedError + self.interface.factory.not_implemented('OptionContainer.remove_content()') def set_option_enabled(self, index, enabled): - return NotImplementedError + self.interface.factory.not_implemented('OptionContainer.set_option_enabled()') def is_option_enabled(self, index): - return NotImplementedError + self.interface.factory.not_implemented('OptionContainer.is_option_enabled()') def set_option_label(self, index, value): - return NotImplementedError + self.interface.factory.not_implemented('OptionContainer.set_option_label()') def get_option_label(self, index): - return NotImplementedError + self.interface.factory.not_implemented('OptionContainer.get_option_label()') From 80c9c0bc2412cbe48251d173e8841a7a62493287 Mon Sep 17 00:00:00 2001 From: Ignacio Cabeza Date: Sat, 9 May 2020 09:32:55 +0800 Subject: [PATCH 09/12] control more edge cases, fix example option names --- .../optioncontainer/optioncontainer/app.py | 23 ++++++------------- .../toga_cocoa/widgets/optioncontainer.py | 20 ++++++++++++++-- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/examples/optioncontainer/optioncontainer/app.py b/examples/optioncontainer/optioncontainer/app.py index 246cb541d9..fe8336d5b1 100644 --- a/examples/optioncontainer/optioncontainer/app.py +++ b/examples/optioncontainer/optioncontainer/app.py @@ -6,23 +6,19 @@ class ExampleOptionContainerApp(toga.App): def _create_options(self): + label_box0 = toga.Label('This is Box 0 ', style=Pack(padding=10)) label_box1 = toga.Label('This is Box 1 ', style=Pack(padding=10)) label_box2 = toga.Label('This is Box 2 ', style=Pack(padding=10)) - label_box3 = toga.Label('This is Box 3 ', style=Pack(padding=10)) + box0 = toga.Box(children=[label_box0]) box1 = toga.Box(children=[label_box1]) box2 = toga.Box(children=[label_box2]) - box3 = toga.Box(children=[label_box3]) - self.optioncontainer.add('Option1', box1) - self.optioncontainer.add('Option2', box2) - self.optioncontainer.add('Option3', box3) + self.optioncontainer.add('Option 0', box0) + self.optioncontainer.add('Option 1', box1) + self.optioncontainer.add('Option 2', box2) self._refresh_select() - def _remove_all(self): - while len(self.optioncontainer.content) > 0: - self.optioncontainer.remove(0) - def _refresh_select(self): items = [] for i in range(len(self.optioncontainer.content)): @@ -30,7 +26,7 @@ def _refresh_select(self): self.select_option.items = items def on_add_option(self, button): - self.optioncontainer.add('Option', toga.Box()) + self.optioncontainer.add('New Option', toga.Box()) self._refresh_select() def on_enable(self, button): @@ -46,10 +42,6 @@ def on_remove(self, button): del self.optioncontainer.content[index] self._refresh_select() - def on_reset_optioncontainer(self, button): - self._remove_all() - self._create_options() - def startup(self): # Set up main window self.main_window = toga.MainWindow(title=self.name) @@ -80,9 +72,8 @@ def startup(self): self.optioncontainer = toga.OptionContainer(style=Pack(padding_bottom=20)) self._create_options() - btn_reset = toga.Button('Reset demo', on_press=self.on_reset_optioncontainer) btn_add = toga.Button('Add Option', on_press=self.on_add_option) - box_general_actions = toga.Box(style=Pack(padding_bottom=10), children=[btn_reset, btn_add]) + box_general_actions = toga.Box(style=Pack(padding_bottom=10), children=[btn_add]) # Outermost box outer_box = toga.Box( diff --git a/src/cocoa/toga_cocoa/widgets/optioncontainer.py b/src/cocoa/toga_cocoa/widgets/optioncontainer.py index dfd4b29eb0..76b3676ec1 100644 --- a/src/cocoa/toga_cocoa/widgets/optioncontainer.py +++ b/src/cocoa/toga_cocoa/widgets/optioncontainer.py @@ -58,11 +58,27 @@ def add_content(self, label, widget): self.native.addTabViewItem(item) def remove_content(self, index): - if self.native.numberOfTabViewItem == 1: + if self.native.numberOfTabViewItems == 1: # don't allow remove if there is one tab left raise OptionException('Cannot remove last remaining option') + # check if option siblings are all disabled, then raise error + is_only_enabled = True + indexes_to_check = [*range(self.native.numberOfTabViewItems)] + indexes_to_check.remove(index) + for siblingindex in indexes_to_check: + if self.is_option_enabled(siblingindex): + is_only_enabled = False + continue + if is_only_enabled: + raise OptionException('Cannot remove last remaining option enabled') + tabview = self.native.tabViewItemAtIndex(index) + + if tabview == self.native.selectedTabViewItem: + # Don't allow remove a selected tab + raise OptionException('Currently selected option cannot be removed') + self.native.removeTabViewItem(tabview) def set_on_select(self, handler): @@ -71,7 +87,7 @@ 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 to disable selected tab + # Don't allow disable a selected tab raise OptionException('Currently selected option cannot be disabled') if not enabled and self.native.numberOfTabViewItems == 1: From 0ada8f044c96d118a0412505353bb3e15d83a3f4 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Sat, 16 May 2020 15:03:25 +0800 Subject: [PATCH 10/12] Small tweaks to the implementation and example. --- .../optioncontainer/optioncontainer/app.py | 75 ++++++++++++++----- .../toga_cocoa/widgets/optioncontainer.py | 36 ++------- src/core/toga/widgets/optioncontainer.py | 2 + 3 files changed, 67 insertions(+), 46 deletions(-) diff --git a/examples/optioncontainer/optioncontainer/app.py b/examples/optioncontainer/optioncontainer/app.py index fe8336d5b1..b55f03acf6 100644 --- a/examples/optioncontainer/optioncontainer/app.py +++ b/examples/optioncontainer/optioncontainer/app.py @@ -29,18 +29,24 @@ def on_add_option(self, button): self.optioncontainer.add('New Option', toga.Box()) self._refresh_select() - def on_enable(self, button): + def on_enable_option(self, button): index = int(self.select_option.value) - self.optioncontainer.content[index].enabled = not self.optioncontainer.content[index].enabled + try: + self.optioncontainer.content[index].enabled = not self.optioncontainer.content[index].enabled + except toga.OptionContainer.OptionException as e: + self.main_window.info_dialog('Oops', str(e)) - def on_change_title(self, button): + def on_change_option_title(self, button): index = int(self.select_option.value) self.optioncontainer.content[index].label = self.input_change_title.value - def on_remove(self, button): - index = int(self.select_option.value) - del self.optioncontainer.content[index] - self._refresh_select() + def on_remove_option(self, button): + try: + index = int(self.select_option.value) + del self.optioncontainer.content[index] + self._refresh_select() + except toga.OptionContainer.OptionException as e: + self.main_window.info_dialog('Oops', str(e)) def startup(self): # Set up main window @@ -56,28 +62,61 @@ def startup(self): label_select = toga.Label('Select an Option position:', style=style_flex) self.select_option = toga.Selection(style=style_flex) # buttons - btn_remove = toga.Button('Remove', on_press=self.on_remove, style=style_flex) - btn_enabled = toga.Button('Toggle enabled', on_press=self.on_enable, style=style_flex) + btn_remove = toga.Button( + 'Remove', + on_press=self.on_remove_option, + style=style_flex + ) + btn_enabled = toga.Button( + 'Toggle enabled', + on_press=self.on_enable_option, + style=style_flex + ) # change label self.input_change_title = toga.TextInput(style=style_flex) - btn_change_title = toga.Button('Change title', on_press=self.on_change_title, - style=style_flex) + btn_change_title = toga.Button( + 'Change title', + on_press=self.on_change_option_title, + style=style_flex + ) - box_select = toga.Box(style=style_select, children=[label_select, self.select_option]) - box_actions_col1 = toga.Box(style=style_row, children=[btn_remove, btn_enabled]) - box_actions_col2 = toga.Box(style=style_row, children=[self.input_change_title, btn_change_title]) - box_actions = toga.Box(style=style_col, children=[box_actions_col1, box_actions_col2]) - box_container_actions = toga.Box(style=style_row, children=[box_select, box_actions]) + box_select = toga.Box( + style=style_select, + children=[label_select, self.select_option] + ) + box_actions_col1 = toga.Box( + style=style_row, + children=[btn_remove, btn_enabled] + ) + box_actions_col2 = toga.Box( + style=style_row, + children=[self.input_change_title, btn_change_title] + ) + box_actions = toga.Box( + style=style_col, + children=[box_actions_col1, box_actions_col2] + ) + box_container_actions = toga.Box( + style=style_row, + children=[box_select, box_actions] + ) self.optioncontainer = toga.OptionContainer(style=Pack(padding_bottom=20)) self._create_options() btn_add = toga.Button('Add Option', on_press=self.on_add_option) - box_general_actions = toga.Box(style=Pack(padding_bottom=10), children=[btn_add]) + box_general_actions = toga.Box( + style=Pack(padding_bottom=10), + children=[btn_add] + ) # Outermost box outer_box = toga.Box( - children=[box_general_actions, box_container_actions, self.optioncontainer], + children=[ + box_general_actions, + box_container_actions, + self.optioncontainer + ], style=Pack( flex=1, direction=COLUMN, diff --git a/src/cocoa/toga_cocoa/widgets/optioncontainer.py b/src/cocoa/toga_cocoa/widgets/optioncontainer.py index 76b3676ec1..60e198551f 100644 --- a/src/cocoa/toga_cocoa/widgets/optioncontainer.py +++ b/src/cocoa/toga_cocoa/widgets/optioncontainer.py @@ -11,10 +11,6 @@ from .base import Widget -class OptionException(ValueError): - pass - - class TogaTabViewDelegate(NSObject): @objc_method def tabView_didSelectTabViewItem_(self, view, item) -> None: @@ -58,26 +54,12 @@ def add_content(self, label, widget): self.native.addTabViewItem(item) def remove_content(self, index): - if self.native.numberOfTabViewItems == 1: - # don't allow remove if there is one tab left - raise OptionException('Cannot remove last remaining option') - - # check if option siblings are all disabled, then raise error - is_only_enabled = True - indexes_to_check = [*range(self.native.numberOfTabViewItems)] - indexes_to_check.remove(index) - for siblingindex in indexes_to_check: - if self.is_option_enabled(siblingindex): - is_only_enabled = False - continue - if is_only_enabled: - raise OptionException('Cannot remove last remaining option enabled') - tabview = self.native.tabViewItemAtIndex(index) - if tabview == self.native.selectedTabViewItem: - # Don't allow remove a selected tab - raise OptionException('Currently selected option cannot be removed') + # Don't allow removal of a selected tab + raise self.interface.OptionException( + 'Currently selected option cannot be removed' + ) self.native.removeTabViewItem(tabview) @@ -86,13 +68,11 @@ 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: + if tabview == self.native.selectedTabViewItem: # Don't allow disable a selected tab - raise OptionException('Currently selected option cannot be disabled') - - if not enabled and self.native.numberOfTabViewItems == 1: - # don't allow disable if there is one tab left - raise OptionException('Cannot disable last remaining option') + raise self.interface.OptionException( + 'Currently selected option cannot be disabled' + ) tabview._setTabEnabled(enabled) diff --git a/src/core/toga/widgets/optioncontainer.py b/src/core/toga/widgets/optioncontainer.py index 5d9cb4fabc..d80cfc4d89 100644 --- a/src/core/toga/widgets/optioncontainer.py +++ b/src/core/toga/widgets/optioncontainer.py @@ -108,6 +108,8 @@ class OptionContainer(Widget): Each tuple in the list is composed of a title for the option and the widget tree that is displayed in the option. """ + class OptionException(ValueError): + pass def __init__(self, id=None, style=None, content=None, on_select=None, factory=None): super().__init__(id=id, style=style, factory=factory) From c91c01c66df8c9765f36bdfdc38f81eb826a9b28 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Sat, 16 May 2020 15:14:12 +0800 Subject: [PATCH 11/12] Updated Winforms API with mocks of non-implemented APIs. --- .../toga_winforms/widgets/optioncontainer.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/winforms/toga_winforms/widgets/optioncontainer.py b/src/winforms/toga_winforms/widgets/optioncontainer.py index 699987db53..88378fb5cc 100644 --- a/src/winforms/toga_winforms/widgets/optioncontainer.py +++ b/src/winforms/toga_winforms/widgets/optioncontainer.py @@ -25,5 +25,20 @@ def add_content(self, label, widget): item.Controls.Add(widget.native) self.native.Controls.Add(item) + def remove_content(self, index): + self.interface.factory.not_implemented('OptionContainer.remove_content()') + def set_on_select(self, handler): self.interface.factory.not_implemented('OptionContainer.set_on_select()') + + def set_option_enabled(self, index, value): + self.interface.factory.not_implemented('OptionContainer.is_option_enabled()') + + def is_option_enabled(self, index): + self.interface.factory.not_implemented('OptionContainer.is_option_enabled()') + + def set_option_label(self, index, value): + self.interface.factory.not_implemented('OptionContainer.set_option_label()') + + def get_option_label(self, index): + self.interface.factory.not_implemented('OptionContainer.get_option_label()') From ce436499360da71675fb47a899a14e9e3f33286f Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Sat, 16 May 2020 15:23:39 +0800 Subject: [PATCH 12/12] Cleanups to GTK and Cocoa implementations. --- src/cocoa/toga_cocoa/widgets/optioncontainer.py | 2 +- src/core/toga/widgets/selection.py | 3 +-- src/gtk/toga_gtk/widgets/selection.py | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/cocoa/toga_cocoa/widgets/optioncontainer.py b/src/cocoa/toga_cocoa/widgets/optioncontainer.py index 60e198551f..1d3ad5a16c 100644 --- a/src/cocoa/toga_cocoa/widgets/optioncontainer.py +++ b/src/cocoa/toga_cocoa/widgets/optioncontainer.py @@ -68,7 +68,7 @@ def set_on_select(self, handler): def set_option_enabled(self, index, enabled): tabview = self.native.tabViewItemAtIndex(index) - if tabview == self.native.selectedTabViewItem: + 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' diff --git a/src/core/toga/widgets/selection.py b/src/core/toga/widgets/selection.py index 90b46d3935..243a717355 100644 --- a/src/core/toga/widgets/selection.py +++ b/src/core/toga/widgets/selection.py @@ -43,12 +43,11 @@ def items(self): @items.setter def items(self, items): self._impl.remove_all_items() + self._items = items for i in items: self._impl.add_item(i) - self._items = items - @property def value(self): """ The value of the currently selected item. diff --git a/src/gtk/toga_gtk/widgets/selection.py b/src/gtk/toga_gtk/widgets/selection.py index ce199f1db2..d7ba56146d 100644 --- a/src/gtk/toga_gtk/widgets/selection.py +++ b/src/gtk/toga_gtk/widgets/selection.py @@ -17,11 +17,9 @@ def gtk_on_select(self, widget): self.interface.on_select(widget) def remove_all_items(self): - # self._text.clear() self.native.remove_all() def add_item(self, item): - # self._text.append(item) self.native.append_text(item) # Gtk.ComboBox does not select the first item, so it's done here.