Browse Source

add Listbox widget type

pull/237/head
chriskiehl 7 years ago
parent
commit
229e8b54c6
6 changed files with 145 additions and 87 deletions
  1. 1
      README.md
  2. 6
      gooey/gui/model.py
  3. 10
      gooey/gui/widgets/components.py
  4. 35
      gooey/gui/widgets/widget_pack.py
  5. 3
      gooey/python_bindings/argparse_to_json.py
  6. 177
      gooey/python_bindings/gooey_parser.py

1
README.md

@ -206,6 +206,7 @@ However, by dropping in `GooeyParser` and supplying a `widget` name, you can dis
| DirChooser/FileChooser | <p align="center"><img src="https://cloud.githubusercontent.com/assets/1408720/7904377/f5483b28-07c5-11e5-9d01-1935635fc22d.gif" width="400"></p> |
| DateChooser &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| <p align="center"><img src="https://cloud.githubusercontent.com/assets/1408720/7904376/f544756a-07c5-11e5-86d6-862ac146ad35.gif" width="400"></p> |
| PasswordField | <p align="center"><img src="https://user-images.githubusercontent.com/1408720/28953722-eae72cca-788e-11e7-8fa1-9a1ef332a053.png" width="400"></p> |
| Listbox | ![image](https://user-images.githubusercontent.com/1408720/31590191-fadd06f2-b1c0-11e7-9a49-7cbf0c6d33d1.png) |

6
gooey/gui/model.py

@ -61,7 +61,11 @@ class MyWidget(object):
arg = str(self.commands[0]).replace('-', '')
repeated_args = arg * int(self._value)
return '-' + repeated_args
if self.type == 'Listbox':
if self.commands and self._value:
return u'{} {}'.format(self.commands[0], ' '.join(map(quote, self._value)))
else:
return ' '.join(map(quote, self._value)) if self._value else ''
if self.type == 'Dropdown':
if self._value == 'Select Option':
return None

10
gooey/gui/widgets/components.py

@ -217,12 +217,22 @@ class RadioGroup(object):
pass
class Listbox(BaseGuiComponent):
widget_class = widget_pack.ListboxPayload
def set_value(self, val):
if val:
self.widget_pack.set_value(val)
def build_subclass(name, widget_class):
# this seemed faster than typing class X a bunch
return type(name, (BaseGuiComponent,), {'widget_class': widget_class})
FileChooser = build_subclass('FileChooser', widget_pack.FileChooserPayload)
MultiFileChooser = build_subclass('MultiFileChooser', widget_pack.MultiFileSaverPayload)
DirChooser = build_subclass('DirChooser', widget_pack.DirChooserPayload)

35
gooey/gui/widgets/widget_pack.py

@ -9,6 +9,7 @@ from gooey.gui.util.filedrop import FileDrop
from gooey.gui.widgets.calender_dialog import CalendarDlg
class WidgetPack(object):
"""
Interface specifying the contract to which
@ -92,10 +93,12 @@ class BaseMultiFileChooser(BaseFileChooser):
def get_path(self, dlg):
return os.pathsep.join(dlg.GetPaths())
class MultiFileSaverPayload(BaseMultiFileChooser):
def __init__(self, *args, **kwargs):
BaseMultiFileChooser.__init__(self, build_dialog(wx.FD_MULTIPLE, False))
class MultiDirChooserPayload(BaseMultiFileChooser):
class MyMultiDirChooser(MDD.MultiDirDialog):
def __init__(self, *args, **kwargs):
@ -150,6 +153,7 @@ class TextAreaPayload(WidgetPack):
def get_value(self):
return self.widget.GetValue()
class DropdownPayload(WidgetPack):
default_value = 'Select Option'
@ -175,6 +179,32 @@ class DropdownPayload(WidgetPack):
self.widget.SetValue(text)
class ListboxPayload(WidgetPack):
default_value = 'Select Option'
def __init__(self, no_quoting=False):
self.widget = None
self.option_string = None
self.no_quoting = no_quoting
def build(self, parent, data, choices=None):
self.widget = wx.ListBox(
parent=parent,
choices=choices,
size=(-1,60),
style=wx.LB_MULTIPLE
)
return self.widget
def get_value(self):
return [self.widget.GetString(index)
for index in self.widget.GetSelections()]
def set_value(self, strings):
for s in strings:
self.widget.SetStringSelection(s)
class CounterPayload(WidgetPack):
def __init__(self):
self.widget = None
@ -192,10 +222,12 @@ class CounterPayload(WidgetPack):
def get_value(self):
return self.widget.GetValue()
class DirDialog(wx.DirDialog):
def __init__(self, parent, *args, **kwargs):
wx.DirDialog.__init__(self, parent, 'Select Directory', style=wx.DD_DEFAULT_STYLE)
class PasswordInputPayload(WidgetPack):
def __init__(self, no_quoting=False):
self.widget = None
@ -214,15 +246,18 @@ class PasswordInputPayload(WidgetPack):
def get_value(self):
return self.widget.GetValue()
def safe_default(data, default):
return ''
def build_dialog(style, exist_constraint=True, **kwargs):
if exist_constraint:
return lambda panel: wx.FileDialog(panel, style=style | wx.FD_FILE_MUST_EXIST, **kwargs)
else:
return lambda panel: wx.FileDialog(panel, style=style, **kwargs)
def build_subclass(subclass, dialog):
return type(subclass, (BaseFileChooser,), {'dialog': dialog})

3
gooey/python_bindings/argparse_to_json.py

@ -32,7 +32,8 @@ VALID_WIDGETS = (
'CheckBox',
'MultiDirChooser',
'Textarea',
'PasswordField'
'PasswordField',
'Listbox'
)

177
gooey/python_bindings/gooey_parser.py

@ -1,96 +1,103 @@
from argparse import ArgumentParser, _SubParsersAction, _MutuallyExclusiveGroup
from gooey.gui.lang.i18n import _
class GooeySubParser(_SubParsersAction):
def __init__(self, *args, **kwargs):
super(GooeySubParser, self).__init__(*args, **kwargs)
def __init__(self, *args, **kwargs):
super(GooeySubParser, self).__init__(*args, **kwargs)
class GooeyMutuallyExclusiveGroup(_MutuallyExclusiveGroup):
def __init__(self, parser, widgets, *args, **kwargs):
self.parser = parser
self.widgets = widgets
super(GooeyMutuallyExclusiveGroup, self).__init__(self.parser, *args, **kwargs)
def __init__(self, parser, widgets, *args, **kwargs):
self.parser = parser
self.widgets = widgets
super(GooeyMutuallyExclusiveGroup, self).__init__(self.parser, *args,
**kwargs)
def add_argument(self, *args, **kwargs):
widget = kwargs.pop('widget', None)
metavar = kwargs.pop('metavar', None)
super(GooeyMutuallyExclusiveGroup, self).add_argument(*args, **kwargs)
self.parser._actions[-1].metavar = metavar
self.widgets[self.parser._actions[-1].dest] = widget
def add_argument(self, *args, **kwargs):
widget = kwargs.pop('widget', None)
metavar = kwargs.pop('metavar', None)
super(GooeyMutuallyExclusiveGroup, self).add_argument(*args, **kwargs)
self.parser._actions[-1].metavar = metavar
self.widgets[self.parser._actions[-1].dest] = widget
class GooeyParser(object):
def __init__(self, **kwargs):
self.__dict__['parser'] = ArgumentParser(**kwargs)
self.widgets = {}
@property
def _mutually_exclusive_groups(self):
return self.parser._mutually_exclusive_groups
@property
def _actions(self):
return self.parser._actions
@property
def description(self):
return self.parser.description
def add_argument(self, *args, **kwargs):
widget = kwargs.pop('widget', None)
metavar = kwargs.pop('metavar', None)
self.parser.add_argument(*args, **kwargs)
self.parser._actions[-1].metavar = metavar
self.widgets[self.parser._actions[-1].dest] = widget
# def add_mutually_exclusive_group(self, **kwargs):
# return self.parser.add_mutually_exclusive_group(**kwargs)
def add_mutually_exclusive_group(self, **kwargs):
group = GooeyMutuallyExclusiveGroup(self.parser, self.widgets, **kwargs)
self.parser._mutually_exclusive_groups.append(group)
return group
def add_argument_group(self, *args, **kwargs):
return self.parser.add_argument_group(*args, **kwargs)
def parse_args(self, args=None, namespace=None):
return self.parser.parse_args(args, namespace)
def add_subparsers(self, **kwargs):
if self._subparsers is not None:
self.error(_('cannot have multiple subparser arguments'))
# add the parser class to the arguments if it's not present
kwargs.setdefault('parser_class', type(self))
if 'title' in kwargs or 'description' in kwargs:
title = _(kwargs.pop('title', 'subcommands'))
description = _(kwargs.pop('description', None))
self._subparsers = self.add_argument_group(title, description)
else:
self._subparsers = self._positionals
# prog defaults to the usage message of this parser, skipping
# optional arguments and with no "usage:" prefix
if kwargs.get('prog') is None:
formatter = self._get_formatter()
positionals = self._get_positional_actions()
groups = self._mutually_exclusive_groups
formatter.add_usage(self.usage, positionals, groups, '')
kwargs['prog'] = formatter.format_help().strip()
# create the parsers action and add it to the positionals list
parsers_class = self._pop_action_class(kwargs, 'parsers')
action = parsers_class(option_strings=[], **kwargs)
self._subparsers._add_action(action)
# return the created parsers action
return action
def __getattr__(self, item):
return getattr(self.parser, item)
def __setattr__(self, key, value):
return setattr(self.parser, key, value)
def __init__(self, **kwargs):
self.__dict__['parser'] = ArgumentParser(**kwargs)
self.widgets = {}
@property
def _mutually_exclusive_groups(self):
return self.parser._mutually_exclusive_groups
@property
def _actions(self):
return self.parser._actions
@property
def description(self):
return self.parser.description
def add_argument(self, *args, **kwargs):
widget = kwargs.pop('widget', None)
metavar = kwargs.pop('metavar', None)
if widget and widget == 'Listbox':
if not 'nargs' in kwargs or kwargs['nargs'] not in ['*', '+']:
raise ValueError(
'Gooey\'s Listbox widget requires that nargs be specified.\n'
'Nargs must be set to either `*` or `+` (e.g. nargs="*")'
)
self.parser.add_argument(*args, **kwargs)
self.parser._actions[-1].metavar = metavar
self.widgets[self.parser._actions[-1].dest] = widget
def add_mutually_exclusive_group(self, **kwargs):
group = GooeyMutuallyExclusiveGroup(self.parser, self.widgets, **kwargs)
self.parser._mutually_exclusive_groups.append(group)
return group
def add_argument_group(self, *args, **kwargs):
return self.parser.add_argument_group(*args, **kwargs)
def parse_args(self, args=None, namespace=None):
return self.parser.parse_args(args, namespace)
def add_subparsers(self, **kwargs):
if self._subparsers is not None:
self.error(_('cannot have multiple subparser arguments'))
# add the parser class to the arguments if it's not present
kwargs.setdefault('parser_class', type(self))
if 'title' in kwargs or 'description' in kwargs:
title = _(kwargs.pop('title', 'subcommands'))
description = _(kwargs.pop('description', None))
self._subparsers = self.add_argument_group(title, description)
else:
self._subparsers = self._positionals
# prog defaults to the usage message of this parser, skipping
# optional arguments and with no "usage:" prefix
if kwargs.get('prog') is None:
formatter = self._get_formatter()
positionals = self._get_positional_actions()
groups = self._mutually_exclusive_groups
formatter.add_usage(self.usage, positionals, groups, '')
kwargs['prog'] = formatter.format_help().strip()
# create the parsers action and add it to the positionals list
parsers_class = self._pop_action_class(kwargs, 'parsers')
action = parsers_class(option_strings=[], **kwargs)
self._subparsers._add_action(action)
# return the created parsers action
return action
def __getattr__(self, item):
return getattr(self.parser, item)
def __setattr__(self, key, value):
return setattr(self.parser, key, value)
Loading…
Cancel
Save