Browse Source

Decoupling views

pull/150/head
chriskiehl 9 years ago
parent
commit
6c4c087f7a
9 changed files with 541 additions and 406 deletions
  1. 283
      gooey/gui/widgets/choosers.py
  2. 162
      gooey/gui/widgets/components.py
  3. 124
      gooey/gui/widgets/widget_pack.py
  4. 94
      gooey/gui/windows/advanced_config.py
  5. 136
      gooey/gui/windows/base_window.py
  6. 37
      gooey/gui/windows/footer.py
  7. 87
      gooey/gui/windows/header.py
  8. 9
      gooey/gui/windows/layouts.py
  9. 15
      gooey/gui/windows/runtime_display_panel.py

283
gooey/gui/widgets/choosers.py

@ -1,143 +1,140 @@
from gooey.gui.lang import i18n
__author__ = 'Chris'
import wx
from gooey.gui.util import wx_util
from gooey.gui.widgets.calender_dialog import CalendarDlg
class AbstractChooser(object):
def __init__(self, data):
self.data = data
# parent
self.panel = None
self.button_text = i18n._('browse')
# Widgets
self.title = None
self.help_msg = None
self.text_box = None
self.button = None
self.panel = None
def build(self, parent):
return self.do_layout(parent)
def do_layout(self, parent):
self.panel = wx.Panel(parent)
self.panel.SetDoubleBuffered(True)
self.title = self.CreateNameLabelWidget(self.panel)
self.help_msg = self.CreateHelpMsgWidget(self.panel)
self.text_box = wx.TextCtrl(self.panel)
self.button = wx.Button(self.panel, label=self.button_text, size=(73, 23))
vertical_container = wx.BoxSizer(wx.VERTICAL)
widget_sizer = wx.BoxSizer(wx.HORIZONTAL)
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)
widget_sizer.Add(self.text_box, 1, wx.EXPAND)
widget_sizer.AddSpacer(10)
widget_sizer.Add(self.button, 0)
vertical_container.Add(widget_sizer, 0, wx.EXPAND)
self.panel.SetSizer(vertical_container)
self.panel.Bind(wx.EVT_SIZE, self.OnResize)
self.panel.Bind(wx.EVT_BUTTON, self.on_button, self.button)
return self.panel
def CreateHelpMsgWidget(self, parent):
base_text = wx.StaticText(parent, label=self.data['help_msg'])
# if self.data['nargs']:
# base_text.SetLabelText(base_text.GetLabelText() + self.CreateNargsMsg(action))
wx_util.dark_grey(base_text)
return base_text
def CreateNameLabelWidget(self, parent):
label = self.data['title'].title()
text = wx.StaticText(parent, label=label)
wx_util.make_bold(text)
return text
def OnResize(self, evt):
if self.help_msg is None:
return
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 on_button(self, evt):
raise NotImplementedError
class FileChooser(AbstractChooser):
def __init__(self, data):
AbstractChooser.__init__(self, data)
def on_button(self, evt):
dlg = wx.FileDialog(self.panel, style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
result = (dlg.GetPath()
if dlg.ShowModal() == wx.ID_OK
else None)
if result:
self.text_box.SetLabelText(result)
class DirectoryChooser(AbstractChooser):
def __init__(self, data):
AbstractChooser.__init__(self, data)
def on_button(self, evt):
dlg = wx.DirDialog(self.panel, 'Select directory', style=wx.DD_DEFAULT_STYLE)
result = (dlg.GetPath()
if dlg.ShowModal() == wx.ID_OK
else None)
if result:
self.text_box.SetLabelText(result)
class CalendarChooser(AbstractChooser):
def __init__(self, data):
AbstractChooser.__init__(self, data)
self.button_text = 'Choose Date'
def on_button(self, evt):
dlg = CalendarDlg(self.panel)
dlg.ShowModal()
if dlg.GetPath():
self.text_box.SetLabelText(dlg.GetPath())
# import wx
#
# from gooey.gui.lang import i18n
# from gooey.gui.util import wx_util
# from gooey.gui.widgets.calender_dialog import CalendarDlg
#
#
# class AbstractChooser(object):
# def __init__(self, data):
# self.data = data
#
# # parent
# self.panel = None
#
# self.button_text = i18n._('browse')
#
# # Widgets
# self.title = None
# self.help_msg = None
# self.text_box = None
# self.button = None
# self.panel = None
#
# def build(self, parent):
# return self.do_layout(parent)
#
# def do_layout(self, parent):
# self.panel = wx.Panel(parent)
# self.panel.SetDoubleBuffered(True)
# self.title = self.CreateNameLabelWidget(self.panel)
# self.help_msg = self.CreateHelpMsgWidget(self.panel)
# self.text_box = wx.TextCtrl(self.panel)
# self.button = wx.Button(self.panel, label=self.button_text, size=(73, 23))
#
# vertical_container = wx.BoxSizer(wx.VERTICAL)
# widget_sizer = wx.BoxSizer(wx.HORIZONTAL)
#
# 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)
#
# widget_sizer.Add(self.text_box, 1, wx.EXPAND)
# widget_sizer.AddSpacer(10)
# widget_sizer.Add(self.button, 0)
#
# vertical_container.Add(widget_sizer, 0, wx.EXPAND)
# self.panel.SetSizer(vertical_container)
#
# self.panel.Bind(wx.EVT_SIZE, self.OnResize)
# self.panel.Bind(wx.EVT_BUTTON, self.on_button, self.button)
# return self.panel
#
# def CreateHelpMsgWidget(self, parent):
# base_text = wx.StaticText(parent, label=self.data['help_msg'])
# # if self.data['nargs']:
# # base_text.SetLabelText(base_text.GetLabelText() + self.CreateNargsMsg(action))
# wx_util.dark_grey(base_text)
# return base_text
#
# def CreateNameLabelWidget(self, parent):
# label = self.data['title'].title()
# text = wx.StaticText(parent, label=label)
# wx_util.make_bold(text)
# return text
#
# def OnResize(self, evt):
# if self.help_msg is None:
# return
#
# 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 on_button(self, evt):
# raise NotImplementedError
#
#
#
# class FileChooser(AbstractChooser):
# def __init__(self, data):
# AbstractChooser.__init__(self, data)
#
# def on_button(self, evt):
# dlg = wx.FileDialog(self.panel, style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
# result = (dlg.GetPath()
# if dlg.ShowModal() == wx.ID_OK
# else None)
# if result:
# self.text_box.SetLabelText(result)
#
#
# class DirectoryChooser(AbstractChooser):
# def __init__(self, data):
# AbstractChooser.__init__(self, data)
#
# def on_button(self, evt):
# dlg = wx.DirDialog(self.panel, 'Select directory', style=wx.DD_DEFAULT_STYLE)
# result = (dlg.GetPath()
# if dlg.ShowModal() == wx.ID_OK
# else None)
# if result:
# self.text_box.SetLabelText(result)
#
#
# class CalendarChooser(AbstractChooser):
# def __init__(self, data):
# AbstractChooser.__init__(self, data)
# self.button_text = 'Choose Date'
#
# def on_button(self, evt):
# dlg = CalendarDlg(self.panel)
# dlg.ShowModal()
# if dlg.GetPath():
# self.text_box.SetLabelText(dlg.GetPath())
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#

162
gooey/gui/widgets/components.py

@ -1,3 +1,5 @@
from functools import partial
import wx
from gooey.gui.util import wx_util
@ -5,34 +7,34 @@ from gooey.gui.widgets import widget_pack
class BaseGuiComponent(object):
def __init__(self, data, widget_pack):
widget_class = None
def __init__(self, parent, title, msg):
'''
:param data: field info (title, help, etc..)
:param widget_pack: internal wxWidgets to render
'''
self.data = data
# parent
self.panel = None
self.parent = parent
# Widgets
self.title = None
self.help_msg = None
# Internal WidgetPack
self.widget_pack = widget_pack
# Internal WidgetPack set in subclasses
def build(self, parent):
return self.do_layout(parent)
self.do_layout(parent, title, msg)
def do_layout(self, parent):
def do_layout(self, parent, title, msg):
self.panel = wx.Panel(parent)
self.widget_pack = self.widget_class()
self.title = self.createTitle(self.panel)
self.help_msg = self.createHelpMsgWidget(self.panel)
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.data)
core_widget_set = self.widget_pack.build(self.panel, {})
vertical_container = wx.BoxSizer(wx.VERTICAL)
@ -48,31 +50,30 @@ class BaseGuiComponent(object):
vertical_container.Add(core_widget_set, 0, wx.EXPAND)
self.panel.SetSizer(vertical_container)
# self.panel.Bind(wx.EVT_SIZE, self.onResize)
return self.panel
def createHelpMsgWidget(self, parent):
label_text = (self.formatExtendedHelpMsg(self.data)
if self.data['nargs']
else self.data['help'])
base_text = wx.StaticText(parent, label=label_text or '')
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 createTitle(self, parent):
text = wx.StaticText(parent, label=self.data['display_name'].title())
def format_title(self, parent, title):
text = wx.StaticText(parent, label=title)
wx_util.make_bold(text)
return text
def formatExtendedHelpMsg(self, data):
base_text = data.get('help', '')
nargs = data['nargs']
if isinstance(nargs, int):
return '{base}\n(Note: exactly {nargs} arguments are required)'.format(base=base_text, nargs=nargs)
elif nargs == '+':
return '{base}\n(Note: at least 1 or more arguments are required)'.format(base=base_text)
return base_text
def onResize(self, evt):
# handle internal widgets
# self.panel.Freeze()
@ -97,39 +98,32 @@ class BaseGuiComponent(object):
def GetValue(self):
return self.widget_pack.getValue()
def HasOptionString(self):
return bool(self.widget_pack.option_string)
def _GetWidget(self):
# used only for unittesting
return self.widget_pack.widget
# def HasOptionString(self):
# return bool(self.widget_pack.option_string)
#
# def _GetWidget(self):
# # used only for unittesting
# return self.widget_pack.widget
def __repr__(self):
return self.__class__.__name__
class CheckBox(BaseGuiComponent):
def __init__(self, data, widget_pack=None):
BaseGuiComponent.__init__(self, data, widget_pack)
self.widget = None
# data
self.option_strings = data['commands'][0]
self.default_value = bool(data['default'])
def build(self, parent):
return self.do_layout(parent)
def __init__(self, parent, title, msg):
BaseGuiComponent.__init__(self, parent, title, msg)
def do_layout(self, parent):
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.createTitle(self.panel)
self.help_msg = self.createHelpMsgWidget(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()))
# 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)
@ -144,9 +138,6 @@ class CheckBox(BaseGuiComponent):
self.panel.Bind(wx.EVT_SIZE, self.onResize)
return self.panel
def onSetter(self, evt):
self.GetValue()
def onResize(self, evt):
msg = self.help_msg
container_width, _ = self.panel.Size
@ -157,37 +148,35 @@ class CheckBox(BaseGuiComponent):
msg.Wrap(container_width)
evt.Skip()
def GetValue(self):
return self.option_strings if self.widget.GetValue() else ''
def HasOptionString(self):
return bool(self.option_strings)
def _GetWidget(self):
return self.widget
# def GetValue(self):
# return self.option_strings if self.widget.GetValue() else ''
#
# def HasOptionString(self):
# return bool(self.option_strings)
#
# def _GetWidget(self):
# return self.widget
class RadioGroup(object):
def __init__(self, data):
def __init__(self, parent, title, msg):
self.panel = None
self.data = data
# self.data = data
self.radio_buttons = []
self.option_strings = []
self.help_msgs = []
self.btn_names = []
def build(self, parent):
return self.do_layout(parent)
self.do_layout(parent, title, msg)
def do_layout(self, parent):
def do_layout(self, parent, titles, msgs):
self.panel = wx.Panel(parent)
self.radio_buttons = [wx.RadioButton(self.panel, -1) for _ in self.data]
self.btn_names = [wx.StaticText(self.panel, label=btn_data['display_name'].title()) for btn_data in self.data]
self.help_msgs = [wx.StaticText(self.panel, label=btn_data['help'].title()) for btn_data in self.data]
self.option_strings = [btn_data['commands'] for btn_data in self.data]
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='')
@ -208,10 +197,13 @@ class RadioGroup(object):
self.panel.SetSizer(vertical_container)
self.panel.Bind(wx.EVT_SIZE, self.onResize)
self.panel.Bind(wx.EVT_RADIOBUTTON, self.showz)
return self.panel
def onSetter(self, evt):
self.GetValue()
def showz(self, evt):
print evt
for i in self.radio_buttons:
print i.GetValue()
def onResize(self, evt):
msg = self.help_msgs[0]
@ -237,14 +229,22 @@ class RadioGroup(object):
return self.radio_buttons
FileChooser = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.FileChooserPayload())
MultiFileChooser = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.MultiFileSaverPayload())
DirChooser = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.DirChooserPayload())
FileSaver = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.FileSaverPayload())
DateChooser = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.DateChooserPayload())
TextField = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.TextInputPayload())
CommandField = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.TextInputPayload(no_quoting=True))
Dropdown = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.DropdownPayload())
Counter = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.CounterPayload())
MultiDirChooser = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.MultiDirChooserPayload())
def build_subclass(name, widget_class):
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)
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)
if __name__ == '__main__':
DirChooser = type('DirChooser', (BaseGuiComponent,), {'widget_pack': widget_pack.DirChooserPayload })
d = DirChooser()

