Browse Source

Remove outdated, rewritten, and unused gooey code

pull/240/head
chriskiehl 7 years ago
parent
commit
014c1c0fe6
24 changed files with 0 additions and 2252 deletions
  1. 32
      gooey/TODO.txt
  2. 17
      gooey/gui/controller.py
  3. 277
      gooey/gui/model.py
  4. 190
      gooey/gui/presenter.py
  5. 17
      gooey/gui/subpresenter.py
  6. 1
      gooey/gui/widgets/__init__.py
  7. 50
      gooey/gui/widgets/calender_dialog.py
  8. 256
      gooey/gui/widgets/components.py
  9. 268
      gooey/gui/widgets/widget_pack.py
  10. 1
      gooey/gui/windows/__init__.py
  11. 114
      gooey/gui/windows/advanced_config.py
  12. 229
      gooey/gui/windows/base_window.py
  13. 112
      gooey/gui/windows/footer.py
  14. 88
      gooey/gui/windows/header.py
  15. 53
      gooey/gui/windows/layouts.py
  16. 52
      gooey/gui/windows/runtime_display_panel.py
  17. 45
      gooey/gui/windows/sidebar.py
  18. 6
      gooey/gui/windows/views.py
  19. 67
      gooey/tests/conftest.py
  20. 58
      gooey/tests/test_image_repositoy.py
  21. 89
      gooey/tests/test_presentation.py
  22. 227
      gooey_config.json
  23. 2
      pytest.ini
  24. 1
      version.txt

32
gooey/TODO.txt

