diff --git a/gooey/gui/application.py b/gooey/gui/application.py new file mode 100644 index 0000000..e87acd0 --- /dev/null +++ b/gooey/gui/application.py @@ -0,0 +1,54 @@ +import itertools +import wx +import os +import sys +import json +import argparse + +from functools import partial + +from gooey.gui.lang import i18n +from gooey.gui.windows.base_window import BaseWindow +from gooey.gui.windows.advanced_config import AdvancedConfigPanel + + +def run(build_spec=None): + if not build_spec: + if len(sys.argv) > 1: + parser = argparse.ArgumentParser(description='Gooey turns your command line programs into beautiful, user friendly GUIs') + parser.add_argument('file', help='Path to the configuration file for Gooey. We need this to run! :) ') + args = parser.parse_args() + gooey_config = args.file + else: + local_files = os.listdir(os.getcwd()) + if 'gooey_config.json' not in local_files: + print "Bugger! gooey_config.json not found!" + sys.exit(1) + gooey_config = os.path.join(os.getcwd(), 'gooey_config.json') + + if not os.path.exists(gooey_config): + raise IOError('Gooey Config not found') + + with open(gooey_config, 'r') as f: + build_spec = json.load(f) + + app = wx.App(False) + + i18n.load(build_spec['language']) + + BodyPanel = partial(AdvancedConfigPanel, build_spec=build_spec) + + frame = BaseWindow(BodyPanel, build_spec) + + frame.Show(True) + app.MainLoop() + + + + + + + + +if __name__ == '__main__': + run() diff --git a/gooey/gui/component_builder.py b/gooey/gui/component_builder.py index 45d5daf..05c9e07 100644 --- a/gooey/gui/component_builder.py +++ b/gooey/gui/component_builder.py @@ -1,6 +1,6 @@ import itertools -from gooey.gui.widgets import components2 +from gooey.gui.widgets import components class ComponentBuilder(object): @@ -13,8 +13,8 @@ class ComponentBuilder(object): optionals = self.build_widget(_optional_specs) if _optional_specs else None if _optional_specs: - self.flags = [widget for widget in optionals if isinstance(widget, components2.CheckBox)] - self.general_options = [widget for widget in optionals if not isinstance(widget, components2.CheckBox)] + self.flags = [widget for widget in optionals if isinstance(widget, components.CheckBox)] + self.general_options = [widget for widget in optionals if not isinstance(widget, components.CheckBox)] else: self.flags = [] self.general_options = [] @@ -25,7 +25,7 @@ class ComponentBuilder(object): widget_type = spec['type'] properties = spec['data'] - Component = getattr(components2, widget_type) + Component = getattr(components, widget_type) assembled_widgets.append(Component(data=properties)) return assembled_widgets diff --git a/gooey/gui/controller.py b/gooey/gui/controller.py index da3e688..e81d263 100644 --- a/gooey/gui/controller.py +++ b/gooey/gui/controller.py @@ -4,13 +4,11 @@ Created on Dec 22, 2013 @author: Chris ''' -import subprocess -import sys -from multiprocessing.dummy import Pool, Process -import time -import platform import wx +import sys +import subprocess +from multiprocessing.dummy import Pool from gooey.gui.lang import i18n @@ -28,8 +26,8 @@ class Controller(object): def __init__(self, base_frame, build_spec): ''' - :param base_frame: BaseWindow - :param build_spec: Json + :type base_frame: BaseWindow + :type build_spec: dict ''' self.core_gui = base_frame self.build_spec = build_spec diff --git a/gooey/gui/widgets/components2.py b/gooey/gui/widgets/components.py similarity index 96% rename from gooey/gui/widgets/components2.py rename to gooey/gui/widgets/components.py index 281e7ae..f990d5c 100644 --- a/gooey/gui/widgets/components2.py +++ b/gooey/gui/widgets/components.py @@ -1,4 +1,4 @@ -import time + from gooey.gui.widgets import widget_pack __author__ = 'Chris' @@ -23,7 +23,6 @@ class BaseGuiComponent(object): # used to throttle resizing (to avoid widget jiggle) # TODO: figure out anti-jiggle technology - # self.last_update = time.time() # self.event_stack = [] def build(self, parent): diff --git a/gooey/gui/windows/advanced_config.py b/gooey/gui/windows/advanced_config.py index 309a57a..4b8b17f 100644 --- a/gooey/gui/windows/advanced_config.py +++ b/gooey/gui/windows/advanced_config.py @@ -4,6 +4,7 @@ Created on Dec 28, 2013 @author: Chris """ from itertools import chain +import itertools import wx from wx.lib.scrolledpanel import ScrolledPanel @@ -15,6 +16,7 @@ from gooey.gui import styling PADDING = 10 + class AdvancedConfigPanel(ScrolledPanel, OptionReader): """ Abstract class for the Footer panels. @@ -26,7 +28,7 @@ class AdvancedConfigPanel(ScrolledPanel, OptionReader): self.SetDoubleBuffered(True) - self._action_groups = build_spec + self._build_spec = build_spec self._positionals = build_spec.get('required', None) self.components = component_builder.ComponentBuilder(build_spec) @@ -67,11 +69,8 @@ class AdvancedConfigPanel(ScrolledPanel, OptionReader): container.Add(styling.HorizontalRule(self), *STD_LAYOUT) container.AddSpacer(20) - self.CreateComponentGrid(container, self.components.general_options, cols=2) - self.CreateComponentGrid(container, self.components.flags, cols=3) - # container.Add(general_opts_grid, *STD_LAYOUT) - # container.AddSpacer(30) - # container.Add(flag_grids, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, PADDING) + self.CreateComponentGrid(container, self.components.general_options, cols=self._build_spec['optionals_cols']) + self.CreateComponentGrid(container, self.components.flags, cols=self._build_spec['optionals_cols']) self.SetSizer(container) @@ -83,10 +82,9 @@ class AdvancedConfigPanel(ScrolledPanel, OptionReader): sizer.AddSpacer(8) def CreateComponentGrid(self, parent_sizer, components, cols=2): - rows = [components[i:i+cols] for i in range(0, len(components), cols)] - for row in rows: + for row in self.chunk(components, cols): hsizer = wx.BoxSizer(wx.HORIZONTAL) - for widget in row: + for widget in filter(None, row): hsizer.Add(widget.build(self), 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 10) # hsizer.FitInside(parent_sizer) parent_sizer.Add(hsizer, 0, wx.EXPAND) @@ -120,6 +118,11 @@ class AdvancedConfigPanel(ScrolledPanel, OptionReader): # Not used anywhere. Keep for debugging? return filter(None, [arg.GetValue() for arg in chain(self.components.general_options, self.components.flags)]) + def chunk(self, iterable, n, fillvalue=None): + "Collect data into fixed-length chunks or blocks" + # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx + args = [iter(iterable)] * n + return itertools.izip_longest(fillvalue=fillvalue, *args) if __name__ == '__main__': pass diff --git a/gooey/gui/windows/base_window.py b/gooey/gui/windows/base_window.py index 66d0e0d..5f4d2b4 100644 --- a/gooey/gui/windows/base_window.py +++ b/gooey/gui/windows/base_window.py @@ -16,10 +16,9 @@ from gooey.gui.windows import footer, header class BaseWindow(wx.Frame): - def __init__(self, BodyPanel, build_spec, params): + def __init__(self, BodyPanel, build_spec): wx.Frame.__init__(self, parent=None, id=-1) - self._params = params self.build_spec = build_spec self._controller = None @@ -40,10 +39,7 @@ class BaseWindow(wx.Frame): self.Bind(wx.EVT_SIZE, self.onResize) def _init_properties(self): - if not self._params['program_name']: - title = os.path.basename(sys.argv[0].replace('.py', '')) - else: - title = self._params['program_name'] + title = self.build_spec['program_name'] self.SetTitle(title) self.SetSize(self.build_spec['default_size']) # self.SetMinSize((400, 300)) diff --git a/gooey/python_bindings/gooey_decorator.py b/gooey/python_bindings/gooey_decorator.py index 93a3d7c..f7aa66b 100644 --- a/gooey/python_bindings/gooey_decorator.py +++ b/gooey/python_bindings/gooey_decorator.py @@ -45,18 +45,18 @@ done. ''' +import wx import os +import sys +import atexit import tempfile -import wx import source_parser -import atexit -from functools import partial -from gooey.gui.lang import i18n + +from gooey.gui import application from gooey.gui.windows import layouts from gooey.python_bindings import argparse_to_json - def Gooey(f=None, advanced=True, language='english', show_config=True, program_name=None, program_description=None): @@ -93,54 +93,30 @@ def Gooey(f=None, advanced=True, # Must be called before anything else app = wx.App(False) - i18n.load(language) - - # load gui components after loading the language pack - from gooey.gui.client_app import ClientApp - from gooey.gui.client_app import EmptyClientApp - from gooey.gui.windows.base_window import BaseWindow - from gooey.gui.windows.advanced_config import AdvancedConfigPanel - from gooey.gui.windows.basic_config_panel import BasicConfigPanel - - meta = { + build_spec = { + 'language': language, 'target': run_cmd, - 'program_name': program_name, + 'program_name': program_name or os.path.basename(sys.argv[0].replace('.py', '')), 'program_description': program_description or '', 'show_config': show_config, 'show_advanced': advanced, 'default_size': (610, 530), 'requireds_cols': 1, - 'optionals_cols': 2, + 'optionals_cols': 4, 'manual_start': False } if show_config: parser = get_parser(main_module_path) - meta['program_description'] = parser.description or program_description - - client_app = ClientApp(parser, payload) - - if advanced: - build_spec = dict(meta.items() + argparse_to_json.convert(parser).items()) - BodyPanel = partial(AdvancedConfigPanel, build_spec=build_spec) - else: - build_spec = dict(meta.items() + layouts.basic_config.items()) - BodyPanel = partial(AdvancedConfigPanel, build_spec=build_spec) - # User doesn't want to display configuration screen - # Just jump straight to the run panel - else: - build_spec = dict(meta.items() + layouts.basic_config.items()) - build_spec['manual_start'] = True - BodyPanel = partial(AdvancedConfigPanel, build_spec=build_spec) - client_app = EmptyClientApp(payload) + build_spec['program_description'] = parser.description or program_description + layout_data = argparse_to_json.convert(parser) if advanced else layouts.basic_config.items() + build_spec.update(layout_data) - frame = BaseWindow(BodyPanel, build_spec, params) + else: + build_spec['manual_start'] = True - if not show_config: - frame.ManualStart() - frame.Show(True) - app.MainLoop() + application.run(build_spec) inner.__name__ = payload.__name__ return inner