124
gooey/gui/widgets/widget_pack.py

@ -25,16 +25,12 @@ class WidgetPack(object):
def build(self, parent, data):
pass
@abstractmethod
def getValue(self):
pass
def onResize(self, evt):
pass
@staticmethod
def get_command(data):
return data['commands'][0] if data['commands'] else ''
return ''
@staticmethod
def disable_quoting(data):
@ -45,7 +41,7 @@ class WidgetPack(object):
class BaseChooser(WidgetPack):
def __init__(self, button_text=''):
def __init__(self):
self.button_text = i18n._('browse')
self.option_string = None
self.parent = None
@ -70,24 +66,24 @@ class BaseChooser(WidgetPack):
parent.Bind(wx.EVT_BUTTON, self.onButton, self.button)
return widget_sizer
def getValue(self):
value = self.text_box.GetValue()
if self.option_string and value:
return '{0} {1}'.format(self.option_string, quote(value))
else:
return quote(value) if value else ''
def onButton(self, evt):
raise NotImplementedError
# def getValue(self):
# value = self.text_box.GetValue()
# if self.option_string and value:
# return '{0} {1}'.format(self.option_string, quote(value))
# else:
# return quote(value) if value else ''
#
# def onButton(self, evt):
# raise NotImplementedError
def __repr__(self):
return self.__class__.__name__
class BaseFileChooser(BaseChooser):
def __init__(self, dialog):
dialog = None
def __init__(self):
BaseChooser.__init__(self)
self.dialog = dialog
def onButton(self, evt):
dlg = self.dialog(self.parent)
@ -103,31 +99,38 @@ class BaseFileChooser(BaseChooser):
class BaseMultiFileChooser(BaseFileChooser):
def __init__(self, dialog):
BaseFileChooser.__init__(self, dialog)
BaseFileChooser.__init__(self)
self.dialog = dialog
def getValue(self):
value = ' '.join(quote(x) for x in self.text_box.GetValue().split(os.pathsep) if x)
if self.option_string and value:
return '{} {}'.format(self.option_string, value)
return value or ''
# def getValue(self):
# value = ' '.join(quote(x) for x in self.text_box.GetValue().split(os.pathsep) if x)
# if self.option_string and value:
# return '{} {}'.format(self.option_string, value)
# return value or ''
def get_path(self, dlg):
return os.pathsep.join(dlg.GetPaths())
class MyMultiDirChooser(MDD.MultiDirDialog):
class MultiFileSaverPayload(BaseMultiFileChooser):
def __init__(self, *args, **kwargs):
super(MyMultiDirChooser, self).__init__(*args, **kwargs)
BaseMultiFileChooser.__init__(self, build_dialog(wx.FD_MULTIPLE, False))
def GetPaths(self):
return self.dirCtrl.GetPaths()
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)
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)
class TextInputPayload(WidgetPack):
@ -148,20 +151,20 @@ class TextInputPayload(WidgetPack):
self.widget.AppendText(safe_default(data, ''))
return self.widget
def getValue(self):
if self.no_quoting:
_quote = lambda value: value
else:
_quote = quote
value = self.widget.GetValue()
if value and self.option_string:
return '{} {}'.format(self.option_string, _quote(value))
else:
return _quote(value) if value else ''
def _SetValue(self, text):
# used for testing
self.widget.SetLabelText(text)
# def getValue(self):
# if self.no_quoting:
# _quote = lambda value: value
# else:
# _quote = quote
# value = self.widget.GetValue()
# if value and self.option_string:
# return '{} {}'.format(self.option_string, _quote(value))
# else:
# return _quote(value) if value else ''
#
# def _SetValue(self, text):
# # used for testing
# self.widget.SetLabelText(text)
class DropdownPayload(WidgetPack):
@ -180,7 +183,7 @@ class DropdownPayload(WidgetPack):
parent=parent,
id=-1,
value=safe_default(data, self.default_value),
choices=data['choices'],
choices=[],
style=wx.CB_DROPDOWN
)
return self.widget
@ -233,15 +236,26 @@ class CounterPayload(WidgetPack):
repeated_args = arg * int(dropdown_value)
return '-' + repeated_args
class DirDialog(wx.DirDialog):
def __init__(self, parent, *args, **kwargs):
wx.DirDialog.__init__(self, parent, 'Select Directory', style=wx.DD_DEFAULT_STYLE)
def safe_default(data, default):
# str(None) is 'None'!? Whaaaaat...?
return str(data['default']) if data['default'] else default
# return str(data['default']) if data['default'] else 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})
FileChooserPayload = partial(BaseFileChooser, dialog=build_dialog(wx.FD_OPEN))
FileSaverPayload = partial(BaseFileChooser, dialog=build_dialog(wx.FD_SAVE, False, defaultFile="Enter Filename"))
MultiFileSaverPayload = partial(BaseMultiFileChooser, dialog=build_dialog(wx.FD_MULTIPLE, False))
DirChooserPayload = partial(BaseFileChooser, dialog=lambda parent: wx.DirDialog(parent, 'Select Directory', style=wx.DD_DEFAULT_STYLE))
DateChooserPayload = partial(BaseFileChooser, dialog=CalendarDlg)
MultiDirChooserPayload = partial(BaseMultiFileChooser, dialog=lambda parent: MyMultiDirChooser(parent, title="Select Directories", defaultPath=os.getcwd(), agwStyle=MDD.DD_MULTIPLE|MDD.DD_DIR_MUST_EXIST))
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)