@ -1,32 +0,0 @@
TODO:
- Update parser to catch all argparse import styles
- Investigate Docopt
- better graphics
Restart Button Change:
- need different strategy for everything added.
- Fix vertical stacking of restart button
- system for supplying custom widgets to the GUI -- e.g. a FileChooser, rather than just a TextBox
- Remove debug statements current printing from program
- add optional cancel button.
- allow NoConfig to run without argparse (Issue #43)
- display warning when this happens (could be a misfire on Gooey's end)
- add suppress warnings flag
- Meta Info
- Program Name
- Program Description
- Client Program
- Desired Size
- Desired Columns (required)
- Desired Columns (optional)

17
gooey/gui/controller.py

@ -1,17 +0,0 @@
from gooey.gui.model import MyModel
from gooey.gui.presenter import Presenter
from gooey.gui.windows.base_window import BaseWindow
class Controller(object):
def __init__(self, build_spec):
self.model = MyModel(build_spec)
self.view = BaseWindow(layout_type=self.model.layout_type)
self.presentation = Presenter(self.view, self.model)
self.presentation.initialize_view()
def run(self):
self.view.Show(True)

277
gooey/gui/model.py

@ -1,277 +0,0 @@
import os
from collections import OrderedDict, namedtuple
from itertools import chain
from gooey.gui.lang.i18n import _
from gooey.gui.util.quoting import quote
import wx
ArgumentGroup = namedtuple('ArgumentGroup', 'name command required_args optional_args')
class MyWidget(object):
# TODO: Undumbify damn
# TODO: Undumbify _value/value access
def __init__(self, type, title, help, default, nargs, commands, choices):
self.type = type
self.title = title
self.help = help
self.default = default
self._value = default
self.nargs = nargs
self.commands = commands
self.choices = choices
@property
def value(self):
# TODO: split into stategy or subclass thingie
if self.type == 'CheckBox':
return self.commands[0] if self._value else None
if self.type == 'RadioGroup':
try:
return self.commands[self._value.index(True)][0]
except ValueError:
return None
if self.type == 'MultiFileChooser':
value = ' '.join(quote(x) for x in self._value.split(os.pathsep) if x)
if self.commands and value:
return u'{} {}'.format(self.commands[0], value)
return value or None
if self.type == 'Textarea':
if self.commands and self._value:
return '{} {}'.format(self.commands[0], quote(self._value.encode('unicode_escape')))
else:
return quote(self._value.encode('unicode_escape')) if self._value else ''
if self.type == 'CommandField':
if self.commands and self._value:
return u'{} {}'.format(self.commands[0], self._value)
else:
return self._value or None
if self.type == 'Counter':
'''
Returns
str(option_string * DropDown Value)
e.g.
-vvvvv
'''
if not str(self._value).isdigit():
return None
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
elif self.commands and self._value:
return u'{} {}'.format(self.commands[0], quote(self._value))
else:
return quote(self._value) if self._value else ''
else:
if self.commands and self._value:
if not self.nargs:
v = quote(self._value)
else:
v = self._value
return u'{0} {1}'.format(self.commands[0], v)
else:
if not self._value:
return None
elif not self.nargs:
return quote(self._value)
else:
return self._value
@value.setter
def value(self, val):
self._value = val
@classmethod
def from_dict(cls, data):
def maybe_unpack(collection, attr):
# TODO: RadioGroups need to support defaults
try:
if isinstance(collection, list):
return [item[attr] for item in collection]
return collection[attr]
except:
return None
details = data['data']
return cls(
data['type'],
maybe_unpack(details, 'display_name'),
maybe_unpack(details, 'help'),
maybe_unpack(details, 'default'),
maybe_unpack(details, 'nargs'),
maybe_unpack(details, 'commands'),
maybe_unpack(details, 'choices')
)
class States(object):
CONFIGURING = 'configuring'
RUNNNING = 'running'
SUCCESS = 'success'
ERROR = 'error'
STOPPED = 'stopped'
class MyModel(object):
'''
'''
def wrap(self, groups):
output = OrderedDict()
for name, group in groups.items():
output[name] = ArgumentGroup(
name,
group['command'],
*self.group_arguments(group['contents'])
)
return output
def __init__(self, build_spec):
self.current_state = States.CONFIGURING
self.build_spec = build_spec
self.layout_type = self.build_spec.get('layout_type')
self.auto_start = self.build_spec.get('auto_start')
self.progress_regex = self.build_spec.get('progress_regex')
self.progress_expr = self.build_spec.get('progress_expr')
self.disable_progress_bar_animation = self.build_spec['disable_progress_bar_animation']
self.program_name = self.build_spec.get('program_name')
self.default_size = self.build_spec.get('default_size')
self.heading_title = _("settings_title")
self.heading_subtitle = self.build_spec['program_description'] or ''
self.use_monospace_font = self.build_spec.get('monospace_display')
self.stop_button_disabled = self.build_spec['disable_stop_button']
self.argument_groups = self.wrap(self.build_spec.get('widgets', {}))
self.active_group = next(iter(self.argument_groups))
self.num_required_cols = self.build_spec['num_required_cols']
self.num_optional_cols = self.build_spec['num_optional_cols']
self.text_states = {
States.CONFIGURING: {
'title': _("settings_title"),
'subtitle': self.build_spec['program_description'] or ''
},
States.RUNNNING: {
'title': _("running_title"),
'subtitle': _('running_msg')
},
States.SUCCESS: {
'title': _('finished_title'),
'subtitle': _('finished_msg')
},
States.ERROR: {
'title': _('finished_title'),
'subtitle': _('finished_error')
}
}
@property
def required_args(self):
return self.argument_groups[self.active_group].required_args
@property
def optional_args(self):
return self.argument_groups[self.active_group].optional_args
def update_state(self, state):
self.current_state = state
text = self.text_states[state]
self.heading_title = text['title']
self.heading_subtitle = text['subtitle']
def is_valid(self):
# TODO: fix skipping_config.. whatever that did
# currently breaks when you supply it as a decorator option
# return self.skipping_config() and self.required_section_complete()
return self.is_required_section_complete()
def skipping_config(self):
return self.build_spec['manual_start']
def is_required_section_complete(self):
error_found = False
for arg in self.required_args:
widget = arg.widget_instance.widget_pack.widget
if arg.value:
widget.SetBackgroundColour(wx.NullColour)
else:
if not error_found:
error_found = True
widget.SetFocus()
widget.SetBackgroundColour("#EF9A9A")
widget.Refresh()
return not error_found
def build_command_line_string(self):
optional_args = [arg.value for arg in self.optional_args]
required_args = [c.value for c in self.required_args if c.commands]
position_args = [c.value for c in self.required_args if not c.commands]
if position_args:
position_args.insert(0, "--")
cmd_string = ' '.join(list(filter(None, chain(required_args, optional_args, position_args))))
if self.layout_type == 'column':
cmd_string = u'{} {}'.format(self.argument_groups[self.active_group].command, cmd_string)
return u'{} --ignore-gooey {}'.format(self.build_spec['target'], cmd_string)
def group_arguments(self, widget_list):
is_required = lambda widget: widget['required']
not_checkbox = lambda widget: widget['type'] != 'CheckBox'
required_args, optional_args = self.partition(widget_list, is_required)
if self.build_spec['group_by_type']:
optional_args = chain(*self.partition(optional_args, not_checkbox))
return list(map(self.to_object, required_args)), list(map(self.to_object, optional_args))
@staticmethod
def partition(collection, condition):
return list(filter(condition, collection)), list(filter(lambda x: not condition(x), collection))
def to_object(self, data):
details = data['data']
return MyWidget(
data['type'],
self.maybe_unpack(details, 'display_name'),
self.maybe_unpack(details, 'help'),
self.maybe_unpack(details, 'default'),
self.maybe_unpack(details, 'nargs'),
self.maybe_unpack(details, 'commands'),
self.maybe_unpack(details, 'choices')
)
@staticmethod
def maybe_unpack(collection, attr):
# TODO: RadioGroups need to support defaults
try:
if isinstance(collection, list):
return [item[attr] for item in collection]
return collection[attr]
except:
return None

190
gooey/gui/presenter.py

@ -1,190 +0,0 @@
import sys
from gooey.gui.processor import ProcessController
from gooey.gui.model import States
from gooey.gui.pubsub import pub
from gooey.gui import events
from gooey.gui.windows import layouts
import wx
class Presenter(object):
def __init__(self, view, model):
self.view = view
self.model = model
self.client_runner = ProcessController(
self.model.progress_regex,
self.model.progress_expr
)
pub.subscribe(self.on_cancel, events.WINDOW_CANCEL)
pub.subscribe(self.on_stop, events.WINDOW_STOP)
pub.subscribe(self.on_start, events.WINDOW_START)
pub.subscribe(self.on_restart, events.WINDOW_RESTART)
pub.subscribe(self.on_edit, events.WINDOW_EDIT)
pub.subscribe(self.on_close, events.WINDOW_CLOSE)
# console statuses from the other thread
pub.subscribe(self.on_new_message, 'console_update')
pub.subscribe(self.on_progress_change, 'progress_update')
pub.subscribe(self.on_client_done, 'execution_complete')
pub.subscribe(self.on_selection_change, events.LIST_BOX)
def on_selection_change(self, selection):
self.update_model()
self.model.active_group = selection
self.redraw_from_model()
self.syncronize_from_model()
def initialize_view(self):
self.view.window_title = self.model.program_name
self.view.window_size = self.model.default_size
self.view.required_section.clear()
self.view.optional_section.clear()
self.view.required_section.populate(self.model.required_args, self.model.num_required_cols)
self.view.optional_section.populate(self.model.optional_args, self.model.num_optional_cols)
if self.model.use_monospace_font:
self.view.set_display_font_style('monospace')
if self.should_disable_stop_button():
self.view.disable_stop_button()
else:
self.view.enable_stop_button()
if self.model.layout_type == layouts.COLUMN:
self.view.set_list_contents(list(self.model.argument_groups.keys()))
if self.model.auto_start:
self.model.update_state(States.RUNNNING)
self.on_start()
self.syncronize_from_model()
def update_model(self):
self.update_list(self.model.required_args, self.view.required_section.get_values())
self.update_list(self.model.optional_args, self.view.optional_section.get_values())
self.syncronize_from_model()
def syncronize_from_model(self):
#TODO move this out of the presenter
#TODO Make all view interactions thread safe
wx.CallAfter(self.syncronize_from_model_async)
def syncronize_from_model_async(self):
# update heading titles
self.view.heading_title = self.model.heading_title
self.view.heading_subtitle = self.model.heading_subtitle
# refresh the widgets
for index, widget in enumerate(self.view.required_section):
widget.set_value(self.model.required_args[index]._value)
for index, widget in enumerate(self.view.optional_section):
widget.set_value(self.model.optional_args[index]._value)
# swap the views
getattr(self, self.model.current_state)()
def redraw_from_model(self):
self.view.freeze()
self.view.required_section.clear()
self.view.optional_section.clear()
self.view.required_section.populate(self.model.required_args, self.model.num_required_cols)
self.view.optional_section.populate(self.model.optional_args, self.model.num_optional_cols)
getattr(self, self.model.current_state)()
self.view.thaw()
def should_disable_stop_button(self):
return self.model.stop_button_disabled
def on_start(self):
self.update_model()
if not self.model.is_valid():
return self.view.show_missing_args_dialog()
command = self.model.build_command_line_string()
self.client_runner.run(command)
self.model.update_state(States.RUNNNING)
self.syncronize_from_model()
def on_stop(self):
self.ask_stop()
def on_edit(self):
self.model.update_state(States.CONFIGURING)
self.syncronize_from_model()
def on_restart(self):
self.on_start()
def on_cancel(self):
if self.view.confirm_exit_dialog():
self.view.Destroy()
sys.exit()
def on_close(self):
self.view.Destroy()
sys.exit()
def on_new_message(self, msg):
# observes changes coming from the subprocess
self.view.update_console_async(msg)
def on_progress_change(self, progress):
# observes changes coming from the subprocess
self.view.update_progress_aync(progress, self.model.disable_progress_bar_animation)
def on_client_done(self):
if self.client_runner.was_success():
self.model.update_state(States.SUCCESS)
else:
self.model.update_state(States.ERROR)
self.syncronize_from_model()
def ask_stop(self):
if self.view.confirm_stop_dialog():
self.stop()
return True
return False
def stop(self):
self.client_runner.stop()
def configuring(self):
self.view.hide_all_buttons()
self.view.hide('check_mark', 'running_img', 'error_symbol', 'runtime_display')
self.view.show('settings_img', 'cancel_button', 'start_button', 'config_panel')
self.view.Layout()
def running(self):
self.view.hide_all_buttons()
self.view.hide('check_mark', 'settings_img', 'error_symbol', 'config_panel')
self.view.show('running_img', 'stop_button', 'progress_bar', 'runtime_display')
self.view.progress_bar.Pulse()
self.view.Layout()
def success(self):
self.view.hide_all_buttons()
self.view.hide('running_img', 'progress_bar', 'config_panel')
self.view.show('check_mark', 'edit_button', 'restart_button', 'close_button', 'runtime_display')
self.view.Layout()
def error(self):
self.view.hide_all_buttons()
self.view.hide('running_img', 'progress_bar', 'config_panel')
self.view.show('error_symbol', 'edit_button', 'restart_button', 'close_button', 'runtime_display')
self.view.Layout()
@staticmethod
def partition(collection, condition):
return filter(condition, collection), filter(lambda x: not condition(x), collection)
def update_list(self, collection, new_values):
# convenience method for syncronizing the model -> widget list collections
for index, val in enumerate(new_values):
collection[index].value = val

17
gooey/gui/subpresenter.py

@ -1,17 +0,0 @@
class SubModel(object):
def __init__(self):
self.section_title = None
class Presenter(object):
def __init__(self, view, model):
self.view = view
self.model = model
def on_selection_change(self):
self.view.refresh

1
gooey/gui/widgets/__init__.py

@ -1 +0,0 @@
__author__ = 'Chris'

50
gooey/gui/widgets/calender_dialog.py

@ -1,50 +0,0 @@
__author__ = 'Chris'
import wx
from gooey.gui.util import wx_util
from gooey.gui.three_to_four import Classes, Constants
class CalendarDlg(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent)
self.SetBackgroundColour('#ffffff')
self.ok_button = wx.Button(self, wx.ID_OK, label='Ok')
self.datepicker = Classes.DatePickerCtrl(self, style=Constants.WX_DP_DROPDOWN)
vertical_container = wx.BoxSizer(wx.VERTICAL)
vertical_container.AddSpacer(10)
vertical_container.Add(wx_util.h1(self, label='Select a Date'), 0, wx.LEFT | wx.RIGHT, 15)
vertical_container.AddSpacer(10)
vertical_container.Add(self.datepicker, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 15)
vertical_container.AddSpacer(10)
button_sizer = wx.BoxSizer(wx.HORIZONTAL)
button_sizer.AddStretchSpacer(1)
button_sizer.Add(self.ok_button, 0)
vertical_container.Add(button_sizer, 0, wx.LEFT | wx.RIGHT, 15)
vertical_container.AddSpacer(20)
self.SetSizerAndFit(vertical_container)
self.Bind(wx.EVT_BUTTON, self.OnOkButton, self.ok_button)
def OnOkButton(self, event):
self.EndModal(wx.ID_OK)
event.Skip()
def OnCancellButton(self, event):
try:
return None
except:
self.Close()
def GetPath(self):
return self.datepicker.GetValue().FormatISODate()

256
gooey/gui/widgets/components.py

@ -1,256 +0,0 @@
from functools import partial
import wx
from gooey.gui.util import wx_util
from gooey.gui.widgets import widget_pack
class BaseGuiComponent(object):
widget_class = None
def __init__(self, parent, title, msg, choices=None):
'''
:param data: field info (title, help, etc..)
:param widget_pack: internal wxWidgets to render
'''
# parent
self.parent = parent
# Widgets
self.title = None
self.help_msg = None
self.choices = choices
# Internal WidgetPack set in subclasses
self.do_layout(parent, title, msg)
def do_layout(self, parent, title, msg):
self.panel = wx.Panel(parent)
self.widget_pack = self.widget_class()
self.title = self.format_title(self.panel, title)
self.help_msg = self.format_help_msg(self.panel, msg)
self.help_msg.SetMinSize((0, -1))
core_widget_set = self.widget_pack.build(self.panel, {}, self.choices)
vertical_container = wx.BoxSizer(wx.VERTICAL)
vertical_container.Add(self.title)
vertical_container.AddSpacer(2)
if self.help_msg.GetLabelText():
vertical_container.Add(self.help_msg, 1, wx.EXPAND)
vertical_container.AddSpacer(2)
else:
vertical_container.AddStretchSpacer(1)
vertical_container.Add(core_widget_set, 0, wx.EXPAND)
self.panel.SetSizer(vertical_container)
return self.panel
def bind(self, *args, **kwargs):
print(self.widget_pack.widget.Bind(*args, **kwargs))
def get_title(self):
return self.title.GetLabel()
def set_title(self, text):
self.title.SetLabel(text)
def get_help_msg(self):
return self.help_msg.GetLabelText()
def set_label_text(self, text):
self.help_msg.SetLabel(text)
def format_help_msg(self, parent, msg):
base_text = wx.StaticText(parent, label=msg or '')
wx_util.dark_grey(base_text)
return base_text
def format_title(self, parent, title):
text = wx.StaticText(parent, label=title)
wx_util.make_bold(text)
return text
def onResize(self, evt):
# handle internal widgets
# self.panel.Freeze()
self._onResize(evt)
# propagate event to child widgets
self.widget_pack.onResize(evt)
evt.Skip()
# self.panel.Thaw()
def _onResize(self, evt):
if not self.help_msg:
return
self.panel.Size = evt.GetSize()
container_width, _ = self.panel.Size
text_width, _ = self.help_msg.Size
if text_width != container_width:
self.help_msg.SetLabel(self.help_msg.GetLabelText().replace('\n', ' '))
self.help_msg.Wrap(container_width)
evt.Skip()
def get_value(self):
return self.widget_pack.get_value()
def set_value(self, val):
if val:
self.widget_pack.widget.SetValue(str(val))
def __repr__(self):
return self.__class__.__name__
class CheckBox(BaseGuiComponent):
def __init__(self, parent, title, msg, choices=None):
BaseGuiComponent.__init__(self, parent, title, msg)
def do_layout(self, parent, title, msg):
self.panel = wx.Panel(parent)
self.widget = wx.CheckBox(self.panel)
# self.widget.SetValue(self.default_value)
self.title = self.format_title(self.panel, title)
self.help_msg = self.format_help_msg(self.panel, msg)
self.help_msg.SetMinSize((0, -1))
# self.help_msg.Bind(wx.EVT_LEFT_UP, lambda event: self.widget.SetValue(not self.widget.GetValue()))
vertical_container = wx.BoxSizer(wx.VERTICAL)
vertical_container.Add(self.title)
horizontal_sizer = wx.BoxSizer(wx.HORIZONTAL)
horizontal_sizer.Add(self.widget, 0, wx.EXPAND | wx.RIGHT, 10)
horizontal_sizer.Add(self.help_msg, 1, wx.EXPAND)
vertical_container.Add(horizontal_sizer, 0, wx.EXPAND)
self.panel.SetSizer(vertical_container)
self.panel.Bind(wx.EVT_SIZE, self.onResize)
return self.panel
def onResize(self, evt):
msg = self.help_msg
container_width, _ = self.panel.Size
text_width, _ = msg.Size
if text_width != container_width:
msg.SetLabel(msg.GetLabelText().replace('\n', ' '))
msg.Wrap(container_width)
evt.Skip()
def get_value(self):
return self.widget.GetValue()
def set_value(self, val):
self.widget.SetValue(val)
class RadioGroup(object):
def __init__(self, parent, title, msg, choices=None):
self.panel = None
self.radio_buttons = []
self.option_strings = []
self.help_msgs = []
self.btn_names = []
self.do_layout(parent, title, msg)
self.selected_button = None
def do_layout(self, parent, titles, msgs):
self.panel = wx.Panel(parent)
self.radio_buttons = [wx.RadioButton(self.panel, -1) for _ in titles]
self.btn_names = [wx.StaticText(self.panel, label=title.title()) for title in titles]
self.help_msgs = [wx.StaticText(self.panel, label=msg.title()) for msg in msgs]
# box = wx.StaticBox(self.panel, -1, label=self.data['group_name'])
box = wx.StaticBox(self.panel, -1, label='')
vertical_container = wx.StaticBoxSizer(box, wx.VERTICAL)
for button, name, help in zip(self.radio_buttons, self.btn_names, self.help_msgs):
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(button, 0, wx.ALIGN_TOP | wx.ALIGN_LEFT)
hbox.Add(name, 0, wx.LEFT, 10)
vertical_container.Add(hbox, 0, wx.EXPAND)
vertical_container.Add(help, 1, wx.EXPAND | wx.LEFT, 25)
vertical_container.AddSpacer(5)
self.panel.SetSizer(vertical_container)
self.panel.Bind(wx.EVT_SIZE, self.onResize)
for button in self.radio_buttons:
button.Bind(wx.EVT_LEFT_DOWN, self.handle_selection)
return self.panel
def handle_selection(self, event):
if event.EventObject.Id == getattr(self.selected_button, 'Id', None):
# if it is already selected, manually deselect it
self.selected_button.SetValue(False)
self.selected_button = None
else:
event.Skip()
self.selected_button = event.EventObject
def onResize(self, evt):
msg = self.help_msgs[0]
container_width, _ = self.panel.Size
text_width, _ = msg.Size
if text_width != container_width:
msg.SetLabel(msg.GetLabelText().replace('\n', ' '))
msg.Wrap(container_width)
evt.Skip()
def get_value(self):
return [button.GetValue() for button in self.radio_buttons]
def set_value(self, val):
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)
FileSaver = build_subclass('FileSaver', widget_pack.FileSaverPayload)
DateChooser = build_subclass('DateChooser', widget_pack.DateChooserPayload)
TextField = build_subclass('TextField', widget_pack.TextInputPayload)
Textarea = build_subclass('TextField', widget_pack.TextAreaPayload)
CommandField = build_subclass('CommandField', widget_pack.TextInputPayload(no_quoting=True))
Dropdown = build_subclass('Dropdown', widget_pack.DropdownPayload)
Counter = build_subclass('Counter', widget_pack.CounterPayload)
MultiDirChooser = build_subclass('MultiDirChooser', widget_pack.MultiDirChooserPayload)
PasswordField = build_subclass('PasswordField', widget_pack.PasswordInputPayload)

268
gooey/gui/widgets/widget_pack.py

@ -1,268 +0,0 @@
import os
import wx
import wx.lib.agw.multidirdialog as MDD
from abc import ABCMeta, abstractmethod
from gooey.gui.lang import i18n
from gooey.gui.util.filedrop import FileDrop
from gooey.gui.widgets.calender_dialog import CalendarDlg
class WidgetPack(object):
"""
Interface specifying the contract to which
all `WidgetPack`s will adhere
"""
__metaclass__ = ABCMeta
@abstractmethod
def build(self, parent, data, choices=None):
pass
def onResize(self, evt):
pass
@staticmethod
def get_command(data):
return ''
@staticmethod
def disable_quoting(data):
nargs = data.get('nargs', None)
if not nargs:
return False
return nargs not in (1, '?')
class BaseChooser(WidgetPack):
def __init__(self):
self.button_text = i18n._('browse')
self.parent = None
self.widget = None
self.button = None
def build(self, parent, data, choices=None):
self.parent = parent
self.widget = wx.TextCtrl(self.parent)
self.widget.AppendText('')
self.widget.SetMinSize((0, -1))
dt = FileDrop(self.widget)
self.widget.SetDropTarget(dt)
self.button = wx.Button(self.parent, label=self.button_text, size=(73, 23))
widget_sizer = wx.BoxSizer(wx.HORIZONTAL)
widget_sizer.Add(self.widget, 1, wx.EXPAND)
widget_sizer.AddSpacer(10)
widget_sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL)
parent.Bind(wx.EVT_BUTTON, self.on_button, self.button)
return widget_sizer
def get_value(self):
return self.widget.GetValue()
def __repr__(self):
return self.__class__.__name__
class BaseFileChooser(BaseChooser):
dialog = None
def __init__(self):
BaseChooser.__init__(self)
def on_button(self, evt):
dlg = self.dialog(self.parent)
result = (self.get_path(dlg)
if dlg.ShowModal() == wx.ID_OK
else None)
if result:
self.widget.SetValue(result)
def get_path(self, dlg):
return dlg.GetPath()
class BaseMultiFileChooser(BaseFileChooser):
def __init__(self, dialog):
BaseFileChooser.__init__(self)
self.dialog = dialog
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):
kwargs.update({
'title': "Select Directories",
'defaultPath': os.getcwd(),
'agwStyle': MDD.DD_MULTIPLE|MDD.DD_DIR_MUST_EXIST
})
MDD.MultiDirDialog.__init__(self, *args, **kwargs)
def GetPaths(self):
return self.dirCtrl.GetPaths()
def __init__(self, *args, **kwargs):
BaseMultiFileChooser.__init__(self, MultiDirChooserPayload.MyMultiDirChooser)
class TextInputPayload(WidgetPack):
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.TextCtrl(parent)
dt = FileDrop(self.widget)
self.widget.SetDropTarget(dt)
self.widget.SetMinSize((0, -1))
self.widget.SetDoubleBuffered(True)
self.widget.AppendText('')
return self.widget
def get_value(self):
return self.widget.GetValue()
class TextAreaPayload(WidgetPack):
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.TextCtrl(parent, style=wx.TE_MULTILINE)
dt = FileDrop(self.widget)
self.widget.SetDropTarget(dt)
self.widget.SetMinSize((0, -1))
self.widget.SetDoubleBuffered(True)
self.widget.AppendText('')
return self.widget
def get_value(self):
return self.widget.GetValue()
class DropdownPayload(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.ComboBox(
parent=parent,
id=-1,
value=self.default_value,
choices=[self.default_value] + choices,
style=wx.CB_DROPDOWN
)
return self.widget
def get_value(self):
return self.widget.GetValue()
def set_value(self, text):
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
def build(self, parent, data, choices=None):
self.widget = wx.ComboBox(
parent=parent,
id=-1,
value='',
choices=list(map(str, range(1, 11))),
style=wx.CB_DROPDOWN
)
return self.widget
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
self.option_string = None
self.no_quoting = no_quoting
def build(self, parent, data, choices=None):
self.widget = wx.TextCtrl(parent, style=wx.TE_PASSWORD)
dt = FileDrop(self.widget)
self.widget.SetDropTarget(dt)
self.widget.SetMinSize((0, -1))
self.widget.SetDoubleBuffered(True)
self.widget.AppendText('')
return self.widget
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})
FileSaverPayload = build_subclass('FileSaverPayload', staticmethod(build_dialog(wx.FD_SAVE, False, defaultFile="Enter Filename")))
FileChooserPayload = build_subclass('FileChooserPayload', staticmethod(build_dialog(wx.FD_OPEN)))
DirChooserPayload = build_subclass('DirChooserPayload', DirDialog)
DateChooserPayload = build_subclass('DateChooserPayload', CalendarDlg)

