mwxlib 1.6.8__py3-none-any.whl → 1.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mwxlib might be problematic. Click here for more details.
- mwx/bookshelf.py +26 -22
- mwx/controls.py +142 -143
- mwx/framework.py +109 -114
- mwx/graphman.py +90 -89
- mwx/matplot2.py +82 -81
- mwx/matplot2g.py +165 -165
- mwx/matplot2lg.py +57 -57
- mwx/mgplt.py +12 -12
- mwx/nutshell.py +306 -288
- mwx/plugins/ffmpeg_view.py +15 -15
- mwx/plugins/fft_view.py +4 -4
- mwx/plugins/frame_listview.py +26 -26
- mwx/plugins/line_profile.py +1 -1
- mwx/utilus.py +40 -40
- mwx/wxmon.py +20 -20
- mwx/wxpdb.py +46 -46
- mwx/wxwil.py +11 -11
- mwx/wxwit.py +15 -15
- {mwxlib-1.6.8.dist-info → mwxlib-1.7.0.dist-info}/METADATA +1 -1
- mwxlib-1.7.0.dist-info/RECORD +28 -0
- mwxlib-1.6.8.dist-info/RECORD +0 -28
- {mwxlib-1.6.8.dist-info → mwxlib-1.7.0.dist-info}/WHEEL +0 -0
- {mwxlib-1.6.8.dist-info → mwxlib-1.7.0.dist-info}/top_level.txt +0 -0
mwx/controls.py
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
from contextlib import contextmanager
|
|
5
5
|
from itertools import chain
|
|
6
6
|
import io
|
|
7
|
+
import re
|
|
7
8
|
import wx
|
|
8
9
|
import wx.lib.platebtn as pb
|
|
9
10
|
import wx.lib.scrolledpanel as scrolled
|
|
@@ -23,7 +24,7 @@ def _Tip(*tips):
|
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
class Param:
|
|
26
|
-
"""Standard Parameter
|
|
27
|
+
"""Standard Parameter.
|
|
27
28
|
|
|
28
29
|
Args:
|
|
29
30
|
name: label
|
|
@@ -72,7 +73,7 @@ class Param:
|
|
|
72
73
|
})
|
|
73
74
|
self._tooltip = _Tip(handler.__doc__,
|
|
74
75
|
updater.__doc__)
|
|
75
|
-
|
|
76
|
+
|
|
76
77
|
def __str__(self, v=None):
|
|
77
78
|
if v is None:
|
|
78
79
|
v = self.value
|
|
@@ -80,16 +81,16 @@ class Param:
|
|
|
80
81
|
return self.__format(v)
|
|
81
82
|
except (TypeError, ValueError):
|
|
82
83
|
return str(v)
|
|
83
|
-
|
|
84
|
+
|
|
84
85
|
def __int__(self):
|
|
85
86
|
return int(self.value)
|
|
86
|
-
|
|
87
|
+
|
|
87
88
|
def __float__(self):
|
|
88
89
|
return float(self.value)
|
|
89
|
-
|
|
90
|
+
|
|
90
91
|
def __len__(self):
|
|
91
92
|
return len(self.range)
|
|
92
|
-
|
|
93
|
+
|
|
93
94
|
def reset(self, v=None, internal_callback=True):
|
|
94
95
|
"""Reset value when indexed (by knobs) with callback."""
|
|
95
96
|
if v is None:
|
|
@@ -105,32 +106,32 @@ class Param:
|
|
|
105
106
|
self.value = v
|
|
106
107
|
if internal_callback:
|
|
107
108
|
self.callback('control', self)
|
|
108
|
-
|
|
109
|
+
|
|
109
110
|
@property
|
|
110
111
|
def check(self):
|
|
111
112
|
"""A knob check-flag (user defined)."""
|
|
112
113
|
return self.__check
|
|
113
|
-
|
|
114
|
+
|
|
114
115
|
@check.setter
|
|
115
116
|
def check(self, v):
|
|
116
117
|
self.__check = bool(v)
|
|
117
118
|
self.callback('checked', self)
|
|
118
|
-
|
|
119
|
+
|
|
119
120
|
@property
|
|
120
121
|
def name(self):
|
|
121
122
|
return self.__name
|
|
122
|
-
|
|
123
|
+
|
|
123
124
|
@name.setter
|
|
124
125
|
def name(self, v):
|
|
125
126
|
self.__name = v
|
|
126
127
|
for knob in self.knobs:
|
|
127
128
|
knob.update_label()
|
|
128
|
-
|
|
129
|
+
|
|
129
130
|
@property
|
|
130
131
|
def value(self):
|
|
131
132
|
"""Current value := std_value + offset."""
|
|
132
133
|
return self.__value
|
|
133
|
-
|
|
134
|
+
|
|
134
135
|
@value.setter
|
|
135
136
|
def value(self, v):
|
|
136
137
|
if v is None:
|
|
@@ -138,11 +139,11 @@ class Param:
|
|
|
138
139
|
if np.isnan(v) or np.isinf(v): # Skip events for nan and inf.
|
|
139
140
|
self.__value = v
|
|
140
141
|
for knob in self.knobs:
|
|
141
|
-
knob.
|
|
142
|
+
knob.update_control(None)
|
|
142
143
|
return
|
|
143
144
|
elif v == self.__value:
|
|
144
145
|
for knob in self.knobs:
|
|
145
|
-
knob.
|
|
146
|
+
knob.update_control()
|
|
146
147
|
return
|
|
147
148
|
|
|
148
149
|
## If the value is out of range, it will be modified.
|
|
@@ -156,14 +157,14 @@ class Param:
|
|
|
156
157
|
self.__value = self.max
|
|
157
158
|
self.callback('overflow', self)
|
|
158
159
|
for knob in self.knobs:
|
|
159
|
-
knob.
|
|
160
|
+
knob.update_control(valid, notify=True)
|
|
160
161
|
self.callback('notified', self)
|
|
161
|
-
|
|
162
|
+
|
|
162
163
|
@property
|
|
163
164
|
def std_value(self):
|
|
164
165
|
"""A standard value (default None)."""
|
|
165
166
|
return self.__std_value
|
|
166
|
-
|
|
167
|
+
|
|
167
168
|
@std_value.setter
|
|
168
169
|
def std_value(self, v):
|
|
169
170
|
if v is None:
|
|
@@ -171,7 +172,7 @@ class Param:
|
|
|
171
172
|
self.__std_value = v
|
|
172
173
|
for knob in self.knobs:
|
|
173
174
|
knob.update_label()
|
|
174
|
-
|
|
175
|
+
|
|
175
176
|
@property
|
|
176
177
|
def offset(self):
|
|
177
178
|
"""Offset value
|
|
@@ -180,21 +181,21 @@ class Param:
|
|
|
180
181
|
if not np.isnan(self.std_value):
|
|
181
182
|
return self.value - self.std_value
|
|
182
183
|
return self.value
|
|
183
|
-
|
|
184
|
+
|
|
184
185
|
@offset.setter
|
|
185
186
|
def offset(self, v):
|
|
186
187
|
if not np.isnan(self.std_value):
|
|
187
188
|
v += self.std_value
|
|
188
189
|
self.value = v
|
|
189
|
-
|
|
190
|
+
|
|
190
191
|
min = property(lambda self: self.__range[0] if self else nan)
|
|
191
192
|
max = property(lambda self: self.__range[-1] if self else nan)
|
|
192
|
-
|
|
193
|
+
|
|
193
194
|
@property
|
|
194
195
|
def range(self):
|
|
195
196
|
"""Index range."""
|
|
196
197
|
return self.__range
|
|
197
|
-
|
|
198
|
+
|
|
198
199
|
@range.setter
|
|
199
200
|
def range(self, v):
|
|
200
201
|
if v is None:
|
|
@@ -203,7 +204,7 @@ class Param:
|
|
|
203
204
|
self.__range = sorted(v)
|
|
204
205
|
for knob in self.knobs:
|
|
205
206
|
knob.update_range() # list range of related knobs
|
|
206
|
-
|
|
207
|
+
|
|
207
208
|
@property
|
|
208
209
|
def index(self):
|
|
209
210
|
"""A knob index -> value.
|
|
@@ -213,7 +214,7 @@ class Param:
|
|
|
213
214
|
if np.isnan(v) or np.isinf(v):
|
|
214
215
|
return -1
|
|
215
216
|
return int(np.searchsorted(self.range, v))
|
|
216
|
-
|
|
217
|
+
|
|
217
218
|
@index.setter
|
|
218
219
|
def index(self, j):
|
|
219
220
|
if self:
|
|
@@ -222,7 +223,7 @@ class Param:
|
|
|
222
223
|
|
|
223
224
|
|
|
224
225
|
class LParam(Param):
|
|
225
|
-
"""Linear Parameter
|
|
226
|
+
"""Linear Parameter.
|
|
226
227
|
|
|
227
228
|
Args:
|
|
228
229
|
name: label
|
|
@@ -248,15 +249,15 @@ class LParam(Param):
|
|
|
248
249
|
min = property(lambda self: self.__min)
|
|
249
250
|
max = property(lambda self: self.__max)
|
|
250
251
|
step = property(lambda self: self.__step)
|
|
251
|
-
|
|
252
|
+
|
|
252
253
|
def __len__(self):
|
|
253
254
|
return 1 + int(round((self.max - self.min) / self.step)) # includes [min,max]
|
|
254
|
-
|
|
255
|
+
|
|
255
256
|
@property
|
|
256
257
|
def range(self):
|
|
257
258
|
"""Index range."""
|
|
258
259
|
return np.arange(self.min, self.max + self.step, self.step)
|
|
259
|
-
|
|
260
|
+
|
|
260
261
|
@range.setter
|
|
261
262
|
def range(self, v):
|
|
262
263
|
assert v is None or len(v) <= 3, "The range must be of length <= 3 or None"
|
|
@@ -267,7 +268,7 @@ class LParam(Param):
|
|
|
267
268
|
self.__step = v[2] if len(v) > 2 else 1
|
|
268
269
|
for knob in self.knobs:
|
|
269
270
|
knob.update_range() # linear range of related knobs
|
|
270
|
-
|
|
271
|
+
|
|
271
272
|
@property
|
|
272
273
|
def index(self):
|
|
273
274
|
"""A knob index -> value
|
|
@@ -277,7 +278,7 @@ class LParam(Param):
|
|
|
277
278
|
if np.isnan(v) or np.isinf(v):
|
|
278
279
|
return -1
|
|
279
280
|
return int(round((v - self.min) / self.step))
|
|
280
|
-
|
|
281
|
+
|
|
281
282
|
@index.setter
|
|
282
283
|
def index(self, j):
|
|
283
284
|
self.value = self.min + j * self.step
|
|
@@ -288,7 +289,7 @@ class LParam(Param):
|
|
|
288
289
|
## --------------------------------
|
|
289
290
|
|
|
290
291
|
class Knob(wx.Panel):
|
|
291
|
-
"""Parameter controller unit
|
|
292
|
+
"""Parameter controller unit.
|
|
292
293
|
|
|
293
294
|
In addition to direct key input to the textctrl,
|
|
294
295
|
[up][down][wheelup][wheeldown] keys can be used,
|
|
@@ -311,24 +312,24 @@ class Knob(wx.Panel):
|
|
|
311
312
|
def param(self):
|
|
312
313
|
"""Param object referred from knobs."""
|
|
313
314
|
return self.__par
|
|
314
|
-
|
|
315
|
+
|
|
315
316
|
@param.setter
|
|
316
317
|
def param(self, v):
|
|
317
318
|
self.__par.knobs.remove(self)
|
|
318
319
|
self.__par = v
|
|
319
320
|
self.__par.knobs.append(self)
|
|
320
321
|
self.update_range()
|
|
321
|
-
self.
|
|
322
|
-
|
|
322
|
+
self.update_control()
|
|
323
|
+
|
|
323
324
|
@property
|
|
324
325
|
def button(self):
|
|
325
326
|
if isinstance(self._label, pb.PlateButton):
|
|
326
327
|
return self._label
|
|
327
|
-
|
|
328
|
+
|
|
328
329
|
@property
|
|
329
330
|
def control(self):
|
|
330
331
|
return self._ctrl
|
|
331
|
-
|
|
332
|
+
|
|
332
333
|
def __init__(self, parent, param, type=None,
|
|
333
334
|
style=None, cw=-1, lw=-1, tw=-1, h=22, **kwargs):
|
|
334
335
|
wx.Panel.__init__(self, parent, **kwargs)
|
|
@@ -422,14 +423,14 @@ class Knob(wx.Panel):
|
|
|
422
423
|
))
|
|
423
424
|
)
|
|
424
425
|
self.update_range()
|
|
425
|
-
self.
|
|
426
|
+
self.update_control()
|
|
426
427
|
|
|
427
428
|
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
|
|
428
|
-
|
|
429
|
+
|
|
429
430
|
def OnDestroy(self, evt):
|
|
430
431
|
self.__par.knobs.remove(self) # パラメータの関連付けを解除する
|
|
431
432
|
evt.Skip()
|
|
432
|
-
|
|
433
|
+
|
|
433
434
|
def update_range(self):
|
|
434
435
|
"""Called when range is being changed (internal use only)."""
|
|
435
436
|
v = self.__par
|
|
@@ -440,7 +441,7 @@ class Knob(wx.Panel):
|
|
|
440
441
|
self._ctrl.SetStringSelection(str(v))
|
|
441
442
|
else:
|
|
442
443
|
self._ctrl.SetRange(0, len(v)-1) #<wx.Slider> #<wx.SpinButton>
|
|
443
|
-
|
|
444
|
+
|
|
444
445
|
def update_label(self):
|
|
445
446
|
"""Called when label is being changed (internal use only)."""
|
|
446
447
|
v = self.__par
|
|
@@ -451,8 +452,8 @@ class Knob(wx.Panel):
|
|
|
451
452
|
self._label.SetLabel(v.name + t)
|
|
452
453
|
self._label.Refresh()
|
|
453
454
|
self.Refresh()
|
|
454
|
-
|
|
455
|
-
def
|
|
455
|
+
|
|
456
|
+
def update_control(self, valid=True, notify=False):
|
|
456
457
|
"""Called when value is being changed (internal use only)."""
|
|
457
458
|
v = self.__par
|
|
458
459
|
self._ctrl.SetValue(v.index)
|
|
@@ -472,19 +473,17 @@ class Knob(wx.Panel):
|
|
|
472
473
|
else:
|
|
473
474
|
self.set_textcolour('#ff8080') # False: light-red
|
|
474
475
|
self.update_label()
|
|
475
|
-
|
|
476
|
+
|
|
476
477
|
def set_textcolour(self, c):
|
|
477
478
|
if self:
|
|
478
479
|
self._text.BackgroundColour = c
|
|
479
480
|
self._text.Refresh()
|
|
480
|
-
|
|
481
|
-
def
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
with modifiers S- 2x, C- 16x, and M- 256x steps.
|
|
487
|
-
"""
|
|
481
|
+
|
|
482
|
+
def _shift_control(self, evt, bit):
|
|
483
|
+
## Called when a key/mouse wheel is pressed/scrolled (internal use only).
|
|
484
|
+
## In addition to direct key input to the textctrl,
|
|
485
|
+
## [up][down][wheelup][wheeldown] keys can be used,
|
|
486
|
+
## with modifiers S- 2x, C- 16x, and M- 256x steps.
|
|
488
487
|
if bit:
|
|
489
488
|
if evt.ShiftDown(): bit *= 2
|
|
490
489
|
if evt.ControlDown(): bit *= 16
|
|
@@ -494,7 +493,7 @@ class Knob(wx.Panel):
|
|
|
494
493
|
if j != v.index:
|
|
495
494
|
v.index = j
|
|
496
495
|
v.reset(v.value)
|
|
497
|
-
|
|
496
|
+
|
|
498
497
|
def OnScroll(self, evt): #<wx._core.ScrollEvent> #<wx._controls.SpinEvent> #<wx._core.CommandEvent>
|
|
499
498
|
v = self.__par
|
|
500
499
|
j = self._ctrl.GetValue()
|
|
@@ -502,15 +501,15 @@ class Knob(wx.Panel):
|
|
|
502
501
|
v.index = j
|
|
503
502
|
v.reset(v.value)
|
|
504
503
|
evt.Skip()
|
|
505
|
-
|
|
504
|
+
|
|
506
505
|
def OnMouseWheel(self, evt): #<wx._core.MouseEvent>
|
|
507
|
-
self.
|
|
506
|
+
self._shift_control(evt, (1 if evt.WheelRotation > 0 else -1))
|
|
508
507
|
evt.Skip(False)
|
|
509
|
-
|
|
508
|
+
|
|
510
509
|
def OnCtrlKeyDown(self, evt): #<wx._core.KeyEvent>
|
|
511
510
|
key = evt.GetKeyCode()
|
|
512
|
-
if key == wx.WXK_LEFT: return self.
|
|
513
|
-
if key == wx.WXK_RIGHT: return self.
|
|
511
|
+
if key == wx.WXK_LEFT: return self._shift_control(evt, -1)
|
|
512
|
+
if key == wx.WXK_RIGHT: return self._shift_control(evt, 1)
|
|
514
513
|
|
|
515
514
|
def _focus(c):
|
|
516
515
|
if isinstance(c, Knob) and c._ctrl.IsEnabled():
|
|
@@ -521,37 +520,37 @@ class Knob(wx.Panel):
|
|
|
521
520
|
i = ls.index(self)
|
|
522
521
|
if key == wx.WXK_DOWN: return any(_focus(c) for c in ls[i+1:])
|
|
523
522
|
if key == wx.WXK_UP: return any(_focus(c) for c in ls[i-1::-1])
|
|
524
|
-
|
|
523
|
+
|
|
525
524
|
def OnTextKeyUp(self, evt): #<wx._core.KeyEvent>
|
|
526
525
|
evt.Skip()
|
|
527
|
-
|
|
526
|
+
|
|
528
527
|
def OnTextKeyDown(self, evt): #<wx._core.KeyEvent>
|
|
529
528
|
key = evt.GetKeyCode()
|
|
530
|
-
if key == wx.WXK_DOWN: return self.
|
|
531
|
-
if key == wx.WXK_UP: return self.
|
|
529
|
+
if key == wx.WXK_DOWN: return self._shift_control(evt, -1)
|
|
530
|
+
if key == wx.WXK_UP: return self._shift_control(evt, 1)
|
|
532
531
|
if key == wx.WXK_ESCAPE:
|
|
533
532
|
self.__par.reset(self.__par.value, internal_callback=None) # restore value
|
|
534
533
|
evt.Skip()
|
|
535
|
-
|
|
534
|
+
|
|
536
535
|
def OnTextEnter(self, evt): #<wx._core.CommandEvent>
|
|
537
536
|
evt.Skip()
|
|
538
537
|
x = self._text.Value.strip()
|
|
539
538
|
self.__par.reset(x)
|
|
540
|
-
|
|
539
|
+
|
|
541
540
|
def OnTextExit(self, evt): #<wx._core.FocusEvent>
|
|
542
541
|
x = self._text.Value.strip()
|
|
543
542
|
if x != str(self.__par):
|
|
544
543
|
self.__par.reset(x)
|
|
545
544
|
evt.Skip()
|
|
546
|
-
|
|
545
|
+
|
|
547
546
|
def OnCheck(self, evt): #<wx._core.CommandEvent>
|
|
548
547
|
self.__par.check = evt.IsChecked()
|
|
549
548
|
evt.Skip()
|
|
550
|
-
|
|
549
|
+
|
|
551
550
|
def OnPress(self, evt): #<wx._core.CommandEvent>
|
|
552
551
|
self.__par.callback('updated', self.__par)
|
|
553
552
|
evt.Skip()
|
|
554
|
-
|
|
553
|
+
|
|
555
554
|
def Enable(self, p=True):
|
|
556
555
|
self._label.Enable(p)
|
|
557
556
|
self._ctrl.Enable(p)
|
|
@@ -559,7 +558,7 @@ class Knob(wx.Panel):
|
|
|
559
558
|
|
|
560
559
|
|
|
561
560
|
class KnobCtrlPanel(scrolled.ScrolledPanel):
|
|
562
|
-
"""Scrollable Control Panel
|
|
561
|
+
"""Scrollable Control Panel.
|
|
563
562
|
"""
|
|
564
563
|
def __init__(self, *args, **kwargs):
|
|
565
564
|
scrolled.ScrolledPanel.__init__(self, *args, **kwargs)
|
|
@@ -591,11 +590,11 @@ class KnobCtrlPanel(scrolled.ScrolledPanel):
|
|
|
591
590
|
self.Bind(wx.EVT_SCROLLWIN_THUMBRELEASE, self.OnRecalcLayout)
|
|
592
591
|
self.Bind(wx.EVT_MOUSEWHEEL, self.OnRecalcLayout)
|
|
593
592
|
self.Bind(wx.EVT_LEFT_DOWN, self.OnRecalcLayout)
|
|
594
|
-
|
|
593
|
+
|
|
595
594
|
def OnRecalcLayout(self, evt): #<wx._core.ScrollWinEvent>
|
|
596
595
|
self.Layout()
|
|
597
596
|
evt.Skip()
|
|
598
|
-
|
|
597
|
+
|
|
599
598
|
def OnToggleFold(self, evt): #<wx._core.MouseEvent>
|
|
600
599
|
x, y = evt.Position
|
|
601
600
|
for child in self.Sizer.Children: # child <wx._core.SizerItem>
|
|
@@ -610,37 +609,37 @@ class KnobCtrlPanel(scrolled.ScrolledPanel):
|
|
|
610
609
|
self.SendSizeEvent()
|
|
611
610
|
break
|
|
612
611
|
evt.Skip()
|
|
613
|
-
|
|
612
|
+
|
|
614
613
|
## --------------------------------
|
|
615
614
|
## Layout commands and attributes
|
|
616
615
|
## --------------------------------
|
|
617
616
|
@property
|
|
618
617
|
def layout_groups(self):
|
|
619
618
|
return self.__groups
|
|
620
|
-
|
|
619
|
+
|
|
621
620
|
def is_enabled(self, groupid, pred=all):
|
|
622
621
|
return pred(win.Enabled for win in self.__groups[groupid])
|
|
623
|
-
|
|
622
|
+
|
|
624
623
|
def enable(self, groupid, p=True):
|
|
625
624
|
for win in self.__groups[groupid]: # child could be deep nesting
|
|
626
625
|
win.Enable(p)
|
|
627
|
-
|
|
626
|
+
|
|
628
627
|
def is_shown(self, groupid):
|
|
629
628
|
## child = self.Sizer.Children[groupid]
|
|
630
629
|
## return child.IsShown()
|
|
631
630
|
return self.Sizer.IsShown(groupid % len(self.__groups))
|
|
632
|
-
|
|
631
|
+
|
|
633
632
|
def show(self, groupid, p=True):
|
|
634
633
|
"""Show/hide all including the box."""
|
|
635
634
|
## child = self.Sizer.Children[groupid]
|
|
636
635
|
## child.Show(p)
|
|
637
636
|
self.Sizer.Show(groupid % len(self.__groups), p)
|
|
638
637
|
self.Layout()
|
|
639
|
-
|
|
638
|
+
|
|
640
639
|
def is_folded(self, groupid):
|
|
641
640
|
child = self.Sizer.Children[groupid]
|
|
642
641
|
return not any(cc.IsShown() for cc in child.Sizer.Children)
|
|
643
|
-
|
|
642
|
+
|
|
644
643
|
def fold(self, groupid, p=True):
|
|
645
644
|
"""Fold/unfold the boxed group."""
|
|
646
645
|
child = self.Sizer.Children[groupid]
|
|
@@ -648,7 +647,7 @@ class KnobCtrlPanel(scrolled.ScrolledPanel):
|
|
|
648
647
|
for cc in child.Sizer.Children: # child of child <wx._core.SizerItem>
|
|
649
648
|
cc.Show(not p)
|
|
650
649
|
self.Layout()
|
|
651
|
-
|
|
650
|
+
|
|
652
651
|
def layout(self, items, title=None,
|
|
653
652
|
row=0, expand=0, border=2, hspacing=1, vspacing=1,
|
|
654
653
|
show=True, visible=True, align=wx.ALIGN_LEFT, **kwargs):
|
|
@@ -711,24 +710,24 @@ class KnobCtrlPanel(scrolled.ScrolledPanel):
|
|
|
711
710
|
self.Sizer.Fit(self)
|
|
712
711
|
|
|
713
712
|
return self.__groups[-1]
|
|
714
|
-
|
|
713
|
+
|
|
715
714
|
## --------------------------------
|
|
716
715
|
## 外部入出力/クリップボード通信
|
|
717
716
|
## --------------------------------
|
|
718
717
|
@property
|
|
719
718
|
def parameters(self):
|
|
720
719
|
return [p.value for p in self.get_params()]
|
|
721
|
-
|
|
720
|
+
|
|
722
721
|
@parameters.setter
|
|
723
722
|
def parameters(self, v):
|
|
724
723
|
self.set_params(v)
|
|
725
|
-
|
|
724
|
+
|
|
726
725
|
def get_params(self, checked_only=False):
|
|
727
726
|
params = chain(*self.__params)
|
|
728
727
|
if not checked_only:
|
|
729
728
|
return params
|
|
730
729
|
return filter(lambda c: getattr(c, 'check', None), params)
|
|
731
|
-
|
|
730
|
+
|
|
732
731
|
def set_params(self, argv, checked_only=False):
|
|
733
732
|
params = self.get_params(checked_only)
|
|
734
733
|
for p, v in zip(params, argv):
|
|
@@ -738,7 +737,7 @@ class KnobCtrlPanel(scrolled.ScrolledPanel):
|
|
|
738
737
|
p.value = v
|
|
739
738
|
except Exception as e:
|
|
740
739
|
print(f"- Failed to eval {v}:", e)
|
|
741
|
-
|
|
740
|
+
|
|
742
741
|
def reset_params(self, checked_only=False):
|
|
743
742
|
params = self.get_params(checked_only)
|
|
744
743
|
for p in params:
|
|
@@ -748,13 +747,13 @@ class KnobCtrlPanel(scrolled.ScrolledPanel):
|
|
|
748
747
|
## TypeError might occur if p.reset(v) is called with
|
|
749
748
|
## missing 1 required positional argument.
|
|
750
749
|
pass
|
|
751
|
-
|
|
750
|
+
|
|
752
751
|
def copy_to_clipboard(self, checked_only=False):
|
|
753
752
|
params = self.get_params(checked_only)
|
|
754
753
|
text = '\t'.join(str(p) if isinstance(p, Param) else
|
|
755
754
|
str(p.value) for p in params)
|
|
756
755
|
Clipboard.write(text)
|
|
757
|
-
|
|
756
|
+
|
|
758
757
|
def paste_from_clipboard(self, checked_only=False):
|
|
759
758
|
text = Clipboard.read()
|
|
760
759
|
if text:
|
|
@@ -770,7 +769,7 @@ class ControlPanel(CtrlInterface, KnobCtrlPanel):
|
|
|
770
769
|
|
|
771
770
|
|
|
772
771
|
class Clipboard:
|
|
773
|
-
"""Clipboard interface of text and image
|
|
772
|
+
"""Clipboard interface of text and image.
|
|
774
773
|
|
|
775
774
|
This does not work unless wx.App instance exists.
|
|
776
775
|
The clipboard data cannot be transferred unless wx.Frame exists.
|
|
@@ -780,14 +779,14 @@ class Clipboard:
|
|
|
780
779
|
def istrstream():
|
|
781
780
|
with io.StringIO(Clipboard.read()) as f:
|
|
782
781
|
yield f
|
|
783
|
-
|
|
782
|
+
|
|
784
783
|
@contextmanager
|
|
785
784
|
@staticmethod
|
|
786
785
|
def ostrstream():
|
|
787
786
|
with io.StringIO() as f:
|
|
788
787
|
yield f
|
|
789
788
|
Clipboard.write(f.getvalue())
|
|
790
|
-
|
|
789
|
+
|
|
791
790
|
@staticmethod
|
|
792
791
|
def read(verbose=False):
|
|
793
792
|
do = wx.TextDataObject()
|
|
@@ -801,7 +800,7 @@ class Clipboard:
|
|
|
801
800
|
else:
|
|
802
801
|
print("- Unable to open clipboard.")
|
|
803
802
|
return None
|
|
804
|
-
|
|
803
|
+
|
|
805
804
|
@staticmethod
|
|
806
805
|
def write(text, verbose=False):
|
|
807
806
|
do = wx.TextDataObject(str(text))
|
|
@@ -813,7 +812,7 @@ class Clipboard:
|
|
|
813
812
|
print(f"To clipboard:\n{text}")
|
|
814
813
|
else:
|
|
815
814
|
print("- Unable to open clipboard.")
|
|
816
|
-
|
|
815
|
+
|
|
817
816
|
@staticmethod
|
|
818
817
|
def imread(verbose=False):
|
|
819
818
|
do = wx.BitmapDataObject()
|
|
@@ -835,7 +834,7 @@ class Clipboard:
|
|
|
835
834
|
except Exception:
|
|
836
835
|
print("- Contents of the clipboard are not images.")
|
|
837
836
|
return None
|
|
838
|
-
|
|
837
|
+
|
|
839
838
|
@staticmethod
|
|
840
839
|
def imwrite(buf, verbose=False):
|
|
841
840
|
try:
|
|
@@ -929,25 +928,29 @@ class Icon(wx.Bitmap):
|
|
|
929
928
|
key = (key.ConvertToImage()
|
|
930
929
|
.Scale(*size, wx.IMAGE_QUALITY_NEAREST)
|
|
931
930
|
.ConvertToBitmap())
|
|
932
|
-
return key
|
|
931
|
+
return key #<wx.Bitmap>
|
|
933
932
|
if size is None:
|
|
934
933
|
size = (16, 16)
|
|
935
934
|
if key:
|
|
935
|
+
## Returns a bitmap of provided artwork.
|
|
936
|
+
## Note: The result could be a zero-shaped bitmap.
|
|
937
|
+
if re.match("bullet(.*)", key):
|
|
938
|
+
return eval(f"Icon.{key}") # -> Icon.bullet(*v, **kw)
|
|
936
939
|
try:
|
|
937
940
|
art = Icon.custom_images.get(key)
|
|
938
941
|
bmp = art.GetBitmap()
|
|
939
942
|
except Exception:
|
|
940
943
|
art = Icon.provided_arts.get(key)
|
|
941
944
|
bmp = wx.ArtProvider.GetBitmap(art or key, wx.ART_OTHER, size)
|
|
942
|
-
## Note: The result could be a zero-shaped bitmap.
|
|
943
945
|
return bmp
|
|
944
|
-
|
|
946
|
+
if key == '':
|
|
947
|
+
## Returns dummy-sized blank bitmap.
|
|
945
948
|
## Note: A zero-shaped bitmap fails with AssertionError since wx ver 4.1.1.
|
|
946
949
|
bmp = wx.Bitmap(size)
|
|
947
950
|
with wx.MemoryDC(bmp) as dc:
|
|
948
951
|
dc.SetBackground(wx.Brush('black'))
|
|
949
952
|
dc.Clear()
|
|
950
|
-
bmp.SetMaskColour('black')
|
|
953
|
+
bmp.SetMaskColour('black')
|
|
951
954
|
return bmp
|
|
952
955
|
return wx.NullBitmap # The standard wx controls accept this.
|
|
953
956
|
|
|
@@ -971,7 +974,7 @@ class Icon(wx.Bitmap):
|
|
|
971
974
|
return back
|
|
972
975
|
|
|
973
976
|
@staticmethod
|
|
974
|
-
def bullet(colour,
|
|
977
|
+
def bullet(colour, radius=4, size=None, ec=None):
|
|
975
978
|
if not size:
|
|
976
979
|
size = (16, 16)
|
|
977
980
|
bmp = wx.Bitmap(size)
|
|
@@ -1001,7 +1004,7 @@ class Icon(wx.Bitmap):
|
|
|
1001
1004
|
|
|
1002
1005
|
|
|
1003
1006
|
class ClassicButton(wx.Button):
|
|
1004
|
-
"""Classic button
|
|
1007
|
+
"""Classic button.
|
|
1005
1008
|
|
|
1006
1009
|
Args:
|
|
1007
1010
|
label: button label
|
|
@@ -1020,7 +1023,7 @@ class ClassicButton(wx.Button):
|
|
|
1020
1023
|
|
|
1021
1024
|
|
|
1022
1025
|
class Button(pb.PlateButton):
|
|
1023
|
-
"""Flat button
|
|
1026
|
+
"""Flat button.
|
|
1024
1027
|
|
|
1025
1028
|
Args:
|
|
1026
1029
|
label: button label
|
|
@@ -1037,7 +1040,7 @@ class Button(pb.PlateButton):
|
|
|
1037
1040
|
self.SetToolTip(_Tip(handler.__doc__))
|
|
1038
1041
|
if icon:
|
|
1039
1042
|
self.SetBitmap(Icon(icon))
|
|
1040
|
-
|
|
1043
|
+
|
|
1041
1044
|
def SetBitmap(self, bmp):
|
|
1042
1045
|
"""Set the bitmap displayed in the button.
|
|
1043
1046
|
|
|
@@ -1051,7 +1054,7 @@ class Button(pb.PlateButton):
|
|
|
1051
1054
|
|
|
1052
1055
|
|
|
1053
1056
|
class ToggleButton(wx.ToggleButton):
|
|
1054
|
-
"""Togglable button
|
|
1057
|
+
"""Togglable button.
|
|
1055
1058
|
|
|
1056
1059
|
Args:
|
|
1057
1060
|
label: button label
|
|
@@ -1077,7 +1080,7 @@ class ToggleButton(wx.ToggleButton):
|
|
|
1077
1080
|
|
|
1078
1081
|
|
|
1079
1082
|
class TextBox(wx.Control):
|
|
1080
|
-
"""Text control
|
|
1083
|
+
"""Text control.
|
|
1081
1084
|
|
|
1082
1085
|
Args:
|
|
1083
1086
|
label: button label
|
|
@@ -1088,16 +1091,15 @@ class TextBox(wx.Control):
|
|
|
1088
1091
|
**kwargs: keywords for wx.TextCtrl
|
|
1089
1092
|
e.g., value:str
|
|
1090
1093
|
"""
|
|
1091
|
-
Value = property(
|
|
1094
|
+
Value = property( # textctrl value:str
|
|
1092
1095
|
lambda self: self._ctrl.GetValue(),
|
|
1093
|
-
lambda self, v: self._ctrl.SetValue(v)
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
+
lambda self, v: self._ctrl.SetValue(v))
|
|
1097
|
+
|
|
1096
1098
|
value = Value #: internal use only
|
|
1097
|
-
|
|
1099
|
+
|
|
1098
1100
|
button = property(lambda self: self._btn)
|
|
1099
1101
|
control = property(lambda self: self._ctrl)
|
|
1100
|
-
|
|
1102
|
+
|
|
1101
1103
|
def __init__(self, parent, label='', handler=None, updater=None,
|
|
1102
1104
|
icon=None, readonly=False, size=(-1,-1), **kwargs):
|
|
1103
1105
|
wx.Control.__init__(self, parent, size=size, style=wx.BORDER_NONE)
|
|
@@ -1126,14 +1128,14 @@ class TextBox(wx.Control):
|
|
|
1126
1128
|
self._btn.SetToolTip(_Tip(updater.__doc__))
|
|
1127
1129
|
|
|
1128
1130
|
self.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavKey)
|
|
1129
|
-
|
|
1131
|
+
|
|
1130
1132
|
def reset(self, v):
|
|
1131
1133
|
try:
|
|
1132
1134
|
self.Value = v
|
|
1133
1135
|
self._handler(self)
|
|
1134
1136
|
except AttributeError:
|
|
1135
1137
|
pass
|
|
1136
|
-
|
|
1138
|
+
|
|
1137
1139
|
def OnNavKey(self, evt):
|
|
1138
1140
|
if evt.EventObject is self._ctrl:
|
|
1139
1141
|
self.Navigate(evt.Direction)
|
|
@@ -1142,7 +1144,7 @@ class TextBox(wx.Control):
|
|
|
1142
1144
|
|
|
1143
1145
|
|
|
1144
1146
|
class Choice(wx.Control):
|
|
1145
|
-
"""Editable Choice (ComboBox) control
|
|
1147
|
+
"""Editable Choice (ComboBox) control.
|
|
1146
1148
|
|
|
1147
1149
|
Args:
|
|
1148
1150
|
label: button label
|
|
@@ -1157,26 +1159,23 @@ class Choice(wx.Control):
|
|
|
1157
1159
|
If the input item is not found in the choices,
|
|
1158
1160
|
it will be added to the list (unless readonly)
|
|
1159
1161
|
"""
|
|
1160
|
-
Value = property(
|
|
1162
|
+
Value = property( # combobox value:str
|
|
1161
1163
|
lambda self: self._ctrl.GetValue(),
|
|
1162
|
-
lambda self, v: self._ctrl.SetValue(v)
|
|
1163
|
-
|
|
1164
|
-
|
|
1164
|
+
lambda self, v: self._ctrl.SetValue(v))
|
|
1165
|
+
|
|
1165
1166
|
value = Value #: internal use only
|
|
1166
|
-
|
|
1167
|
-
Selection = property(
|
|
1167
|
+
|
|
1168
|
+
Selection = property( # combobox selection:int or NOT_FOUND(-1)
|
|
1168
1169
|
lambda self: self._ctrl.GetSelection(),
|
|
1169
|
-
lambda self, v: self._ctrl.SetSelection(v)
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
Items = property(
|
|
1170
|
+
lambda self, v: self._ctrl.SetSelection(v))
|
|
1171
|
+
|
|
1172
|
+
Items = property( # combobox items:list
|
|
1173
1173
|
lambda self: self._ctrl.GetItems(),
|
|
1174
|
-
lambda self, v: self._ctrl.SetItems(v)
|
|
1175
|
-
|
|
1176
|
-
|
|
1174
|
+
lambda self, v: self._ctrl.SetItems(v))
|
|
1175
|
+
|
|
1177
1176
|
button = property(lambda self: self._btn)
|
|
1178
1177
|
control = property(lambda self: self._ctrl)
|
|
1179
|
-
|
|
1178
|
+
|
|
1180
1179
|
def __init__(self, parent, label='', handler=None, updater=None,
|
|
1181
1180
|
icon=None, readonly=False, size=(-1,-1), **kwargs):
|
|
1182
1181
|
wx.Control.__init__(self, parent, size=size, style=wx.BORDER_NONE)
|
|
@@ -1207,14 +1206,14 @@ class Choice(wx.Control):
|
|
|
1207
1206
|
self._btn.SetToolTip(_Tip(updater.__doc__))
|
|
1208
1207
|
|
|
1209
1208
|
self.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavKey)
|
|
1210
|
-
|
|
1209
|
+
|
|
1211
1210
|
def reset(self, v):
|
|
1212
1211
|
try:
|
|
1213
1212
|
self.Value = v
|
|
1214
1213
|
self._handler(self)
|
|
1215
1214
|
except AttributeError:
|
|
1216
1215
|
pass
|
|
1217
|
-
|
|
1216
|
+
|
|
1218
1217
|
def OnTextEnter(self, evt):
|
|
1219
1218
|
s = evt.String.strip()
|
|
1220
1219
|
if not s:
|
|
@@ -1223,7 +1222,7 @@ class Choice(wx.Control):
|
|
|
1223
1222
|
self._ctrl.Append(s)
|
|
1224
1223
|
self._ctrl.SetStringSelection(s)
|
|
1225
1224
|
evt.Skip()
|
|
1226
|
-
|
|
1225
|
+
|
|
1227
1226
|
def OnNavKey(self, evt):
|
|
1228
1227
|
if evt.EventObject is self._ctrl:
|
|
1229
1228
|
self.Navigate(evt.Direction)
|
|
@@ -1232,7 +1231,7 @@ class Choice(wx.Control):
|
|
|
1232
1231
|
|
|
1233
1232
|
|
|
1234
1233
|
class Indicator(wx.Control):
|
|
1235
|
-
"""Traffic light indicator
|
|
1234
|
+
"""Traffic light indicator.
|
|
1236
1235
|
|
|
1237
1236
|
Args:
|
|
1238
1237
|
colors: list of colors (default is tricolour) cf. wx.ColourDatabase
|
|
@@ -1242,17 +1241,17 @@ class Indicator(wx.Control):
|
|
|
1242
1241
|
@property
|
|
1243
1242
|
def Value(self):
|
|
1244
1243
|
return self.__value
|
|
1245
|
-
|
|
1244
|
+
|
|
1246
1245
|
@Value.setter
|
|
1247
1246
|
def Value(self, v):
|
|
1248
1247
|
self.__value = int(v)
|
|
1249
1248
|
self.Refresh()
|
|
1250
|
-
|
|
1249
|
+
|
|
1251
1250
|
def redesign(self, **kwargs):
|
|
1252
1251
|
"""Update multiple design properties at once.
|
|
1253
1252
|
|
|
1254
1253
|
This method is useful for changing colors, spacing, radius, etc.
|
|
1255
|
-
The best size will be automatically invalidated and
|
|
1254
|
+
The best size will be automatically invalidated and recalculated.
|
|
1256
1255
|
|
|
1257
1256
|
Args:
|
|
1258
1257
|
**kwargs: class attributes, e.g. colors, spacing, radius.
|
|
@@ -1262,14 +1261,14 @@ class Indicator(wx.Control):
|
|
|
1262
1261
|
"""
|
|
1263
1262
|
self.__dict__.update(kwargs)
|
|
1264
1263
|
self.InvalidateBestSize()
|
|
1265
|
-
|
|
1264
|
+
|
|
1266
1265
|
colors = ('green', 'yellow', 'red') # default tricolor style
|
|
1267
1266
|
backgroundColour = 'dark gray'
|
|
1268
1267
|
foregroundColour = 'light gray'
|
|
1269
1268
|
spacing = 7
|
|
1270
1269
|
radius = 4
|
|
1271
1270
|
glow = 0
|
|
1272
|
-
|
|
1271
|
+
|
|
1273
1272
|
def __init__(self, parent, colors=None, value=0,
|
|
1274
1273
|
style=wx.BORDER_NONE, **kwargs):
|
|
1275
1274
|
wx.Control.__init__(self, parent, style=style, **kwargs)
|
|
@@ -1287,15 +1286,15 @@ class Indicator(wx.Control):
|
|
|
1287
1286
|
|
|
1288
1287
|
self.Bind(wx.EVT_SIZE, self.OnSize)
|
|
1289
1288
|
self.Bind(wx.EVT_PAINT, self.OnPaint)
|
|
1290
|
-
|
|
1289
|
+
|
|
1291
1290
|
def DoGetBestSize(self):
|
|
1292
1291
|
N = len(self.colors)
|
|
1293
1292
|
s = self.spacing
|
|
1294
1293
|
return wx.Size((2*s-1)*N+3, 2*s+2)
|
|
1295
|
-
|
|
1294
|
+
|
|
1296
1295
|
def OnSize(self, evt):
|
|
1297
1296
|
self.Refresh()
|
|
1298
|
-
|
|
1297
|
+
|
|
1299
1298
|
def OnPaint(self, evt):
|
|
1300
1299
|
dc = wx.BufferedPaintDC(self)
|
|
1301
1300
|
dc.Clear()
|
|
@@ -1331,7 +1330,7 @@ class Indicator(wx.Control):
|
|
|
1331
1330
|
gc.DrawPath(path)
|
|
1332
1331
|
dc.SetBrush(wx.Brush(name if b else self.foregroundColour))
|
|
1333
1332
|
dc.DrawCircle(x, y, r)
|
|
1334
|
-
|
|
1333
|
+
|
|
1335
1334
|
def blink(self, msec, mask=0):
|
|
1336
1335
|
"""Blinks once for given milliseconds.
|
|
1337
1336
|
|
|
@@ -1350,7 +1349,7 @@ class Indicator(wx.Control):
|
|
|
1350
1349
|
|
|
1351
1350
|
|
|
1352
1351
|
class Gauge(wx.Control):
|
|
1353
|
-
"""Rainbow gauge
|
|
1352
|
+
"""Rainbow gauge.
|
|
1354
1353
|
|
|
1355
1354
|
Args:
|
|
1356
1355
|
range: maximum value
|
|
@@ -1360,21 +1359,21 @@ class Gauge(wx.Control):
|
|
|
1360
1359
|
@property
|
|
1361
1360
|
def Value(self):
|
|
1362
1361
|
return self.__value
|
|
1363
|
-
|
|
1362
|
+
|
|
1364
1363
|
@Value.setter
|
|
1365
1364
|
def Value(self, v):
|
|
1366
1365
|
self.__value = int(v)
|
|
1367
1366
|
self.Refresh()
|
|
1368
|
-
|
|
1367
|
+
|
|
1369
1368
|
@property
|
|
1370
1369
|
def Range(self):
|
|
1371
1370
|
return self.__range
|
|
1372
|
-
|
|
1371
|
+
|
|
1373
1372
|
@Range.setter
|
|
1374
1373
|
def Range(self, v):
|
|
1375
1374
|
self.__range = int(v)
|
|
1376
1375
|
self.Refresh()
|
|
1377
|
-
|
|
1376
|
+
|
|
1378
1377
|
def __init__(self, parent, range=24, value=0,
|
|
1379
1378
|
style=wx.BORDER_NONE, **kwargs):
|
|
1380
1379
|
wx.Control.__init__(self, parent, style=style, **kwargs)
|
|
@@ -1386,10 +1385,10 @@ class Gauge(wx.Control):
|
|
|
1386
1385
|
|
|
1387
1386
|
self.Bind(wx.EVT_SIZE, self.OnSize)
|
|
1388
1387
|
self.Bind(wx.EVT_PAINT, self.OnPaint)
|
|
1389
|
-
|
|
1388
|
+
|
|
1390
1389
|
def OnSize(self, evt):
|
|
1391
1390
|
self.Refresh()
|
|
1392
|
-
|
|
1391
|
+
|
|
1393
1392
|
def OnPaint(self, evt):
|
|
1394
1393
|
dc = wx.BufferedPaintDC(self)
|
|
1395
1394
|
dc.Clear()
|