94
gooey/gui/windows/advanced_config.py

@ -12,13 +12,58 @@ from itertools import chain, izip_longest
from gooey.gui.util import wx_util
from gooey.gui.lang import i18n
from gooey.gui import component_builder
from gooey.gui.option_reader import OptionReader
from gooey.gui.widgets import components
PADDING = 10
class WidgetContainer(wx.Panel):
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 populate(self, widgets):
for w in widgets:
widget_class = getattr(components, w.type)
self.widgets.append(widget_class(self, w.title, w.msg))
self.layout()
def layout(self):
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=2)
self.container.AddSpacer(10)
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"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
class ConfigPanel(ScrolledPanel, OptionReader):
def __init__(self, parent, widgets=None, req_cols=1, opt_cols=3, title=None, **kwargs):
@ -29,11 +74,12 @@ class ConfigPanel(ScrolledPanel, OptionReader):
self.title = title
self.widgets = component_builder.build_components(widgets)
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)
@ -44,41 +90,11 @@ class ConfigPanel(ScrolledPanel, OptionReader):
container = wx.BoxSizer(wx.VERTICAL)
container.AddSpacer(15)
if self.title:
container.Add(wx_util.h0(self, self.title), 0, wx.LEFT | wx.RIGHT, PADDING)
container.AddSpacer(30)
if self.widgets.required_args:
container.Add(wx_util.h1(self, i18n._("required_args_msg")), 0, wx.LEFT | wx.RIGHT, PADDING)
container.AddSpacer(5)
container.Add(wx_util.horizontal_rule(self), *STD_LAYOUT)
container.AddSpacer(20)
self.CreateComponentGrid(container, self.widgets.required_args, cols=self._num_req_cols)
container.AddSpacer(10)
if self.widgets.optional_args:
# container.AddSpacer(10)
container.Add(wx_util.h1(self, i18n._("optional_args_msg")), 0, wx.LEFT | wx.RIGHT, PADDING)
container.AddSpacer(5)
container.Add(wx_util.horizontal_rule(self), *STD_LAYOUT)
container.AddSpacer(20)
self.CreateComponentGrid(container, self.widgets.optional_args, cols=self._num_opt_cols)
container.Add(self.required_section, *STD_LAYOUT)
container.Add(self.optional_section, *STD_LAYOUT)
self.SetSizer(container)
def CreateComponentGrid(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.build(self), 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 10)
# hsizer.FitInside(parent_sizer)
parent_sizer.Add(hsizer, 0, wx.EXPAND)
parent_sizer.AddSpacer(20)
def OnResize(self, evt):
self.SetupScrolling(scroll_x=False, scrollToTop=False)
evt.Skip()
@ -97,11 +113,5 @@ class ConfigPanel(ScrolledPanel, OptionReader):
def GetRequiredArgs(self):
return [arg.GetValue() for arg in self.widgets.required_args]
def chunk(self, iterable, n, fillvalue=None):
"itertools recipe: Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
if __name__ == '__main__':
pass