1
gooey/gui/windows/__init__.py

@ -1 +0,0 @@
__author__ = 'Chris'

114
gooey/gui/windows/advanced_config.py

@ -1,114 +0,0 @@
"""
Managed the internal layout for configuration options
@author: Chris
"""
import wx
from wx.lib.scrolledpanel import ScrolledPanel
try:
from itertools import zip_longest
except ImportError:
from itertools import izip_longest as zip_longest
from gooey.gui.util import wx_util
from gooey.gui.lang import i18n
from gooey.gui.widgets import components
PADDING = 10
class WidgetContainer(wx.Panel):
'''
Collection of widgets
'''
def __init__(self, parent, section_name, *args, **kwargs):
wx.Panel.__init__(self, parent, *args, **kwargs)
self.section_name = section_name
self.title = None
self.widgets = []
self.container = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self.container)
def layout(self, num_columns):
STD_LAYOUT = (0, wx.LEFT | wx.RIGHT | wx.EXPAND, PADDING)
if self.title:
self.container.Add(wx_util.h0(self, self.title), 0, wx.LEFT | wx.RIGHT, PADDING)
self.container.AddSpacer(30)
if self.widgets:
self.container.Add(wx_util.h1(self, self.section_name), 0, wx.LEFT | wx.RIGHT, PADDING)
self.container.AddSpacer(5)
self.container.Add(wx_util.horizontal_rule(self), *STD_LAYOUT)
self.container.AddSpacer(20)
self.create_component_grid(self.container, self.widgets, cols=num_columns)
self.container.AddSpacer(10)
def populate(self, widgets, num_columns):
for index, widget in enumerate(widgets):
widget_class = getattr(components, widget.type)
widget_instance = widget_class(self, widget.title, widget.help, widget.choices)
widget.widget_instance = widget_instance
self.widgets.append(widget_instance)
self.layout(num_columns)
def get_values(self):
return [x.get_value() for x in self.widgets]
def clear(self):
self.container.Clear(True)
self.widgets = []
def create_component_grid(self, parent_sizer, components, cols=2):
for row in self.chunk(components, cols):
hsizer = wx.BoxSizer(wx.HORIZONTAL)
for widget in filter(None, row):
hsizer.Add(widget.panel, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 10)
parent_sizer.Add(hsizer, 0, wx.EXPAND)
parent_sizer.AddSpacer(20)
def chunk(self, iterable, n, fillvalue=None):
"itertools recipe: Collect data into fixed-length chunks or blocks"
args = [iter(iterable)] * n
return zip_longest(fillvalue=fillvalue, *args)
def __iter__(self):
return iter(self.widgets)
class ConfigPanel(ScrolledPanel):
def __init__(self, parent, req_cols=1, opt_cols=3, title=None, **kwargs):
ScrolledPanel.__init__(self, parent, **kwargs)
self.SetupScrolling(scroll_x=False, scrollToTop=False)
self.SetDoubleBuffered(True)
self.title = title
self._num_req_cols = req_cols
self._num_opt_cols = opt_cols
self.required_section = WidgetContainer(self, i18n._("required_args_msg"))
self.optional_section = WidgetContainer(self, i18n._("optional_args_msg"))
self._do_layout()
self.Bind(wx.EVT_SIZE, self.OnResize)
def _do_layout(self):
STD_LAYOUT = (0, wx.LEFT | wx.RIGHT | wx.EXPAND, PADDING)
container = wx.BoxSizer(wx.VERTICAL)
container.AddSpacer(15)
container.Add(self.required_section, *STD_LAYOUT)
container.Add(self.optional_section, *STD_LAYOUT)
self.SetSizer(container)
def OnResize(self, evt):
self.SetupScrolling(scroll_x=False, scrollToTop=False)
evt.Skip()
def clear(self):
self.required_section.clear()
self.optional_section.clear()

