forked from marcelstoer/nodemcu-pyflasher
-
Notifications
You must be signed in to change notification settings - Fork 3
/
AppConfigDialog.py
103 lines (79 loc) · 4.08 KB
/
AppConfigDialog.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# coding=utf-8
import wx
# ---------------------------------------------------------------------------
class AppConfigDialog(wx.Dialog):
"""A dynamic input form dialog with cancel/ok buttons. It renders a two-column layout with labels on the left and
input controls on the right. Labels, controls and their default values are derived from the parameters passed to
the constructor.
"""
def __init__(self, app_name, properties_definitions, default_app_properties):
"""Builds the dynamic UI based on the parameters.
:param app_name: Some string literal for the dialog title, expecting app and/or release name
:param properties_definitions: A list of property definitions for the app. Each one is required to have three
attributes: prop (an identifier), type, label
:param default_app_properties: A dictionary with (default) values to assign to UI controls, the key maps to a
prop in the `properties_definitions` param
"""
wx.Dialog.__init__(self, None, title="{0} Configuration".format(app_name),
style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
self.controls = {}
vbox = wx.BoxSizer(wx.VERTICAL)
hbox = wx.BoxSizer(wx.HORIZONTAL)
fgs = wx.FlexGridSizer(len(properties_definitions), 2, 9, 25)
for property_definition in properties_definitions:
identifier = property_definition["prop"]
default_value = default_app_properties[identifier] if default_app_properties and identifier in default_app_properties else None
ctrl_type = property_definition["type"]
if ctrl_type == "number":
ctrl = NumberCtrl(self)
if default_value:
ctrl.SetValue(str(default_value))
elif ctrl_type == "password":
ctrl = wx.TextCtrl(self, style=wx.TE_PASSWORD | wx.TE_PROCESS_ENTER)
ctrl.SetMinSize((300, -1))
if default_value:
ctrl.SetValue(default_value)
elif ctrl_type == "boolean":
ctrl = wx.CheckBox(self)
ctrl.SetValue(default_value)
else:
ctrl = wx.TextCtrl(self)
ctrl.SetMinSize((300, -1))
if default_value:
ctrl.SetValue(default_value)
self.controls[identifier] = ctrl
fgs.Add(wx.StaticText(self, label="{0}:".format(property_definition["label"])))
fgs.Add(ctrl)
fgs.AddGrowableCol(1, 1)
hbox.Add(fgs, flag=wx.ALL | wx.EXPAND, border=10)
btnsizer = wx.StdDialogButtonSizer()
btn = wx.Button(self, wx.ID_OK)
btnsizer.AddButton(btn)
btn = wx.Button(self, wx.ID_CANCEL)
btn.SetHelpText("The Cancel button cancels the dialog. (Cool, huh?)")
btnsizer.AddButton(btn)
btnsizer.Realize()
vbox.Add(hbox, border=10)
vbox.Add(btnsizer, flag=wx.ALIGN_RIGHT)
self.SetSizerAndFit(vbox)
# ----------------------------------------------------------------------
def get_properties(self):
application_properties = {}
for prop, ctrl in self.controls.items():
application_properties[prop] = ctrl.GetValue()
return application_properties
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
class NumberCtrl(wx.TextCtrl):
"""The wxPython wx.lib.masked.NumCtrl has some really odd quirks. It's straight forward to create a more
GUI-friendly version inline."""
def __init__(self, parent):
wx.TextCtrl.__init__(self, parent=parent)
self.Bind(wx.EVT_CHAR, lambda event: self.force_numeric(event))
def force_numeric(self, event):
raw_value = self.GetValue().strip()
keycode = event.GetKeyCode()
if keycode < 255:
if chr(keycode).isdigit() or chr(keycode) == '.' and '.' not in raw_value:
event.Skip()
# ---------------------------------------------------------------------------