mirror of https://github.com/chriskiehl/Gooey.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
334 lines
11 KiB
334 lines
11 KiB
"""
|
|
Houses all the supporting rewx components for
|
|
the main application window.
|
|
"""
|
|
import wx # type: ignore
|
|
from typing_extensions import TypedDict
|
|
|
|
from gooey.gui.components.config import ConfigPage, TabbedConfigPage
|
|
from gooey.gui.components.console import Console
|
|
from gooey.gui.components.mouse import notifyMouseEvent
|
|
from gooey.gui.components.sidebar import Sidebar
|
|
from gooey.gui.components.tabbar import Tabbar
|
|
from gooey.gui.lang.i18n import _
|
|
from gooey.gui.pubsub import pub
|
|
from gooey.gui.state import present_time
|
|
from gooey.gui.three_to_four import Constants
|
|
from gooey.python_bindings import constants
|
|
from rewx import components as c # type: ignore
|
|
from rewx import wsx, mount, update # type: ignore
|
|
from rewx.core import Component, Ref # type: ignore
|
|
from rewx.widgets import set_basic_props # type: ignore
|
|
|
|
|
|
def attach_notifier(parent):
|
|
"""
|
|
Recursively attaches the mouseEvent notifier
|
|
to all elements in the tree
|
|
"""
|
|
parent.Bind(wx.EVT_LEFT_DOWN, notifyMouseEvent)
|
|
for child in parent.Children:
|
|
attach_notifier(child)
|
|
|
|
|
|
class HeaderProps(TypedDict):
|
|
background_color: str
|
|
title: str
|
|
show_title: bool
|
|
subtitle: str
|
|
show_subtitle: bool
|
|
|
|
|
|
class RHeader(Component):
|
|
def __init__(self, props):
|
|
super().__init__(props)
|
|
self.parentRef = Ref()
|
|
|
|
def component_did_mount(self):
|
|
attach_notifier(self.parentRef.instance)
|
|
|
|
def render(self):
|
|
if 'running' not in self.props['image_uri']:
|
|
imageProps = {
|
|
'uri': self.props['image_uri'],
|
|
'size': self.props['image_size'],
|
|
'flag': wx.RIGHT,
|
|
'border': 10}
|
|
else:
|
|
imageProps = {
|
|
'size': self.props['image_size'],
|
|
'flag': wx.RIGHT,
|
|
'border': 10}
|
|
return wsx(
|
|
[c.Block, {'orient': wx.HORIZONTAL,
|
|
'ref': self.parentRef,
|
|
'min_size': (120, self.props['height']),
|
|
'background_color': self.props['background_color']},
|
|
[c.Block, {'orient': wx.VERTICAL,
|
|
'flag': wx.ALIGN_CENTER_VERTICAL | wx.ALL,
|
|
'proportion': 1,
|
|
'border': 10},
|
|
[TitleText, {'label': self.props['title'],
|
|
'show': self.props['show_title'],
|
|
'wx_name': 'header_title'}],
|
|
[c.StaticText, {'label': self.props['subtitle'],
|
|
'show': self.props['show_subtitle'],
|
|
'wx_name': 'header_subtitle'}]],
|
|
[c.StaticBitmap, imageProps]]
|
|
)
|
|
|
|
|
|
|
|
class RFooter(Component):
|
|
def __init__(self, props):
|
|
super().__init__(props)
|
|
self.ref = Ref()
|
|
|
|
def component_did_mount(self):
|
|
"""
|
|
We have to manually wire up LEFT_DOWN handlers
|
|
for every component due to wx limitations.
|
|
See: mouse.py docs for background.
|
|
"""
|
|
block: wx.BoxSizer = self.ref.instance
|
|
attach_notifier(block)
|
|
|
|
def handle(self, btn):
|
|
def inner(*args, **kwargs):
|
|
pub.send_message(btn['id'])
|
|
return inner
|
|
|
|
def render(self):
|
|
return wsx(
|
|
[c.Block, {'orient': wx.VERTICAL,
|
|
'min_size': (30, 53),
|
|
'background_color': self.props['bg_color']},
|
|
[c.Block, {'orient': wx.VERTICAL, 'proportion': 1}],
|
|
[c.Block, {'orient': wx.HORIZONTAL,
|
|
'border': 20,
|
|
'flag': wx.EXPAND | wx.LEFT | wx.RIGHT,
|
|
'ref': self.ref},
|
|
[c.Gauge, {'range': 100,
|
|
'proportion': 1,
|
|
'value': self.props['progress']['value'],
|
|
'show': self.props['progress']['show']}],
|
|
[c.StaticText, {'label': present_time(self.props['timing']),
|
|
'flag': wx.LEFT,
|
|
'wx_name': 'timing',
|
|
'show': self.props['timing']['show'],
|
|
'border': 20}],
|
|
[c.Block, {'orient': wx.HORIZONTAL, 'proportion': 1}],
|
|
*[[c.Button, {**btn,
|
|
'label': _(btn['label_id']),
|
|
'min_size': (90, 23),
|
|
'flag': wx.LEFT,
|
|
'border': 10,
|
|
'on_click': self.handle(btn)
|
|
}]
|
|
for btn in self.props['buttons']]],
|
|
[c.Block, {'orient': wx.VERTICAL, 'proportion': 1}]]
|
|
)
|
|
|
|
|
|
class RNavbar(Component):
|
|
def __init__(self, props):
|
|
super().__init__(props)
|
|
|
|
# if self.buildSpec['navigation'] == constants.TABBED:
|
|
# navigation = Tabbar(self, self.buildSpec, self.configs)
|
|
# else:
|
|
# navigation = Sidebar(self, self.buildSpec, self.configs)
|
|
# if self.buildSpec['navigation'] == constants.HIDDEN:
|
|
# navigation.Hide()
|
|
def render(self):
|
|
return wsx(
|
|
|
|
)
|
|
|
|
def VerticalSpacer(props):
|
|
return wsx([c.Block, {'orient': wx.VERTICAL, 'min_size': (-1, props['height'])}])
|
|
|
|
def SidebarControls(props):
|
|
return wsx(
|
|
[c.Block, {'orient': wx.VERTICAL,
|
|
'min_size': (180, 0),
|
|
'size': (180, 0),
|
|
'show': props.get('show', True),
|
|
'flag': wx.EXPAND,
|
|
'proportion': 0,
|
|
'background_color': props['bg_color']},
|
|
[c.Block, {'orient': wx.VERTICAL,
|
|
'min_size': (180, 0),
|
|
'size': (180, 0),
|
|
'flag': wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
|
|
'border': 10,
|
|
'proportion': 1,
|
|
'background_color': props['bg_color']},
|
|
[VerticalSpacer, {'height': 15}],
|
|
[TitleText, {'label': props['label']}],
|
|
[VerticalSpacer, {'height': 5}],
|
|
[c.ListBox, {'choices': props['options'],
|
|
'value': props['activeSelection'],
|
|
'proportion': 1,
|
|
'on_change': props['on_change'],
|
|
'flag': wx.EXPAND}],
|
|
[VerticalSpacer, {'height': 10}]]]
|
|
)
|
|
|
|
|
|
def ProgressSpinner(props):
|
|
return wsx(
|
|
[c.Block, {'flag': wx.EXPAND, 'show': props['show']},
|
|
[c.Gauge, {'flag': wx.EXPAND,
|
|
'value': -1,
|
|
'size': (-1, 4)}],
|
|
[c.StaticLine, {'style': wx.LI_HORIZONTAL,
|
|
'flag': wx.EXPAND}]]
|
|
)
|
|
|
|
|
|
def ErrorWarning(props):
|
|
return wsx(
|
|
[c.Block, {'orient': wx.HORIZONTAL,
|
|
'background_color': '#fdeded',
|
|
'style': wx.SIMPLE_BORDER,
|
|
'flag': wx.EXPAND | wx.ALL,
|
|
'proportion': 0,
|
|
'border': 5,
|
|
'min_size': (-1, 45),
|
|
'show': props.get('show', True)},
|
|
[c.StaticBitmap, {'size': (24, 24),
|
|
'flag': wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL,
|
|
'border': 6,
|
|
'uri': props['uri']}],
|
|
[c.StaticText, {'label': 'Whoops! You have some errors which must be corrected',
|
|
'flag': wx.ALIGN_CENTER_VERTICAL}]]
|
|
)
|
|
|
|
def RSidebar(props):
|
|
return wsx(
|
|
[c.Block, {'orient': wx.HORIZONTAL,
|
|
'show': props.get('show', True),
|
|
'flag': props['flag'],
|
|
'proportion': props['proportion'],
|
|
'ref': props['ref']},
|
|
[SidebarControls, {**props, 'show': props['show_sidebar']}],
|
|
[c.StaticLine, {'style': wx.LI_VERTICAL,
|
|
'flag': wx.EXPAND,
|
|
'min_size': (1, -1)}],
|
|
*[[TabbedConfigPage if props['tabbed_groups'] else ConfigPage,
|
|
{'flag': wx.EXPAND,
|
|
'proportion': 3,
|
|
'config': config,
|
|
'show': i == props['activeSelection']}]
|
|
for i, config in enumerate(props['config'].values())]
|
|
]
|
|
)
|
|
|
|
|
|
def RTabbedLayout(props):
|
|
return wsx(
|
|
[c.Notebook, {'flag': wx.EXPAND | wx.ALL,
|
|
'show': props.get('show', True),
|
|
'proportion': 1,
|
|
'on_change': props['on_change'],
|
|
'ref': props['ref']},
|
|
*[[c.NotebookItem,
|
|
{'title': props['options'][i], 'selected': props['activeSelection'] == i},
|
|
[TabbedConfigPage if props['tabbed_groups'] else ConfigPage,
|
|
{'flag': wx.EXPAND,
|
|
'proportion': 3,
|
|
'config': config,
|
|
'show': i == props['activeSelection']}]]
|
|
for i, config in enumerate(props['config'].values())]]
|
|
)
|
|
|
|
|
|
|
|
def layout_choose():
|
|
def buildNavigation(self):
|
|
"""
|
|
Chooses the appropriate layout navigation component based on user prefs
|
|
"""
|
|
if self.buildSpec['navigation'] == constants.TABBED:
|
|
navigation = Tabbar(self, self.buildSpec, self.configs)
|
|
else:
|
|
navigation = Sidebar(self, self.buildSpec, self.configs)
|
|
if self.buildSpec['navigation'] == constants.HIDDEN:
|
|
navigation.Hide()
|
|
return navigation
|
|
|
|
|
|
def buildConfigPanels(self, parent):
|
|
page_class = TabbedConfigPage if self.buildSpec['tabbed_groups'] else ConfigPage
|
|
|
|
return [page_class(parent, widgets, self.buildSpec)
|
|
for widgets in self.buildSpec['widgets'].values()]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TitleText(Component):
|
|
def __init__(self, props):
|
|
super().__init__(props)
|
|
self.ref = Ref()
|
|
|
|
def component_did_mount(self):
|
|
text: wx.StaticText = self.ref.instance
|
|
font_size = text.GetFont().GetPointSize()
|
|
text.SetFont(wx.Font(
|
|
int(font_size * 1.2),
|
|
wx.FONTFAMILY_DEFAULT,
|
|
Constants.WX_FONTSTYLE_NORMAL,
|
|
wx.FONTWEIGHT_BOLD,
|
|
False
|
|
))
|
|
|
|
def render(self):
|
|
return wsx([c.StaticText, {**self.props, 'label': self.props['label'], 'ref': self.ref}])
|
|
|
|
|
|
##
|
|
## REWX definitions:
|
|
##
|
|
|
|
@mount.register(ConfigPage) # type: ignore
|
|
def config(element, parent):
|
|
return update(element, ConfigPage(parent, element['props']['config'], {'contents': []}))
|
|
|
|
@update.register(ConfigPage) # type: ignore
|
|
def config(element, instance: ConfigPage):
|
|
set_basic_props(instance, element['props'])
|
|
return instance
|
|
|
|
@mount.register(TabbedConfigPage) # type: ignore
|
|
def tabbedconfig(element, parent):
|
|
return update(element, TabbedConfigPage(parent, element['props']['config'], {'contents': []}))
|
|
|
|
@update.register(TabbedConfigPage) # type: ignore
|
|
def tabbedconfig(element, instance: TabbedConfigPage):
|
|
set_basic_props(instance, element['props'])
|
|
return instance
|
|
|
|
@mount.register(Console) # type: ignore
|
|
def console(element, parent):
|
|
return update(element, Console(parent, element['props']))
|
|
|
|
@update.register(Console) # type: ignore
|
|
def console(element, instance: Console):
|
|
set_basic_props(instance, element['props'])
|
|
if 'show' in element['props']:
|
|
instance.Show(element['props']['show'])
|
|
return instance
|
|
|