229
gooey/gui/windows/base_window.py

@ -1,229 +0,0 @@
'''
Created on Jan 19, 2014
@author: Chris
'''
import sys
import wx
from gooey.gui import image_repository, events
from gooey.gui.lang.i18n import _
from gooey.gui.pubsub import pub
from gooey.gui.util import wx_util
from gooey.gui.windows import footer, header, layouts
from gooey.gui.windows.runtime_display_panel import RuntimeDisplay
YES = 5103
NO = 5104
class BaseWindow(wx.Frame):
'''
Primary Frame under which all sub-Panels are organized.
'''
def __init__(self, layout_type):
wx.Frame.__init__(self, parent=None, id=-1)
self.SetDoubleBuffered(True)
# type of gui to render
self.layout_type = layout_type
# Components
self.icon = None
self.head_panel = None
self.config_panel = None
self.runtime_display = None
self.foot_panel = None
self.panels = None
self._init_properties()
self._init_components()
self._do_layout()
self.Bind(wx.EVT_SIZE, self.onResize)
self.Bind(wx.EVT_CLOSE, self.onClose)
@property
def window_size(self):
return self.GetSize()
@window_size.setter
def window_size(self, size_tuple):
self.SetSize(size_tuple)
@property
def window_title(self):
return self.GetTitle()
@window_title.setter
def window_title(self, title):
self.SetTitle(title)
@property
def heading_title(self):
return self.head_panel.title
@heading_title.setter
def heading_title(self, text):
self.head_panel.title = text
@property
def heading_subtitle(self):
return self.head_panel.subtitle
@heading_subtitle.setter
def heading_subtitle(self, text):
self.head_panel.subtitle = text
@property
def required_section(self):
return self.config_panel.main_content.required_section
@property
def optional_section(self):
return self.config_panel.main_content.optional_section
@property
def progress_bar(self):
return self.foot_panel.progress_bar
def set_list_contents(self, contents):
self.config_panel.sidebar.set_list_contents(contents)
def set_display_font_style(self, style):
# TODO: make this not stupid
# TODO: _actual_ font support
self.runtime_display.set_font_style(
wx.MODERN if style == 'monospace' else wx.DEFAULT)
def _init_properties(self):
# self.SetTitle(self.build_spec['program_name'])
# self.SetSize(self.build_spec['default_size'])
# # self.SetMinSize((400, 300))
self.icon = wx.Icon(image_repository.program_icon, wx.BITMAP_TYPE_ICO)
self.SetIcon(self.icon)
def _init_components(self):
self.runtime_display = RuntimeDisplay(self)
self.head_panel = header.FrameHeader(parent=self)
self.foot_panel = footer.Footer(self)
self.panels = [self.head_panel, self.config_panel, self.foot_panel]
def _do_layout(self):
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.head_panel, 0, wx.EXPAND)
sizer.Add(wx_util.horizontal_rule(self), 0, wx.EXPAND)
if self.layout_type == layouts.COLUMN:
self.config_panel = layouts.ColumnLayout(self)
else:
self.config_panel = layouts.FlatLayout(self)
sizer.Add(self.config_panel, 1, wx.EXPAND)
sizer.Add(self.runtime_display, 1, wx.EXPAND)
self.runtime_display.Hide()
sizer.Add(wx_util.horizontal_rule(self), 0, wx.EXPAND)
sizer.Add(self.foot_panel, 0, wx.EXPAND)
self.SetSizer(sizer)
self.sizer = sizer
def freeze(self):
self.Freeze()
def thaw(self):
self.Thaw()
def enable_stop_button(self):
self.foot_panel.stop_button.Enable()
def disable_stop_button(self):
self.foot_panel.stop_button.Disable()
def show(self, *args):
'''
Looks up the attribute across all available
panels and calls `Show()`
'''
self._set_visibility('Show', *args)
def hide(self, *args):
'''
Looks up the attribute across all available
panels and calls `Show()`
'''
self._set_visibility('Hide', *args)
def _set_visibility(self, action, *args):
'''
Checks for the existence `attr` on a given `panel` and
performs `action` if found
'''
def _set_visibility(obj, attrs):
for attr in attrs:
if hasattr(obj, attr):
instance = getattr(obj, attr)
getattr(instance, action)()
instance.Layout()
for panel in [self, self.head_panel, self.foot_panel, self.config_panel]:
_set_visibility(panel, args)
def hide_all_buttons(self):
self.foot_panel.hide_all_buttons()
def update_console_async(self, msg):
wx.CallAfter(self.runtime_display.append_text, msg)
def update_progress_aync(self, progress, disable_animation=False):
wx.CallAfter(self.UpdateProgressBar, progress, disable_animation)
def onResize(self, evt):
evt.Skip()
def onClose(self, evt):
if evt.CanVeto():
evt.Veto()
pub.send_message(str(events.WINDOW_CLOSE))
def UpdateProgressBar(self, value, disable_animation=False):
pb = self.foot_panel.progress_bar
if value is None:
return
if value < 0:
pb.Pulse()
else:
value = min(int(value), pb.GetRange())
if pb.GetValue() != value:
# Windows 7 progress bar animation hack
# http://stackoverflow.com/questions/5332616/disabling-net-progressbar-animation-when-changing-value
if disable_animation and sys.platform.startswith("win"):
if pb.GetRange() == value:
pb.SetValue(value)
pb.SetValue(value-1)
else:
pb.SetValue(value+1)
pb.SetValue(value)
def show_dialog(self, title, content, style):
dlg = wx.MessageDialog(None, content, title, style)
result = dlg.ShowModal()
dlg.Destroy()
return result
def show_missing_args_dialog(self):
self.show_dialog(_('error_title'), _('error_required_fields'), wx.ICON_ERROR)
def confirm_exit_dialog(self):
result = self.show_dialog(_('sure_you_want_to_exit'), _('close_program'), wx.YES_NO)
return result == YES
def confirm_stop_dialog(self):
result = self.show_dialog(_('sure_you_want_to_stop'), _('stop_task'), wx.YES_NO)
return result == YES
if __name__ == '__main__':
pass

