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

"""
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