style=wx.DIRCTRL_SHOW_FILTERS,\r
filter=self.gui.config['folders-filters'],\r
defaultFilter=int(self.gui.config['folders-filter-index'])), 'left'), #HACK: config should convert\r
- ('playlists', panel.playlist.Playlist(self), 'left'),\r
+ ('playlists', panel.playlist.Playlist(\r
+ config=self.gui.config,\r
+ callbacks={},\r
+ parent=self,\r
+ style=wx.WANTS_CHARS|wx.NO_BORDER,\r
+ # WANTS_CHARS so the panel doesn't eat the Return key.\r
+ size=(160, 200)), 'left'),\r
('note', panel.note.Note(self), 'left'),\r
('notebook', Notebook(\r
parent=self,\r
treeCtrl = self._c['folders'].GetTreeCtrl()\r
treeCtrl.Bind(wx.EVT_LEFT_DCLICK, self._on_dir_ctrl_left_double_click)\r
\r
+ # TODO: playlist callbacks\r
return # TODO: cleanup\r
- self._c['playlists'].PlaylistsTree.Bind(wx.EVT_LEFT_DOWN, self.OnPlaylistsLeftDown)\r
- self._c['playlists'].PlaylistsTree.Bind(wx.EVT_LEFT_DCLICK, self.OnPlaylistsLeftDclick)\r
#commands tree\r
evtmgr.eventManager.Register(self.OnExecute, wx.EVT_BUTTON, self._c['commands'].ExecuteButton)\r
evtmgr.eventManager.Register(self.OnTreeCtrlCommandsSelectionChanged, wx.EVT_TREE_SEL_CHANGED, self._c['commands']._c['tree'])\r
def _GetActiveFileIndex(self):\r
lib.playlist.Playlist = self.GetActivePlaylist()\r
#get the selected item from the tree\r
- selected_item = self._c['playlists'].PlaylistsTree.GetSelection()\r
+ selected_item = self._c['playlists']._c['tree'].GetSelection()\r
#test if a playlist or a curve was double-clicked\r
- if self._c['playlists'].PlaylistsTree.ItemHasChildren(selected_item):\r
+ if self._c['playlists']._c['tree'].ItemHasChildren(selected_item):\r
return -1\r
else:\r
count = 0\r
- selected_item = self._c['playlists'].PlaylistsTree.GetPrevSibling(selected_item)\r
+ selected_item = self._c['playlists']._c['tree'].GetPrevSibling(selected_item)\r
while selected_item.IsOk():\r
count += 1\r
- selected_item = self._c['playlists'].PlaylistsTree.GetPrevSibling(selected_item)\r
+ selected_item = self._c['playlists']._c['tree'].GetPrevSibling(selected_item)\r
return count\r
\r
def _GetPlaylistTab(self, name):\r
return index\r
return -1\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
-\r
def _restore_perspective(self, name):\r
# TODO: cleanup\r
self.gui.config['active perspective'] = name # TODO: push to engine's Hooke\r
perspectivesFile.write(perspective)\r
perspectivesFile.close()\r
\r
- def AddPlaylist(self, playlist=None, name='Untitled'):\r
- if playlist and playlist.count > 0:\r
- playlist.name = self._GetUniquePlaylistName(name)\r
- playlist.reset()\r
- self.AddToPlaylists(playlist)\r
-\r
def AddPlaylistFromFiles(self, files=[], name='Untitled'):\r
if files:\r
playlist = lib.playlist.Playlist(self, self.drivers)\r
playlist.reset()\r
self.AddTayliss(playlist)\r
\r
- def AddToPlaylists(self, playlist):\r
- if playlist.count > 0:\r
- #setup the playlist in the Playlist tree\r
- tree_root = self._c['playlists'].PlaylistsTree.GetRootItem()\r
- playlist_root = self._c['playlists'].PlaylistsTree.AppendItem(tree_root, playlist.name, 0)\r
- #add all files to the Playlist tree\r
-# files = {}\r
- hide_curve_extension = self.GetBoolFromConfig('core', 'preferences', 'hide_curve_extension')\r
- for index, file_to_add in enumerate(playlist.files):\r
- #optionally remove the extension from the name of the curve\r
- if hide_curve_extension:\r
- file_to_add.name = lh.remove_extension(file_to_add.name)\r
- file_ID = self._c['playlists'].PlaylistsTree.AppendItem(playlist_root, file_to_add.name, 1)\r
- if index == playlist.index:\r
- self._c['playlists'].PlaylistsTree.SelectItem(file_ID)\r
- playlist.reset()\r
- #create the plot tab and add playlist to the dictionary\r
- plotPanel = panel.plot.PlotPanel(self, ID_FirstPlot + len(self.playlists))\r
- notebook_tab = self._c['notebook'].AddPage(plotPanel, playlist.name, True)\r
- #tab_index = self._c['notebook'].GetSelection()\r
- playlist.figure = plotPanel.get_figure()\r
- self.playlists[playlist.name] = playlist\r
- #self.playlists[playlist.name] = [playlist, figure]\r
- self._c['playlists'].PlaylistsTree.Expand(playlist_root)\r
- self.statusbar.SetStatusText(playlist.get_status_string(), 0)\r
- self.UpdateNote()\r
- self.UpdatePlot()\r
-\r
def AppendToOutput(self, text):\r
self.panelOutput.AppendText(''.join([text, '\n']))\r
\r
manipulated_plot = plotmanipulator.method(manipulated_plot, plot_file)\r
return manipulated_plot\r
\r
- def DeleteFromPlaylists(self, name):\r
- if name in self.playlists:\r
- del self.playlists[name]\r
- tree_root = self._c['playlists'].PlaylistsTree.GetRootItem()\r
- item, cookie = self._c['playlists'].PlaylistsTree.GetFirstChild(tree_root)\r
- while item.IsOk():\r
- playlist_name = self._c['playlists'].PlaylistsTree.GetItemText(item)\r
- if playlist_name == name:\r
- try:\r
- self._c['playlists'].PlaylistsTree.Delete(item)\r
- except:\r
- pass\r
- item = self._c['playlists'].PlaylistsTree.GetNextSibling(item)\r
-\r
def GetActiveFigure(self):\r
playlist_name = self.GetActivePlaylistName()\r
figure = self.playlists[playlist_name].figure\r
return playlist.get_active_file()\r
return None\r
\r
- def GetActivePlaylist(self):\r
- playlist_name = self.GetActivePlaylistName()\r
- if playlist_name in self.playlists:\r
- return self.playlists[playlist_name]\r
- return None\r
-\r
- def GetActivePlaylistName(self):\r
- #get the selected item from the tree\r
- selected_item = self._c['playlists'].PlaylistsTree.GetSelection()\r
- #test if a playlist or a curve was double-clicked\r
- if self._c['playlists'].PlaylistsTree.ItemHasChildren(selected_item):\r
- playlist_item = selected_item\r
- else:\r
- #get the name of the playlist\r
- playlist_item = self._c['playlists'].PlaylistsTree.GetItemParent(selected_item)\r
- #now we have a playlist\r
- return self._c['playlists'].PlaylistsTree.GetItemText(playlist_item)\r
-\r
def GetActivePlot(self):\r
playlist = self.GetActivePlaylist()\r
if playlist is not None:\r
-----\r
Syntax: next, n\r
'''\r
- selected_item = self._c['playlists'].PlaylistsTree.GetSelection()\r
- if self._c['playlists'].PlaylistsTree.ItemHasChildren(selected_item):\r
+ selected_item = self._c['playlists']._c['tree'].GetSelection()\r
+ if self._c['playlists']._c['tree'].ItemHasChildren(selected_item):\r
#GetFirstChild returns a tuple\r
#we only need the first element\r
- next_item = self._c['playlists'].PlaylistsTree.GetFirstChild(selected_item)[0]\r
+ next_item = self._c['playlists']._c['tree'].GetFirstChild(selected_item)[0]\r
else:\r
- next_item = self._c['playlists'].PlaylistsTree.GetNextSibling(selected_item)\r
+ next_item = self._c['playlists']._c['tree'].GetNextSibling(selected_item)\r
if not next_item.IsOk():\r
- parent_item = self._c['playlists'].PlaylistsTree.GetItemParent(selected_item)\r
+ parent_item = self._c['playlists']._c['tree'].GetItemParent(selected_item)\r
#GetFirstChild returns a tuple\r
#we only need the first element\r
- next_item = self._c['playlists'].PlaylistsTree.GetFirstChild(parent_item)[0]\r
- self._c['playlists'].PlaylistsTree.SelectItem(next_item, True)\r
- if not self._c['playlists'].PlaylistsTree.ItemHasChildren(selected_item):\r
+ next_item = self._c['playlists']._c['tree'].GetFirstChild(parent_item)[0]\r
+ self._c['playlists']._c['tree'].SelectItem(next_item, True)\r
+ if not self._c['playlists']._c['tree'].ItemHasChildren(selected_item):\r
playlist = self.GetActivePlaylist()\r
if playlist.count > 1:\r
playlist.next()\r
def OnPaneClose(self, event):\r
event.Skip()\r
\r
- def OnPlaylistsLeftDclick(self, event):\r
- if self._c['playlists'].PlaylistsTree.Count > 0:\r
- playlist_name = self.GetActivePlaylistName()\r
- #if that playlist already exists\r
- #we check if it is the active playlist (ie selected in panelPlaylists)\r
- #and switch to it if necessary\r
- if playlist_name in self.playlists:\r
- index = self._c['notebook'].GetSelection()\r
- current_playlist = self._c['notebook'].GetPageText(index)\r
- if current_playlist != playlist_name:\r
- index = self._GetPlaylistTab(playlist_name)\r
- self._c['notebook'].SetSelection(index)\r
- #if a curve was double-clicked\r
- item = self._c['playlists'].PlaylistsTree.GetSelection()\r
- if not self._c['playlists'].PlaylistsTree.ItemHasChildren(item):\r
- index = self._GetActiveFileIndex()\r
- else:\r
- index = 0\r
- if index >= 0:\r
- playlist = self.GetActivePlaylist()\r
- playlist.index = index\r
- self.statusbar.SetStatusText(playlist.get_status_string(), 0)\r
- self.UpdateNote()\r
- self.UpdatePlot()\r
- #if you uncomment the following line, the tree will collapse/expand as well\r
- #event.Skip()\r
-\r
- def OnPlaylistsLeftDown(self, event):\r
- hit_item, hit_flags = self._c['playlists'].PlaylistsTree.HitTest(event.GetPosition())\r
- if (hit_flags & wx.TREE_HITTEST_ONITEM) != 0:\r
- self._c['playlists'].PlaylistsTree.SelectItem(hit_item)\r
- playlist_name = self.GetActivePlaylistName()\r
- playlist = self.GetActivePlaylist()\r
- #if a curve was clicked\r
- item = self._c['playlists'].PlaylistsTree.GetSelection()\r
- if not self._c['playlists'].PlaylistsTree.ItemHasChildren(item):\r
- index = self._GetActiveFileIndex()\r
- if index >= 0:\r
- playlist.index = index\r
- self.playlists[playlist_name] = playlist\r
- event.Skip()\r
-\r
def _on_previous(self, event):\r
'''\r
PREVIOUS\r
#playlist = self.playlists[self.GetActivePlaylistName()][0]\r
#select the previous curve and tell the user if we wrapped around\r
#self.AppendToOutput(playlist.previous())\r
- selected_item = self._c['playlists'].PlaylistsTree.GetSelection()\r
- if self._c['playlists'].PlaylistsTree.ItemHasChildren(selected_item):\r
- previous_item = self._c['playlists'].PlaylistsTree.GetLastChild(selected_item)\r
+ selected_item = self._c['playlists']._c['tree'].GetSelection()\r
+ if self._c['playlists']._c['tree'].ItemHasChildren(selected_item):\r
+ previous_item = self._c['playlists']._c['tree'].GetLastChild(selected_item)\r
else:\r
- previous_item = self._c['playlists'].PlaylistsTree.GetPrevSibling(selected_item)\r
+ previous_item = self._c['playlists']._c['tree'].GetPrevSibling(selected_item)\r
if not previous_item.IsOk():\r
- parent_item = self._c['playlists'].PlaylistsTree.GetItemParent(selected_item)\r
- previous_item = self._c['playlists'].PlaylistsTree.GetLastChild(parent_item)\r
- self._c['playlists'].PlaylistsTree.SelectItem(previous_item, True)\r
+ parent_item = self._c['playlists']._c['tree'].GetItemParent(selected_item)\r
+ previous_item = self._c['playlists']._c['tree'].GetLastChild(parent_item)\r
+ self._c['playlists']._c['tree'].SelectItem(previous_item, True)\r
playlist = self.GetActivePlaylist()\r
if playlist.count > 1:\r
playlist.previous()\r
#refresh the plot\r
figure.canvas.draw()\r
\r
+ def _on_curve_select(self, playlist, curve):\r
+ #create the plot tab and add playlist to the dictionary\r
+ plotPanel = panel.plot.PlotPanel(self, ID_FirstPlot + len(self.playlists))\r
+ notebook_tab = self._c['notebook'].AddPage(plotPanel, playlist.name, True)\r
+ #tab_index = self._c['notebook'].GetSelection()\r
+ playlist.figure = plotPanel.get_figure()\r
+ self.playlists[playlist.name] = playlist\r
+ #self.playlists[playlist.name] = [playlist, figure]\r
+ self.statusbar.SetStatusText(playlist.get_status_string(), 0)\r
+ self.UpdateNote()\r
+ self.UpdatePlot()\r
+\r
\r
+ def _on_playlist_left_doubleclick(self):\r
+ index = self._c['notebook'].GetSelection()\r
+ current_playlist = self._c['notebook'].GetPageText(index)\r
+ if current_playlist != playlist_name:\r
+ index = self._GetPlaylistTab(playlist_name)\r
+ self._c['notebook'].SetSelection(index)\r
+ self.statusbar.SetStatusText(playlist.get_status_string(), 0)\r
+ self.UpdateNote()\r
+ self.UpdatePlot()\r
+\r
+ def _on_playlist_delete(self, playlist):\r
+ notebook = self.Parent.plotNotebook\r
+ index = self.Parent._GetPlaylistTab(playlist.name)\r
+ notebook.SetSelection(index)\r
+ notebook.DeletePage(notebook.GetSelection())\r
+ self.Parent.DeleteFromPlaylists(playlist_name)\r
+ \r
\r
class HookeApp (wx.App):\r
def __init__(self, gui, commands, inqueue, outqueue, *args, **kwargs):\r
Setting(section=self.setting_section, option='perspective path',\r
value=os.path.join('resources', 'gui', 'perspective'),\r
help='Directory containing perspective files.'), # TODO: allow colon separated list, like $PATH.\r
+ Setting(section=self.setting_section, option='hide extensions',\r
+ value=False,\r
+ help='Hide file extensions when displaying names.'),\r
Setting(section=self.setting_section, option='folders-workdir',\r
value='.',\r
help='This should probably go...'),\r
# Copyright\r
\r
"""Playlist panel for Hooke.\r
+\r
+Provides a nice GUI interface to the\r
+:class:`~hooke.plugin.playlist.PlaylistPlugin`.\r
"""\r
\r
+import types\r
+\r
import wx\r
\r
-class Playlist(wx.Panel):\r
+from ....util.callback import callback, in_callback\r
\r
- def __init__(self, parent):\r
- # Use the WANTS_CHARS style so the panel doesn't eat the Return key.\r
- wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS|wx.NO_BORDER, size=(160, 200))\r
\r
- self.PlaylistsTree = wx.TreeCtrl(self, -1, wx.Point(0, 0), wx.Size(160, 250), wx.TR_DEFAULT_STYLE | wx.NO_BORDER | wx.TR_HIDE_ROOT)\r
- imglist = wx.ImageList(16, 16, True, 2)\r
- imglist.Add(wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, wx.Size(16, 16)))\r
- imglist.Add(wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16, 16)))\r
- self.PlaylistsTree.AssignImageList(imglist)\r
- self.PlaylistsTree.AddRoot('Playlists', 0)\r
- self.PlaylistsTree.Bind(wx.EVT_RIGHT_DOWN , self.OnContextMenu)\r
+class Menu (wx.Menu):\r
+ """Popup menu for selecting playlist :class:`Tree` actions.\r
+ """\r
+ def __init__(self, on_delete, *args, **kwargs):\r
+ super(Menu, self).__init__(*args, **kwargs)\r
+ self._c = {\r
+ 'delete': self.Append(id=wx.ID_ANY, text='Delete'),\r
+ }\r
+ self.Bind(wx.EVT_MENU, on_delete)\r
\r
- self.Playlists = {}\r
\r
- sizer = wx.BoxSizer(wx.VERTICAL)\r
- sizer.Add(self.PlaylistsTree, 1, wx.EXPAND)\r
- self.SetSizer(sizer)\r
- sizer.Fit(self)\r
+class Tree (wx.TreeCtrl):\r
+ """:class:`wx.TreeCtrl` subclass handling playlist and curve selection.\r
+ """\r
+ def __init__(self, config, callbacks, *args, **kwargs):\r
+ super(Tree, self).__init__(*args, **kwargs)\r
+ imglist = wx.ImageList(width=16, height=16, mask=True, initialCount=2)\r
+ imglist.Add(wx.ArtProvider.GetBitmap(\r
+ wx.ART_FOLDER, wx.ART_OTHER, wx.Size(16, 16)))\r
+ imglist.Add(wx.ArtProvider.GetBitmap(\r
+ wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16, 16)))\r
+ self.AssignImageList(imglist)\r
+ self.image = {\r
+ 'root': 0,\r
+ 'playlist': 0,\r
+ 'curve': 1,\r
+ }\r
+ self._c = {\r
+ 'menu': Menu(self._on_delete),\r
+ 'root': self.AddRoot('Playlists', 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
+\r
+ self.config = config\r
+ self._callbacks = callbacks\r
+ self._setup_playlists()\r
+\r
+ def _setup_playlists(self):\r
+ self._playlists = {} # {name: hooke.playlist.Playlist()}\r
+\r
+ # In both of the following dicts, curve names are\r
+ # (playlist.name, curve.name) to avoid cross-playlist\r
+ # collisions. See ._is_curve().\r
+ self._id_for_name = {} # {name: id}\r
+ self._name_for_id = {} # {id: name}\r
+\r
+ def _name(self, name):\r
+ """Cleanup names according to configured preferences.\r
+ """\r
+ if self.config['hide extensions'] == 'True': # HACK: config should decode\r
+ name,ext = os.path.splitext(name)\r
+ return name\r
+\r
+ def _is_curve(self, name): # name from ._id_for_name / ._name_for_id\r
+ """Return `True` if `name` corresponds to a :class:`hooke.curve.Curve`.\r
+ """\r
+ # Playlist names are strings, Curve names are tuples.\r
+ # See ._setup_playlists().\r
+ return not isinstance(name, types.StringTypes)\r
\r
- def OnContextMenu(self, event):\r
- hit_item, hit_flags = self.PlaylistsTree.HitTest(event.GetPosition())\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(_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[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
+ playlist.index = index\r
+ event.Skip()\r
+\r
+ def _on_context_menu(self, event):\r
+ """Launch a popup :class:`Menu` with per-playlist/curve activities.\r
+ """\r
+ hit_id,hit_flags = self.HitTest(event.GetPosition())\r
if (hit_flags & wx.TREE_HITTEST_ONITEM) != 0:\r
- self.PlaylistsTree.SelectItem(hit_item)\r
- # only do this part the first time so the events are only bound once\r
- # Yet another alternate way to do IDs. Some prefer them up top to\r
- # avoid clutter, some prefer them close to the object of interest\r
- # for clarity.\r
- if not hasattr(self, 'ID_popupAdd'):\r
- #self.ID_popupAdd = wx.NewId()\r
- self.ID_popupDelete = wx.NewId()\r
- #self.Bind(wx.EVT_MENU, self.OnPopupAdd, id=self.ID_popupAdd)\r
- self.Bind(wx.EVT_MENU, self.OnPopupDelete, id=self.ID_popupDelete)\r
- # make a menu\r
- menu = wx.Menu()\r
- #items = [['Add', self.ID_popupAdd] , ['Delete', self.ID_popupDelete]]\r
- items = [['Delete', self.ID_popupDelete]]\r
- for item in items:\r
- menu.Append(item[1], item[0])\r
- # Popup the menu. If an item is selected then its handler\r
- # will be called before PopupMenu returns.\r
- self.PopupMenu(menu)\r
+ self._hit_id = hit_id # store for the callbacks\r
+ self.PopupMenu(\r
+ Menu(self._on_delete), event.GetPoint())\r
menu.Destroy()\r
\r
- def OnPopupAdd(self, event):\r
- pass\r
+ def _on_delete(self, event):\r
+ """Handler for :class:`Menu`'s `Delete` button.\r
\r
- def OnPopupDelete(self, event):\r
- item = self.PlaylistsTree.GetSelection()\r
- playlist = self.Parent.GetActivePlaylist()\r
- if self.PlaylistsTree.ItemHasChildren(item):\r
- playlist_name = self.PlaylistsTree.GetItemText(item)\r
- notebook = self.Parent.plotNotebook\r
- index = self.Parent._GetPlaylistTab(playlist_name)\r
- notebook.SetSelection(index)\r
- notebook.DeletePage(notebook.GetSelection())\r
- self.Parent.DeleteFromPlaylists(playlist_name)\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
- if playlist is not None:\r
- if playlist.count == 1:\r
- notebook = self.Parent.plotNotebook\r
- index = self.Parent._GetPlaylistTab(playlist.name)\r
- notebook.SetSelection(index)\r
- notebook.DeletePage(notebook.GetSelection())\r
- self.Parent.DeleteFromPlaylists(playlist.name)\r
- else:\r
- file_name = self.PlaylistsTree.GetItemText(item)\r
- playlist.delete_file(file_name)\r
- self.PlaylistsTree.Delete(item)\r
- self.Parent.UpdatePlaylistsTreeSelection()\r
+ self.delete_playlist(name)\r
+\r
+ def add_playlist(self, playlist):\r
+ """Add a :class:`hooke.playlist.Playlist` to the tree.\r
+ """\r
+ if playlist.name not in self._playlists:\r
+ pass\r
+ else:\r
+ raise ValueError('duplicate playlist: %s' % playlist.name)\r
+ self._playlists[playlist.name] = playlist\r
+ p_id = self.AppendItem(\r
+ parent=self._c['root'],\r
+ text=self._name(playlist.name),\r
+ image=self.image['playlist'])\r
+ self._id_for_name[playlist.name] = p_id\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
+\r
+ def add_curve(self, playlist_name, curve):\r
+ """Add a :class:`hooke.curve.Curve` to a curently loaded playlist.\r
+ """\r
+ p = self._playlists[playlist_name]\r
+ p.append(curve)\r
+ c_id = AppendItem(\r
+ parent=self._id_for_name[playlist_name],\r
+ text=self._name(curve.name),\r
+ image=self.image['curve'])\r
+ self._id_for_name[(playlist.name, curve.name)] = c_id\r
+ in_callback(self, p, curve)\r
+\r
+ def delete_playlist(self, name):\r
+ """Delete a :class:`hooke.playlist.Playlist` by name.\r
+ """\r
+ _id = self._id_for_name.pop(name)\r
+ self.Delete(_id)\r
+ playlist = self._playlists.pop(name)\r
+ del(self._name_for_id[_id])\r
+ for curve in playlist:\r
+ _id = self._id_for_name.pop((name, curve.name))\r
+ del(self._name_for_id[_id])\r
+ in_callback(self, playlist)\r
+\r
+ def delete_curve(self, playlist_name, name):\r
+ """Delete a :class:`hooke.curve.Curve` by name.\r
+ """\r
+ if playlist is not None:\r
+ if playlist.count == 1:\r
+ notebook = self.Parent.plotNotebook\r
+ index = self.Parent._GetPlaylistTab(playlist.name)\r
+ notebook.SetSelection(index)\r
+ notebook.DeletePage(notebook.GetSelection())\r
+ self.Parent.DeleteFromPlaylists(playlist.name)\r
+ else:\r
+ file_name = self.GetItemText(item)\r
+ playlist.delete_file(file_name)\r
+ self.Delete(item)\r
+ self.Parent.UpdatePlaylistsTreeSelection()\r
+ in_callback(self, playlist, curve)\r
+\r
+ def get_selected_playlist(self):\r
+ """Return the selected :class:`hooke.playlist.Playlist`.\r
+ """\r
+ _id = self.GetSelection()\r
+ name = self._name_for_id(_id)\r
+ if self._is_curve(name):\r
+ name = name[0]\r
+ return self._playlists[name]\r
+\r
+ def get_selected_curve(self):\r
+ """Return the selected :class:`hooke.curve.Curve`.\r
+ """\r
+ _id = self.GetSelection()\r
+ name = self._name_for_id(_id)\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
+ else:\r
+ playlist = self._playlists[name]\r
+ return playlist.current()\r
+\r
+ def set_selected_playlist(self, name):\r
+ """Set the selected :class:`hooke.playlist.Playlist` by name.\r
+ """\r
+ playlist = self._playlists[name]\r
+ curve = playlist.current()\r
+ self.set_selected_curve(playlist.name, curve.name)\r
+\r
+ def set_selected_curve(self, playlist_name, name):\r
+ """Set the selected :class:`hooke.curve.Curve` by name.\r
+ """\r
+ playlist = self._playlists[playlist.name]\r
+ for i,curve in enumerate(playlist):\r
+ if curve.name == name:\r
+ playlist.jump(i)\r
+ break\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
+\r
+\r
+class Playlist (wx.Panel):\r
+ """:class:`wx.Panel` subclass wrapper for :class:`Tree`.\r
+ """\r
+ def __init__(self, config, callbacks, *args, **kwargs):\r
+ # Use the WANTS_CHARS style so the panel doesn't eat the Return key.\r
+ super(Playlist, self).__init__(*args, **kwargs)\r
+ self.name = 'playlist panel'\r
+\r
+ self._c = {\r
+ 'tree': Tree(\r
+ config=config,\r
+ callbacks=callbacks,\r
+ parent=self,\r
+ size=wx.Size(160, 250),\r
+ style=wx.TR_DEFAULT_STYLE | wx.NO_BORDER | wx.TR_HIDE_ROOT),\r
+ }\r
+\r
+ sizer = wx.BoxSizer(wx.VERTICAL)\r
+ sizer.Add(self._c['tree'], 1, wx.EXPAND)\r
+ self.SetSizer(sizer)\r
+ sizer.Fit(self)\r
+\r
+ # Expose all Tree's public curve/playlist methods directly.\r
+ for attribute_name in dir(self._c['tree']):\r
+ if (attribute_name.startswith('_')\r
+ or 'playlist' not in attribute_name\r
+ or 'curve' not in attribute_name):\r
+ continue # not an attribute we're interested in\r
+ attr = getattr(self._c['tree'], attribute_name)\r
+ if hasattr(attr, '__call__'): # attr is a function / method\r
+ setattr(self, attribute_name, attr) # expose it\r