112
gooey/gui/windows/footer.py

@ -1,112 +0,0 @@
'''
Created on Dec 23, 2013
@author: Chris
'''
import wx
from gooey.gui.pubsub import pub
from gooey.gui.lang import i18n
from gooey.gui import imageutil, events
class Footer(wx.Panel):
'''
Footer section used on the configuration
screen of the application
args:
parent: wxPython parent windows
controller: controller class used in delagating all the commands
'''
def __init__(self, parent, **kwargs):
wx.Panel.__init__(self, parent, **kwargs)
self.SetMinSize((30, 53))
# components
self.cancel_button = None
self.start_button = None
self.progress_bar = None
self.close_button = None
self.stop_button = None
self.restart_button = None
self.buttons = None
self.layouts = {}
self._init_components()
self._do_layout()
for button in self.buttons:
self.Bind(wx.EVT_BUTTON, self.dispatch_click, button)
def _init_components(self):
self.cancel_button = self.button(i18n._('cancel'), wx.ID_CANCEL, event_id=int(events.WINDOW_CANCEL))
self.stop_button = self.button(i18n._('stop'), wx.ID_OK, event_id=int(events.WINDOW_STOP))
self.start_button = self.button(i18n._('start'), wx.ID_OK, event_id=int(events.WINDOW_START))
self.close_button = self.button(i18n._("close"), wx.ID_OK, event_id=int(events.WINDOW_CLOSE))
self.restart_button = self.button(i18n._('restart'), wx.ID_OK, event_id=int(events.WINDOW_RESTART))
self.edit_button = self.button(i18n._('edit'), wx.ID_OK, event_id=int(events.WINDOW_EDIT))
self.progress_bar = wx.Gauge(self, range=100)
self.buttons = [self.cancel_button, self.start_button,
self.stop_button, self.close_button,
self.restart_button, self.edit_button]
def _do_layout(self):
self.stop_button.Hide()
self.restart_button.Hide()
v_sizer = wx.BoxSizer(wx.VERTICAL)
h_sizer = wx.BoxSizer(wx.HORIZONTAL)
h_sizer.Add(self.progress_bar, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 20)
self.progress_bar.Hide()
h_sizer.AddStretchSpacer(1)
h_sizer.Add(self.cancel_button, 0, wx.ALIGN_RIGHT | wx.RIGHT, 20)
h_sizer.Add(self.start_button, 0, wx.ALIGN_RIGHT | wx.RIGHT, 20)
h_sizer.Add(self.stop_button, 0, wx.ALIGN_RIGHT | wx.RIGHT, 20)
v_sizer.AddStretchSpacer(1)
v_sizer.Add(h_sizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
h_sizer.Add(self.edit_button, 0, wx.ALIGN_RIGHT | wx.RIGHT, 10)
h_sizer.Add(self.restart_button, 0, wx.ALIGN_RIGHT | wx.RIGHT, 10)
h_sizer.Add(self.close_button, 0, wx.ALIGN_RIGHT | wx.RIGHT, 20)
self.edit_button.Hide()
self.restart_button.Hide()
self.close_button.Hide()
v_sizer.AddStretchSpacer(1)
self.SetSizer(v_sizer)
def button(self, label=None, style=None, event_id=-1):
return wx.Button(
parent=self,
id=event_id,
size=(90, 24),
label=label,
style=style)
def dispatch_click(self, event):
pub.send_message(str(event.GetId()))
event.Skip()
def hide_all_buttons(self):
for button in self.buttons:
button.Hide()
def _load_image(self, img_path, height=70):
return imageutil.resize_bitmap(self, imageutil._load_image(img_path), height)

88
gooey/gui/windows/header.py

@ -1,88 +0,0 @@
'''
Created on Dec 23, 2013
@author: Chris
'''
import wx
from gooey.gui import imageutil, image_repository
from gooey.gui.util import wx_util
PAD_SIZE = 10
class FrameHeader(wx.Panel):
def __init__(self, parent=None, **kwargs):
wx.Panel.__init__(self, parent, **kwargs)
self.SetDoubleBuffered(True)
self._header = None
self._subheader = None
self.settings_img = None
self.running_img = None
self.check_mark = None
self.error_symbol = None
self._init_properties()
self._init_components()
self._do_layout()
@property
def title(self):
return self._header.GetLabel()
@title.setter
def title(self, text):
self._header.SetLabel(text)
@property
def subtitle(self):
return self._subheader.GetLabel()
@subtitle.setter
def subtitle(self, text):
self._subheader.SetLabel(text)
def _init_properties(self):
self.SetBackgroundColour('#ffffff')
self.SetSize((30, 90))
self.SetMinSize((120, 80))
def _init_components(self):
self._header = wx_util.h1(self, '')
self._subheader = wx.StaticText(self, label='')
self.settings_img = self._load_image(image_repository.config_icon, height=79)
self.running_img = self._load_image(image_repository.running_icon, 79)
self.check_mark = self._load_image(image_repository.success_icon, height=75)
self.error_symbol = self._load_image(image_repository.error_icon, height=75)
def _do_layout(self):
vsizer = wx.BoxSizer(wx.VERTICAL)
sizer = wx.BoxSizer(wx.HORIZONTAL)
headings_sizer = self.build_heading_sizer()
sizer.Add(headings_sizer, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_HORIZONTAL | wx.EXPAND | wx.LEFT, PAD_SIZE)
sizer.Add(self.settings_img, 0, wx.ALIGN_RIGHT | wx.EXPAND | wx.RIGHT, PAD_SIZE)
sizer.Add(self.running_img, 0, wx.ALIGN_RIGHT | wx.EXPAND | wx.RIGHT, PAD_SIZE)
sizer.Add(self.check_mark, 0, wx.ALIGN_RIGHT | wx.EXPAND | wx.RIGHT, PAD_SIZE)
sizer.Add(self.error_symbol, 0, wx.ALIGN_RIGHT | wx.EXPAND | wx.RIGHT, PAD_SIZE)
self.running_img.Hide()
self.check_mark.Hide()
self.error_symbol.Hide()
vsizer.Add(sizer, 1, wx.EXPAND)
self.SetSizer(vsizer)
def _load_image(self, img_path, height=70):
return imageutil.resize_bitmap(self, imageutil._load_image(img_path), height)
def build_heading_sizer(self):
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.AddStretchSpacer(1)
sizer.Add(self._header, 0)
sizer.Add(self._subheader, 0)
sizer.AddStretchSpacer(1)
return sizer

53
gooey/gui/windows/layouts.py

@ -1,53 +0,0 @@
import wx
from gooey.gui.util import wx_util
from gooey.gui.windows.advanced_config import ConfigPanel
from gooey.gui.windows.sidebar import Sidebar
basic_config = {
'widgets': [{
'type': 'CommandField',
'required': True,
'data': {
'display_name': 'Enter Commands',
'help': 'Enter command line arguments',
'nargs': '',
'commands': '',
'choices': [],
'default': None,
}
}],
}
FLAT = 'standard'
COLUMN = 'column'
class FlatLayout(wx.Panel):
def __init__(self, *args, **kwargs):
super(FlatLayout, self).__init__(*args, **kwargs)
self.SetDoubleBuffered(True)
self.main_content = ConfigPanel(self, opt_cols=3)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.main_content, 3, wx.EXPAND)
self.SetSizer(sizer)
class ColumnLayout(wx.Panel):
def __init__(self, *args, **kwargs):
super(ColumnLayout, self).__init__(*args, **kwargs)
self.SetDoubleBuffered(True)
self.sidebar = Sidebar(self)
self.main_content = ConfigPanel(self, opt_cols=2)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.sidebar, 1, wx.EXPAND)
sizer.Add(wx_util.vertical_rule(self), 0, wx.EXPAND)
sizer.Add(self.main_content, 3, wx.EXPAND)
self.SetSizer(sizer)

