'root': self.AddRoot(text='Playlists', image=self.image['root'])\r
}\r
self.Bind(wx.EVT_RIGHT_DOWN, self._on_context_menu)\r
- self.Bind(wx.EVT_TREE_SEL_CHANGED, self._on_curve_select)\r
- self.Bind(wx.EVT_LEFT_DOWN, self._on_left_down)\r
- self.Bind(wx.EVT_LEFT_DCLICK, self._on_left_doubleclick)\r
+ self.Bind(wx.EVT_TREE_SEL_CHANGED, self._on_select)\r
\r
self.config = config\r
self._callbacks = callbacks\r
return c_id\r
raise KeyError(_id)\r
\r
- def _on_curve_select(self, event):\r
- """Act on playlist/curve selection.\r
\r
- Currently just a hook for a potential callback.\r
- """\r
- _id = self.GetSelection()\r
- name = self._name_for_id[self._canonical_id(_id)]\r
- if self._is_curve(name):\r
- playlist = self._playlists[name[0]]\r
- curve = playlist.current()\r
- in_callback(self, playlist, curve)\r
-\r
- def _on_left_down(self, event):\r
- """Select the clicked-on curve/playlist.\r
- """ # TODO: dup with _on_curve_select?\r
- hit_id, hit_flags = self.HitTest(event.GetPosition())\r
- if (hit_flags & wx.TREE_HITTEST_ONITEM) != 0:\r
- name = self._name_for_id[self._canonical_id(hit_id)]\r
- if self._is_curve(name):\r
- self.set_selected_curve(name[0], name[1])\r
- else:\r
- self.set_selected_playlist(name)\r
- event.Skip()\r
-\r
- def _on_left_doubleclick(self, event):\r
- pass\r
- #playlist.index = index\r
- #event.Skip()\r
+ # Context menu\r
\r
def _on_context_menu(self, event):\r
"""Launch a popup :class:`Menu` with per-playlist/curve activities.\r
self.PopupMenu(menu, event.GetPosition())\r
menu.Destroy()\r
\r
- def _on_delete(self, event):\r
- """Handler for :class:`Menu`'s `Delete` button.\r
-\r
- Determines the clicked item and calls the appropriate\r
- `.delete_*()` method on it.\r
- """\r
- #if hasattr(self, '_hit_id'): # called via ._c['menu']\r
- _id = self._hit_id\r
- del(self._hit_id)\r
- name = self._name_for_id[_id]\r
- if self._is_curve(name):\r
- self.delete_curve(playlist_name=name[0], name=name[1])\r
- else:\r
- self.delete_playlist(name)\r
+ # Add\r
+ # add_* called directly by HookeFrame\r
+ # _add_* called on every addition\r
\r
def add_playlist(self, playlist):\r
"""Add a :class:`hooke.playlist.Playlist` to the tree.\r
+\r
+ Calls :meth:`_add_playlist` and triggers a callback.\r
+ """\r
+ self._add_playlist(playlist)\r
+ in_callback(self, playlist)\r
+\r
+ def _add_playlist(self, playlist):\r
+ """Add a class:`hooke.playlist.Playlist` to the tree.\r
+\r
+ No callback triggered.\r
"""\r
if playlist.name not in self._playlists:\r
pass\r
image=self.image['playlist'])\r
self._id_for_name[playlist.name] = p_id\r
self._name_for_id[p_id] = playlist.name\r
-\r
- # temporarily disable any add_curve callbacks\r
- acc = self._callbacks.get('add_curve', None)\r
- self._callbacks['add_curve'] = None\r
-\r
for curve in playlist:\r
- self.add_curve(playlist.name, curve)\r
-\r
- # restore the add_curve callback\r
- self._callbacks['add_curve'] = acc\r
-\r
- in_callback(self, playlist)\r
+ self._add_curve(playlist.name, curve)\r
\r
def add_curve(self, playlist_name, curve):\r
"""Add a :class:`hooke.curve.Curve` to a curently loaded playlist.\r
+\r
+ Calls :meth:`_add_curve` and triggers a callback.\r
+ """\r
+ self._add_curve(playlist_name, curve)\r
+ playlist = self._playlists[playlist_name]\r
+ in_callback(self, playlist, curve)\r
+\r
+ def _add_curve(self, playlist_name, curve):\r
+ """Add a class:`hooke.curve.Curve` to the tree.\r
+\r
+ No callback triggered.\r
"""\r
p = self._playlists[playlist_name]\r
if curve not in p:\r
image=self.image['curve'])\r
self._id_for_name[(p.name, curve.name)] = c_id\r
self._name_for_id[c_id] = (p.name, curve.name)\r
- in_callback(self, p, curve)\r
+\r
+ @callback\r
+ def generate_new_playlist(self):\r
+ pass # TODO\r
+\r
+ def _GetUniquePlaylistName(self, name): # TODO\r
+ playlist_name = name\r
+ count = 1\r
+ while playlist_name in self.playlists:\r
+ playlist_name = ''.join([name, str(count)])\r
+ count += 1\r
+ return playlist_name\r
+\r
+ # Delete\r
+ # delete_* called by _on_delete handler (user click) or HookeFrame\r
+ # _delete_* called on every deletion\r
+\r
+ def _on_delete(self, event):\r
+ """Handler for :class:`Menu`'s `Delete` button.\r
+\r
+ Determines the clicked item and calls the appropriate\r
+ `.delete_*()` method on it.\r
+ """\r
+ #if hasattr(self, '_hit_id'): # called via ._c['menu']\r
+ _id = self._hit_id\r
+ del(self._hit_id)\r
+ name = self._name_for_id[_id]\r
+ if self._is_curve(name):\r
+ self.delete_curve(playlist_name=name[0], name=name[1])\r
+ else:\r
+ self.delete_playlist(name)\r
\r
def delete_playlist(self, name):\r
"""Delete a :class:`hooke.playlist.Playlist` by name.\r
del(self._name_for_id[_id])\r
in_callback(self, playlist, curve)\r
\r
+ # Get selection\r
+\r
def get_selected_playlist(self):\r
"""Return the selected :class:`hooke.playlist.Playlist`.\r
"""\r
if self._is_curve(name):\r
p_name,c_name = name\r
playlist = self._playlists[p_name]\r
- index = [i for i,c in enumerate(playlist) if c.name == c_name]\r
- playlist.jump(index)\r
+ c = playlist.current()\r
+ assert c.name == c_name, '%s != %s' % (c.name, c_name)\r
else:\r
playlist = self._playlists[name]\r
return playlist.current()\r
\r
+ # Set selection\r
+ # set_* called by HookeFrame, includes tree display updates\r
+ # _set_* called on every selection (including _on_select)\r
+ #\r
+ # Selection is a bit tricky, because playlists are never selected\r
+ # directly. Selecting a playlist is equivalent to selecting its\r
+ # current curve.\r
+\r
+ def _on_select(self, event):\r
+ """Select the clicked-on curve/playlist.\r
+ """\r
+ _id = self.GetSelection()\r
+ name = self._name_for_id[self._canonical_id(_id)]\r
+ if self._is_curve(name):\r
+ p_name,c_name = name\r
+ self._set_selected_curve(p_name, c_name)\r
+ else:\r
+ self._set_selected_playlist(name)\r
+\r
def set_selected_playlist(self, name):\r
"""Set the selected :class:`hooke.playlist.Playlist` by name.\r
+\r
+ Just a wrapper around :meth:`_set_selected_playlist`.\r
+ """\r
+ # Selection would be overridden by _set_select_playlist\r
+ #self.SelectItem(self._id_for_name[name])\r
+ self.Expand(self._id_for_name[name])\r
+ self._set_selected_playlist(name)\r
+\r
+ def _set_selected_playlist(self, name):\r
+ """Selects the playlist's current :class:`hooke.curve.Curve`.\r
+\r
+ Updates the tree to display, which calls\r
+ :meth:`_set_selected_curvet` via :meth:`_on_select`.\r
"""\r
playlist = self._playlists[name]\r
curve = playlist.current()\r
- self.set_selected_curve(playlist.name, curve.name)\r
-\r
+ self.SelectItem(self._id_for_name[(name, curve.name)])\r
+ # triggers _set_selected_curve\r
+ \r
def set_selected_curve(self, playlist_name, name):\r
"""Set the selected :class:`hooke.curve.Curve` by name.\r
+\r
+ Updates the tree display, which calls\r
+ :meth:`_set_selected_curvet` via :meth:`_on_select`.\r
"""\r
- playlist = self._playlists[playlist.name]\r
- for i,curve in enumerate(playlist):\r
- if curve.name == name:\r
+ self.Expand(self._id_for_name[playlist_name])\r
+ self.SelectItem(self._id_for_name[(playlist_name, name)])\r
+ # triggers _set_selected_curve\r
+\r
+ def _set_selected_curve(self, playlist_name, name):\r
+ """Make the curve the playlist's current curve.\r
+ """\r
+ playlist = self._playlists[playlist_name]\r
+ curve = None\r
+ for i,c in enumerate(playlist):\r
+ if c.name == name:\r
+ curve = c\r
playlist.jump(i)\r
break\r
+ if curve == None:\r
+ raise ValueError(name)\r
curve = playlist.current()\r
- _id = self._id_for_name[(playlist.name, curve.name)]\r
- self.Expand(self._id_for_name[playlist.name])\r
- self.SelectItem(_id)\r
- in_callback(self, playlist, curve) # TODO: dup callback with _on_curve_select\r
-\r
- @callback\r
- def generate_new_playlist(self):\r
- pass\r
-\r
- def _GetUniquePlaylistName(self, name):\r
- playlist_name = name\r
- count = 1\r
- while playlist_name in self.playlists:\r
- playlist_name = ''.join([name, str(count)])\r
- count += 1\r
- return playlist_name\r
+ in_callback(self, playlist, curve)\r
\r
\r
class Playlist (Panel, wx.Panel):\r