# Copyright\r
\r
-"""Defines :class:`GUI` providing a wxWindows interface to Hooke.\r
+"""Defines :class:`GUI` providing a wxWidgets interface to Hooke.\r
"""\r
\r
WX_GOOD=['2.8']\r
\r
from matplotlib.ticker import FuncFormatter\r
\r
-from ... import version\r
-from ...command import CommandExit, Exit, Command, Argument, StoreValue\r
+from ...command import CommandExit, Exit, Success, Failure, Command, Argument\r
from ...config import Setting\r
from ...interaction import Request, BooleanRequest, ReloadUserInterfaceConfig\r
from ...ui import UserInterface, CommandMessage\r
\r
# Create the menubar after the panes so that the default\r
# perspective is created with all panes open\r
- self._c['menu bar'] = menu.MenuBar(\r
- callbacks={},\r
- )\r
+ self._c['menu bar'] = menu.HookeMenuBar(\r
+ parent=self,\r
+ callbacks={\r
+ 'close': self._on_close,\r
+ 'about': self._on_about,\r
+ })\r
self.SetMenuBar(self._c['menu bar'])\r
\r
- self._c['status bar'] = statubar.StatusBar(\r
+ self._c['status bar'] = statusbar.StatusBar(\r
parent=self,\r
style=wx.ST_SIZEGRIP)\r
+ self.SetStatusBar(self._c['status bar'])\r
\r
self._update_perspectives()\r
self._bind_events()\r
def _setup_panels(self):\r
client_size = self.GetClientSize()\r
for label,p,style in [\r
- ('folders', wx.GenericDirCtrl(\r
- parent=self,\r
- dir=self.gui.config['folders-workdir'],\r
- size=(200, 250),\r
- 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(\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
- pos=wx.Point(client_size.x, client_size.y),\r
- size=wx.Size(430, 200),\r
- style=aui.AUI_NB_DEFAULT_STYLE\r
- | aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER), 'center'),\r
- ('commands', panel.commands.Commands(\r
+# ('folders', wx.GenericDirCtrl(\r
+# parent=self,\r
+# dir=self.gui.config['folders-workdir'],\r
+# size=(200, 250),\r
+# 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.PANELS['playlist'](\r
+# callbacks={},\r
+# config=self.gui.config,\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(\r
+# parent=self\r
+# style=wx.WANTS_CHARS|wx.NO_BORDER,\r
+# size=(160, 200)), 'left'),\r
+# ('notebook', Notebook(\r
+# parent=self,\r
+# pos=wx.Point(client_size.x, client_size.y),\r
+# size=wx.Size(430, 200),\r
+# style=aui.AUI_NB_DEFAULT_STYLE\r
+# | aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER), 'center'),\r
+ ('commands', panel.PANELS['commands'](\r
commands=self.commands,\r
selected=self.gui.config['selected command'],\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)), 'right'),\r
+# size=(160, 200)\r
+ ), 'center'),\r
#('properties', panel.propertyeditor.PropertyEditor(self),'right'),\r
- ('assistant', wx.TextCtrl(\r
- parent=self,\r
- pos=wx.Point(0, 0),\r
- size=wx.Size(150, 90),\r
- style=wx.NO_BORDER|wx.TE_MULTILINE), 'right'),\r
- ('output', wx.TextCtrl(\r
- parent=self,\r
- pos=wx.Point(0, 0),\r
- size=wx.Size(150, 90),\r
- style=wx.NO_BORDER|wx.TE_MULTILINE), 'bottom'),\r
- ('results', panel.results.Results(self), 'bottom'),\r
+# ('assistant', wx.TextCtrl(\r
+# parent=self,\r
+# pos=wx.Point(0, 0),\r
+# size=wx.Size(150, 90),\r
+# style=wx.NO_BORDER|wx.TE_MULTILINE), 'right'),\r
+# ('output', wx.TextCtrl(\r
+# parent=self,\r
+# pos=wx.Point(0, 0),\r
+# size=wx.Size(150, 90),\r
+# style=wx.NO_BORDER|wx.TE_MULTILINE), 'bottom'),\r
+# ('results', panel.results.Results(self), 'bottom'),\r
]:\r
self._add_panel(label, p, style)\r
- self._c['assistant'].SetEditable(False)\r
+ #self._c['assistant'].SetEditable(False)\r
\r
def _add_panel(self, label, panel, style):\r
self._c[label] = panel\r
cap_label = label.capitalize()\r
info = aui.AuiPaneInfo().Name(cap_label).Caption(cap_label)\r
- if style == 'left':\r
- info.Left().CloseButton(True).MaximizeButton(False)\r
+ info.PaneBorder(False).CloseButton(True).MaximizeButton(False)\r
+ if style == 'top':\r
+ info.Top()\r
elif style == 'center':\r
- info.CenterPane().PaneBorder(False)\r
+ info.CenterPane()\r
+ elif style == 'left':\r
+ info.Left()\r
elif style == 'right':\r
- info.Right().CloseButton(True).MaximizeButton(False)\r
+ info.Right()\r
else:\r
assert style == 'bottom', style\r
- info.Bottom().CloseButton(True).MaximizeButton(False)\r
+ info.Bottom()\r
self._c['manager'].AddPane(panel, info)\r
\r
def _setup_toolbars(self):\r
- self._c['navbar'] = navbar.NavBar(\r
+ self._c['navigation bar'] = navbar.NavBar(\r
callbacks={\r
'next': self._next_curve,\r
'previous': self._previous_curve,\r
},\r
parent=self,\r
style=wx.TB_FLAT | wx.TB_NODIVIDER)\r
-\r
self._c['manager'].AddPane(\r
- self._c['navbar'],\r
+ self._c['navigation bar'],\r
aui.AuiPaneInfo().Name('Navigation').Caption('Navigation'\r
).ToolbarPane().Top().Layer(1).Row(1).LeftDockable(False\r
).RightDockable(False))\r
self.Bind(wx.EVT_ERASE_BACKGROUND, self._on_erase_background)\r
self.Bind(wx.EVT_SIZE, self._on_size)\r
self.Bind(wx.EVT_CLOSE, self._on_close)\r
- self.Bind(wx.EVT_MENU, self._on_close, id=wx.ID_EXIT)\r
- self.Bind(wx.EVT_MENU, self._on_about, id=wx.ID_ABOUT)\r
self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPaneClose)\r
self.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self._on_notebook_page_close)\r
\r
+ return # TODO: cleanup\r
for value in self._c['menu bar']._c['view']._c.values():\r
self.Bind(wx.EVT_MENU_RANGE, self._on_view, value)\r
\r
#results panel\r
self.panelResults.results_list.OnCheckItem = self.OnResultsCheck\r
\r
+ def _command_by_name(self, name):\r
+ cs = [c for c in self.commands if c.name == name]\r
+ if len(cs) == 0:\r
+ raise KeyError(name)\r
+ elif len(cs) > 1:\r
+ raise Exception('Multiple commands named "%s"' % name)\r
+ return cs[0]\r
+\r
+ def execute_command(self, _class=None, method=None,\r
+ command=None, args=None):\r
+ self.inqueue.put(CommandMessage(command, args))\r
+ results = []\r
+ while True:\r
+ msg = self.outqueue.get()\r
+ results.append(msg)\r
+ print type(msg), msg\r
+ if isinstance(msg, Exit):\r
+ self._on_close()\r
+ break\r
+ elif isinstance(msg, CommandExit):\r
+ # TODO: display command complete\r
+ break\r
+ elif isinstance(msg, ReloadUserInterfaceConfig):\r
+ self.gui.reload_config(msg.config)\r
+ continue\r
+ elif isinstance(msg, Request):\r
+ h = handler.HANDLERS[msg.type]\r
+ h.run(self, msg) # TODO: pause for response?\r
+ continue\r
+ pp = getattr(\r
+ self, '_postprocess_%s' % command.name.replace(' ', '_'), None)\r
+ if pp != None:\r
+ pp(command=command, results=results)\r
+ return results\r
+\r
+ def _handle_request(self, msg):\r
+ """Repeatedly try to get a response to `msg`.\r
+ """\r
+ if prompt == None:\r
+ raise NotImplementedError('_%s_request_prompt' % msg.type)\r
+ prompt_string = prompt(msg)\r
+ parser = getattr(self, '_%s_request_parser' % msg.type, None)\r
+ if parser == None:\r
+ raise NotImplementedError('_%s_request_parser' % msg.type)\r
+ error = None\r
+ while True:\r
+ if error != None:\r
+ self.cmd.stdout.write(''.join([\r
+ error.__class__.__name__, ': ', str(error), '\n']))\r
+ self.cmd.stdout.write(prompt_string)\r
+ value = parser(msg, self.cmd.stdin.readline())\r
+ try:\r
+ response = msg.response(value)\r
+ break\r
+ except ValueError, error:\r
+ continue\r
+ self.inqueue.put(response)\r
+\r
+\r
def _GetActiveFileIndex(self):\r
lib.playlist.Playlist = self.GetActivePlaylist()\r
#get the selected item from the tree\r
perspectivesFile.write(perspective)\r
perspectivesFile.close()\r
\r
- def execute_command(self, _class, method, command, args):\r
- self.cmd.inqueue.put(CommandMessage(command, args))\r
- while True:\r
- msg = self.cmd.outqueue.get()\r
- if isinstance(msg, Exit):\r
- return True\r
- elif isinstance(msg, CommandExit):\r
- self.cmd.stdout.write(msg.__class__.__name__+'\n')\r
- self.cmd.stdout.write(str(msg).rstrip()+'\n')\r
- break\r
- elif isinstance(msg, ReloadUserInterfaceConfig):\r
- self.cmd.ui.reload_config(msg.config)\r
- continue\r
- elif isinstance(msg, Request):\r
- self._handle_request(msg)\r
- continue\r
- self.cmd.stdout.write(str(msg).rstrip()+'\n')\r
- #TODO: run the command\r
- #command = ''.join(['self.do_', item_text, '()'])\r
- #self.AppendToOutput(command + '\n')\r
- #exec(command)\r
-\r
- def select_plugin(self, _class, method, plugin):\r
+ def select_plugin(self, _class=None, method=None, plugin=None):\r
for option in config[section]:\r
properties.append([option, config[section][option]])\r
\r
def select_command(self, _class, method, command):\r
- self.select_plugin(command.plugin)\r
+ self.select_plugin(plugin=command.plugin)\r
plugin = self.GetItemText(selected_item)\r
if plugin != 'core':\r
doc_string = eval('plugins.' + plugin + '.' + plugin + 'Commands.__doc__')\r
perspectives_list.sort()\r
index = perspectives_list.index(name)\r
perspective_Id = ID_FirstPerspective + index\r
- menu_item = self.MenuBar.FindItemById(perspective_Id)\r
+ menu_item = self._c['menu bar'].FindItemById(perspective_Id)\r
return menu_item\r
else:\r
return None\r
return True\r
return False\r
\r
- def _on_about(self, event):\r
- message = 'Hooke\n\n'+\\r
- 'A free, open source data analysis platform\n\n'+\\r
- 'Copyright 2006-2008 by Massimo Sandal\n'+\\r
- 'Copyright 2010 by Dr. Rolf Schmidt\n\n'+\\r
- 'Hooke is released under the GNU General Public License version 2.'\r
- dialog = wx.MessageDialog(self, message, 'About Hooke', wx.OK | wx.ICON_INFORMATION)\r
+ def _on_about(self, *args):\r
+ dialog = wx.MessageDialog(\r
+ parent=self,\r
+ message=self.gui._splash_text(),\r
+ caption='About Hooke',\r
+ style=wx.OK|wx.ICON_INFORMATION)\r
dialog.ShowModal()\r
dialog.Destroy()\r
\r
- def _on_close(self, event):\r
+ def _on_close(self, *args):\r
# apply changes\r
self.gui.config['main height'] = str(self.GetSize().GetHeight())\r
self.gui.config['main left'] = str(self.GetPosition()[0])\r
self._on_restore_perspective)\r
\r
def _on_restore_perspective(self, event):\r
- name = self.MenuBar.FindItemById(event.GetId()).GetLabel()\r
+ name = self._c['menu bar'].FindItemById(event.GetId()).GetLabel()\r
self._restore_perspective(name)\r
\r
def _on_save_perspective(self, event):\r
def nameExists(name):\r
- menu_position = self.MenuBar.FindMenu('Perspective')\r
- menu = self.MenuBar.GetMenu(menu_position)\r
+ menu_position = self._c['menu bar'].FindMenu('Perspective')\r
+ menu = self._c['menu bar'].GetMenu(menu_position)\r
for item in menu.GetMenuItems():\r
if item.GetText() == name:\r
return True\r
options=sorted(os.listdir(self.gui.config['perspective path'])),\r
message="\nPlease check the perspectives\n\nyou want to delete and click 'Delete'.\n",\r
button_id=wx.ID_DELETE,\r
- button_callback=self._on_delete_perspective,\r
+ callbacks={'button': self._on_delete_perspective},\r
+ selection_style='multiple',\r
parent=self,\r
label='Delete perspective(s)',\r
style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)\r
# ) that makes the radio item indicator in the menu disappear.\r
# The code should be fine once this issue is fixed.\r
\r
- def _on_delete_perspective(self, event, items, selected_items):\r
- for item in selected_items:\r
- self._perspectives.remove(item)\r
- if item == self.gui.config['active perspective']:\r
+ def _on_delete_perspective(self, _class, method, options, selected):\r
+ for p in selected:\r
+ self._perspectives.remove(p)\r
+ if p == self.gui.config['active perspective']:\r
self.gui.config['active perspective'] = 'Default'\r
path = os.path.join(self.gui.config['perspective path'],\r
- item+'.txt')\r
+ p+'.txt')\r
remove(path)\r
self._update_perspective_menu()\r
\r
event.Skip()\r
\r
def _next_curve(self, *args):\r
- '''\r
- NEXT\r
- Go to the next curve in the playlist.\r
- If we are at the last curve, we come back to the first.\r
- -----\r
- Syntax: next, n\r
- '''\r
+ """Call the `next curve` command.\r
+ """\r
+ results = self.execute_command(\r
+ command=self._command_by_name('next curve'))\r
+ if isinstance(results[-1], Success):\r
+ self.execute_command(\r
+ command=self._command_by_name('get curve'))\r
+\r
+ def _previous_curve(self, *args):\r
+ """Call the `previous curve` command.\r
+ """\r
+ self.execute_command(\r
+ command=self._command_by_name('previous curve'))\r
+ if isinstance(results[-1], Success):\r
+ self.execute_command(\r
+ command=self._command_by_name('get curve'))\r
+\r
+ def _postprocess_get_curve(self, command, results):\r
+ """Update `self` to show the curve.\r
+ """\r
+ if not isinstance(results[-1], Success):\r
+ return # error executing 'get curve'\r
+ assert len(results) == 2, results\r
+ curve = results[0]\r
+ print curve\r
+\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
self.UpdateNote()\r
self.UpdatePlot()\r
\r
- def _previous_curve(self, *args):\r
- '''\r
- PREVIOUS\r
- Go to the previous curve in the playlist.\r
- If we are at the first curve, we jump to the last.\r
- -------\r
- Syntax: previous, p\r
- '''\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']._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']._c['tree'].GetPrevSibling(selected_item)\r
- if not previous_item.IsOk():\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
- self._c['status bar'].set_playlist(playlist)\r
- self.UpdateNote()\r
- self.UpdatePlot()\r
-\r
def _on_notebook_page_close(self, event):\r
ctrl = event.GetEventObject()\r
playlist_name = ctrl.GetPageText(ctrl._curpage)\r
\r
def _on_view(self, event):\r
menu_id = event.GetId()\r
- menu_item = self.MenuBar.FindItemById(menu_id)\r
+ menu_item = self._c['menu bar'].FindItemById(menu_id)\r
menu_label = menu_item.GetLabel()\r
\r
pane = self._c['manager'].GetPane(menu_label)\r