52
gooey/gui/windows/runtime_display_panel.py

@ -1,52 +0,0 @@
'''
Created on Dec 23, 2013
@author: Chris
'''
import wx
from gooey.gui.lang import i18n
from gooey.gui.three_to_four import Constants
class RuntimeDisplay(wx.Panel):
'''
Textbox displayed during the client program's execution.
'''
def __init__(self, parent, **kwargs):
wx.Panel.__init__(self, parent, **kwargs)
self._init_properties()
self._init_components()
self._do_layout()
def set_font_style(self, style):
pointsize = self.cmd_textbox.GetFont().GetPointSize()
font = wx.Font(pointsize, style,
Constants.WX_FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False)
self.cmd_textbox.SetFont(font)
def _init_properties(self):
self.SetBackgroundColour('#F0F0F0')
def _init_components(self):
self.text = wx.StaticText(self, label=i18n._("status"))
self.cmd_textbox = wx.TextCtrl(
self, -1, "",
style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH)
def _do_layout(self):
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.AddSpacer(10)
sizer.Add(self.text, 0, wx.LEFT, 30)
sizer.AddSpacer(10)
sizer.Add(self.cmd_textbox, 1, wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, 30)
sizer.AddSpacer(20)
self.SetSizer(sizer)
def append_text(self, txt):
self.cmd_textbox.AppendText(txt)