136
gooey/gui/windows/base_window.py

@ -4,6 +4,7 @@ Created on Jan 19, 2014
'''
import sys
from distutils import config
import wx
from gooey.gui.pubsub import pub
@ -17,13 +18,16 @@ from gooey.gui.windows import footer, header, layouts
class BaseWindow(wx.Frame):
def __init__(self, build_spec):
def __init__(self, build_spec, layout_type):
wx.Frame.__init__(self, parent=None, id=-1)
self.build_spec = build_spec
self.SetDoubleBuffered(True)
# type of gui to render
self.layout_type = layout_type
# Components
self.icon = None
self.head_panel = None
@ -39,28 +43,122 @@ class BaseWindow(wx.Frame):
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
def set_display_font_style(self, style):
'''
wx.FONTFAMILY_DEFAULT Chooses a default font.
wx.FONTFAMILY_DECORATIVE A decorative font.
wx.FONTFAMILY_ROMAN A formal, serif font.
wx.FONTFAMILY_SCRIPT A handwriting font.
wx.FONTFAMILY_SWISS A sans-serif font.
wx.FONTFAMILY_MODERN Usually a fixed pitch font.
wx.FONTFAMILY_TELETYPE A teletype font.
'''
# 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.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 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 _init_components(self):
# init gui
_desc = self.build_spec['program_description']
self.head_panel = header.FrameHeader(
heading=i18n._("settings_title"),
subheading=_desc or '',
parent=self)
self.runtime_display = RuntimeDisplay(self, self.build_spec)
# _desc = self.build_spec['program_description']
# self.head_panel = header.FrameHeader(
# heading=i18n._("settings_title"),
# subheading=_desc or '',
# parent=self)
self.runtime_display = RuntimeDisplay(self)
self.head_panel = header.FrameHeader(parent=self)
self.foot_panel = footer.Footer(self)
if self.build_spec['disable_stop_button']:
self.foot_panel.stop_button.Disable()
else:
self.foot_panel.stop_button.Enable()
# if self.build_spec['disable_stop_button']:
# self.foot_panel.stop_button.Disable()
# else:
# self.foot_panel.stop_button.Enable()
self.panels = [self.head_panel, self.config_panel, self.foot_panel]
@ -69,12 +167,12 @@ class BaseWindow(wx.Frame):
sizer.Add(self.head_panel, 0, wx.EXPAND)
sizer.Add(wx_util.horizontal_rule(self), 0, wx.EXPAND)
if self.build_spec['layout_type'] == 'column':
self.config_panel = layouts.ColumnLayout(self, build_spec=self.build_spec)
sizer.Add(self.config_panel, 1, wx.EXPAND)
if self.layout_type == layouts.COLUMN:
self.config_panel = layouts.ColumnLayout(self)
else:
self.config_panel = layouts.FlatLayout(self, build_spec=self.build_spec)
sizer.Add(self.config_panel, 1, wx.EXPAND)
sizer.Add(self.config_panel, 1, wx.EXPAND)
sizer.Add(self.runtime_display, 1, wx.EXPAND)

37
gooey/gui/windows/footer.py

@ -13,9 +13,14 @@ from gooey.gui.lang import i18n
from gooey.gui import imageutil, events
class AbstractFooter(wx.Panel):
class Footer(wx.Panel):
'''
Abstract class for the Footer panels.
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):
@ -39,6 +44,9 @@ class AbstractFooter(wx.Panel):
pub.subscribe(self.load_view, events.WINDOW_CHANGE)
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))
@ -50,7 +58,13 @@ class AbstractFooter(wx.Panel):
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]
self.buttons = [self.cancel_button, self.start_button,
self.stop_button, self.close_button,
self.restart_button, self.edit_button]
def dispatch_click(self, event):
pub.send_message(str(event.GetId()))
event.Skip()
def _init_pages(self):
def config():
@ -126,24 +140,7 @@ class AbstractFooter(wx.Panel):
return imageutil.resize_bitmap(self, imageutil._load_image(img_path), height)
class Footer(AbstractFooter):
'''
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):
AbstractFooter.__init__(self, parent, **kwargs)
for button in self.buttons:
self.Bind(wx.EVT_BUTTON, self.dispatch_click, button)
def dispatch_click(self, event):
pub.send_message(str(event.GetId()))
event.Skip()

87
gooey/gui/windows/header.py

@ -16,43 +16,56 @@ PAD_SIZE = 10
class FrameHeader(wx.Panel):
def __init__(self, heading, subheading, **kwargs):
wx.Panel.__init__(self, **kwargs)
def __init__(self, parent=None, **kwargs):
wx.Panel.__init__(self, parent, **kwargs)
self.SetDoubleBuffered(True)
self.heading_msg = heading
self.subheading_msg = subheading
self._header = None
self._subheader = None
self._settings_img = None
self._running_img = None
self._check_mark = None
self._error_symbol = None
self.settings_img = None
self.running_img = None
self.check_mark = None
self.error_symbol = None
self.layouts = {}
self._init_properties()
self._init_components(heading, subheading)
# self._init_components(heading, subheading)
self._init_components()
self._init_pages()
self._do_layout()
pub.subscribe(self.load_view, events.WINDOW_CHANGE)
@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, heading, subheading):
self._header = wx_util.h1(self, heading)
self._subheader = wx.StaticText(self, label=subheading)
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)
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):
@ -60,13 +73,13 @@ class FrameHeader(wx.Panel):
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()
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)
@ -86,33 +99,33 @@ class FrameHeader(wx.Panel):
def config():
self._header.SetLabel(self.heading_msg)
self._subheader.SetLabel(self.subheading_msg)
self._settings_img.Show()
self._check_mark.Hide()
self._running_img.Hide()
self._error_symbol.Hide()
self.settings_img.Show()
self.check_mark.Hide()
self.running_img.Hide()
self.error_symbol.Hide()
self.Layout()
def running():
self._header.SetLabel(i18n._("running_title"))
self._subheader.SetLabel(i18n._('running_msg'))
self._check_mark.Hide()
self._settings_img.Hide()
self._running_img.Show()
self._error_symbol.Hide()
self.check_mark.Hide()
self.settings_img.Hide()
self.running_img.Show()
self.error_symbol.Hide()
self.Layout()
def success():
self._header.SetLabel(i18n._('finished_title'))
self._subheader.SetLabel(i18n._('finished_msg'))
self._running_img.Hide()
self._check_mark.Show()
self.running_img.Hide()
self.check_mark.Show()
self.Layout()
def error():
self._header.SetLabel(i18n._('finished_title'))
self._subheader.SetLabel(i18n._('finished_error'))
self._running_img.Hide()
self._error_symbol.Show()
self.running_img.Hide()
self.error_symbol.Show()
self.Layout()
self.layouts = locals()

9
gooey/gui/windows/layouts.py

@ -25,13 +25,18 @@ basic_config = {
}
FLAT = 'standard'
COLUMN = 'column'
class FlatLayout(wx.Panel):
def __init__(self, *args, **kwargs):
self._build_spec = kwargs.pop('build_spec')
self._build_spec = kwargs.pop('build_spec', None)
super(FlatLayout, self).__init__(*args, **kwargs)
self.SetDoubleBuffered(True)
self.main_content = ConfigPanel(self, widgets=self._build_spec['widgets'], opt_cols=self._build_spec['num_optional_cols'])
# self.main_content = ConfigPanel(self, widgets=self._build_spec['widgets'], opt_cols=self._build_spec['num_optional_cols'])
self.main_content = ConfigPanel(self, widgets=self._build_spec['widgets'], opt_cols=3)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.main_content, 3, wx.EXPAND)

15
gooey/gui/windows/runtime_display_panel.py

@ -12,13 +12,19 @@ class RuntimeDisplay(wx.Panel):
'''
Textbox displayed during the client program's execution.
'''
def __init__(self, parent, build_spec, **kwargs):
def __init__(self, parent, **kwargs):
wx.Panel.__init__(self, parent, **kwargs)
self.build_spec = build_spec
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,
wx.FONTWEIGHT_NORMAL, wx.FONTWEIGHT_BOLD, False)
self.cmd_textbox.SetFont(font)
def _init_properties(self):
self.SetBackgroundColour('#F0F0F0')
@ -29,11 +35,6 @@ class RuntimeDisplay(wx.Panel):
self, -1, "",
style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH)
if self.build_spec.get('monospace_display'):
pointsize = self.cmd_textbox.GetFont().GetPointSize()
font = wx.Font(pointsize, wx.FONTFAMILY_MODERN,
wx.FONTWEIGHT_NORMAL, wx.FONTWEIGHT_BOLD, False)
self.cmd_textbox.SetFont(font)
def _do_layout(self):
sizer = wx.BoxSizer(wx.VERTICAL)

Loading…
Cancel
Save