Add a `Delete` button to the GUI NavBar, and cleanup deletion callbacks.
authorW. Trevor King <wking@drexel.edu>
Thu, 8 Mar 2012 16:04:28 +0000 (11:04 -0500)
committerW. Trevor King <wking@drexel.edu>
Thu, 8 Mar 2012 16:04:28 +0000 (11:04 -0500)
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
hooke/ui/gui/navbar.py
hooke/ui/gui/panel/playlist.py
hooke/ui/gui/perspectives/Default.txt

index 2c58923..3ea8631 100644 (file)
@@ -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
index 3d18e64..2203e43 100644 (file)
@@ -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
index e8c8f84..cf069e8 100644 (file)
@@ -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.
index 046ad46..b873a37 100644 (file)
@@ -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|