mwxlib 1.4.20__py3-none-any.whl → 1.5.9__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 +19 -13
- mwx/controls.py +10 -10
- mwx/framework.py +85 -71
- mwx/graphman.py +114 -121
- mwx/matplot2.py +13 -12
- mwx/matplot2g.py +22 -30
- mwx/matplot2lg.py +10 -10
- mwx/mgplt.py +1 -1
- mwx/nutshell.py +116 -97
- mwx/plugins/ffmpeg_view.py +3 -4
- mwx/plugins/fft_view.py +2 -2
- mwx/plugins/frame_listview.py +1 -1
- mwx/testsuite.py +10 -10
- mwx/utilus.py +31 -9
- mwx/wxpdb.py +3 -3
- {mwxlib-1.4.20.dist-info → mwxlib-1.5.9.dist-info}/METADATA +1 -1
- mwxlib-1.5.9.dist-info/RECORD +28 -0
- {mwxlib-1.4.20.dist-info → mwxlib-1.5.9.dist-info}/WHEEL +1 -1
- mwxlib-1.4.20.dist-info/RECORD +0 -28
- {mwxlib-1.4.20.dist-info → mwxlib-1.5.9.dist-info}/top_level.txt +0 -0
mwx/graphman.py
CHANGED
|
@@ -100,8 +100,6 @@ class Thread:
|
|
|
100
100
|
None : {
|
|
101
101
|
'thread_begin' : [ None ], # begin processing
|
|
102
102
|
'thread_end' : [ None ], # end processing
|
|
103
|
-
'thread_quit' : [ None ], # terminated by user
|
|
104
|
-
'thread_error' : [ None ], # failed in error
|
|
105
103
|
},
|
|
106
104
|
})
|
|
107
105
|
|
|
@@ -115,9 +113,7 @@ class Thread:
|
|
|
115
113
|
Allows only this worker (but no other thread) to enter.
|
|
116
114
|
"""
|
|
117
115
|
frame = inspect.currentframe().f_back.f_back
|
|
118
|
-
filename = frame.f_code.co_filename
|
|
119
116
|
name = frame.f_code.co_name
|
|
120
|
-
fname, _ = os.path.splitext(os.path.basename(filename))
|
|
121
117
|
|
|
122
118
|
## Other threads are not allowed to enter.
|
|
123
119
|
ct = threading.current_thread()
|
|
@@ -125,17 +121,22 @@ class Thread:
|
|
|
125
121
|
|
|
126
122
|
## The thread must be activated to enter.
|
|
127
123
|
## assert self.active, f"{self!r} must be activated to enter {name!r}."
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
124
|
+
yield self
|
|
125
|
+
|
|
126
|
+
def enters(self, f):
|
|
127
|
+
"""Decorator to add a one-time handler for the enter event.
|
|
128
|
+
The specified function will be called from the main thread.
|
|
129
|
+
"""
|
|
130
|
+
return self.handler.binds('thread_begin', _F(f))
|
|
131
|
+
|
|
132
|
+
def exits(self, f):
|
|
133
|
+
"""Decorator to add a one-time handler for the exit event.
|
|
134
|
+
The specified function will be called from the main thread.
|
|
135
|
+
"""
|
|
136
|
+
return self.handler.binds('thread_end', _F(f))
|
|
136
137
|
|
|
137
138
|
def wraps(self, f, *args, **kwargs):
|
|
138
|
-
"""Decorator
|
|
139
|
+
"""Decorator for a function that starts a new thread."""
|
|
139
140
|
@wraps(f)
|
|
140
141
|
def _f(*v, **kw):
|
|
141
142
|
return self.Start(f, *v, *args, **kw, **kwargs)
|
|
@@ -186,21 +187,23 @@ class Thread:
|
|
|
186
187
|
@wraps(f)
|
|
187
188
|
def _f(*v, **kw):
|
|
188
189
|
try:
|
|
189
|
-
self.handler
|
|
190
|
+
wx.CallAfter(self.handler, 'thread_begin', self)
|
|
190
191
|
self.result = f(*v, **kw)
|
|
191
192
|
except BdbQuit:
|
|
192
193
|
pass
|
|
193
194
|
except KeyboardInterrupt as e:
|
|
194
|
-
print("- Thread
|
|
195
|
-
except AssertionError as e:
|
|
196
|
-
print("- Thread execution failed:", e)
|
|
195
|
+
print("- Thread terminated by user:", e)
|
|
197
196
|
except Exception as e:
|
|
197
|
+
tbstr = traceback.format_tb(e.__traceback__)
|
|
198
|
+
wx.CallAfter(wx.MessageBox,
|
|
199
|
+
f"{e}\n\n" + tbstr[-1] + f"{type(e).__name__}: {e}",
|
|
200
|
+
f"Error in the thread running {f.__name__!r}\n\n",
|
|
201
|
+
style=wx.ICON_ERROR)
|
|
198
202
|
traceback.print_exc()
|
|
199
|
-
print("- Thread
|
|
200
|
-
self.handler('thread_error', self)
|
|
203
|
+
print("- Thread failed in error:", e)
|
|
201
204
|
finally:
|
|
202
205
|
self.active = 0
|
|
203
|
-
self.handler
|
|
206
|
+
wx.CallAfter(self.handler, 'thread_end', self)
|
|
204
207
|
|
|
205
208
|
if self.running:
|
|
206
209
|
wx.MessageBox("The thread is running (Press [C-g] to quit).",
|
|
@@ -226,11 +229,10 @@ class Thread:
|
|
|
226
229
|
def _stop():
|
|
227
230
|
with wx.BusyInfo("One moment please, "
|
|
228
231
|
"waiting for threads to die..."):
|
|
229
|
-
self.handler('thread_quit', self)
|
|
230
232
|
self.worker.join(1)
|
|
231
233
|
if self.running:
|
|
232
234
|
self.active = 0
|
|
233
|
-
wx.CallAfter(_stop)
|
|
235
|
+
wx.CallAfter(_stop) # main thread で終了させる
|
|
234
236
|
|
|
235
237
|
|
|
236
238
|
class LayerInterface(CtrlInterface):
|
|
@@ -349,10 +351,6 @@ class LayerInterface(CtrlInterface):
|
|
|
349
351
|
|
|
350
352
|
self.handler.append({ # DNA<Layer>
|
|
351
353
|
None : {
|
|
352
|
-
'thread_begin' : [ None ], # begin processing
|
|
353
|
-
'thread_end' : [ None ], # end processing
|
|
354
|
-
'thread_quit' : [ None ], # terminated by user
|
|
355
|
-
'thread_error' : [ None ], # failed in error
|
|
356
354
|
'page_shown' : [ None, _F(self.Draw, show=True) ],
|
|
357
355
|
'page_closed' : [ None, _F(self.Draw, show=False) ],
|
|
358
356
|
'page_hidden' : [ None, _F(self.Draw, show=False) ],
|
|
@@ -448,7 +446,7 @@ class LayerInterface(CtrlInterface):
|
|
|
448
446
|
|
|
449
447
|
Shown = property(
|
|
450
448
|
lambda self: self.IsShown(),
|
|
451
|
-
lambda self,v: self.Show(v))
|
|
449
|
+
lambda self, v: self.Show(v))
|
|
452
450
|
|
|
453
451
|
def IsShown(self):
|
|
454
452
|
"""Return True if the window is physically visible on the screen.
|
|
@@ -465,11 +463,11 @@ class LayerInterface(CtrlInterface):
|
|
|
465
463
|
(override) Show associated pane window.
|
|
466
464
|
Note: This might be called from a thread.
|
|
467
465
|
"""
|
|
468
|
-
wx.CallAfter(self.parent.show_pane, self, show)
|
|
466
|
+
wx.CallAfter(self.parent.show_pane, self, show) # Show pane windows in the main thread.
|
|
469
467
|
|
|
470
468
|
Drawn = property(
|
|
471
469
|
lambda self: self.IsDrawn(),
|
|
472
|
-
lambda self,v: self.Draw(v))
|
|
470
|
+
lambda self, v: self.Draw(v))
|
|
473
471
|
|
|
474
472
|
def IsDrawn(self):
|
|
475
473
|
return any(art.get_visible() for art in self.Arts)
|
|
@@ -503,6 +501,30 @@ class Layer(LayerInterface, KnobCtrlPanel):
|
|
|
503
501
|
LayerInterface.__init__(self, parent, session)
|
|
504
502
|
|
|
505
503
|
|
|
504
|
+
def register(cls, module=None):
|
|
505
|
+
"""Register dummy plug; Add module.Plugin <Layer>.
|
|
506
|
+
"""
|
|
507
|
+
if not module:
|
|
508
|
+
module = inspect.getmodule(cls) # rebase module or __main__
|
|
509
|
+
|
|
510
|
+
if issubclass(cls, LayerInterface):
|
|
511
|
+
cls.__module__ = module.__name__ # __main__ to module
|
|
512
|
+
warn(f"Duplicate iniheritance of LayerInterface by {cls}.")
|
|
513
|
+
module.Plugin = cls
|
|
514
|
+
return cls
|
|
515
|
+
|
|
516
|
+
class _Plugin(LayerInterface, cls):
|
|
517
|
+
def __init__(self, parent, session=None, **kwargs):
|
|
518
|
+
cls.__init__(self, parent, **kwargs)
|
|
519
|
+
LayerInterface.__init__(self, parent, session)
|
|
520
|
+
|
|
521
|
+
_Plugin.__module__ = cls.__module__ = module.__name__
|
|
522
|
+
_Plugin.__name__ = cls.__name__ + str("~")
|
|
523
|
+
_Plugin.__doc__ = cls.__doc__
|
|
524
|
+
module.Plugin = _Plugin
|
|
525
|
+
return _Plugin
|
|
526
|
+
|
|
527
|
+
|
|
506
528
|
class Graph(GraphPlot):
|
|
507
529
|
"""GraphPlot (override) to better make use for graph manager
|
|
508
530
|
|
|
@@ -583,7 +605,7 @@ class MyFileDropLoader(wx.FileDropTarget):
|
|
|
583
605
|
self.loader = loader
|
|
584
606
|
|
|
585
607
|
def OnDropFiles(self, x, y, filenames):
|
|
586
|
-
pos = self.view.ScreenPosition + (x,y)
|
|
608
|
+
pos = self.view.ScreenPosition + (x, y)
|
|
587
609
|
paths = []
|
|
588
610
|
for fn in filenames:
|
|
589
611
|
name, ext = os.path.splitext(fn)
|
|
@@ -660,7 +682,7 @@ class Frame(mwx.Frame):
|
|
|
660
682
|
self.histogram.Name = "histogram"
|
|
661
683
|
|
|
662
684
|
self._mgr.AddPane(self.graph,
|
|
663
|
-
aui.AuiPaneInfo().CenterPane()
|
|
685
|
+
aui.AuiPaneInfo().CenterPane()
|
|
664
686
|
.Name("graph").Caption("graph").CaptionVisible(1))
|
|
665
687
|
|
|
666
688
|
size = (200, 200)
|
|
@@ -785,7 +807,7 @@ class Frame(mwx.Frame):
|
|
|
785
807
|
self.menubar.reset()
|
|
786
808
|
|
|
787
809
|
def show_frameview(frame):
|
|
788
|
-
wx.CallAfter(self.show_pane, frame.parent)
|
|
810
|
+
wx.CallAfter(self.show_pane, frame.parent) # Show graph / output in the main thread.
|
|
789
811
|
|
|
790
812
|
self.graph.handler.append({ # DNA<Graph:Frame>
|
|
791
813
|
None : {
|
|
@@ -824,8 +846,8 @@ class Frame(mwx.Frame):
|
|
|
824
846
|
_display(self.graph, show)
|
|
825
847
|
_display(self.output, show)
|
|
826
848
|
evt.Skip()
|
|
827
|
-
self.Bind(wx.EVT_MOVE_START, lambda v
|
|
828
|
-
self.Bind(wx.EVT_MOVE_END, lambda v
|
|
849
|
+
self.Bind(wx.EVT_MOVE_START, lambda v: on_move(v, show=0))
|
|
850
|
+
self.Bind(wx.EVT_MOVE_END, lambda v: on_move(v, show=1))
|
|
829
851
|
|
|
830
852
|
## Custom Key Bindings
|
|
831
853
|
self.define_key('* C-g', self.Quit)
|
|
@@ -843,13 +865,13 @@ class Frame(mwx.Frame):
|
|
|
843
865
|
def sync(self, a, b):
|
|
844
866
|
"""Synchronize b to a."""
|
|
845
867
|
if (self.SYNC_SWITCH
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
868
|
+
and a.frame and b.frame
|
|
869
|
+
and a.frame.unit == b.frame.unit
|
|
870
|
+
and a.buffer.shape == b.buffer.shape):
|
|
871
|
+
b.xlim = a.xlim
|
|
872
|
+
b.ylim = a.ylim
|
|
873
|
+
b.OnDraw(None)
|
|
874
|
+
b.canvas.draw_idle()
|
|
853
875
|
|
|
854
876
|
def set_title(self, frame):
|
|
855
877
|
ssn = os.path.basename(self.session_file or '--')
|
|
@@ -927,7 +949,7 @@ class Frame(mwx.Frame):
|
|
|
927
949
|
## ドッキング時に再計算される
|
|
928
950
|
if name == "output" or name is self.output:
|
|
929
951
|
w, h = self.graph.GetClientSize()
|
|
930
|
-
pane.best_size = (w//2 - 3, h)
|
|
952
|
+
pane.best_size = (w//2 - 3, h) # 分割線幅補正 -12pix (Windows only ?)
|
|
931
953
|
|
|
932
954
|
## Force Layer windows to show.
|
|
933
955
|
if interactive:
|
|
@@ -943,12 +965,8 @@ class Frame(mwx.Frame):
|
|
|
943
965
|
pane.Float()
|
|
944
966
|
show = True
|
|
945
967
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
## - pane.window is floating (win.Parent is AuiFloatingFrame) or docked.
|
|
949
|
-
|
|
950
|
-
plug = self.get_plug(name) # -> None if pane.window is a Graph
|
|
951
|
-
win = pane.window # -> Window (plug / notebook / Graph)
|
|
968
|
+
plug = self.get_plug(name) # -> None if pane.window is a Graph
|
|
969
|
+
win = pane.window
|
|
952
970
|
try:
|
|
953
971
|
shown = plug.IsShown()
|
|
954
972
|
except AttributeError:
|
|
@@ -958,7 +976,7 @@ class Frame(mwx.Frame):
|
|
|
958
976
|
if isinstance(win, aui.AuiNotebook):
|
|
959
977
|
j = win.GetPageIndex(plug)
|
|
960
978
|
if j != win.Selection:
|
|
961
|
-
win.Selection = j
|
|
979
|
+
win.Selection = j # the focus moves => EVT_SHOW
|
|
962
980
|
else:
|
|
963
981
|
plug.handler('page_shown', plug)
|
|
964
982
|
else:
|
|
@@ -999,7 +1017,7 @@ class Frame(mwx.Frame):
|
|
|
999
1017
|
pane.dock_direction = dock
|
|
1000
1018
|
if not plug.caption:
|
|
1001
1019
|
pane.CaptionVisible(False) # no caption bar
|
|
1002
|
-
pane.Gripper(dock not in (0,
|
|
1020
|
+
pane.Gripper(dock not in (0,5)) # show a grip when docked
|
|
1003
1021
|
pane.Dockable(dock)
|
|
1004
1022
|
|
|
1005
1023
|
if pane.dock_direction:
|
|
@@ -1050,30 +1068,6 @@ class Frame(mwx.Frame):
|
|
|
1050
1068
|
elif isinstance(name, LayerInterface):
|
|
1051
1069
|
return name
|
|
1052
1070
|
|
|
1053
|
-
@staticmethod
|
|
1054
|
-
def register(cls, module=None):
|
|
1055
|
-
"""Register dummy plug; Add module.Plugin <Layer>.
|
|
1056
|
-
"""
|
|
1057
|
-
if not module:
|
|
1058
|
-
module = inspect.getmodule(cls) # rebase module or __main__
|
|
1059
|
-
|
|
1060
|
-
if issubclass(cls, LayerInterface):
|
|
1061
|
-
cls.__module__ = module.__name__ # __main__ to module
|
|
1062
|
-
warn(f"Duplicate iniheritance of LayerInterface by {cls}.")
|
|
1063
|
-
module.Plugin = cls
|
|
1064
|
-
return cls
|
|
1065
|
-
|
|
1066
|
-
class _Plugin(LayerInterface, cls):
|
|
1067
|
-
def __init__(self, parent, session=None, **kwargs):
|
|
1068
|
-
cls.__init__(self, parent, **kwargs)
|
|
1069
|
-
LayerInterface.__init__(self, parent, session)
|
|
1070
|
-
|
|
1071
|
-
_Plugin.__module__ = cls.__module__ = module.__name__
|
|
1072
|
-
_Plugin.__name__ = cls.__name__ + str("~")
|
|
1073
|
-
_Plugin.__doc__ = cls.__doc__
|
|
1074
|
-
module.Plugin = _Plugin
|
|
1075
|
-
return _Plugin
|
|
1076
|
-
|
|
1077
1071
|
def load_module(self, root):
|
|
1078
1072
|
"""Load module of plugin (internal use only).
|
|
1079
1073
|
|
|
@@ -1102,17 +1096,17 @@ class Frame(mwx.Frame):
|
|
|
1102
1096
|
print(f"- Unable to load {root!r}.", e)
|
|
1103
1097
|
return False
|
|
1104
1098
|
|
|
1105
|
-
## the module
|
|
1099
|
+
## Check if the module has a class `Plugin`.
|
|
1106
1100
|
if not hasattr(module, 'Plugin'):
|
|
1107
1101
|
if isinstance(root, type):
|
|
1108
1102
|
warn(f"Use dummy plug for debugging {name!r}.")
|
|
1109
1103
|
module.__dummy_plug__ = root
|
|
1110
|
-
|
|
1104
|
+
register(root, module)
|
|
1111
1105
|
else:
|
|
1112
1106
|
if hasattr(module, '__dummy_plug__'):
|
|
1113
1107
|
root = module.__dummy_plug__ # old class (imported)
|
|
1114
1108
|
cls = getattr(module, root.__name__) # new class (reloaded)
|
|
1115
|
-
|
|
1109
|
+
register(cls, module)
|
|
1116
1110
|
return module
|
|
1117
1111
|
|
|
1118
1112
|
def load_plug(self, root, force=False, session=None, show=False,
|
|
@@ -1159,48 +1153,47 @@ class Frame(mwx.Frame):
|
|
|
1159
1153
|
|
|
1160
1154
|
module = self.load_module(root)
|
|
1161
1155
|
if not module:
|
|
1162
|
-
return False
|
|
1156
|
+
return False
|
|
1163
1157
|
|
|
1158
|
+
## assert name == Plugin.__module__
|
|
1164
1159
|
try:
|
|
1165
|
-
|
|
1166
|
-
title =
|
|
1167
|
-
|
|
1168
|
-
pane = self._mgr.GetPane(title)
|
|
1169
|
-
|
|
1170
|
-
if pane.IsOk(): # <pane:title> is already registered
|
|
1171
|
-
nb = pane.window
|
|
1172
|
-
if not isinstance(nb, aui.AuiNotebook):
|
|
1173
|
-
raise NameError("Notebook name must not be the same as any other plugins")
|
|
1160
|
+
Plugin = module.Plugin # Check if the module has a class `Plugin`.
|
|
1161
|
+
title = Plugin.category # Plugin <LayerInterface>
|
|
1174
1162
|
|
|
1175
|
-
pane = self.
|
|
1163
|
+
pane = self._mgr.GetPane(title) # Check if <pane:title> is already registered.
|
|
1164
|
+
if pane.IsOk():
|
|
1165
|
+
if not isinstance(pane.window, aui.AuiNotebook):
|
|
1166
|
+
raise NameError("Notebook name must not be the same as any other plugin")
|
|
1176
1167
|
|
|
1177
|
-
|
|
1168
|
+
pane = self.get_pane(name) # Check if <pane:name> is already registered.
|
|
1169
|
+
if pane.IsOk():
|
|
1178
1170
|
if name not in self.plugins:
|
|
1179
|
-
raise NameError("Plugin name must not be the same as any other
|
|
1180
|
-
|
|
1181
|
-
show = show or pane.IsShown()
|
|
1182
|
-
props.update(
|
|
1183
|
-
dock_direction = pane.IsDocked() and pane.dock_direction,
|
|
1184
|
-
floating_pos = floating_pos or pane.floating_pos[:], # copy unloading pane
|
|
1185
|
-
floating_size = floating_size or pane.floating_size[:], # copy unloading pane
|
|
1186
|
-
)
|
|
1171
|
+
raise NameError("Plugin name must not be the same as any other pane")
|
|
1172
|
+
|
|
1187
1173
|
except (AttributeError, NameError) as e:
|
|
1188
1174
|
traceback.print_exc()
|
|
1189
|
-
wx.CallAfter(wx.MessageBox,
|
|
1175
|
+
wx.CallAfter(wx.MessageBox, # Show the message after load_session has finished.
|
|
1190
1176
|
f"{e}\n\n" + traceback.format_exc(),
|
|
1191
1177
|
f"Error in loading {module.__name__!r}",
|
|
1192
1178
|
style=wx.ICON_ERROR)
|
|
1193
1179
|
return False
|
|
1194
1180
|
|
|
1195
|
-
##
|
|
1181
|
+
## Unload the plugin if loaded.
|
|
1196
1182
|
if pane.IsOk():
|
|
1197
|
-
|
|
1183
|
+
show = show or pane.IsShown()
|
|
1184
|
+
props.update(
|
|
1185
|
+
dock_direction = pane.IsDocked() and pane.dock_direction,
|
|
1186
|
+
floating_pos = floating_pos or pane.floating_pos[:], # copy unloading pane
|
|
1187
|
+
floating_size = floating_size or pane.floating_size[:], # copy unloading pane
|
|
1188
|
+
)
|
|
1189
|
+
self.unload_plug(name)
|
|
1198
1190
|
|
|
1191
|
+
## Create the plugin object.
|
|
1199
1192
|
try:
|
|
1200
|
-
plug =
|
|
1193
|
+
plug = Plugin(self, session, **kwargs)
|
|
1201
1194
|
except Exception as e:
|
|
1202
1195
|
traceback.print_exc()
|
|
1203
|
-
wx.CallAfter(wx.MessageBox,
|
|
1196
|
+
wx.CallAfter(wx.MessageBox, # Show the message after load_session has finished.
|
|
1204
1197
|
f"{e}\n\n" + traceback.format_exc(),
|
|
1205
1198
|
f"Error in loading {name!r}",
|
|
1206
1199
|
style=wx.ICON_ERROR)
|
|
@@ -1209,10 +1202,10 @@ class Frame(mwx.Frame):
|
|
|
1209
1202
|
## Add to the list after the plug is created successfully.
|
|
1210
1203
|
self.plugins[name] = module
|
|
1211
1204
|
|
|
1212
|
-
##
|
|
1205
|
+
## Set reference of a plug (one module, one plugin).
|
|
1213
1206
|
module.__plug__ = plug
|
|
1214
1207
|
|
|
1215
|
-
## Create pane or notebook pane
|
|
1208
|
+
## Create pane or notebook pane.
|
|
1216
1209
|
caption = plug.caption
|
|
1217
1210
|
if not isinstance(caption, str):
|
|
1218
1211
|
caption = name
|
|
@@ -1224,7 +1217,7 @@ class Frame(mwx.Frame):
|
|
|
1224
1217
|
nb = pane.window
|
|
1225
1218
|
nb.AddPage(plug, caption)
|
|
1226
1219
|
else:
|
|
1227
|
-
size = plug.GetSize() + (2,30)
|
|
1220
|
+
size = plug.GetSize() + (2,30) # padding for notebook
|
|
1228
1221
|
nb = AuiNotebook(self, name=title)
|
|
1229
1222
|
nb.AddPage(plug, caption)
|
|
1230
1223
|
self._mgr.AddPane(nb, aui.AuiPaneInfo()
|
|
@@ -1246,11 +1239,11 @@ class Frame(mwx.Frame):
|
|
|
1246
1239
|
self.update_pane(name, **props)
|
|
1247
1240
|
self.show_pane(name, show)
|
|
1248
1241
|
|
|
1249
|
-
## Create a menu
|
|
1242
|
+
## Create a menu.
|
|
1250
1243
|
plug.__Menu_item = None
|
|
1251
1244
|
|
|
1252
|
-
if not hasattr(module, 'ID_'):
|
|
1253
|
-
global __plug_ID__
|
|
1245
|
+
if not hasattr(module, 'ID_'): # give a unique index to the module
|
|
1246
|
+
global __plug_ID__ # cache ID *not* in [ID_LOWEST(4999):ID_HIGHEST(5999)]
|
|
1254
1247
|
try:
|
|
1255
1248
|
__plug_ID__
|
|
1256
1249
|
except NameError:
|
|
@@ -1322,11 +1315,6 @@ class Frame(mwx.Frame):
|
|
|
1322
1315
|
traceback.print_exc()
|
|
1323
1316
|
print("- Failed to save session of", plug)
|
|
1324
1317
|
self.load_plug(plug.__module__, force=1, session=session)
|
|
1325
|
-
|
|
1326
|
-
## Update shell.target --> new plug
|
|
1327
|
-
for shell in self.shellframe.get_all_shells():
|
|
1328
|
-
if shell.target is plug:
|
|
1329
|
-
shell.handler('shell_activated', shell)
|
|
1330
1318
|
|
|
1331
1319
|
def inspect_plug(self, name):
|
|
1332
1320
|
"""Dive into the process to inspect plugs in the shell.
|
|
@@ -1339,10 +1327,11 @@ class Frame(mwx.Frame):
|
|
|
1339
1327
|
|
|
1340
1328
|
@shell.handler.bind("shell_activated")
|
|
1341
1329
|
def init(shell):
|
|
1330
|
+
"""Called when the plug shell is activated."""
|
|
1342
1331
|
nonlocal plug
|
|
1343
1332
|
_plug = self.get_plug(name)
|
|
1344
1333
|
if _plug is not plug:
|
|
1345
|
-
shell.target = _plug or self
|
|
1334
|
+
shell.target = _plug or self # Reset the target to the reloaded plug.
|
|
1346
1335
|
plug = _plug
|
|
1347
1336
|
init(shell)
|
|
1348
1337
|
self.shellframe.Show()
|
|
@@ -1459,7 +1448,7 @@ class Frame(mwx.Frame):
|
|
|
1459
1448
|
return frames
|
|
1460
1449
|
|
|
1461
1450
|
## --------------------------------
|
|
1462
|
-
## load/save frames and attributes
|
|
1451
|
+
## load/save frames and attributes
|
|
1463
1452
|
## --------------------------------
|
|
1464
1453
|
|
|
1465
1454
|
@classmethod
|
|
@@ -1744,14 +1733,18 @@ class Frame(mwx.Frame):
|
|
|
1744
1733
|
self._mgr.Update()
|
|
1745
1734
|
self.menubar.reset()
|
|
1746
1735
|
|
|
1747
|
-
dirname_ = os.path.dirname(i.name)
|
|
1748
|
-
if dirname_:
|
|
1749
|
-
os.chdir(dirname_)
|
|
1750
|
-
|
|
1751
1736
|
## Reposition the window if it is not on the desktop.
|
|
1752
1737
|
if wx.Display.GetFromWindow(self) == -1:
|
|
1753
1738
|
self.Position = (0, 0)
|
|
1754
1739
|
|
|
1740
|
+
## LoadPerspective => 表示状態の不整合.手動でイベントを発生させる.
|
|
1741
|
+
for pane in self._mgr.GetAllPanes():
|
|
1742
|
+
if pane.IsShown():
|
|
1743
|
+
win = pane.window
|
|
1744
|
+
if isinstance(win, aui.AuiNotebook):
|
|
1745
|
+
win = win.CurrentPage
|
|
1746
|
+
win.handler('page_shown', win)
|
|
1747
|
+
|
|
1755
1748
|
self.message("\b done.")
|
|
1756
1749
|
|
|
1757
1750
|
def save_session_as(self):
|
|
@@ -1799,8 +1792,8 @@ class Frame(mwx.Frame):
|
|
|
1799
1792
|
o.write(f"self.{view.Name}.unit = {view.unit:g}\n")
|
|
1800
1793
|
o.write(f"self.load_frame({paths!r}, self.{view.Name})\n")
|
|
1801
1794
|
try:
|
|
1802
|
-
|
|
1803
|
-
|
|
1795
|
+
if view.frame.pathname in paths:
|
|
1796
|
+
o.write(f"self.{view.Name}.select({view.frame.name!r})\n")
|
|
1804
1797
|
except Exception:
|
|
1805
1798
|
pass
|
|
1806
1799
|
|
mwx/matplot2.py
CHANGED
|
@@ -11,7 +11,7 @@ from matplotlib.figure import Figure
|
|
|
11
11
|
import numpy as np
|
|
12
12
|
|
|
13
13
|
from . import framework as mwx
|
|
14
|
-
from .framework import hotkey, regulate_key, pack, Menu, FSM
|
|
14
|
+
from .framework import hotkey, regulate_key, postcall, pack, Menu, FSM
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
## state constants
|
|
@@ -178,8 +178,6 @@ class MatplotPanel(wx.Panel):
|
|
|
178
178
|
'axes_enter' : [ None, ],
|
|
179
179
|
'axes_leave' : [ None, ],
|
|
180
180
|
'home pressed' : [ None, self.OnHomePosition ],
|
|
181
|
-
'left pressed' : [ None, self.OnBackPosition ],
|
|
182
|
-
'right pressed' : [ None, self.OnForwardPosition ],
|
|
183
181
|
'Xbutton1 pressed' : [ None, self.OnBackPosition ],
|
|
184
182
|
'Xbutton2 pressed' : [ None, self.OnForwardPosition ],
|
|
185
183
|
},
|
|
@@ -314,6 +312,8 @@ class MatplotPanel(wx.Panel):
|
|
|
314
312
|
self.cursor = Cursor(self.axes, useblit=True, color='grey', linewidth=1)
|
|
315
313
|
self.cursor.visible = 1
|
|
316
314
|
|
|
315
|
+
## Note: To avoid a wxAssertionError when running in a thread.
|
|
316
|
+
@postcall
|
|
317
317
|
def draw(self, art=None):
|
|
318
318
|
"""Draw plots.
|
|
319
319
|
Call each time the drawing should be updated.
|
|
@@ -345,22 +345,22 @@ class MatplotPanel(wx.Panel):
|
|
|
345
345
|
|
|
346
346
|
xbound = property(
|
|
347
347
|
lambda self: np.array(self.axes.get_xbound()),
|
|
348
|
-
lambda self,v: self.axes.set_xbound(v),
|
|
348
|
+
lambda self, v: self.axes.set_xbound(v),
|
|
349
349
|
doc="X-axis numerical bounds where lowerBound < upperBound)")
|
|
350
350
|
|
|
351
351
|
ybound = property(
|
|
352
352
|
lambda self: np.array(self.axes.get_ybound()),
|
|
353
|
-
lambda self,v: self.axes.set_ybound(v),
|
|
353
|
+
lambda self, v: self.axes.set_ybound(v),
|
|
354
354
|
doc="Y-axis numerical bounds where lowerBound < upperBound)")
|
|
355
355
|
|
|
356
356
|
xlim = property(
|
|
357
357
|
lambda self: np.array(self.axes.get_xlim()),
|
|
358
|
-
lambda self,v: self.axes.set_xlim(v),
|
|
358
|
+
lambda self, v: self.axes.set_xlim(v),
|
|
359
359
|
doc="X-axis range [left, right]")
|
|
360
360
|
|
|
361
361
|
ylim = property(
|
|
362
362
|
lambda self: np.array(self.axes.get_ylim()),
|
|
363
|
-
lambda self,v: self.axes.set_ylim(v),
|
|
363
|
+
lambda self, v: self.axes.set_ylim(v),
|
|
364
364
|
doc="Y-axis range [bottom, top]")
|
|
365
365
|
|
|
366
366
|
@property
|
|
@@ -418,7 +418,7 @@ class MatplotPanel(wx.Panel):
|
|
|
418
418
|
wx.UIActionSimulator().KeyUp(wx.WXK_ESCAPE)
|
|
419
419
|
|
|
420
420
|
## --------------------------------
|
|
421
|
-
## External I/O file and clipboard
|
|
421
|
+
## External I/O file and clipboard
|
|
422
422
|
## --------------------------------
|
|
423
423
|
|
|
424
424
|
def copy_to_clipboard(self):
|
|
@@ -561,7 +561,7 @@ class MatplotPanel(wx.Panel):
|
|
|
561
561
|
## Overwrite evt.key with modifiers.
|
|
562
562
|
key = self.__key
|
|
563
563
|
if evt.button in (1,2,3):
|
|
564
|
-
key += 'LMR'[evt.button-1] #{1:L, 2:M, 3:R}
|
|
564
|
+
key += 'LMR'[evt.button-1] # {1:L, 2:M, 3:R}
|
|
565
565
|
evt.key = key + 'button'
|
|
566
566
|
elif evt.button in ('up', 'down'):
|
|
567
567
|
key += 'wheel{}'.format(evt.button) # wheel[up|down]
|
|
@@ -621,10 +621,11 @@ class MatplotPanel(wx.Panel):
|
|
|
621
621
|
self.p_event = None
|
|
622
622
|
|
|
623
623
|
## --------------------------------
|
|
624
|
-
## Pan/Zoom actions
|
|
624
|
+
## Pan/Zoom actions
|
|
625
625
|
## --------------------------------
|
|
626
626
|
|
|
627
|
-
ZOOM_RATIO = 10**0.2
|
|
627
|
+
ZOOM_RATIO = 10 ** 0.2
|
|
628
|
+
ZOOM_LIMIT = 0.1 # logical limit <= epsilon
|
|
628
629
|
|
|
629
630
|
def OnDraw(self, evt):
|
|
630
631
|
"""Called before canvas.draw."""
|
|
@@ -663,7 +664,7 @@ class MatplotPanel(wx.Panel):
|
|
|
663
664
|
if c is None:
|
|
664
665
|
c = (lim[1] + lim[0]) / 2
|
|
665
666
|
y = c - M * (c - lim)
|
|
666
|
-
if abs(y[1] - y[0]) >
|
|
667
|
+
if abs(y[1] - y[0]) > self.ZOOM_LIMIT:
|
|
667
668
|
return y
|
|
668
669
|
|
|
669
670
|
def OnZoom(self, evt):
|