diff --git a/gooey/TODO.txt b/gooey/TODO.txt deleted file mode 100644 index c60df19..0000000 --- a/gooey/TODO.txt +++ /dev/null @@ -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) - - - - - diff --git a/gooey/gui/controller.py b/gooey/gui/controller.py deleted file mode 100644 index c31841c..0000000 --- a/gooey/gui/controller.py +++ /dev/null @@ -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) - diff --git a/gooey/gui/model.py b/gooey/gui/model.py deleted file mode 100644 index c3c1629..0000000 --- a/gooey/gui/model.py +++ /dev/null @@ -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 - - - diff --git a/gooey/gui/presenter.py b/gooey/gui/presenter.py deleted file mode 100644 index 1bf3161..0000000 --- a/gooey/gui/presenter.py +++ /dev/null @@ -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 - - diff --git a/gooey/gui/subpresenter.py b/gooey/gui/subpresenter.py deleted file mode 100644 index bb797d4..0000000 --- a/gooey/gui/subpresenter.py +++ /dev/null @@ -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 - diff --git a/gooey/gui/widgets/__init__.py b/gooey/gui/widgets/__init__.py deleted file mode 100644 index 6bca6f6..0000000 --- a/gooey/gui/widgets/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'Chris' diff --git a/gooey/gui/widgets/calender_dialog.py b/gooey/gui/widgets/calender_dialog.py deleted file mode 100644 index 4b98161..0000000 --- a/gooey/gui/widgets/calender_dialog.py +++ /dev/null @@ -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() - - - diff --git a/gooey/gui/widgets/components.py b/gooey/gui/widgets/components.py deleted file mode 100644 index 7c9f65b..0000000 --- a/gooey/gui/widgets/components.py +++ /dev/null @@ -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) diff --git a/gooey/gui/widgets/widget_pack.py b/gooey/gui/widgets/widget_pack.py deleted file mode 100644 index 0ad1eb2..0000000 --- a/gooey/gui/widgets/widget_pack.py +++ /dev/null @@ -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) diff --git a/gooey/gui/windows/__init__.py b/gooey/gui/windows/__init__.py deleted file mode 100644 index 6bca6f6..0000000 --- a/gooey/gui/windows/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'Chris' diff --git a/gooey/gui/windows/advanced_config.py b/gooey/gui/windows/advanced_config.py deleted file mode 100644 index 2cde317..0000000 --- a/gooey/gui/windows/advanced_config.py +++ /dev/null @@ -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() - diff --git a/gooey/gui/windows/base_window.py b/gooey/gui/windows/base_window.py deleted file mode 100644 index 377b205..0000000 --- a/gooey/gui/windows/base_window.py +++ /dev/null @@ -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 diff --git a/gooey/gui/windows/footer.py b/gooey/gui/windows/footer.py deleted file mode 100644 index c58fe0a..0000000 --- a/gooey/gui/windows/footer.py +++ /dev/null @@ -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) - - - - - - diff --git a/gooey/gui/windows/header.py b/gooey/gui/windows/header.py deleted file mode 100644 index fa17e2d..0000000 --- a/gooey/gui/windows/header.py +++ /dev/null @@ -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 - diff --git a/gooey/gui/windows/layouts.py b/gooey/gui/windows/layouts.py deleted file mode 100644 index 4ee84e5..0000000 --- a/gooey/gui/windows/layouts.py +++ /dev/null @@ -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) - - diff --git a/gooey/gui/windows/runtime_display_panel.py b/gooey/gui/windows/runtime_display_panel.py deleted file mode 100644 index b3c1444..0000000 --- a/gooey/gui/windows/runtime_display_panel.py +++ /dev/null @@ -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) - diff --git a/gooey/gui/windows/sidebar.py b/gooey/gui/windows/sidebar.py deleted file mode 100644 index fc148c6..0000000 --- a/gooey/gui/windows/sidebar.py +++ /dev/null @@ -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() diff --git a/gooey/gui/windows/views.py b/gooey/gui/windows/views.py deleted file mode 100644 index 941e5ce..0000000 --- a/gooey/gui/windows/views.py +++ /dev/null @@ -1,6 +0,0 @@ - - -CONFIG_SCREEN = 'config' -RUNNING_SCREEN = 'running' -SUCCESS_SCREEN = 'success' -ERROR_SCREEN = 'error' diff --git a/gooey/tests/conftest.py b/gooey/tests/conftest.py deleted file mode 100644 index 88782a3..0000000 --- a/gooey/tests/conftest.py +++ /dev/null @@ -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') diff --git a/gooey/tests/test_image_repositoy.py b/gooey/tests/test_image_repositoy.py deleted file mode 100644 index ba764bf..0000000 --- a/gooey/tests/test_image_repositoy.py +++ /dev/null @@ -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)) diff --git a/gooey/tests/test_presentation.py b/gooey/tests/test_presentation.py deleted file mode 100644 index 1bf17e7..0000000 --- a/gooey/tests/test_presentation.py +++ /dev/null @@ -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 - - - - - - - diff --git a/gooey_config.json b/gooey_config.json deleted file mode 100644 index 402d2bc..0000000 --- a/gooey_config.json +++ /dev/null @@ -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" -} diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 5af8ed4..0000000 --- a/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -python_files=*unittest*.py diff --git a/version.txt b/version.txt deleted file mode 100644 index 2d8794b..0000000 --- a/version.txt +++ /dev/null @@ -1 +0,0 @@ -0.9.5.2