45
gooey/gui/windows/sidebar.py

@ -1,45 +0,0 @@
import wx
from gooey.gui.pubsub import pub
from gooey.gui import events
from gooey.gui.util import wx_util
class Sidebar(wx.Panel):
def __init__(self, parent, *args, **kwargs):
super(Sidebar, self).__init__(parent, *args, **kwargs)
self.SetDoubleBuffered(True)
self._parent = parent
self._do_layout()
def _do_layout(self):
self.SetDoubleBuffered(True)
self.SetBackgroundColour('#f2f2f2')
self.SetSize((180, 0))
self.SetMinSize((180, 0))
STD_LAYOUT = (0, wx.LEFT | wx.RIGHT | wx.EXPAND, 10)
container = wx.BoxSizer(wx.VERTICAL)
container.AddSpacer(15)
container.Add(wx_util.h1(self, 'Actions'), *STD_LAYOUT)
container.AddSpacer(5)
self.listbox = wx.ListBox(self, -1)
container.Add(self.listbox, 1, wx.LEFT | wx.RIGHT | wx.EXPAND, 10)
container.AddSpacer(20)
self.SetSizer(container)
self.Bind(wx.EVT_LISTBOX, self.selection_change, self.listbox)
def set_list_contents(self, contents):
self.listbox.AppendItems(contents)
self.listbox.SetSelection(0)
def selection_change(self, evt):
pub.send_message(
events.LIST_BOX,
selection=self.listbox.GetItems()[self.listbox.GetSelection()])
evt.Skip()

6
gooey/gui/windows/views.py

@ -1,6 +0,0 @@
CONFIG_SCREEN = 'config'
RUNNING_SCREEN = 'running'
SUCCESS_SCREEN = 'success'
ERROR_SCREEN = 'error'

67
gooey/tests/conftest.py

@ -1,67 +0,0 @@
import argparse
import pytest
@pytest.fixture
def empty_parser():
return argparse.ArgumentParser(description='description')
@pytest.fixture
def complete_parser():
parser = argparse.ArgumentParser(description='description')
parser.add_argument("req1", help='filename help msg') # positional
parser.add_argument("req2", help="Name of the file where you'll save the output") # positional
parser.add_argument('-r', dest="req3", default=10, type=int, help='sets the time to count down from', required=True)
parser.add_argument('--req4', dest="req4", default=10, type=int, help='sets the time to count down from', required=True)
parser.add_argument("-a", "--aa", action="store_true", help="aaa")
parser.add_argument("-b", "--bb", action="store_true", help="bbb")
parser.add_argument('-c', '--cc', action='count')
parser.add_argument("-d", "--dd", action="store_true", help="ddd")
parser.add_argument('-e', '--ee', choices=['yes', 'no'], help='eee')
parser.add_argument("-f", "--ff", default="0000", help="fff")
parser.add_argument("-g", "--gg", action="store_true", help="ggg")
verbosity = parser.add_mutually_exclusive_group()
verbosity.add_argument('-i', '--ii', action="store_true", help="iii")
verbosity.add_argument('-j', '--jj', action="store_true", help="hhh")
return parser
@pytest.fixture
def subparser():
parser = argparse.ArgumentParser(description='qidev')
parser.add_argument('--verbose', help='be verbose', dest='verbose', action='store_true', default=False)
subs = parser.add_subparsers(help='commands', dest='command')
config_parser = subs.add_parser('config', help='configure defaults for qidev')
config_parser.add_argument('field', help='the field to configure', type=str)
config_parser.add_argument('value', help='set field to value', type=str)
# ########################################################
connect_parser = subs.add_parser('connect', help='connect to a robot (ip/hostname)')
connect_parser.add_argument('hostname', help='hostname or IP address of the robot', type=str)
# ########################################################
install_parser = subs.add_parser('install', help='package and install a project directory on a robot')
install_parser.add_argument('path', help='path to the project directory (containing manifest.xml', type=str)
install_parser.add_argument('--ip', nargs='*', type=str, dest='ip', help='specify hostname(es)/IP address(es)')
return parser
@pytest.fixture
def exclusive_group():
parser = argparse.ArgumentParser(description='description')
verbosity = parser.add_mutually_exclusive_group()
verbosity.add_argument('-i', dest="option1", action="store_true", help="iii")
verbosity.add_argument('-j', dest="option2", action="store_true", help="hhh")
mutually_exclusive_group = [mutex_action
for group_actions in parser._mutually_exclusive_groups
for mutex_action in group_actions._group_actions]
return mutually_exclusive_group
@pytest.fixture
def expected_attrs():
return ('program_icon', 'success_icon', 'running_icon',
'loading_icon', 'config_icon', 'error_icon')

58
gooey/tests/test_image_repositoy.py

