mwxlib 0.98.1__py3-none-any.whl → 0.98.5__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/controls.py +5 -4
- mwx/framework.py +38 -40
- mwx/graphman.py +49 -57
- mwx/matplot2g.py +3 -3
- mwx/mgplt.py +1 -1
- mwx/nutshell.py +85 -92
- mwx/plugins/ffmpeg_view.py +2 -2
- mwx/utilus.py +1 -1
- {mwxlib-0.98.1.dist-info → mwxlib-0.98.5.dist-info}/METADATA +1 -1
- {mwxlib-0.98.1.dist-info → mwxlib-0.98.5.dist-info}/RECORD +13 -13
- {mwxlib-0.98.1.dist-info → mwxlib-0.98.5.dist-info}/WHEEL +1 -1
- {mwxlib-0.98.1.dist-info → mwxlib-0.98.5.dist-info}/LICENSE +0 -0
- {mwxlib-0.98.1.dist-info → mwxlib-0.98.5.dist-info}/top_level.txt +0 -0
mwx/controls.py
CHANGED
|
@@ -9,7 +9,7 @@ import wx.lib.scrolledpanel as scrolled
|
|
|
9
9
|
from . import images
|
|
10
10
|
from .utilus import SSM
|
|
11
11
|
from .utilus import funcall as _F
|
|
12
|
-
from .framework import pack, Menu
|
|
12
|
+
from .framework import pack, Menu, postcall
|
|
13
13
|
|
|
14
14
|
import numpy as np
|
|
15
15
|
from numpy import nan, inf # noqa: necessary to eval
|
|
@@ -20,7 +20,7 @@ def _Tip(*tips):
|
|
|
20
20
|
return '\n'.join(filter(None, tips)).strip()
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
class Param
|
|
23
|
+
class Param:
|
|
24
24
|
"""Standard Parameter
|
|
25
25
|
|
|
26
26
|
Args:
|
|
@@ -438,6 +438,8 @@ class Knob(wx.Panel):
|
|
|
438
438
|
self.label.SetLabel(v.name + t)
|
|
439
439
|
self.label.Refresh()
|
|
440
440
|
|
|
441
|
+
## Note: wxAssertionError in text.SetValue
|
|
442
|
+
@postcall
|
|
441
443
|
def update_ctrl(self, valid=True, notify=False):
|
|
442
444
|
"""Called when value is being changed (internal use only)."""
|
|
443
445
|
v = self.__par
|
|
@@ -724,8 +726,7 @@ class ControlPanel(scrolled.ScrolledPanel):
|
|
|
724
726
|
except AttributeError:
|
|
725
727
|
p.value = v
|
|
726
728
|
except Exception as e: # failed to eval
|
|
727
|
-
print(f"- Failed to reset {p!r}
|
|
728
|
-
pass
|
|
729
|
+
print(f"- Failed to reset {p!r}.", e)
|
|
729
730
|
|
|
730
731
|
reset_params = set_params #: for backward compatibility
|
|
731
732
|
|
mwx/framework.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#! python3
|
|
2
2
|
"""mwxlib framework.
|
|
3
3
|
"""
|
|
4
|
-
__version__ = "0.98.
|
|
4
|
+
__version__ = "0.98.5"
|
|
5
5
|
__author__ = "Kazuya O'moto <komoto@jeol.co.jp>"
|
|
6
6
|
|
|
7
7
|
from contextlib import contextmanager
|
|
@@ -222,8 +222,6 @@ class KeyCtrlInterfaceMixin:
|
|
|
222
222
|
spec-map : 'C-c'
|
|
223
223
|
esc-map : 'escape'
|
|
224
224
|
"""
|
|
225
|
-
message = print # override this in subclass
|
|
226
|
-
|
|
227
225
|
@postcall
|
|
228
226
|
def post_message(self, *args, **kwargs):
|
|
229
227
|
return self.message(*args, **kwargs)
|
|
@@ -332,17 +330,22 @@ class CtrlInterface(KeyCtrlInterfaceMixin):
|
|
|
332
330
|
"""
|
|
333
331
|
handler = property(lambda self: self.__handler)
|
|
334
332
|
|
|
333
|
+
message = print # override this in subclass
|
|
334
|
+
|
|
335
335
|
def __init__(self):
|
|
336
336
|
self.__key = ''
|
|
337
337
|
self.__button = ''
|
|
338
338
|
self.__isDragging = False
|
|
339
|
-
self.__handler = FSM({
|
|
339
|
+
self.__handler = FSM({ # DNA<CtrlInterface>
|
|
340
|
+
None : {
|
|
341
|
+
},
|
|
342
|
+
0 : {
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
)
|
|
340
346
|
|
|
341
347
|
_M = self._mouse_handler
|
|
342
|
-
|
|
343
|
-
def _N(event, evt):
|
|
344
|
-
if self.handler(event, evt) is None:
|
|
345
|
-
evt.Skip()
|
|
348
|
+
_N = self._normal_handler
|
|
346
349
|
|
|
347
350
|
def activate(evt):
|
|
348
351
|
self.handler('focus_set', evt)
|
|
@@ -383,7 +386,7 @@ class CtrlInterface(KeyCtrlInterfaceMixin):
|
|
|
383
386
|
self.Bind(wx.EVT_MOUSE_AUX2_DCLICK, lambda v: _M('Xbutton2 dblclick', v))
|
|
384
387
|
|
|
385
388
|
self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, lambda v: _N('capture_lost', v))
|
|
386
|
-
self.Bind(wx.EVT_MOUSE_CAPTURE_CHANGED, lambda v: _N('
|
|
389
|
+
self.Bind(wx.EVT_MOUSE_CAPTURE_CHANGED, lambda v: _N('capture_changed', v))
|
|
387
390
|
|
|
388
391
|
def on_hotkey_press(self, evt): #<wx._core.KeyEvent>
|
|
389
392
|
"""Called when a key is pressed."""
|
|
@@ -461,6 +464,10 @@ class CtrlInterface(KeyCtrlInterfaceMixin):
|
|
|
461
464
|
self.SetFocusIgnoringChildren() # let the panel accept keys
|
|
462
465
|
except AttributeError:
|
|
463
466
|
pass
|
|
467
|
+
|
|
468
|
+
def _normal_handler(self, event, evt): #<wx._core.Event>
|
|
469
|
+
if self.handler(event, evt) is None:
|
|
470
|
+
evt.Skip()
|
|
464
471
|
|
|
465
472
|
|
|
466
473
|
## --------------------------------
|
|
@@ -763,15 +770,10 @@ class Frame(wx.Frame, KeyCtrlInterfaceMixin):
|
|
|
763
770
|
evt.Skip()
|
|
764
771
|
self.Bind(wx.EVT_CHAR_HOOK, hook_char)
|
|
765
772
|
|
|
766
|
-
def close(evt):
|
|
767
|
-
"""Close the window."""
|
|
768
|
-
self.Close()
|
|
769
|
-
|
|
770
773
|
self.__handler = FSM({ # DNA<Frame>
|
|
771
774
|
None : {
|
|
772
775
|
},
|
|
773
776
|
0 : {
|
|
774
|
-
'M-q pressed' : (0, close),
|
|
775
777
|
},
|
|
776
778
|
},
|
|
777
779
|
)
|
|
@@ -829,15 +831,10 @@ class MiniFrame(wx.MiniFrame, KeyCtrlInterfaceMixin):
|
|
|
829
831
|
## To default close >>> self.Unbind(wx.EVT_CLOSE)
|
|
830
832
|
self.Bind(wx.EVT_CLOSE, lambda v: self.Show(0))
|
|
831
833
|
|
|
832
|
-
def close(evt):
|
|
833
|
-
"""Close the window."""
|
|
834
|
-
self.Close()
|
|
835
|
-
|
|
836
834
|
self.__handler = FSM({ # DNA<MiniFrame>
|
|
837
835
|
None : {
|
|
838
836
|
},
|
|
839
837
|
0 : {
|
|
840
|
-
'M-q pressed' : (0, close),
|
|
841
838
|
},
|
|
842
839
|
},
|
|
843
840
|
)
|
|
@@ -1010,7 +1007,7 @@ class AuiNotebook(aui.AuiNotebook):
|
|
|
1010
1007
|
self._mgr.LoadPerspective(frames)
|
|
1011
1008
|
self._mgr.Update()
|
|
1012
1009
|
except Exception as e:
|
|
1013
|
-
print("- Failed to load perspective
|
|
1010
|
+
print("- Failed to load perspective.", e)
|
|
1014
1011
|
finally:
|
|
1015
1012
|
self.Parent.Thaw()
|
|
1016
1013
|
|
|
@@ -1278,16 +1275,14 @@ class ShellFrame(MiniFrame):
|
|
|
1278
1275
|
|
|
1279
1276
|
@self.Scratch.define_key('C-j')
|
|
1280
1277
|
def eval_line(evt):
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
evt.Skip(False)
|
|
1278
|
+
self.Scratch.buffer.eval_line()
|
|
1279
|
+
evt.Skip(False) # Don't skip explicitly.
|
|
1284
1280
|
|
|
1285
1281
|
@self.Scratch.define_key('C-S-j')
|
|
1286
1282
|
@self.Scratch.define_key('M-j')
|
|
1287
1283
|
def eval_buffer(evt):
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
evt.Skip(False)
|
|
1284
|
+
self.Scratch.buffer.exec_region()
|
|
1285
|
+
evt.Skip(False) # Don't skip explicitly.
|
|
1291
1286
|
|
|
1292
1287
|
## Session
|
|
1293
1288
|
self.SESSION_FILE = get_rootpath(".debrc")
|
|
@@ -1298,7 +1293,9 @@ class ShellFrame(MiniFrame):
|
|
|
1298
1293
|
os.path.abspath(debrc) if debrc else self.SESSION_FILE)
|
|
1299
1294
|
|
|
1300
1295
|
def load_session(self, filename):
|
|
1301
|
-
"""Load session from file.
|
|
1296
|
+
"""Load session from file.
|
|
1297
|
+
Buffers, pointers, and the entire layout are loaded.
|
|
1298
|
+
"""
|
|
1302
1299
|
def _fload(editor, filename):
|
|
1303
1300
|
try:
|
|
1304
1301
|
buffer = editor.default_buffer or editor.new_buffer()
|
|
@@ -1325,7 +1322,9 @@ class ShellFrame(MiniFrame):
|
|
|
1325
1322
|
self.Position = (0, 0)
|
|
1326
1323
|
|
|
1327
1324
|
def save_session(self):
|
|
1328
|
-
"""Save session to file.
|
|
1325
|
+
"""Save session to file.
|
|
1326
|
+
Buffers, pointers, and the entire layout are saved.
|
|
1327
|
+
"""
|
|
1329
1328
|
def _fsave(editor, filename):
|
|
1330
1329
|
try:
|
|
1331
1330
|
buffer = editor.default_buffer
|
|
@@ -1340,20 +1339,20 @@ class ShellFrame(MiniFrame):
|
|
|
1340
1339
|
with open(self.SESSION_FILE, 'w', encoding='utf-8', newline='') as o:
|
|
1341
1340
|
o.write("#! Session file (This file is generated automatically)\n")
|
|
1342
1341
|
|
|
1343
|
-
for book in self.
|
|
1342
|
+
for book in (self.Scratch, self.Log):
|
|
1344
1343
|
for buf in book.all_buffers:
|
|
1345
1344
|
if buf.mtdelta is not None:
|
|
1346
|
-
o.write("self.
|
|
1347
|
-
.format(buf.filename, buf.markline+1
|
|
1345
|
+
o.write("self.{}.load_file({!r}, {})\n"
|
|
1346
|
+
.format(book.Name, buf.filename, buf.markline+1))
|
|
1348
1347
|
o.write('\n'.join((
|
|
1349
1348
|
"self.SetSize({})".format(self.Size),
|
|
1350
1349
|
"self.SetPosition({})".format(self.Position),
|
|
1351
|
-
"self.
|
|
1352
|
-
"self.
|
|
1350
|
+
"self.Scratch.loadPerspective({!r})".format(self.Scratch.savePerspective()),
|
|
1351
|
+
"self.Log.loadPerspective({!r})".format(self.Log.savePerspective()),
|
|
1353
1352
|
## Note: Perspectives should be called after all pages have been added.
|
|
1354
|
-
"
|
|
1355
|
-
"
|
|
1356
|
-
"
|
|
1353
|
+
"self.ghost.loadPerspective({!r})".format(self.ghost.savePerspective()),
|
|
1354
|
+
"self.watcher.loadPerspective({!r})".format(self.watcher.savePerspective()),
|
|
1355
|
+
"self._mgr.LoadPerspective({!r})".format(self._mgr.SavePerspective()),
|
|
1357
1356
|
"self._mgr.Update()\n",
|
|
1358
1357
|
)))
|
|
1359
1358
|
|
|
@@ -1547,9 +1546,8 @@ class ShellFrame(MiniFrame):
|
|
|
1547
1546
|
pane = self._mgr.GetPane(win)
|
|
1548
1547
|
if pane.IsDocked():
|
|
1549
1548
|
if not self.console.IsShown():
|
|
1550
|
-
self._mgr.RestoreMaximizedPane()
|
|
1551
|
-
self._mgr.Update()
|
|
1552
|
-
return
|
|
1549
|
+
self._mgr.RestoreMaximizedPane() # いったん表示切替
|
|
1550
|
+
self._mgr.Update() # 更新後に best_size 取得
|
|
1553
1551
|
if pane.IsShown():
|
|
1554
1552
|
pane.best_size = win.Size
|
|
1555
1553
|
self.popup_window(win, not pane.IsShown())
|
|
@@ -1597,7 +1595,7 @@ class ShellFrame(MiniFrame):
|
|
|
1597
1595
|
self.indicator.Value = 1
|
|
1598
1596
|
self.message("Quit")
|
|
1599
1597
|
|
|
1600
|
-
def _load(self, filename, lineno, editor):
|
|
1598
|
+
def _load(self, filename, lineno, editor): # for backward compatibility
|
|
1601
1599
|
"""Load file in the session (internal use only)."""
|
|
1602
1600
|
if isinstance(editor, str):
|
|
1603
1601
|
editor = getattr(self, editor, None)
|
mwx/graphman.py
CHANGED
|
@@ -50,7 +50,7 @@ def split_paths(obj):
|
|
|
50
50
|
return os.path.split(obj)
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
class Thread
|
|
53
|
+
class Thread:
|
|
54
54
|
"""Thread manager for graphman.Layer
|
|
55
55
|
|
|
56
56
|
The worker:thread runs the given target.
|
|
@@ -342,7 +342,6 @@ class LayerInterface(CtrlInterface):
|
|
|
342
342
|
'thread_error' : [ None ], # failed in error
|
|
343
343
|
'page_shown' : [ None, _F(self.Draw, True) ],
|
|
344
344
|
'page_closed' : [ None, _F(self.Draw, False) ],
|
|
345
|
-
'page_hidden' : [ None, _F(self.Draw, False) ],
|
|
346
345
|
},
|
|
347
346
|
0 : {
|
|
348
347
|
'C-c pressed' : (0, _F(copy_params)),
|
|
@@ -387,7 +386,6 @@ class LayerInterface(CtrlInterface):
|
|
|
387
386
|
lambda v: Menu.Popup(self, self.menu))
|
|
388
387
|
|
|
389
388
|
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
|
|
390
|
-
self.Bind(wx.EVT_SHOW, self.OnShow)
|
|
391
389
|
|
|
392
390
|
try:
|
|
393
391
|
self.Init()
|
|
@@ -427,15 +425,6 @@ class LayerInterface(CtrlInterface):
|
|
|
427
425
|
del self.Arts
|
|
428
426
|
evt.Skip()
|
|
429
427
|
|
|
430
|
-
def OnShow(self, evt):
|
|
431
|
-
if not self:
|
|
432
|
-
return
|
|
433
|
-
if evt.IsShown():
|
|
434
|
-
self.handler('page_shown', self)
|
|
435
|
-
elif isinstance(self.Parent, aui.AuiNotebook):
|
|
436
|
-
self.handler('page_hidden', self)
|
|
437
|
-
evt.Skip()
|
|
438
|
-
|
|
439
428
|
Shown = property(
|
|
440
429
|
lambda self: self.IsShown(),
|
|
441
430
|
lambda self,v: self.Show(v))
|
|
@@ -443,16 +432,19 @@ class LayerInterface(CtrlInterface):
|
|
|
443
432
|
def IsShown(self):
|
|
444
433
|
"""Returns True if the window is physically visible on the screen.
|
|
445
434
|
|
|
446
|
-
|
|
447
|
-
|
|
435
|
+
(override) Equivalent to ``IsShownOnScreen``.
|
|
436
|
+
Note: The instance could be a page within a notebook.
|
|
448
437
|
"""
|
|
449
438
|
## return self.pane.IsShown()
|
|
450
439
|
return self.IsShownOnScreen()
|
|
451
440
|
|
|
452
|
-
def Show(self, show=True
|
|
453
|
-
"""
|
|
454
|
-
|
|
455
|
-
|
|
441
|
+
def Show(self, show=True):
|
|
442
|
+
"""Shows or hides the window.
|
|
443
|
+
|
|
444
|
+
(override) Show associated pane window.
|
|
445
|
+
Note: This might be called from a thread.
|
|
446
|
+
"""
|
|
447
|
+
wx.CallAfter(self.parent.show_pane, self, show)
|
|
456
448
|
|
|
457
449
|
Drawn = property(
|
|
458
450
|
lambda self: self.IsDrawn(),
|
|
@@ -478,21 +470,16 @@ class LayerInterface(CtrlInterface):
|
|
|
478
470
|
if canvas:
|
|
479
471
|
canvas.draw_idle()
|
|
480
472
|
except Exception as e:
|
|
481
|
-
print(f"- Failed to draw Arts of {self.__module__}
|
|
473
|
+
print(f"- Failed to draw Arts of {self.__module__}.", e)
|
|
482
474
|
del self.Arts
|
|
483
475
|
|
|
484
476
|
|
|
485
|
-
class Layer(
|
|
477
|
+
class Layer(LayerInterface, ControlPanel):
|
|
486
478
|
"""Graphman.Layer
|
|
487
479
|
"""
|
|
488
480
|
def __init__(self, parent, session=None, **kwargs):
|
|
489
481
|
ControlPanel.__init__(self, parent, **kwargs)
|
|
490
482
|
LayerInterface.__init__(self, parent, session)
|
|
491
|
-
|
|
492
|
-
## Explicit (override) precedence
|
|
493
|
-
IsShown = LayerInterface.IsShown
|
|
494
|
-
Shown = LayerInterface.Shown
|
|
495
|
-
Show = LayerInterface.Show
|
|
496
483
|
|
|
497
484
|
|
|
498
485
|
class Graph(GraphPlot):
|
|
@@ -942,9 +929,6 @@ class Frame(mwx.Frame):
|
|
|
942
929
|
pane.Float()
|
|
943
930
|
show = True
|
|
944
931
|
|
|
945
|
-
## Fork page shown/closed events to emulatie EVT_SHOW => plug.on_show.
|
|
946
|
-
## cf. >>> win.EventHandler.ProcessEvent(wx.ShowEvent(win.Id, show))
|
|
947
|
-
##
|
|
948
932
|
## Note: We need to distinguish cases whether:
|
|
949
933
|
## - pane.window is AuiNotebook or normal Panel,
|
|
950
934
|
## - pane.window is floating (win.Parent is AuiFloatingFrame) or docked.
|
|
@@ -1023,6 +1007,7 @@ class Frame(mwx.Frame):
|
|
|
1023
1007
|
plug.handler('page_closed', plug)
|
|
1024
1008
|
else:
|
|
1025
1009
|
win.handler('page_closed', win)
|
|
1010
|
+
evt.Skip()
|
|
1026
1011
|
|
|
1027
1012
|
## --------------------------------
|
|
1028
1013
|
## Plugin <Layer> interface
|
|
@@ -1070,15 +1055,10 @@ class Frame(mwx.Frame):
|
|
|
1070
1055
|
module.Plugin = cls
|
|
1071
1056
|
return cls
|
|
1072
1057
|
|
|
1073
|
-
class _Plugin(
|
|
1058
|
+
class _Plugin(LayerInterface, cls):
|
|
1074
1059
|
def __init__(self, parent, session=None, **kwargs):
|
|
1075
1060
|
cls.__init__(self, parent, **kwargs)
|
|
1076
1061
|
LayerInterface.__init__(self, parent, session)
|
|
1077
|
-
|
|
1078
|
-
## Explicit (override) precedence
|
|
1079
|
-
IsShown = LayerInterface.IsShown
|
|
1080
|
-
Shown = LayerInterface.Shown
|
|
1081
|
-
Show = LayerInterface.Show
|
|
1082
1062
|
|
|
1083
1063
|
_Plugin.__module__ = cls.__module__ = module.__name__
|
|
1084
1064
|
_Plugin.__name__ = cls.__name__ + str("~")
|
|
@@ -1110,7 +1090,7 @@ class Frame(mwx.Frame):
|
|
|
1110
1090
|
else:
|
|
1111
1091
|
module = import_module(name)
|
|
1112
1092
|
except Exception as e:
|
|
1113
|
-
print(f"- Unable to load {root!r}
|
|
1093
|
+
print(f"- Unable to load {root!r}.", e)
|
|
1114
1094
|
return False
|
|
1115
1095
|
|
|
1116
1096
|
## the module must have a class `Plugin`.
|
|
@@ -1172,7 +1152,7 @@ class Frame(mwx.Frame):
|
|
|
1172
1152
|
|
|
1173
1153
|
module = self.load_module(root)
|
|
1174
1154
|
if not module:
|
|
1175
|
-
return
|
|
1155
|
+
return False # failed to import
|
|
1176
1156
|
|
|
1177
1157
|
try:
|
|
1178
1158
|
name = module.Plugin.__module__
|
|
@@ -1328,18 +1308,21 @@ class Frame(mwx.Frame):
|
|
|
1328
1308
|
|
|
1329
1309
|
def reload_plug(self, name):
|
|
1330
1310
|
plug = self.get_plug(name)
|
|
1331
|
-
if not plug:
|
|
1311
|
+
if not plug or not plug.reloadable:
|
|
1332
1312
|
return
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1313
|
+
session = {}
|
|
1314
|
+
try:
|
|
1315
|
+
print("Reloading {}...".format(plug))
|
|
1316
|
+
plug.save_session(session)
|
|
1317
|
+
except Exception:
|
|
1318
|
+
traceback.print_exc()
|
|
1319
|
+
print("- Failed to save session of", plug)
|
|
1320
|
+
self.load_plug(plug.__module__, force=1, session=session)
|
|
1321
|
+
|
|
1322
|
+
## Update shell.target --> new plug
|
|
1323
|
+
for shell in self.shellframe.all_shells:
|
|
1324
|
+
if shell.target is plug:
|
|
1325
|
+
shell.handler('shell_activated', shell)
|
|
1343
1326
|
|
|
1344
1327
|
@ignore(ResourceWarning)
|
|
1345
1328
|
def edit_plug(self, name):
|
|
@@ -1398,12 +1381,16 @@ class Frame(mwx.Frame):
|
|
|
1398
1381
|
|
|
1399
1382
|
def load_index(self, filename=None, view=None):
|
|
1400
1383
|
"""Load frames :ref to the Index file.
|
|
1384
|
+
|
|
1385
|
+
If no view given, the currently selected view is chosen.
|
|
1401
1386
|
"""
|
|
1402
1387
|
if not view:
|
|
1403
1388
|
view = self.selected_view
|
|
1404
1389
|
|
|
1405
1390
|
if not filename:
|
|
1391
|
+
fn = view.frame.pathname if view.frame else ''
|
|
1406
1392
|
with wx.FileDialog(self, "Select index file to import",
|
|
1393
|
+
defaultDir=os.path.dirname(fn or ''),
|
|
1407
1394
|
defaultFile=self.ATTRIBUTESFILE,
|
|
1408
1395
|
wildcard="Index (*.index)|*.index|"
|
|
1409
1396
|
"ALL files (*.*)|*.*",
|
|
@@ -1431,15 +1418,16 @@ class Frame(mwx.Frame):
|
|
|
1431
1418
|
def save_index(self, filename=None, frames=None):
|
|
1432
1419
|
"""Save frames :ref to the Index file.
|
|
1433
1420
|
"""
|
|
1421
|
+
view = self.selected_view
|
|
1434
1422
|
if not frames:
|
|
1435
|
-
frames =
|
|
1423
|
+
frames = view.all_frames
|
|
1436
1424
|
if not frames:
|
|
1437
1425
|
return None
|
|
1438
1426
|
|
|
1439
1427
|
if not filename:
|
|
1440
|
-
fn =
|
|
1428
|
+
fn = view.frame.pathname if view.frame else ''
|
|
1441
1429
|
with wx.FileDialog(self, "Select index file to export",
|
|
1442
|
-
defaultDir=os.path.dirname(fn),
|
|
1430
|
+
defaultDir=os.path.dirname(fn or ''),
|
|
1443
1431
|
defaultFile=self.ATTRIBUTESFILE,
|
|
1444
1432
|
wildcard="Index (*.index)|*.index",
|
|
1445
1433
|
style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dlg:
|
|
@@ -1463,8 +1451,8 @@ class Frame(mwx.Frame):
|
|
|
1463
1451
|
frame.name = os.path.basename(fn) # new name and pathname
|
|
1464
1452
|
output_frames.append(frame)
|
|
1465
1453
|
print(' ', self.message("\b done."))
|
|
1466
|
-
except (PermissionError, OSError):
|
|
1467
|
-
print('-', self.message("\b failed."))
|
|
1454
|
+
except (PermissionError, OSError) as e:
|
|
1455
|
+
print('-', self.message("\b failed.", e))
|
|
1468
1456
|
|
|
1469
1457
|
frames = output_frames
|
|
1470
1458
|
res, mis = self.write_attributes(filename, frames)
|
|
@@ -1504,7 +1492,7 @@ class Frame(mwx.Frame):
|
|
|
1504
1492
|
except FileNotFoundError:
|
|
1505
1493
|
pass
|
|
1506
1494
|
except Exception as e:
|
|
1507
|
-
print("- Failed to read attributes
|
|
1495
|
+
print("- Failed to read attributes.", e)
|
|
1508
1496
|
wx.MessageBox(str(e), style=wx.ICON_ERROR)
|
|
1509
1497
|
finally:
|
|
1510
1498
|
return res, mis # finally raises no exception
|
|
@@ -1526,7 +1514,7 @@ class Frame(mwx.Frame):
|
|
|
1526
1514
|
print(pformat(tuple(new.items())), file=o)
|
|
1527
1515
|
|
|
1528
1516
|
except Exception as e:
|
|
1529
|
-
print("- Failed to write attributes
|
|
1517
|
+
print("- Failed to write attributes.", e)
|
|
1530
1518
|
wx.MessageBox(str(e), style=wx.ICON_ERROR)
|
|
1531
1519
|
finally:
|
|
1532
1520
|
return new, mis # finally raises no exception
|
|
@@ -1607,7 +1595,10 @@ class Frame(mwx.Frame):
|
|
|
1607
1595
|
paths = [paths]
|
|
1608
1596
|
|
|
1609
1597
|
if paths is None:
|
|
1598
|
+
fn = view.frame.pathname if view.frame else ''
|
|
1610
1599
|
with wx.FileDialog(self, "Open image files",
|
|
1600
|
+
defaultDir=os.path.dirname(fn or ''),
|
|
1601
|
+
defaultFile='',
|
|
1611
1602
|
wildcard='|'.join(self.wildcards),
|
|
1612
1603
|
style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST
|
|
1613
1604
|
|wx.FD_MULTIPLE) as dlg:
|
|
@@ -1653,16 +1644,17 @@ class Frame(mwx.Frame):
|
|
|
1653
1644
|
|
|
1654
1645
|
def save_buffer(self, path=None, frame=None):
|
|
1655
1646
|
"""Save buffer of the frame to a file.
|
|
1656
|
-
|
|
1657
|
-
If no view given, the currently selected view is chosen.
|
|
1658
1647
|
"""
|
|
1648
|
+
view = self.selected_view
|
|
1659
1649
|
if not frame:
|
|
1660
|
-
frame =
|
|
1650
|
+
frame = view.frame
|
|
1661
1651
|
if not frame:
|
|
1662
1652
|
return None
|
|
1663
1653
|
|
|
1664
1654
|
if not path:
|
|
1655
|
+
fn = view.frame.pathname if view.frame else ''
|
|
1665
1656
|
with wx.FileDialog(self, "Save buffer as",
|
|
1657
|
+
defaultDir=os.path.dirname(fn or ''),
|
|
1666
1658
|
defaultFile=re.sub(r'[\/:*?"<>|]', '_', frame.name),
|
|
1667
1659
|
wildcard='|'.join(self.wildcards),
|
|
1668
1660
|
style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dlg:
|
mwx/matplot2g.py
CHANGED
|
@@ -110,7 +110,7 @@ def _Property(name):
|
|
|
110
110
|
lambda self: delattr(self.parent, name))
|
|
111
111
|
|
|
112
112
|
|
|
113
|
-
class AxesImagePhantom
|
|
113
|
+
class AxesImagePhantom:
|
|
114
114
|
"""Phantom of frame facade
|
|
115
115
|
|
|
116
116
|
Args:
|
|
@@ -957,7 +957,7 @@ class GraphPlot(MatplotPanel):
|
|
|
957
957
|
self.message("Write buffer to clipboard.")
|
|
958
958
|
except Exception as e:
|
|
959
959
|
traceback.print_exc()
|
|
960
|
-
self.message("- Failed to write to clipboard
|
|
960
|
+
self.message("- Failed to write to clipboard.", e)
|
|
961
961
|
|
|
962
962
|
def read_buffer_from_clipboard(self):
|
|
963
963
|
"""Read buffer data from clipboard."""
|
|
@@ -974,7 +974,7 @@ class GraphPlot(MatplotPanel):
|
|
|
974
974
|
self.load(Clipboard.imread())
|
|
975
975
|
except Exception as e:
|
|
976
976
|
traceback.print_exc()
|
|
977
|
-
self.message("- No data in clipboard
|
|
977
|
+
self.message("- No data in clipboard.", e)
|
|
978
978
|
|
|
979
979
|
def destroy_colorbar(self):
|
|
980
980
|
if self.cbar:
|
mwx/mgplt.py
CHANGED
mwx/nutshell.py
CHANGED
|
@@ -10,7 +10,6 @@ import traceback
|
|
|
10
10
|
import inspect
|
|
11
11
|
import builtins
|
|
12
12
|
import operator
|
|
13
|
-
import dis
|
|
14
13
|
import pydoc
|
|
15
14
|
import keyword
|
|
16
15
|
import linecache
|
|
@@ -102,12 +101,13 @@ class AutoCompInterfaceMixin:
|
|
|
102
101
|
(override) Snip the tip of max N lines if it is too long.
|
|
103
102
|
Keep the tip for calltip-click event.
|
|
104
103
|
"""
|
|
105
|
-
self._calltips =
|
|
104
|
+
self._calltips = [pos, tip, False]
|
|
106
105
|
lines = tip.splitlines()
|
|
107
106
|
if N and len(lines) > N > 0:
|
|
108
107
|
lines[N+1:] = ["\n...(snip) This tips are too long... "
|
|
109
108
|
"Click to show more details."]
|
|
110
109
|
tip = '\n'.join(lines)
|
|
110
|
+
self._calltips[-1] = True # snipped (needs to be shown)
|
|
111
111
|
super().CallTipShow(pos, tip)
|
|
112
112
|
|
|
113
113
|
def autoCallTipShow(self, command, insertcalltip=True):
|
|
@@ -142,7 +142,7 @@ class AutoCompInterfaceMixin:
|
|
|
142
142
|
self.message("- {} : {!r}".format(e, text))
|
|
143
143
|
|
|
144
144
|
def call_helpTip(self, evt):
|
|
145
|
-
"""Show
|
|
145
|
+
"""Show a calltip for the selected function."""
|
|
146
146
|
if self.CallTipActive():
|
|
147
147
|
self.CallTipCancel()
|
|
148
148
|
|
|
@@ -174,8 +174,11 @@ class AutoCompInterfaceMixin:
|
|
|
174
174
|
n = len(self.__comp_hint)
|
|
175
175
|
p = self.cpos
|
|
176
176
|
if not self.SelectedText:
|
|
177
|
-
p,
|
|
178
|
-
|
|
177
|
+
p, q, sty = self.get_following_atom(p) # word-right-selection
|
|
178
|
+
if sty == 'word':
|
|
179
|
+
self.anchor = q
|
|
180
|
+
with self.off_undocollection():
|
|
181
|
+
self.ReplaceSelection(word[n:])
|
|
179
182
|
self.cpos = p # backward selection to the point
|
|
180
183
|
self.__comp_ind = j
|
|
181
184
|
except IndexError:
|
|
@@ -264,7 +267,7 @@ class AutoCompInterfaceMixin:
|
|
|
264
267
|
self.message("[module]>>> loading {}...".format(text))
|
|
265
268
|
modules = set(dir(import_module(text)))
|
|
266
269
|
except ImportError as e:
|
|
267
|
-
self.message("\b failed
|
|
270
|
+
self.message("\b failed.", e)
|
|
268
271
|
return
|
|
269
272
|
else:
|
|
270
273
|
## Add unimported module names.
|
|
@@ -356,7 +359,7 @@ class AutoCompInterfaceMixin:
|
|
|
356
359
|
self.message("- {} : {!r}".format(e, text))
|
|
357
360
|
|
|
358
361
|
|
|
359
|
-
class EditorInterface(CtrlInterface):
|
|
362
|
+
class EditorInterface(AutoCompInterfaceMixin, CtrlInterface):
|
|
360
363
|
"""Interface of Python code editor.
|
|
361
364
|
|
|
362
365
|
Note:
|
|
@@ -364,6 +367,7 @@ class EditorInterface(CtrlInterface):
|
|
|
364
367
|
"""
|
|
365
368
|
def __init__(self):
|
|
366
369
|
CtrlInterface.__init__(self)
|
|
370
|
+
AutoCompInterfaceMixin.__init__(self)
|
|
367
371
|
|
|
368
372
|
def dispatch(evt):
|
|
369
373
|
"""Fork events to the parent."""
|
|
@@ -414,8 +418,8 @@ class EditorInterface(CtrlInterface):
|
|
|
414
418
|
'C-S-; pressed' : (0, _F(self.comment_out_line)),
|
|
415
419
|
'C-: pressed' : (0, _F(self.uncomment_line)),
|
|
416
420
|
'C-S-: pressed' : (0, _F(self.uncomment_line)),
|
|
417
|
-
'select_line' : (
|
|
418
|
-
'select_lines' : (
|
|
421
|
+
'select_line' : (11, self.on_linesel_begin),
|
|
422
|
+
'select_lines' : (11, self.on_linesel_next),
|
|
419
423
|
},
|
|
420
424
|
10 : {
|
|
421
425
|
'quit' : (0, self.on_itext_exit),
|
|
@@ -424,8 +428,8 @@ class EditorInterface(CtrlInterface):
|
|
|
424
428
|
'down pressed' : (10, skip),
|
|
425
429
|
'enter pressed' : (0, self.on_itext_selection),
|
|
426
430
|
},
|
|
427
|
-
|
|
428
|
-
'*Ldrag move' : (
|
|
431
|
+
11 : {
|
|
432
|
+
'*Ldrag move' : (11, self.on_linesel_motion),
|
|
429
433
|
'capture_lost' : (0, self.on_linesel_end),
|
|
430
434
|
'Lbutton released' : (0, self.on_linesel_end),
|
|
431
435
|
},
|
|
@@ -887,6 +891,7 @@ class EditorInterface(CtrlInterface):
|
|
|
887
891
|
## --------------------------------
|
|
888
892
|
## Python syntax and indentation
|
|
889
893
|
## --------------------------------
|
|
894
|
+
|
|
890
895
|
def on_indent_line(self, evt):
|
|
891
896
|
if self.SelectedText:
|
|
892
897
|
evt.Skip()
|
|
@@ -1191,10 +1196,10 @@ class EditorInterface(CtrlInterface):
|
|
|
1191
1196
|
"""
|
|
1192
1197
|
n = self.LinesOnScreen() # lines completely visible
|
|
1193
1198
|
m = n//2 if ln is None else ln % n if ln < n else n # ln[0:n]
|
|
1194
|
-
vl = self.
|
|
1199
|
+
vl = self._calc_vline(self.cline)
|
|
1195
1200
|
self.ScrollToLine(vl - m)
|
|
1196
1201
|
|
|
1197
|
-
def
|
|
1202
|
+
def _calc_vline(self, line):
|
|
1198
1203
|
"""Virtual line numberin the buffer window."""
|
|
1199
1204
|
pos = self.PositionFromLine(line)
|
|
1200
1205
|
w, h = self.PointFromPosition(pos)
|
|
@@ -1206,7 +1211,7 @@ class EditorInterface(CtrlInterface):
|
|
|
1206
1211
|
"""
|
|
1207
1212
|
n = self.LinesOnScreen() # lines completely visible
|
|
1208
1213
|
hl = self.FirstVisibleLine
|
|
1209
|
-
vl = self.
|
|
1214
|
+
vl = self._calc_vline(line)
|
|
1210
1215
|
if vl < hl:
|
|
1211
1216
|
self.ScrollToLine(vl)
|
|
1212
1217
|
elif vl > hl + n - 1:
|
|
@@ -1219,7 +1224,7 @@ class EditorInterface(CtrlInterface):
|
|
|
1219
1224
|
"""
|
|
1220
1225
|
n = self.LinesOnScreen() # lines completely visible
|
|
1221
1226
|
hl = self.FirstVisibleLine
|
|
1222
|
-
vl = self.
|
|
1227
|
+
vl = self._calc_vline(line)
|
|
1223
1228
|
if not hl + offset < vl < hl + n - 1 - offset:
|
|
1224
1229
|
self.ScrollToLine(vl - n//2)
|
|
1225
1230
|
|
|
@@ -1512,16 +1517,6 @@ class EditorInterface(CtrlInterface):
|
|
|
1512
1517
|
else:
|
|
1513
1518
|
self.anchor = q
|
|
1514
1519
|
|
|
1515
|
-
@contextmanager
|
|
1516
|
-
def off_readonly(self):
|
|
1517
|
-
"""Set buffer to be writable (ReadOnly=False) temporarily."""
|
|
1518
|
-
r = self.ReadOnly
|
|
1519
|
-
try:
|
|
1520
|
-
self.ReadOnly = 0
|
|
1521
|
-
yield
|
|
1522
|
-
finally:
|
|
1523
|
-
self.ReadOnly = r
|
|
1524
|
-
|
|
1525
1520
|
@contextmanager
|
|
1526
1521
|
def save_attributes(self, **kwargs):
|
|
1527
1522
|
"""Save buffer attributes (e.g. ReadOnly=False)."""
|
|
@@ -1534,6 +1529,14 @@ class EditorInterface(CtrlInterface):
|
|
|
1534
1529
|
for k, v in kwargs.items():
|
|
1535
1530
|
setattr(self, k, v)
|
|
1536
1531
|
|
|
1532
|
+
def off_readonly(self):
|
|
1533
|
+
"""Disables buffer read-only lock temporarily."""
|
|
1534
|
+
return self.save_attributes(ReadOnly=False)
|
|
1535
|
+
|
|
1536
|
+
def off_undocollection(self):
|
|
1537
|
+
"""Disables buffer undo stack temporarily."""
|
|
1538
|
+
return self.save_attributes(UndoCollection=False)
|
|
1539
|
+
|
|
1537
1540
|
## --------------------------------
|
|
1538
1541
|
## Edit: comment / insert / kill
|
|
1539
1542
|
## --------------------------------
|
|
@@ -1640,7 +1643,7 @@ class EditorInterface(CtrlInterface):
|
|
|
1640
1643
|
self.ReplaceSelection('')
|
|
1641
1644
|
|
|
1642
1645
|
|
|
1643
|
-
class Buffer(
|
|
1646
|
+
class Buffer(EditorInterface, EditWindow):
|
|
1644
1647
|
"""Python code buffer.
|
|
1645
1648
|
|
|
1646
1649
|
Attributes:
|
|
@@ -1766,7 +1769,6 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
|
|
|
1766
1769
|
def __init__(self, parent, filename=None, **kwargs):
|
|
1767
1770
|
EditWindow.__init__(self, parent, **kwargs)
|
|
1768
1771
|
EditorInterface.__init__(self)
|
|
1769
|
-
AutoCompInterfaceMixin.__init__(self)
|
|
1770
1772
|
|
|
1771
1773
|
self.parent = parent
|
|
1772
1774
|
self.__filename = filename
|
|
@@ -1795,18 +1797,18 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
|
|
|
1795
1797
|
def clear(evt):
|
|
1796
1798
|
## """Clear selection and message, no skip."""
|
|
1797
1799
|
## *do not* clear autocomp, so that the event can skip to AutoComp properly.
|
|
1798
|
-
## if self.AutoCompActive():
|
|
1799
|
-
## self.AutoCompCancel() # may delete selection
|
|
1800
1800
|
if self.CanEdit():
|
|
1801
|
-
self.
|
|
1801
|
+
with self.off_undocollection():
|
|
1802
|
+
self.ReplaceSelection("")
|
|
1802
1803
|
self.message("")
|
|
1803
1804
|
|
|
1804
1805
|
def clear_autocomp(evt):
|
|
1805
|
-
## """Clear
|
|
1806
|
+
## """Clear autocomp, selection, and message."""
|
|
1806
1807
|
if self.AutoCompActive():
|
|
1807
1808
|
self.AutoCompCancel()
|
|
1808
1809
|
if self.CanEdit():
|
|
1809
|
-
self.
|
|
1810
|
+
with self.off_undocollection():
|
|
1811
|
+
self.ReplaceSelection("")
|
|
1810
1812
|
self.message("")
|
|
1811
1813
|
|
|
1812
1814
|
def fork(evt):
|
|
@@ -1840,7 +1842,7 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
|
|
|
1840
1842
|
'* released' : (0, skip, dispatch),
|
|
1841
1843
|
'escape pressed' : (-1, self.on_enter_escmap),
|
|
1842
1844
|
'C-h pressed' : (0, self.call_helpTip),
|
|
1843
|
-
'. pressed' : (2,
|
|
1845
|
+
'. pressed' : (2, self.OnEnterDot),
|
|
1844
1846
|
'M-. pressed' : (2, self.call_word_autocomp),
|
|
1845
1847
|
'M-/ pressed' : (3, self.call_apropos_autocomp),
|
|
1846
1848
|
},
|
|
@@ -1922,7 +1924,9 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
|
|
|
1922
1924
|
def OnCallTipClick(self, evt):
|
|
1923
1925
|
if self.CallTipActive():
|
|
1924
1926
|
self.CallTipCancel()
|
|
1925
|
-
self.
|
|
1927
|
+
pos, tip, more = self._calltips
|
|
1928
|
+
if more:
|
|
1929
|
+
self.CallTipShow(pos, tip, N=None)
|
|
1926
1930
|
evt.Skip()
|
|
1927
1931
|
|
|
1928
1932
|
def OnIndicatorClick(self, evt):
|
|
@@ -1960,6 +1964,14 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
|
|
|
1960
1964
|
self.update_caption()
|
|
1961
1965
|
evt.Skip()
|
|
1962
1966
|
|
|
1967
|
+
def OnEnterDot(self, evt):
|
|
1968
|
+
p = self.cpos
|
|
1969
|
+
st = self.get_style(p-1)
|
|
1970
|
+
rst = self.get_style(p)
|
|
1971
|
+
if st not in ('moji', 'word', 'rparen') or rst == 'word':
|
|
1972
|
+
self.handler('quit', evt) # don't enter autocomp
|
|
1973
|
+
evt.Skip()
|
|
1974
|
+
|
|
1963
1975
|
def on_activated(self, buf):
|
|
1964
1976
|
"""Called when the buffer is activated."""
|
|
1965
1977
|
self.update_caption()
|
|
@@ -2052,6 +2064,9 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
|
|
|
2052
2064
|
dispatcher.send(signal='Interpreter.push',
|
|
2053
2065
|
sender=self, command=None, more=False)
|
|
2054
2066
|
|
|
2067
|
+
def eval_line(self):
|
|
2068
|
+
self.py_eval_line(self.globals, self.locals)
|
|
2069
|
+
|
|
2055
2070
|
def py_eval_line(self, globals=None, locals=None):
|
|
2056
2071
|
if self.CallTipActive():
|
|
2057
2072
|
self.CallTipCancel()
|
|
@@ -2068,6 +2083,9 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
|
|
|
2068
2083
|
return
|
|
2069
2084
|
self.message(status)
|
|
2070
2085
|
|
|
2086
|
+
def exec_region(self):
|
|
2087
|
+
self.py_exec_region(self.globals, self.locals)
|
|
2088
|
+
|
|
2071
2089
|
def py_exec_region(self, globals=None, locals=None, filename=None):
|
|
2072
2090
|
if not filename:
|
|
2073
2091
|
filename = self.filename
|
|
@@ -2100,23 +2118,6 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
|
|
|
2100
2118
|
self.handler('buffer_region_executed', self)
|
|
2101
2119
|
self.message("Evaluated {!r} successfully.".format(filename))
|
|
2102
2120
|
self.AnnotationClearAll()
|
|
2103
|
-
|
|
2104
|
-
def py_get_region(self, line):
|
|
2105
|
-
"""Line numbers of code head and tail containing the line.
|
|
2106
|
-
|
|
2107
|
-
Requires a code object.
|
|
2108
|
-
If the code doesn't exist, return the folding region.
|
|
2109
|
-
"""
|
|
2110
|
-
if not self.code:
|
|
2111
|
-
return self.get_region(line)
|
|
2112
|
-
lc, le = 0, self.LineCount
|
|
2113
|
-
linestarts = list(dis.findlinestarts(self.code))
|
|
2114
|
-
for i, ln in reversed(linestarts):
|
|
2115
|
-
if line >= ln-1:
|
|
2116
|
-
lc = ln-1
|
|
2117
|
-
break
|
|
2118
|
-
le = ln-1
|
|
2119
|
-
return lc, le
|
|
2120
2121
|
|
|
2121
2122
|
|
|
2122
2123
|
class EditorBook(AuiNotebook, CtrlInterface):
|
|
@@ -2402,7 +2403,7 @@ class EditorBook(AuiNotebook, CtrlInterface):
|
|
|
2402
2403
|
return True
|
|
2403
2404
|
return False
|
|
2404
2405
|
except Exception as e:
|
|
2405
|
-
self.post_message(f"Failed to load {filename!r}
|
|
2406
|
+
self.post_message(f"Failed to load {filename!r}.", e)
|
|
2406
2407
|
self.delete_buffer(buf)
|
|
2407
2408
|
return False
|
|
2408
2409
|
|
|
@@ -2410,6 +2411,7 @@ class EditorBook(AuiNotebook, CtrlInterface):
|
|
|
2410
2411
|
"""Open the specified file."""
|
|
2411
2412
|
if not filename:
|
|
2412
2413
|
with wx.FileDialog(self, "Open buffer",
|
|
2414
|
+
defaultDir=os.path.dirname(self.buffer.filename),
|
|
2413
2415
|
wildcard='|'.join(self.wildcards),
|
|
2414
2416
|
style=wx.FD_OPEN|wx.FD_MULTIPLE) as dlg:
|
|
2415
2417
|
if dlg.ShowModal() == wx.ID_OK:
|
|
@@ -2444,7 +2446,7 @@ class EditorBook(AuiNotebook, CtrlInterface):
|
|
|
2444
2446
|
return True
|
|
2445
2447
|
return False
|
|
2446
2448
|
except Exception as e:
|
|
2447
|
-
self.post_message(f"Failed to save {filename!r}
|
|
2449
|
+
self.post_message(f"Failed to save {filename!r}.", e)
|
|
2448
2450
|
return False
|
|
2449
2451
|
|
|
2450
2452
|
def load_buffer(self, buf=None):
|
|
@@ -2477,6 +2479,7 @@ class EditorBook(AuiNotebook, CtrlInterface):
|
|
|
2477
2479
|
"""Confirm the saveas with the dialog."""
|
|
2478
2480
|
buf = buf or self.buffer
|
|
2479
2481
|
with wx.FileDialog(self, "Save buffer as",
|
|
2482
|
+
defaultDir=os.path.dirname(self.buffer.filename),
|
|
2480
2483
|
defaultFile=re.sub(r'[\/:*?"<>|]', '_', buf.name),
|
|
2481
2484
|
wildcard='|'.join(self.wildcards),
|
|
2482
2485
|
style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dlg:
|
|
@@ -2519,11 +2522,10 @@ class EditorBook(AuiNotebook, CtrlInterface):
|
|
|
2519
2522
|
class Interpreter(interpreter.Interpreter):
|
|
2520
2523
|
"""Interpreter based on code.InteractiveInterpreter.
|
|
2521
2524
|
"""
|
|
2522
|
-
def __init__(self, *args, **kwargs):
|
|
2523
|
-
parent = kwargs.pop('interpShell')
|
|
2525
|
+
def __init__(self, interpShell, *args, **kwargs):
|
|
2524
2526
|
interpreter.Interpreter.__init__(self, *args, **kwargs)
|
|
2525
2527
|
|
|
2526
|
-
self.parent =
|
|
2528
|
+
self.parent = interpShell
|
|
2527
2529
|
self.globals = self.locals
|
|
2528
2530
|
|
|
2529
2531
|
def runcode(self, code):
|
|
@@ -2587,7 +2589,7 @@ class Interpreter(interpreter.Interpreter):
|
|
|
2587
2589
|
return interpreter.Interpreter.getCallTip(self) # dummy
|
|
2588
2590
|
|
|
2589
2591
|
|
|
2590
|
-
class Nautilus(
|
|
2592
|
+
class Nautilus(EditorInterface, Shell):
|
|
2591
2593
|
"""Nautilus in the Shell.
|
|
2592
2594
|
|
|
2593
2595
|
Facade objects for accessing the APIs:
|
|
@@ -2624,8 +2626,8 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
2624
2626
|
|
|
2625
2627
|
C-up : [0] retrieve previous history
|
|
2626
2628
|
C-down : [0] retrieve next history
|
|
2627
|
-
C-j, M-j : [0]
|
|
2628
|
-
C-h, M-h : [0]
|
|
2629
|
+
C-j, M-j : [0] tooltip of eval (for the selected or focused word)
|
|
2630
|
+
C-h, M-h : [0] calltip of help (for the selected or focused func)
|
|
2629
2631
|
TAB : [1] history-comp
|
|
2630
2632
|
M-p : [1] retrieve previous history in history-comp mode
|
|
2631
2633
|
M-n : [1] retrieve next history in history-comp mode
|
|
@@ -2697,7 +2699,9 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
2697
2699
|
raise TypeError("primitive objects cannot be targeted")
|
|
2698
2700
|
|
|
2699
2701
|
self.__target = obj
|
|
2700
|
-
self.
|
|
2702
|
+
self.locals = obj.__dict__
|
|
2703
|
+
self.globals = obj.__dict__
|
|
2704
|
+
self.globals.update(self.__globals)
|
|
2701
2705
|
try:
|
|
2702
2706
|
obj.self = obj
|
|
2703
2707
|
obj.this = inspect.getmodule(obj)
|
|
@@ -2730,9 +2734,9 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
2730
2734
|
@globals.deleter
|
|
2731
2735
|
def globals(self): # internal use only
|
|
2732
2736
|
self.interp.globals = self.__target.__dict__
|
|
2737
|
+
self.interp.globals.update(self.__globals)
|
|
2733
2738
|
|
|
2734
|
-
|
|
2735
|
-
wrap = EditorInterface.wrap
|
|
2739
|
+
__globals = {}
|
|
2736
2740
|
|
|
2737
2741
|
def __init__(self, parent, target, name="root",
|
|
2738
2742
|
introText=None,
|
|
@@ -2741,14 +2745,13 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
2741
2745
|
**kwargs):
|
|
2742
2746
|
Shell.__init__(self, parent,
|
|
2743
2747
|
locals=target.__dict__,
|
|
2744
|
-
interpShell=self,
|
|
2748
|
+
interpShell=self, # **kwds of InterpClass
|
|
2745
2749
|
InterpClass=Interpreter,
|
|
2746
2750
|
introText=introText,
|
|
2747
2751
|
startupScript=startupScript,
|
|
2748
|
-
execStartupScript=execStartupScript, #
|
|
2752
|
+
execStartupScript=execStartupScript, # executes ~/.py
|
|
2749
2753
|
**kwargs)
|
|
2750
2754
|
EditorInterface.__init__(self)
|
|
2751
|
-
AutoCompInterfaceMixin.__init__(self)
|
|
2752
2755
|
|
|
2753
2756
|
self.parent = parent #: parent<ShellFrame> is not Parent<AuiNotebook>
|
|
2754
2757
|
self.target = target
|
|
@@ -2780,28 +2783,20 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
2780
2783
|
def clear(evt):
|
|
2781
2784
|
## """Clear selection and message, no skip."""
|
|
2782
2785
|
## *do not* clear autocomp, so that the event can skip to AutoComp properly.
|
|
2783
|
-
## if self.AutoCompActive():
|
|
2784
|
-
## self.AutoCompCancel() # may delete selection
|
|
2785
2786
|
if self.CanEdit():
|
|
2786
|
-
self.
|
|
2787
|
+
with self.off_undocollection():
|
|
2788
|
+
self.ReplaceSelection("")
|
|
2787
2789
|
self.message("")
|
|
2788
2790
|
|
|
2789
2791
|
def clear_autocomp(evt):
|
|
2790
|
-
## """Clear
|
|
2792
|
+
## """Clear autocomp, selection, and message."""
|
|
2791
2793
|
if self.AutoCompActive():
|
|
2792
2794
|
self.AutoCompCancel()
|
|
2793
2795
|
if self.CanEdit():
|
|
2794
|
-
self.
|
|
2796
|
+
with self.off_undocollection():
|
|
2797
|
+
self.ReplaceSelection("")
|
|
2795
2798
|
self.message("")
|
|
2796
2799
|
|
|
2797
|
-
def skip_autocomp(evt):
|
|
2798
|
-
## """Don't eat backward prompt whitespace."""
|
|
2799
|
-
## Prevent autocomp from eating prompts.
|
|
2800
|
-
## Quit to avoid backspace over the last non-continuation prompt.
|
|
2801
|
-
if self.cpos == self.bolc:
|
|
2802
|
-
self.handler('quit', evt)
|
|
2803
|
-
evt.Skip()
|
|
2804
|
-
|
|
2805
2800
|
def fork(evt):
|
|
2806
2801
|
self.handler.fork(self.handler.current_event, evt)
|
|
2807
2802
|
|
|
@@ -2844,7 +2839,6 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
2844
2839
|
'C-enter pressed' : (0, _F(self.insertLineBreak)),
|
|
2845
2840
|
'C-S-enter pressed' : (0, _F(self.insertLineBreak)),
|
|
2846
2841
|
'*enter pressed' : (0, ), # -> OnShowCompHistory 無効
|
|
2847
|
-
'left pressed' : (0, self.OnBackspace),
|
|
2848
2842
|
'C-[ pressed' : (0, _F(self.goto_previous_mark_arrow)),
|
|
2849
2843
|
'C-S-[ pressed' : (0, _F(self.goto_previous_mark_arrow, selection=1)),
|
|
2850
2844
|
'C-] pressed' : (0, _F(self.goto_next_mark_arrow)),
|
|
@@ -2915,7 +2909,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
2915
2909
|
'S-[a-z\\] released' : (2, self.call_word_autocomp),
|
|
2916
2910
|
'\\ released' : (2, self.call_word_autocomp),
|
|
2917
2911
|
'*delete pressed' : (2, skip),
|
|
2918
|
-
'*backspace pressed' : (2,
|
|
2912
|
+
'*backspace pressed' : (2, self.OnBackspace),
|
|
2919
2913
|
'*backspace released' : (2, self.call_word_autocomp),
|
|
2920
2914
|
'C-S-backspace pressed' : (2, ),
|
|
2921
2915
|
'C-j pressed' : (2, self.eval_line),
|
|
@@ -2943,7 +2937,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
2943
2937
|
'S-[a-z\\] released' : (3, self.call_apropos_autocomp),
|
|
2944
2938
|
'\\ released' : (3, self.call_apropos_autocomp),
|
|
2945
2939
|
'*delete pressed' : (3, skip),
|
|
2946
|
-
'*backspace pressed' : (3,
|
|
2940
|
+
'*backspace pressed' : (3, self.OnBackspace),
|
|
2947
2941
|
'*backspace released' : (3, self.call_apropos_autocomp),
|
|
2948
2942
|
'C-S-backspace pressed' : (3, ),
|
|
2949
2943
|
'C-j pressed' : (3, self.eval_line),
|
|
@@ -2971,7 +2965,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
2971
2965
|
'S-[a-z\\] released' : (4, self.call_text_autocomp),
|
|
2972
2966
|
'\\ released' : (4, self.call_text_autocomp),
|
|
2973
2967
|
'*delete pressed' : (4, skip),
|
|
2974
|
-
'*backspace pressed' : (4,
|
|
2968
|
+
'*backspace pressed' : (4, self.OnBackspace),
|
|
2975
2969
|
'*backspace released' : (4, self.call_text_autocomp),
|
|
2976
2970
|
'C-S-backspace pressed' : (4, ),
|
|
2977
2971
|
'C-j pressed' : (4, self.eval_line),
|
|
@@ -3000,7 +2994,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
3000
2994
|
'\\ released' : (5, self.call_module_autocomp),
|
|
3001
2995
|
'M-m pressed' : (5, _F(self.call_module_autocomp, force=1)),
|
|
3002
2996
|
'*delete pressed' : (5, skip),
|
|
3003
|
-
'*backspace pressed' : (5,
|
|
2997
|
+
'*backspace pressed' : (5, self.OnBackspace),
|
|
3004
2998
|
'*backspace released' : (5, self.call_module_autocomp),
|
|
3005
2999
|
'C-S-backspace pressed' : (5, ),
|
|
3006
3000
|
'*alt pressed' : (5, ),
|
|
@@ -3076,12 +3070,11 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
3076
3070
|
evt.Skip()
|
|
3077
3071
|
|
|
3078
3072
|
def OnBackspace(self, evt):
|
|
3079
|
-
"""Called when backspace
|
|
3080
|
-
Backspace-guard from
|
|
3073
|
+
"""Called when backspace pressed.
|
|
3074
|
+
Backspace-guard from autocomp eating over a prompt whitespace.
|
|
3081
3075
|
"""
|
|
3082
3076
|
if self.cpos == self.bolc:
|
|
3083
|
-
|
|
3084
|
-
## so not to backspace over the latest non-continuation prompt
|
|
3077
|
+
self.handler('quit', evt) # don't eat backward prompt
|
|
3085
3078
|
return
|
|
3086
3079
|
evt.Skip()
|
|
3087
3080
|
|
|
@@ -3153,7 +3146,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
3153
3146
|
self.ReplaceSelection('self')
|
|
3154
3147
|
elif st not in ('moji', 'word', 'rparen') or rst == 'word':
|
|
3155
3148
|
self.handler('quit', evt) # don't enter autocomp
|
|
3156
|
-
|
|
3149
|
+
evt.Skip()
|
|
3157
3150
|
|
|
3158
3151
|
def on_enter_escmap(self, evt):
|
|
3159
3152
|
self.__caret_mode = self.CaretPeriod
|
|
@@ -3203,7 +3196,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
3203
3196
|
def magic(self, cmd):
|
|
3204
3197
|
"""Called before command pushed.
|
|
3205
3198
|
|
|
3206
|
-
(override)
|
|
3199
|
+
(override) Disable old magic: `f x --> f(x)`.
|
|
3207
3200
|
"""
|
|
3208
3201
|
if cmd:
|
|
3209
3202
|
if cmd[0:2] == '??': cmd = 'help({})'.format(cmd[2:])
|
|
@@ -3461,7 +3454,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
3461
3454
|
(override) Add globals when executing su:startupScript.
|
|
3462
3455
|
Fix history point.
|
|
3463
3456
|
"""
|
|
3464
|
-
|
|
3457
|
+
keys = set(self.locals.keys()) # check for locals map changes
|
|
3465
3458
|
self.promptPosEnd = self.TextLength # fix history point
|
|
3466
3459
|
if su and os.path.isfile(su):
|
|
3467
3460
|
self.push("print('Startup script executed:', {0!r})\n".format(su))
|
|
@@ -3471,6 +3464,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
3471
3464
|
else:
|
|
3472
3465
|
self.push("")
|
|
3473
3466
|
self.interp.startupScript = None
|
|
3467
|
+
self.__globals = {k: self.locals[k] for k in (self.locals.keys() - keys)}
|
|
3474
3468
|
|
|
3475
3469
|
def Paste(self, rectangle=False):
|
|
3476
3470
|
"""Replace selection with clipboard contents.
|
|
@@ -3617,8 +3611,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
|
|
|
3617
3611
|
self.EnsureCaretVisible()
|
|
3618
3612
|
|
|
3619
3613
|
def eval_line(self, evt):
|
|
3620
|
-
"""Evaluate the selected word or line.
|
|
3621
|
-
"""
|
|
3614
|
+
"""Evaluate the selected word or line."""
|
|
3622
3615
|
if self.CallTipActive():
|
|
3623
3616
|
self.CallTipCancel()
|
|
3624
3617
|
|
mwx/plugins/ffmpeg_view.py
CHANGED
|
@@ -122,7 +122,7 @@ class Plugin(Layer):
|
|
|
122
122
|
(1, "&Load file", Icon('open'),
|
|
123
123
|
lambda v: self.load_media()),
|
|
124
124
|
|
|
125
|
-
(2, "&Snapshot", Icon('
|
|
125
|
+
(2, "&Snapshot", Icon('clip'),
|
|
126
126
|
lambda v: self.snapshot(),
|
|
127
127
|
lambda v: v.Enable(self._path is not None)),
|
|
128
128
|
(),
|
|
@@ -175,7 +175,7 @@ class Plugin(Layer):
|
|
|
175
175
|
def load_media(self, path=None):
|
|
176
176
|
if path is None:
|
|
177
177
|
with wx.FileDialog(self, "Choose a media file",
|
|
178
|
-
|
|
178
|
+
style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST) as dlg:
|
|
179
179
|
if dlg.ShowModal() != wx.ID_OK:
|
|
180
180
|
return None
|
|
181
181
|
path = dlg.Path
|
mwx/utilus.py
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
mwx/__init__.py,sha256=nN62CGTWjME7Zz2h-jIRB8MxwuErIkHPGrlBzydkF0o,643
|
|
2
2
|
mwx/bookshelf.py,sha256=Y4xI2SrEO22DrI1hyyfFx7DfFZA8znOzX9RWMPsA2BE,5137
|
|
3
|
-
mwx/controls.py,sha256=
|
|
4
|
-
mwx/framework.py,sha256=
|
|
5
|
-
mwx/graphman.py,sha256=
|
|
3
|
+
mwx/controls.py,sha256=jhru4HiIijb3QJz2elGt0in9soaR3xilgHsfItYY0JI,47595
|
|
4
|
+
mwx/framework.py,sha256=I4Hvu2swHbgvbjqVXNnuU2V8kkxKmK6eRktqQa5D0cE,75518
|
|
5
|
+
mwx/graphman.py,sha256=A53ufapRAysL0wTCr1anrg_T_PqpumonnYn-swaC598,70165
|
|
6
6
|
mwx/images.py,sha256=_-Eh3xF7Khu42ivkYp97NXIzSNGbjcidqtWjZQFGtqE,47827
|
|
7
7
|
mwx/matplot2.py,sha256=xCJ_ZzdDEWmzctpPaOrzTnwXyHINP4nfFHweoTZa6ug,32899
|
|
8
|
-
mwx/matplot2g.py,sha256=
|
|
8
|
+
mwx/matplot2g.py,sha256=3hS0ilXCif0mZkSufE_Rf-taRs3m1hIxiIFMuioYYuc,64371
|
|
9
9
|
mwx/matplot2lg.py,sha256=JRWjWnLJUytbSq6wxs4P0gbVUr3xoLSF6Wwqd5V_pJI,27404
|
|
10
|
-
mwx/mgplt.py,sha256=
|
|
11
|
-
mwx/nutshell.py,sha256=
|
|
12
|
-
mwx/utilus.py,sha256=
|
|
10
|
+
mwx/mgplt.py,sha256=r56SFryorIgO12mvHJY-z6uwWsaPEqk6pHYwKWqbTY4,5663
|
|
11
|
+
mwx/nutshell.py,sha256=vz3RTrIECi9LpjgAj2jKAIjMCeJ7ZvJ8mbH3phBxuvg,141423
|
|
12
|
+
mwx/utilus.py,sha256=B76pDg6_kW8FMNdQ6xO0Bwy4KJ0laY98Gg6N3iqV7c8,37325
|
|
13
13
|
mwx/wxmon.py,sha256=f3V24EF7kdMlYF7usLYK9QE5KU6fSu0jVqsvwAiA-Ag,12647
|
|
14
14
|
mwx/wxpdb.py,sha256=lLowkkAgMhPFHAfklD7wZHq0qbSMjRxnBFtSajmVgME,19133
|
|
15
15
|
mwx/wxwil.py,sha256=hhyB1lPrF9ixeObxCOKQv0Theu-B-kpJg_yVU3EGSNg,5406
|
|
16
16
|
mwx/wxwit.py,sha256=ifxMwdIz-QhDEr8vyAztToF8VVSxKNXlq4Ap1awBZvo,7362
|
|
17
17
|
mwx/plugins/__init__.py,sha256=jnJ-Sl9XJ_7BFDslD_r7dsbxsOT57q_IaEriV53XIGY,41
|
|
18
|
-
mwx/plugins/ffmpeg_view.py,sha256=
|
|
18
|
+
mwx/plugins/ffmpeg_view.py,sha256=epO_26sPmdDyr_lApa2Jtgxp-yCEdW0OEz0_QbrFEuM,10427
|
|
19
19
|
mwx/plugins/fft_view.py,sha256=xxTDD-_z4l18u4t2ybPB3xAMIslJmJ0gQlTxEqJUhNI,2782
|
|
20
20
|
mwx/plugins/frame_listview.py,sha256=hbApzZWa9-BmQthu7uZBlBbGbtf4iJ_prO8IhxoGMs8,10421
|
|
21
21
|
mwx/plugins/line_profile.py,sha256=--9NIc3x5EfRB3L59JvD7rzENQHyiYfu7wWJo6AuMkA,820
|
|
22
22
|
mwx/py/__init__.py,sha256=xykgfOytOwNuvXsfkLoumFZSTN-iBsHOjczYXngjmUE,12
|
|
23
23
|
mwx/py/filling.py,sha256=fumUG1F5M9TL-Dfqni4G85uk7TmvnUunTbdcPDV0vfo,16857
|
|
24
|
-
mwxlib-0.98.
|
|
25
|
-
mwxlib-0.98.
|
|
26
|
-
mwxlib-0.98.
|
|
27
|
-
mwxlib-0.98.
|
|
28
|
-
mwxlib-0.98.
|
|
24
|
+
mwxlib-0.98.5.dist-info/LICENSE,sha256=PGtRKCaTkmUDlBQwpptJAxJtdqxIUtAmdBsaT9nUVkA,1091
|
|
25
|
+
mwxlib-0.98.5.dist-info/METADATA,sha256=nGXEgL3ckNH2HlXpYXQsjteMpc8MhQWDZ_5DtjAtp2A,1880
|
|
26
|
+
mwxlib-0.98.5.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
|
|
27
|
+
mwxlib-0.98.5.dist-info/top_level.txt,sha256=SI1Mh118AstnUFGPNq5aMNKiAnVNmZk1S9Ij-OwAEpY,4
|
|
28
|
+
mwxlib-0.98.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|