From 26b91a633c6264f2fb11cbb7a418894dbdce4759 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 8 Mar 2012 11:04:28 -0500 Subject: [PATCH] Add a `Delete` button to the GUI NavBar, and cleanup deletion callbacks. The most confusing part of this change is the adjustment to `Default.txt`. The NavBar was not expanding to display the new button (which was avialable via a flyout), so I had to manually adjust the default perspective. Because we load the default perspective after setting up the GUI, any changes in the code (e.g. setting a reasonable width) get clobbered later by `Default.txt`. Anyhow, the change I made to `Default.txt` was to change the toolbar's `bestw` from 100 to 300. --- hooke/ui/gui/interface.py | 60 +++++++++++++++++---------- hooke/ui/gui/navbar.py | 19 ++++++++- hooke/ui/gui/panel/playlist.py | 52 +++++++++-------------- hooke/ui/gui/perspectives/Default.txt | 2 +- 4 files changed, 75 insertions(+), 58 deletions(-) diff --git a/hooke/ui/gui/interface.py b/hooke/ui/gui/interface.py index 2c58923..3ea8631 100644 --- a/hooke/ui/gui/interface.py +++ b/hooke/ui/gui/interface.py @@ -130,10 +130,8 @@ class HookeFrame (wx.Frame): # defaultFilter=self.gui.config['folders-filter-index']), 'left'), (panel.PANELS['playlist']( callbacks={ - 'delete_playlist':self._on_user_delete_playlist, - '_delete_playlist':self._on_delete_playlist, - 'delete_curve':self._on_user_delete_curve, - '_delete_curve':self._on_delete_curve, + '_delete_playlist':self._delete_playlist, + '_delete_curve':self._delete_curve, '_on_set_selected_playlist':self._on_set_selected_playlist, '_on_set_selected_curve':self._on_set_selected_curve, }, @@ -221,9 +219,9 @@ class HookeFrame (wx.Frame): callbacks={ 'next': self._next_curve, 'previous': self._previous_curve, + 'delete': self._delete_curve, }, - parent=self, - style=wx.TB_FLAT | wx.TB_NODIVIDER) + parent=self) self._c['manager'].AddPane( self._c['navigation bar'], aui.AuiPaneInfo().Name('Navigation').Caption('Navigation' @@ -238,6 +236,7 @@ class HookeFrame (wx.Frame): self.Bind(wx.EVT_SIZE, self._on_size) self.Bind(wx.EVT_CLOSE, self._on_close) self.Bind(aui.EVT_AUI_PANE_CLOSE, self._on_pane_close) + self.Bind(wx.EVT_CHAR_HOOK, self._on_key) return # TODO: cleanup treeCtrl = self._c['folders'].GetTreeCtrl() @@ -259,6 +258,7 @@ class HookeFrame (wx.Frame): def _on_close(self, *args): self.log.info('closing GUI framework') + # apply changes self._set_config('main height', self.GetSize().GetHeight()) self._set_config('main left', self.GetPosition()[0]) @@ -271,6 +271,16 @@ class HookeFrame (wx.Frame): def _on_erase_background(self, event): event.Skip() + def _on_key(self, event): + code = event.GetKeyCode() + if code == wx.WXK_RIGHT: + self._next_curve() + elif code == wx.WXK_LEFT: + self._previous_curve() + elif code == wx.WXK_DELETE or code == wx.WXK_BACK: + self._delete_curve() + else: + event.Skip() # Panel utility functions @@ -520,6 +530,11 @@ class HookeFrame (wx.Frame): self.execute_command( command=self._command_by_name('get playlist')) + def _postprocess_delete_curve(self, command, args={}, results=[]): + """No-op. Only call 'delete curve' via `self._delete_curve()`. + """ + pass + def _update_curve(self, command, args={}, results=[]): """Update the curve, since the available columns may have changed. """ @@ -594,22 +609,11 @@ class HookeFrame (wx.Frame): # Playlist panel interface - def _on_user_delete_playlist(self, _class, method, playlist): - pass - - def _on_delete_playlist(self, _class, method, playlist): - if hasattr(playlist, 'path') and playlist.path != None: - os.remove(playlist.path) - - def _on_user_delete_curve(self, _class, method, playlist, curve): - pass - - def _on_delete_curve(self, _class, method, playlist, curve): - index = playlist.index(curve) - results = self.execute_command( - command=self._command_by_name('remove curve from playlist'), - args={'index': index}) - #os.remove(curve.path) + def _delete_playlist(self, _class, method, playlist): + #if hasattr(playlist, 'path') and playlist.path != None: + # os.remove(playlist.path) + # TODO: remove playlist from underlying hooke instance and call ._c['playlist'].delete_playlist() + # possibly rename this method to _postprocess_delete_playlist... pass def _on_set_selected_playlist(self, _class, method, playlist): @@ -675,6 +679,18 @@ class HookeFrame (wx.Frame): self.execute_command( command=self._command_by_name('get curve')) + def _delete_curve(self, *args, **kwargs): + cmd_kwargs = {} + playlist = kwargs.get('playlist', None) + curve = kwargs.get('curve', None) + if playlist is not None and curve is not None: + cmd_kwargs['index'] = playlist.index(curve) + results = self.execute_command( + command=self._command_by_name('remove curve from playlist'), + args=cmd_kwargs) + if isinstance(results[-1], Success): + results = self.execute_command( + command=self._command_by_name('get playlist')) # Panel display handling diff --git a/hooke/ui/gui/navbar.py b/hooke/ui/gui/navbar.py index 3d18e64..2203e43 100644 --- a/hooke/ui/gui/navbar.py +++ b/hooke/ui/gui/navbar.py @@ -51,11 +51,22 @@ class NavBar (aui.AuiToolBar): short_help_string='Next curve', long_help_string='', client_data=None), + 'delete': self.AddTool( + tool_id=wx.ID_DELETE, + label='Delete', + bitmap=wx.ArtProvider_GetBitmap( + wx.ART_DELETE, wx.ART_OTHER, bitmap_size), + disabled_bitmap=wx.NullBitmap, + kind=wx.ITEM_NORMAL, + short_help_string='Remove curve from playlist', + long_help_string='', + client_data=None), } self.Realize() self._callbacks = callbacks self.Bind(wx.EVT_TOOL, self._on_next, self._c['next']) self.Bind(wx.EVT_TOOL, self._on_previous, self._c['previous']) + self.Bind(wx.EVT_TOOL, self._on_delete, self._c['delete']) def _on_next(self, event): self.next() @@ -63,6 +74,9 @@ class NavBar (aui.AuiToolBar): def _on_previous(self, event): self.previous() + def _on_delete(self, event): + self.delete() + @callback def next(self): pass @@ -71,5 +85,6 @@ class NavBar (aui.AuiToolBar): def previous(self): pass - - + @callback + def delete(self): + pass diff --git a/hooke/ui/gui/panel/playlist.py b/hooke/ui/gui/panel/playlist.py index e8c8f84..cf069e8 100644 --- a/hooke/ui/gui/panel/playlist.py +++ b/hooke/ui/gui/panel/playlist.py @@ -196,46 +196,39 @@ class Tree (wx.TreeCtrl): del(self._hit_id) name = self._name_for_id[_id] if self._is_curve(name): - self.delete_curve(playlist_name=name[0], name=name[1]) + self._delete_curve(playlist_name=name[0], name=name[1]) else: - self.delete_playlist(name) + self._delete_playlist(name) - def delete_playlist(self, name): + def _delete_playlist(self, name): """Delete a :class:`hooke.playlist.Playlist` by name. - Called by the :meth:`_on_delete` handler. - - Removes the playlist and its curves from the tree, then calls - :meth:`_delete_playlist`. + Called by the :meth:`_on_delete` handler. Calls the + approptiate interface callback. """ _id = self._id_for_name[name] - self.Delete(_id) playlist = self._playlists[name] - self._delete_playlist(playlist) in_callback(self, playlist) - def _delete_playlist(self, playlist): - """Adjust name/id caches for the playlist and its curves. + def delete_playlist(self, playlist): + """Respond to playlist deletion. Called on *every* playlist deletion. """ self._playlists.pop(playlist.name) _id = self._id_for_name.pop(playlist.name) + self.Delete(_id) del(self._name_for_id[_id]) for curve in playlist: self._delete_curve(playlist, curve) - in_callback(self, playlist) - def delete_curve(self, playlist_name, name): + def _delete_curve(self, playlist_name, name): """Delete a :class:`hooke.curve.Curve` by name. - Called by the :meth:`_on_delete` handler. - - Removes the curve from the tree, then calls - :meth:`_delete_curve`. + Called by the :meth:`_on_delete` handler. Calls the + approptiate interface callback. """ _id = self._id_for_name[(playlist_name, name)] - self.Delete(_id) playlist = self._playlists[playlist_name] curve = None for i,c in enumerate(playlist): @@ -244,17 +237,16 @@ class Tree (wx.TreeCtrl): break if curve is None: raise ValueError(name) - self._delete_curve(playlist=playlist, curve=curve) in_callback(self, playlist, curve) - def _delete_curve(self, playlist, curve): - """Adjust name/id caches. + def delete_curve(self, playlist_name, name): + """Respond to curve deletions. - Called on _every_ curve deletion. + Called on *every* curve deletion. """ - _id = self._id_for_name.pop((playlist.name, curve.name)) + _id = self._id_for_name.pop((playlist_name, name)) + self.Delete(_id) del(self._name_for_id[_id]) - in_callback(self, playlist=playlist, curve=curve) # Get selection @@ -334,15 +326,11 @@ class Tree (wx.TreeCtrl): """Absorb changed `.index()`, etc. """ self._playlists[playlist.name] = playlist - cnames = [] + cnames = set() for curve in playlist: if (playlist.name, curve.name) not in self._id_for_name: self._add_curve(playlist.name, curve) - cnames.append(curve.name) - dc = self._callbacks['delete_curve'] - _dc = self._callbacks['_delete_curve'] - self._callbacks['delete_curve'] = None - self._callbacks['_delete_curve'] = None + cnames.add(curve.name) for name in self._id_for_name.keys(): if not self._is_curve(name): continue @@ -350,9 +338,7 @@ class Tree (wx.TreeCtrl): if pname != playlist.name: continue if cname not in cnames: - self.delete_curve(playlist.name, cname) - self._callbacks['delete_curve'] = dc - self._callbacks['_delete_curve'] = _dc + self.delete_curve(playlist_name=pname, name=cname) def is_playlist_loaded(self, playlist): """Return `True` if `playlist` is loaded, `False` otherwise. diff --git a/hooke/ui/gui/perspectives/Default.txt b/hooke/ui/gui/perspectives/Default.txt index 046ad46..b873a37 100644 --- a/hooke/ui/gui/perspectives/Default.txt +++ b/hooke/ui/gui/perspectives/Default.txt @@ -1 +1 @@ -layout2|name=Folders;caption=Folders;state=33818620;dir=4;layer=0;row=0;pos=0;prop=100000;bestw=196;besth=246;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Playlists;caption=Playlists;state=33818620;dir=4;layer=0;row=0;pos=1;prop=100000;bestw=160;besth=250;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Plots;caption=;state=256;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=430;besth=200;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Commands;caption=Settings and commands;state=33818620;dir=2;layer=0;row=0;pos=0;prop=100000;bestw=160;besth=273;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Properties;caption=Properties;state=33818620;dir=2;layer=0;row=0;pos=1;prop=100000;bestw=60;besth=58;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Assistant;caption=Assistant;state=33818620;dir=2;layer=0;row=0;pos=2;prop=100000;bestw=133;besth=90;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Output;caption=Output;state=33818620;dir=3;layer=0;row=0;pos=0;prop=100000;bestw=133;besth=90;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Results;caption=Results;state=33818620;dir=3;layer=0;row=0;pos=1;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=toolbar;caption=Toolbar;state=33827568;dir=1;layer=1;row=1;pos=0;prop=100000;bestw=100;besth=23;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=toolbarNavigation;caption=Navigation;state=33827568;dir=1;layer=1;row=1;pos=111;prop=100000;bestw=46;besth=23;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(4,0,0)=198|dock_size(5,0,0)=325|dock_size(2,0,0)=162|dock_size(3,0,0)=111|dock_size(1,1,1)=25| +layout2|name=Folders;caption=Folders;state=33818620;dir=4;layer=0;row=0;pos=0;prop=100000;bestw=196;besth=246;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Playlists;caption=Playlists;state=33818620;dir=4;layer=0;row=0;pos=1;prop=100000;bestw=160;besth=250;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Plots;caption=;state=256;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=430;besth=200;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Commands;caption=Settings and commands;state=33818620;dir=2;layer=0;row=0;pos=0;prop=100000;bestw=160;besth=273;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Properties;caption=Properties;state=33818620;dir=2;layer=0;row=0;pos=1;prop=100000;bestw=60;besth=58;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Assistant;caption=Assistant;state=33818620;dir=2;layer=0;row=0;pos=2;prop=100000;bestw=133;besth=90;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Output;caption=Output;state=33818620;dir=3;layer=0;row=0;pos=0;prop=100000;bestw=133;besth=90;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=Results;caption=Results;state=33818620;dir=3;layer=0;row=0;pos=1;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=toolbar;caption=Toolbar;state=33827568;dir=1;layer=1;row=1;pos=0;prop=100000;bestw=300;besth=23;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|name=toolbarNavigation;caption=Navigation;state=33827568;dir=1;layer=1;row=1;pos=111;prop=100000;bestw=46;besth=23;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1;notebookid=-1;transparent=255|dock_size(4,0,0)=198|dock_size(5,0,0)=325|dock_size(2,0,0)=162|dock_size(3,0,0)=111|dock_size(1,1,1)=25| -- 2.26.2