@ -1,58 +0,0 @@
'''
Image Repository acts as a funky dynamic singlton module.
'''
import os
import pytest
import tempfile
def test_variable_names_are_pushed_to_module_scope(expected_attrs):
'''
The dynamically initialized Globals() should contain the expected images at runtime
'''
from gooey.gui import image_repository
assert all((attr in image_repository.__dict__) for attr in expected_attrs)
def test_patch_returns_error_on_invalid_dir():
'''
patch should explode with a helpful message if it
cannot find the supplied directory
'''
from gooey.gui import image_repository
with pytest.raises(IOError) as kaboom:
image_repository.patch_images('foo/bar/not/a/path')
# our error
assert ' user supplied' in str(kaboom.value)
assert 'foo/bar/not/a/path' in str(kaboom.value)
def test_module_scope_is_updated_on_patch(expected_attrs):
'''
Patch should update the module's globals() on success
'''
from gooey.gui import image_repository
testing_icons = ('config_icon.png', 'success_icon.png')
try:
# setup
make_user_files(*testing_icons)
old_icon = image_repository.config_icon
# load up our new icon(s)
image_repository.patch_images(tempfile.tempdir)
new_icon = image_repository.config_icon
assert old_icon != new_icon
finally:
cleanup_temp(*testing_icons)
# helpers
def make_user_files(*filenames):
for filename in filenames:
with open(os.path.join(tempfile.gettempdir(), filename), 'w') as f:
f.write('temp')
def cleanup_temp(*filenames):
for filename in filenames:
os.remove(os.path.join(tempfile.gettempdir(), filename))

89
gooey/tests/test_presentation.py

@ -1,89 +0,0 @@
import sys
import pytest
import wx
from mock import MagicMock
from gooey.gui.lang import i18n
from gooey.gui.model import MyModel
from gooey.gui.presenter import Presenter
from gooey.gui.util.freeze import get_resource_path
from gooey.python_bindings import config_generator
@pytest.fixture
def build_spec(complete_parser):
return config_generator.create_from_parser(complete_parser, sys.argv[0])
@pytest.fixture
def build_spec_subparser(subparser):
return config_generator.create_from_parser(subparser, sys.argv[0])
@pytest.fixture
def presentation_model(build_spec):
app = wx.App(False)
i18n.load(get_resource_path('languages'), build_spec['language'])
model = MyModel(build_spec)
view = MagicMock()
presentation = Presenter(view, model)
return presentation
@pytest.fixture
def subparser_presentation_model(build_spec_subparser):
app = wx.App(False)
i18n.load(get_resource_path('languages'), 'english')
model = MyModel(build_spec_subparser)
view = MagicMock()
presentation = Presenter(view, model)
return presentation
# ----------------------------
# Tests #
# ----------------------------
def test_presentation_init(presentation_model):
'''Sanity check that the primary fields are set on init '''
presentation = presentation_model
presentation.initialize_view()
assert presentation.view.heading_title == presentation.model.heading_title
assert presentation.view.heading_subtitle == presentation.model.heading_subtitle
assert presentation.view.required_section.populate.called
assert presentation.view.optional_section.populate.called
# should not call when not running in column format
assert not presentation.view.set_list_contents.called
def test_subparser_presentation_init_sets_sidebar(subparser_presentation_model):
presentation = subparser_presentation_model
presentation.initialize_view()
# should be called to initialize the sidebar
assert presentation.view.set_list_contents.called
def test_on_start_shows_err_dlg_if_missing_args(presentation_model):
presentation = presentation_model
presentation.initialize_view()
presentation.on_start()
assert presentation.view.show_missing_args_dialog.called
presentation.view.show_missing_args_dialog.reset_mock()
# the inverse:
# fill the missing args
for arg in presentation.model.required_args:
arg.value = 'foo'
# patch the methods we don't need
presentation.client_runner = MagicMock()
presentation.update_model = MagicMock()
presentation.model.build_command_line_string = MagicMock()
presentation.on_start()
# should no longer show the dialog
assert not presentation.view.show_missing_args_dialog.called

227
gooey_config.json

@ -1,227 +0,0 @@
{
"show_advanced": true,
"language": "english",
"manual_start": false,
"optionals_cols": 3,
"required": [
{
"data": {
"nargs": "",
"commands": [],
"display_name": "FileChooser",
"help": "Name of the file you want to process",
"choices": []
},
"type": "FileChooser"
},
{
"data": {
"nargs": "",
"commands": [],
"display_name": "DirectoryChooser",
"help": "Name of the file you want to process",
"choices": []
},
"type": "DirChooser"
},
{
"data": {
"nargs": "",
"commands": [],
"display_name": "FileSaver",
"help": "Name of the file you want to process",
"choices": []
},
"type": "FileSaver"
},
{
"data": {
"nargs": "",
"commands": [],
"display_name": "MultiFileSaver",
"help": "Name of the file you want to process",
"choices": []
},
"type": "MultiFileChooser"
},
{
"data": {
"nargs": "",
"commands": [],
"display_name": "directory",
"help": "Directory to store output",
"choices": []
},
"type": "TextField"
}
],
"requireds_cols": 3,
"show_config": true,
"default_size": [
610,
530
],
"optional": [
{
"data": {
"nargs": "",
"commands": [
"-r",
"--recursive"
],
"display_name": "recursive",
"help": "Recurse into subfolders",
"choices": [
"yes",
"no"
]
},
"type": "Dropdown"
},
{
"data": {
"nargs": "",
"commands": [
"-c",
"--countdown"
],
"display_name": "countdown",
"help": "sets the time to count down from you see its quite simple!",
"choices": []
},
"type": "TextField"
},
{
"data": {
"nargs": "",
"commands": [
"-j",
"--cron-schedule"
],
"display_name": "cron_schedule",
"help": "Set the datetime when the cron should begin",
"choices": []
},
"type": "DateChooser"
},
{
"data": {
"nargs": "",
"commands": [
"-w",
"--writelog"
],
"display_name": "writelog",
"help": "write log to some file or something",
"choices": []
},
"type": "TextField"
},
{
"data": {
"nargs": "",
"commands": [
"-v",
"--verbose"
],
"display_name": "verbose",
"help": null,
"choices": []
},
"type": "Counter",
"choices": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9
]
},
{
"data": [
{
"nargs": "",
"commands": [
"-t",
"--verbozze"
],
"display_name": "verbose",
"help": "Show more details",
"choices": null
},
{
"nargs": "",
"commands": [
"-q",
"--quiet"
],
"display_name": "quiet",
"help": "Only output on error",
"choices": null
}
],
"type": "RadioGroup",
"group_name": "Choose Option"
},
{
"data": {
"nargs": "",
"commands": [
"-s",
"--showtime"
],
"display_name": "showtime",
"help": "display the countdown timer",
"choices": []
},
"type": "CheckBox"
},
{
"data": {
"nargs": "",
"commands": [
"-d",
"--delay"
],
"display_name": "delay",
"help": "Delay execution for a bit",
"choices": []
},
"type": "CheckBox"
},
{
"data": {
"nargs": "",
"commands": [
"-o",
"--obfuscate"
],
"display_name": "obfuscate",
"help": "obfuscate the countdown timer!",
"choices": []
},
"type": "CheckBox"
},
{
"data": {
"nargs": "",
"commands": [
"-e",
"--expandAll"
],
"display_name": "expandAll",
"help": "expand all processes",
"choices": []
},
"type": "CheckBox"
}
],
"program_name": "widget_demo",
"program_description": "Example application to show Gooey's various widgetz",
"target": "python C:\\Users\\Chris\\Dropbox\\pretty_gui\\Gooey\\gooey\\examples\\widget_demo.py"
}

2
pytest.ini

@ -1,2 +0,0 @@
[pytest]
python_files=*unittest*.py

1
version.txt

@ -1 +0,0 @@
0.9.5.2
Loading…
Cancel
Save