-# Copyright (C) 2008-2010 Fabrizio Benedetti
-# Massimo Sandal <devicerandom@gmail.com>
-# Rolf Schmidt <rschmidt@alcor.concordia.ca>
-# W. Trevor King <wking@drexel.edu>
+# Copyright (C) 2010-2011 W. Trevor King <wking@drexel.edu>
#
# This file is part of Hooke.
#
from ...command import CommandExit, Exit, Success, Failure, Command, Argument
from ...config import Setting
+from ...engine import CommandMessage
from ...interaction import Request, BooleanRequest, ReloadUserInterfaceConfig
-from ...ui import UserInterface, CommandMessage
+from ...ui import UserInterface
from .dialog.selection import Selection as SelectionDialog
from .dialog.save_file import select_save_file
from . import menu as menu
self._perspectives = {} # {name: perspective_str}
self._c = {}
- self.SetIcon(wx.Icon(self.gui.config['icon image'], wx.BITMAP_TYPE_ICO))
+ self.SetIcon(wx.Icon(
+ os.path.expanduser(self.gui.config['icon image']),
+ wx.BITMAP_TYPE_ICO))
# setup frame manager
self._c['manager'] = aui.AuiManager()
self._setup_perspectives()
self._bind_events()
-
- self.execute_command(
- command=self._command_by_name('load playlist'),
- args={'input':'test/data/test'},#vclamp_picoforce/playlist'},
- )
- self.execute_command(
- command=self._command_by_name('load playlist'),
- args={'input':'test/data/vclamp_picoforce/playlist'},
- )
- self.execute_command(
- command=self._command_by_name('polymer fit'),
- args={'block':1, 'bounds':[918, 1103]},
- )
return # TODO: cleanup
- self.playlists = self._c['playlist'].Playlists
self._displayed_plot = None
#load default list, if possible
self.do_loadlist(self.GetStringFromConfig('core', 'preferences', 'playlists'))
commands=self.commands,
selected=self.gui.config['selected command'],
callbacks={
- 'execute': self.execute_command,
+ 'execute': self.explicit_execute_command,
'select_plugin': self.select_plugin,
'select_command': self.select_command,
# 'selection_changed': self.panelProperties.select(self, method, command), #SelectedTreeItem = selected_item,
size=wx.Size(150, 90),
style=wx.TE_READONLY|wx.NO_BORDER|wx.TE_MULTILINE),
'bottom'),
-# ('results', panel.results.Results(self), 'bottom'),
]:
self._add_panel(p, style)
+ self.execute_command( # setup already loaded playlists
+ command=self._command_by_name('playlists'))
+ self.execute_command( # setup already loaded curve
+ command=self._command_by_name('get curve'))
def _add_panel(self, panel, style):
self._c[panel.name] = panel
self.Bind(wx.EVT_ERASE_BACKGROUND, self._on_erase_background)
self.Bind(wx.EVT_SIZE, self._on_size)
self.Bind(wx.EVT_CLOSE, self._on_close)
- self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPaneClose)
- self.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self._on_notebook_page_close)
+ self.Bind(aui.EVT_AUI_PANE_CLOSE, self._on_pane_close)
return # TODO: cleanup
treeCtrl = self._c['folders'].GetTreeCtrl()
treeCtrl.Bind(wx.EVT_LEFT_DCLICK, self._on_dir_ctrl_left_double_click)
-
- #property editor
- self.panelProperties.pg.Bind(wxpg.EVT_PG_CHANGED, self.OnPropGridChanged)
- #results panel
- self.panelResults.results_list.OnCheckItem = self.OnResultsCheck
def _on_about(self, *args):
dialog = wx.MessageDialog(
dialog.ShowModal()
dialog.Destroy()
+ def _on_size(self, event):
+ event.Skip()
+
def _on_close(self, *args):
self.log.info('closing GUI framework')
# apply changes
- self.gui.config['main height'] = str(self.GetSize().GetHeight())
- self.gui.config['main left'] = str(self.GetPosition()[0])
- self.gui.config['main top'] = str(self.GetPosition()[1])
- self.gui.config['main width'] = str(self.GetSize().GetWidth())
- # push changes back to Hooke.config?
+ self._set_config('main height', self.GetSize().GetHeight())
+ self._set_config('main left', self.GetPosition()[0])
+ self._set_config('main top', self.GetPosition()[1])
+ self._set_config('main width', self.GetSize().GetWidth())
self._c['manager'].UnInit()
del self._c['manager']
self.Destroy()
+ def _on_erase_background(self, event):
+ event.Skip()
+
# Panel utility functions
raise Exception('Multiple commands named "%s"' % name)
return cs[0]
+ def explicit_execute_command(self, _class=None, method=None,
+ command=None, args=None):
+ return self.execute_command(
+ _class=_class, method=method, command=command, args=args,
+ explicit_user_call=True)
+
def execute_command(self, _class=None, method=None,
- command=None, args=None):
+ command=None, args=None, explicit_user_call=False):
if args == None:
args = {}
if ('property editor' in self._c
- and self.gui.config['selected command'] == command):
+ and self.gui.config['selected command'] == command.name):
for name,value in self._c['property editor'].get_values().items():
arg = self._c['property editor']._argument_from_label.get(
name, None)
index = int(name[len(arg.name):])
args[arg.name][index] = value
for arg in command.arguments:
+ if arg.name not in args:
+ continue # undisplayed argument, e.g. 'driver' types.
count = arg.count
if hasattr(arg, '_display_count'): # support HACK in props_from_argument()
count = arg._display_count
args[arg.name].pop()
if len(args[arg.name]) == 0:
args[arg.name] = arg.default
- self.log.debug('executing %s with %s' % (command.name, args))
- self.inqueue.put(CommandMessage(command, args))
+ cm = CommandMessage(command.name, args)
+ self.gui._submit_command(
+ cm, self.inqueue, explicit_user_call=explicit_user_call)
+ # TODO: skip responses for commands that were captured by the
+ # command stack. We'd need to poll on each request, remember
+ # capture state, or add a flag to the response...
+ return self._handle_response(command_message=cm)
+
+ def _handle_response(self, command_message):
results = []
while True:
msg = self.outqueue.get()
h.run(self, msg) # TODO: pause for response?
continue
pp = getattr(
- self, '_postprocess_%s' % command.name.replace(' ', '_'),
- self._postprocess_text)
- pp(command=command, args=args, results=results)
+ self, '_postprocess_%s' % command_message.command.replace(' ', '_'),
+ self._postprocess_text)
+ pp(command=command_message.command,
+ args=command_message.arguments,
+ results=results)
return results
def _handle_request(self, msg):
continue
self.inqueue.put(response)
+ def _set_config(self, option, value, section=None):
+ self.gui._set_config(section=section, option=option, value=value,
+ ui_to_command_queue=self.inqueue,
+ response_handler=self._handle_response)
# Command-specific postprocessing
self._c['output'].write(result.__class__.__name__+'\n')
self._c['output'].write(str(result).rstrip()+'\n')
+ def _postprocess_playlists(self, command, args={}, results=None):
+ """Update `self` to show the playlists.
+ """
+ if not isinstance(results[-1], Success):
+ self._postprocess_text(command, results=results)
+ return
+ assert len(results) == 2, results
+ playlists = results[0]
+ if 'playlist' in self._c:
+ for playlist in playlists:
+ if self._c['playlist'].is_playlist_loaded(playlist):
+ self._c['playlist'].update_playlist(playlist)
+ else:
+ self._c['playlist'].add_playlist(playlist)
+
+ def _postprocess_new_playlist(self, command, args={}, results=None):
+ """Update `self` to show the new playlist.
+ """
+ if not isinstance(results[-1], Success):
+ self._postprocess_text(command, results=results)
+ return
+ assert len(results) == 2, results
+ playlist = results[0]
+ if 'playlist' in self._c:
+ loaded = self._c['playlist'].is_playlist_loaded(playlist)
+ assert loaded == False, loaded
+ self._c['playlist'].add_playlist(playlist)
+
def _postprocess_load_playlist(self, command, args={}, results=None):
"""Update `self` to show the playlist.
"""
return
assert len(results) == 2, results
playlist = results[0]
- self._c['playlist']._c['tree'].add_playlist(playlist)
+ self._c['playlist'].add_playlist(playlist)
def _postprocess_get_playlist(self, command, args={}, results=[]):
if not isinstance(results[-1], Success):
return
assert len(results) == 2, results
playlist = results[0]
- self._c['playlist']._c['tree'].update_playlist(playlist)
+ if 'playlist' in self._c:
+ loaded = self._c['playlist'].is_playlist_loaded(playlist)
+ assert loaded == True, loaded
+ self._c['playlist'].update_playlist(playlist)
def _postprocess_get_curve(self, command, args={}, results=[]):
"""Update `self` to show the curve.
else:
raise NotImplementedError()
if 'note' in self._c:
- self._c['note'].set_text(curve.info['note'])
+ self._c['note'].set_text(curve.info.get('note', ''))
if 'playlist' in self._c:
- self._c['playlist']._c['tree'].set_selected_curve(
+ self._c['playlist'].set_selected_curve(
playlist, curve)
if 'plot' in self._c:
self._c['plot'].set_curve(curve, config=self.gui.config)
"""
pass
- def _postprocess_zero_block_surface_contact_point(
+ def _postprocess_glob_curves_to_playlist(
self, command, args={}, results=[]):
- """Update the curve, since the available columns may have changed.
+ """Update `self` to show new curves.
"""
- if isinstance(results[-1], Success):
- self.execute_command(
- command=self._command_by_name('get curve'))
-
- def _postprocess_add_block_force_array(
- self, command, args={}, results=[]):
+ if not isinstance(results[-1], Success):
+ self._postprocess_text(command, results=results)
+ return
+ if 'playlist' in self._c:
+ if args.get('playlist', None) != None:
+ playlist = args['playlist']
+ pname = playlist.name
+ loaded = self._c['playlist'].is_playlist_name_loaded(pname)
+ assert loaded == True, loaded
+ for curve in results[:-1]:
+ self._c['playlist']._add_curve(pname, curve)
+ else:
+ self.execute_command(
+ command=self._command_by_name('get playlist'))
+
+ def _update_curve(self, command, args={}, results=[]):
"""Update the curve, since the available columns may have changed.
"""
if isinstance(results[-1], Success):
command=self._command_by_name('get curve'))
-
- # TODO: cruft
-
- def _GetActiveFileIndex(self):
- lib.playlist.Playlist = self.GetActivePlaylist()
- #get the selected item from the tree
- selected_item = self._c['playlist']._c['tree'].GetSelection()
- #test if a playlist or a curve was double-clicked
- if self._c['playlist']._c['tree'].ItemHasChildren(selected_item):
- return -1
- else:
- count = 0
- selected_item = self._c['playlist']._c['tree'].GetPrevSibling(selected_item)
- while selected_item.IsOk():
- count += 1
- selected_item = self._c['playlist']._c['tree'].GetPrevSibling(selected_item)
- return count
-
- def _GetPlaylistTab(self, name):
- for index, page in enumerate(self._c['notebook']._tabs._pages):
- if page.caption == name:
- return index
- return -1
-
- def select_plugin(self, _class=None, method=None, plugin=None):
- pass
-
- def AddPlaylistFromFiles(self, files=[], name='Untitled'):
- if files:
- playlist = lib.playlist.Playlist(self, self.drivers)
- for item in files:
- playlist.add_curve(item)
- if playlist.count > 0:
- playlist.name = self._GetUniquePlaylistName(name)
- playlist.reset()
- self.AddTayliss(playlist)
-
- def AppliesPlotmanipulator(self, name):
- '''
- Returns True if the plotmanipulator 'name' is applied, False otherwise
- name does not contain 'plotmanip_', just the name of the plotmanipulator (e.g. 'flatten')
- '''
- return self.GetBoolFromConfig('core', 'plotmanipulators', name)
-
- def ApplyPlotmanipulators(self, plot, plot_file):
- '''
- Apply all active plotmanipulators.
- '''
- if plot is not None and plot_file is not None:
- manipulated_plot = copy.deepcopy(plot)
- for plotmanipulator in self.plotmanipulators:
- if self.GetBoolFromConfig('core', 'plotmanipulators', plotmanipulator.name):
- manipulated_plot = plotmanipulator.method(manipulated_plot, plot_file)
- return manipulated_plot
-
- def GetActiveFigure(self):
- playlist_name = self.GetActivePlaylistName()
- figure = self.playlists[playlist_name].figure
- if figure is not None:
- return figure
- return None
-
- def GetActiveFile(self):
- playlist = self.GetActivePlaylist()
- if playlist is not None:
- return playlist.get_active_file()
- return None
-
- def GetActivePlot(self):
- playlist = self.GetActivePlaylist()
- if playlist is not None:
- return playlist.get_active_file().plot
- return None
-
- def GetDisplayedPlot(self):
- plot = copy.deepcopy(self.displayed_plot)
- #plot.curves = []
- #plot.curves = copy.deepcopy(plot.curves)
- return plot
-
- def GetDisplayedPlotCorrected(self):
- plot = copy.deepcopy(self.displayed_plot)
- plot.curves = []
- plot.curves = copy.deepcopy(plot.corrected_curves)
- return plot
-
- def GetDisplayedPlotRaw(self):
- plot = copy.deepcopy(self.displayed_plot)
- plot.curves = []
- plot.curves = copy.deepcopy(plot.raw_curves)
- return plot
-
- def GetDockArt(self):
- return self._c['manager'].GetArtProvider()
-
- def GetPlotmanipulator(self, name):
- '''
- Returns a plot manipulator function from its name
- '''
- for plotmanipulator in self.plotmanipulators:
- if plotmanipulator.name == name:
- return plotmanipulator
- return None
-
- def HasPlotmanipulator(self, name):
- '''
- returns True if the plotmanipulator 'name' is loaded, False otherwise
- '''
- for plotmanipulator in self.plotmanipulators:
- if plotmanipulator.command == name:
- return True
- return False
-
-
- def _on_dir_ctrl_left_double_click(self, event):
- file_path = self.panelFolders.GetPath()
- if os.path.isfile(file_path):
- if file_path.endswith('.hkp'):
- self.do_loadlist(file_path)
- event.Skip()
-
- def _on_erase_background(self, event):
- event.Skip()
-
- def _on_notebook_page_close(self, event):
- ctrl = event.GetEventObject()
- playlist_name = ctrl.GetPageText(ctrl._curpage)
- self.DeleteFromPlaylists(playlist_name)
-
- def OnPaneClose(self, event):
- event.Skip()
-
- def OnPropGridChanged (self, event):
- prop = event.GetProperty()
- if prop:
- item_section = self.panelProperties.SelectedTreeItem
- item_plugin = self._c['commands']._c['tree'].GetItemParent(item_section)
- plugin = self._c['commands']._c['tree'].GetItemText(item_plugin)
- config = self.gui.config[plugin]
- property_section = self._c['commands']._c['tree'].GetItemText(item_section)
- property_key = prop.GetName()
- property_value = prop.GetDisplayedString()
-
- config[property_section][property_key]['value'] = property_value
-
- def OnResultsCheck(self, index, flag):
- results = self.GetActivePlot().results
- if results.has_key(self.results_str):
- results[self.results_str].results[index].visible = flag
- results[self.results_str].update()
- self.UpdatePlot()
-
-
- def _on_size(self, event):
- event.Skip()
-
- def UpdatePlaylistsTreeSelection(self):
- playlist = self.GetActivePlaylist()
- if playlist is not None:
- if playlist.index >= 0:
- self._c['status bar'].set_playlist(playlist)
- self.UpdateNote()
- self.UpdatePlot()
-
- def _on_curve_select(self, playlist, curve):
- #create the plot tab and add playlist to the dictionary
- plotPanel = panel.plot.PlotPanel(self, ID_FirstPlot + len(self.playlists))
- notebook_tab = self._c['notebook'].AddPage(plotPanel, playlist.name, True)
- #tab_index = self._c['notebook'].GetSelection()
- playlist.figure = plotPanel.get_figure()
- self.playlists[playlist.name] = playlist
- #self.playlists[playlist.name] = [playlist, figure]
- self._c['status bar'].set_playlist(playlist)
- self.UpdateNote()
- self.UpdatePlot()
-
-
- def _on_playlist_left_doubleclick(self):
- index = self._c['notebook'].GetSelection()
- current_playlist = self._c['notebook'].GetPageText(index)
- if current_playlist != playlist_name:
- index = self._GetPlaylistTab(playlist_name)
- self._c['notebook'].SetSelection(index)
- self._c['status bar'].set_playlist(playlist)
- self.UpdateNote()
- self.UpdatePlot()
-
- def _on_playlist_delete(self, playlist):
- notebook = self.Parent.plotNotebook
- index = self.Parent._GetPlaylistTab(playlist.name)
- notebook.SetSelection(index)
- notebook.DeletePage(notebook.GetSelection())
- self.Parent.DeleteFromPlaylists(playlist_name)
-
-
-
# Command panel interface
def select_command(self, _class, method, command):
self._c['property editor']._argument_from_label[label] = (
argument)
- self.gui.config['selected command'] = command # TODO: push to engine
+ self._set_config('selected command', command.name)
+
+ def select_plugin(self, _class=None, method=None, plugin=None):
+ pass
+
+
+
+ # Folders panel interface
+
+ def _on_dir_ctrl_left_double_click(self, event):
+ file_path = self.panelFolders.GetPath()
+ if os.path.isfile(file_path):
+ if file_path.endswith('.hkp'):
+ self.do_loadlist(file_path)
+ event.Skip()
# Panel display handling
+ def _on_pane_close(self, event):
+ pane = event.pane
+ view = self._c['menu bar']._c['view']
+ if pane.name in view._c.keys():
+ view._c[pane.name].Check(False)
+ event.Skip()
+
def _on_panel_visibility(self, _class, method, panel_name, visible):
pane = self._c['manager'].GetPane(panel_name)
pane.Show(visible)
self._perspectives = {
'Default': self._c['manager'].SavePerspective(),
}
- path = self.gui.config['perspective path']
+ path = os.path.expanduser(self.gui.config['perspective path'])
if os.path.isdir(path):
files = sorted(os.listdir(path))
for fname in files:
selected_perspective = self.gui.config['active perspective']
if not self._perspectives.has_key(selected_perspective):
- self.gui.config['active perspective'] = 'Default' # TODO: push to engine's Hooke
+ self._set_config('active perspective', 'Default')
self._restore_perspective(selected_perspective, force=True)
self._update_perspective_menu()
def _restore_perspective(self, name, force=False):
if name != self.gui.config['active perspective'] or force == True:
self.log.debug('restore perspective %s' % name)
- self.gui.config['active perspective'] = name # TODO: push to engine's Hooke
+ self._set_config('active perspective', name)
self._c['manager'].LoadPerspective(self._perspectives[name])
self._c['manager'].Update()
for pane in self._c['manager'].GetAllPanes():
if name == 'Default':
name = 'New perspective'
name = select_save_file(
- directory=self.gui.config['perspective path'],
+ directory=os.path.expanduser(self.gui.config['perspective path']),
name=name,
extension=self.gui.config['perspective extension'],
parent=self,
if name == None:
return
self._save_perspective(
- perspective, self.gui.config['perspective path'], name=name,
+ perspective,
+ os.path.expanduser(self.gui.config['perspective path']), name=name,
extension=self.gui.config['perspective extension'])
def _on_delete_perspective(self, *args, **kwargs):
names = [options[i] for i in dialog.selected]
dialog.Destroy()
self._delete_perspectives(
- self.gui.config['perspective path'], names=names,
- extension=self.gui.config['perspective extension'])
+ os.path.expanduser(self.gui.config['perspective path']),
+ names=names, extension=self.gui.config['perspective extension'])
def _on_select_perspective(self, _class, method, name):
self._restore_perspective(name)
+# setup per-command versions of HookeFrame._update_curve
+for _command in ['convert_distance_to_force',
+ 'polymer_fit_peaks',
+ 'remove_cantilever_from_extension',
+ 'zero_surface_contact_point',
+ ]:
+ setattr(HookeFrame, '_postprocess_%s' % _command, HookeFrame._update_curve)
+del _command
+
class HookeApp (wx.App):
"""A :class:`wx.App` wrapper around :class:`HookeFrame`.
def _setup_splash_screen(self):
if self.gui.config['show splash screen'] == True:
- path = self.gui.config['splash screen image']
+ path = os.path.expanduser(self.gui.config['splash screen image'])
if os.path.isfile(path):
duration = self.gui.config['splash screen duration']
wx.SplashScreen(