Browse Source

closes #593 & #591 - dynamic updates causes slowdowns and loses selection

1.0.5-release-candidate
Chris 4 years ago
parent
commit
5fd17ed210
2 changed files with 74 additions and 6 deletions
  1. 28
      gooey/gui/components/widgets/dropdown.py
  2. 52
      gooey/tests/test_dropdown.py

28
gooey/gui/components/widgets/dropdown.py

@ -1,3 +1,5 @@
from contextlib import contextmanager
from gooey.gui.components.widgets.bases import TextContainer from gooey.gui.components.widgets.bases import TextContainer
import wx import wx
@ -18,12 +20,9 @@ class Dropdown(TextContainer):
style=wx.CB_DROPDOWN) style=wx.CB_DROPDOWN)
def setOptions(self, options): def setOptions(self, options):
prevSelection = self.widget.GetSelection()
self.widget.Clear()
for option in [_('select_option')] + options:
self.widget.Append(option)
self.widget.SetSelection(0)
with self.retainSelection():
self.widget.Clear()
self.widget.SetItems([_('select_option')] + options)
def setValue(self, value): def setValue(self, value):
## +1 to offset the default placeholder value ## +1 to offset the default placeholder value
@ -40,3 +39,20 @@ class Dropdown(TextContainer):
def formatOutput(self, metadata, value): def formatOutput(self, metadata, value):
return formatters.dropdown(metadata, value) return formatters.dropdown(metadata, value)
@contextmanager
def retainSelection(self):
""""
Retains the selected dropdown option (when possible)
across mutations due to dynamic updates.
"""
prevSelection = self.widget.GetSelection()
prevValue = self.widget.GetValue()
try:
yield
finally:
current_at_index = self.widget.GetString(prevSelection)
if prevValue == current_at_index:
self.widget.SetSelection(prevSelection)
else:
self.widget.SetSelection(0)

52
gooey/tests/test_dropdown.py

@ -0,0 +1,52 @@
import unittest
from argparse import ArgumentParser
from unittest.mock import patch
from tests.harness import instrumentGooey
class TestGooeyDropdown(unittest.TestCase):
def make_parser(self, **kwargs):
parser = ArgumentParser(description='description')
parser.add_argument('--dropdown', **kwargs)
return parser
@patch("gui.containers.application.seeder.fetchDynamicProperties")
def test_dropdown_behavior(self, mock):
"""
Testing that:
- default values are used as the initial selection (when present)
- Initial selection defaults to placeholder when no defaults supplied
- selection is preserved (when possible) across dynamic updates
"""
testcases = [
# tuples of [choices, default, initalSelection, dynamicUpdate, expectedFinalSelection]
[['1', '2'], None, 'Select Option', ['1', '2','3'], 'Select Option'],
[['1', '2'], '2', '2', ['1', '2','3'], '2'],
[['1', '2'], '1', '1', ['1', '2','3'], '1'],
# dynamic updates removed our selected value; defaults back to placeholder
[['1', '2'], '2', '2', ['1', '3'], 'Select Option'],
]
for choices, default, initalSelection, dynamicUpdate, expectedFinalSelection in testcases:
parser = self.make_parser(choices=choices, default=default)
with instrumentGooey(parser) as (app, gooeyApp):
dropdown = gooeyApp.configs[0].reifiedWidgets[0]
# ensure that default values (when supplied) are selected in the UI
self.assertEqual(dropdown.widget.GetValue(), initalSelection)
# fire a dynamic update with the mock values
mock.return_value = {'--dropdown': dynamicUpdate}
gooeyApp.fetchExternalUpdates()
# the values in the UI now reflect those returned from the update
# note: we're appending the ['select option'] bit here as it gets automatically added
# in the UI.
expectedValues = ['Select Option'] + dynamicUpdate
self.assertEqual(dropdown.widget.GetItems(), expectedValues)
# and our selection is what we expect
self.assertEqual(dropdown.widget.GetValue(), expectedFinalSelection)
if __name__ == '__main__':
unittest.main()
Loading…
Cancel
Save