From 94d115294fa7d650a20fb5c4fa5c996d874c8f30 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 27 Jul 2010 16:51:27 -0400 Subject: [PATCH] Reordered gui.HookeFrame methods to group by category --- hooke/ui/gui/__init__.py | 588 ++++++++++++++-------------------- hooke/ui/gui/dialog/points.py | 33 ++ 2 files changed, 267 insertions(+), 354 deletions(-) create mode 100644 hooke/ui/gui/dialog/points.py diff --git a/hooke/ui/gui/__init__.py b/hooke/ui/gui/__init__.py index 1a6492e..f4aaaef 100644 --- a/hooke/ui/gui/__init__.py +++ b/hooke/ui/gui/__init__.py @@ -40,7 +40,7 @@ from . import prettyformat as prettyformat from . import statusbar as statusbar -class HookeFrame (wx.Frame): +class HookeFrame (PerspectiveHooks, wx.Frame): """The main Hooke-interface window. @@ -99,15 +99,14 @@ class HookeFrame (wx.Frame): name = self.gui.config['active perspective'] return # TODO: cleanup - menu_item = self.GetPerspectiveMenuItem(name) - if menu_item is not None: - self._on_restore_perspective(menu_item) - #TODO: config setting to remember playlists from last session self.playlists = self._c['playlists'].Playlists self._displayed_plot = None #load default list, if possible self.do_loadlist(self.GetStringFromConfig('core', 'preferences', 'playlist')) + + # GUI maintenance + def _setup_panels(self): client_size = self.GetClientSize() for label,p,style in [ @@ -227,6 +226,29 @@ class HookeFrame (wx.Frame): #results panel self.panelResults.results_list.OnCheckItem = self.OnResultsCheck + def _on_about(self, *args): + dialog = wx.MessageDialog( + parent=self, + message=self.gui._splash_text(), + caption='About Hooke', + style=wx.OK|wx.ICON_INFORMATION) + dialog.ShowModal() + dialog.Destroy() + + def _on_close(self, *args): + # 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._c['manager'].UnInit() + del self._c['manager'] + self.Destroy() + + + # Command handling + def _command_by_name(self, name): cs = [c for c in self.commands if c.name == name] if len(cs) == 0: @@ -286,6 +308,43 @@ class HookeFrame (wx.Frame): self.inqueue.put(response) + + # Command-specific postprocessing + + def _postprocess_get_curve(self, command, results): + """Update `self` to show the curve. + """ + if not isinstance(results[-1], Success): + return # error executing 'get curve' + assert len(results) == 2, results + curve = results[0] + print curve + + selected_item = self._c['playlists']._c['tree'].GetSelection() + if self._c['playlists']._c['tree'].ItemHasChildren(selected_item): + #GetFirstChild returns a tuple + #we only need the first element + next_item = self._c['playlists']._c['tree'].GetFirstChild(selected_item)[0] + else: + next_item = self._c['playlists']._c['tree'].GetNextSibling(selected_item) + if not next_item.IsOk(): + parent_item = self._c['playlists']._c['tree'].GetItemParent(selected_item) + #GetFirstChild returns a tuple + #we only need the first element + next_item = self._c['playlists']._c['tree'].GetFirstChild(parent_item)[0] + self._c['playlists']._c['tree'].SelectItem(next_item, True) + if not self._c['playlists']._c['tree'].ItemHasChildren(selected_item): + playlist = self.GetActivePlaylist() + if playlist.count > 1: + playlist.next() + self._c['status bar'].set_playlist(playlist) + self.UpdateNote() + self.UpdatePlot() + + + + # TODO: cruft + def _GetActiveFileIndex(self): lib.playlist.Playlist = self.GetActivePlaylist() #get the selected item from the tree @@ -311,20 +370,6 @@ class HookeFrame (wx.Frame): for option in config[section]: properties.append([option, config[section][option]]) - def select_command(self, _class, method, command): - self.select_plugin(plugin=command.plugin) - plugin = self.GetItemText(selected_item) - if plugin != 'core': - doc_string = eval('plugins.' + plugin + '.' + plugin + 'Commands.__doc__') - else: - doc_string = 'The module "core" contains Hooke core functionality' - if doc_string is not None: - self.panelAssistant.ChangeValue(doc_string) - else: - self.panelAssistant.ChangeValue('') - panel.propertyeditor.PropertyEditor.Initialize(self.panelProperties, properties) - self.gui.config['selected command'] = command - def AddPlaylistFromFiles(self, files=[], name='Untitled'): if files: playlist = lib.playlist.Playlist(self, self.drivers) @@ -405,17 +450,6 @@ class HookeFrame (wx.Frame): return plotmanipulator return None - def GetPerspectiveMenuItem(self, name): - if self._perspectives.has_key(name): - perspectives_list = [key for key, value in self._perspectives.iteritems()] - perspectives_list.sort() - index = perspectives_list.index(name) - perspective_Id = ID_FirstPerspective + index - menu_item = self._c['menu bar'].FindItemById(perspective_Id) - return menu_item - else: - return None - def HasPlotmanipulator(self, name): ''' returns True if the plotmanipulator 'name' is loaded, False otherwise @@ -425,140 +459,6 @@ class HookeFrame (wx.Frame): return True return False - def _on_about(self, *args): - dialog = wx.MessageDialog( - parent=self, - message=self.gui._splash_text(), - caption='About Hooke', - style=wx.OK|wx.ICON_INFORMATION) - dialog.ShowModal() - dialog.Destroy() - - def _on_close(self, *args): - # 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._c['manager'].UnInit() - del self._c['manager'] - self.Destroy() - - def _setup_perspectives(self): - """Add perspectives to menubar and _perspectives. - """ - self._perspectives = { - 'Default': self._c['manager'].SavePerspective(), - } - path = self.gui.config['perspective path'] - if os.path.isdir(path): - files = sorted(os.listdir(path)) - for fname in files: - name, extension = os.path.splitext(fname) - if extension != self.gui.config['perspective extension']: - continue - fpath = os.path.join(path, fname) - if not os.path.isfile(fpath): - continue - perspective = None - with open(fpath, 'rU') as f: - perspective = f.readline() - if perspective: - self._perspectives[name] = perspective - - 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._restore_perspective(selected_perspective) - self._update_perspective_menu() - - def _update_perspective_menu(self): - self._c['menu bar']._c['perspective'].update( - sorted(self._perspectives.keys()), - self.gui.config['active perspective']) - - def _save_perspective(self, perspective, perspective_dir, name, - extension=None): - path = os.path.join(perspective_dir, name) - if extension != None: - path += extension - if not os.path.isdir(perspective_dir): - os.makedirs(perspective_dir) - with open(path, 'w') as f: - f.write(perspective) - self._perspectives[name] = perspective - self._restore_perspective(name) - self._update_perspective_menu() - - def _delete_perspectives(self, perspective_dir, names, - extension=None): - print 'pop', names - for name in names: - path = os.path.join(perspective_dir, name) - if extension != None: - path += extension - os.remove(path) - del(self._perspectives[name]) - self._update_perspective_menu() - if self.gui.config['active perspective'] in names: - self._restore_perspective('Default') - # TODO: does this bug still apply? - # Unfortunately, there is a bug in wxWidgets for win32 (Ticket #3258 - # http://trac.wxwidgets.org/ticket/3258 - # ) that makes the radio item indicator in the menu disappear. - # The code should be fine once this issue is fixed. - - def _restore_perspective(self, name): - if name != self.gui.config['active perspective']: - print 'restoring perspective:', name - self.gui.config['active perspective'] = name # TODO: push to engine's Hooke - self._c['manager'].LoadPerspective(self._perspectives[name]) - self._c['manager'].Update() - for pane in self._c['manager'].GetAllPanes(): - if pane.name in self._c['menu bar']._c['view']._c.keys(): - pane.Check(pane.window.IsShown()) - - def _on_save_perspective(self, *args): - perspective = self._c['manager'].SavePerspective() - name = self.gui.config['active perspective'] - if name == 'Default': - name = 'New perspective' - name = select_save_file( - directory=self.gui.config['perspective path'], - name=name, - extension=self.gui.config['perspective extension'], - parent=self, - message='Enter a name for the new perspective:', - caption='Save perspective') - if name == None: - return - self._save_perspective( - perspective, self.gui.config['perspective path'], name=name, - extension=self.gui.config['perspective extension']) - - def _on_delete_perspective(self, *args, **kwargs): - options = sorted([p for p in self._perspectives.keys() - if p != 'Default']) - dialog = SelectionDialog( - options=options, - message="\nPlease check the perspectives\n\nyou want to delete and click 'Delete'.\n", - button_id=wx.ID_DELETE, - selection_style='multiple', - parent=self, - title='Delete perspective(s)', - style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) - dialog.CenterOnScreen() - dialog.ShowModal() - 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']) - - def _on_select_perspective(self, _class, method, name): - self._restore_perspective(name) def _on_dir_ctrl_left_double_click(self, event): file_path = self.panelFolders.GetPath() @@ -570,54 +470,6 @@ class HookeFrame (wx.Frame): def _on_erase_background(self, event): event.Skip() - def _next_curve(self, *args): - """Call the `next curve` command. - """ - results = self.execute_command( - command=self._command_by_name('next curve')) - if isinstance(results[-1], Success): - self.execute_command( - command=self._command_by_name('get curve')) - - def _previous_curve(self, *args): - """Call the `previous curve` command. - """ - self.execute_command( - command=self._command_by_name('previous curve')) - if isinstance(results[-1], Success): - self.execute_command( - command=self._command_by_name('get curve')) - - def _postprocess_get_curve(self, command, results): - """Update `self` to show the curve. - """ - if not isinstance(results[-1], Success): - return # error executing 'get curve' - assert len(results) == 2, results - curve = results[0] - print curve - - selected_item = self._c['playlists']._c['tree'].GetSelection() - if self._c['playlists']._c['tree'].ItemHasChildren(selected_item): - #GetFirstChild returns a tuple - #we only need the first element - next_item = self._c['playlists']._c['tree'].GetFirstChild(selected_item)[0] - else: - next_item = self._c['playlists']._c['tree'].GetNextSibling(selected_item) - if not next_item.IsOk(): - parent_item = self._c['playlists']._c['tree'].GetItemParent(selected_item) - #GetFirstChild returns a tuple - #we only need the first element - next_item = self._c['playlists']._c['tree'].GetFirstChild(parent_item)[0] - self._c['playlists']._c['tree'].SelectItem(next_item, True) - if not self._c['playlists']._c['tree'].ItemHasChildren(selected_item): - playlist = self.GetActivePlaylist() - if playlist.count > 1: - playlist.next() - self._c['status bar'].set_playlist(playlist) - self.UpdateNote() - self.UpdatePlot() - def _on_notebook_page_close(self, event): ctrl = event.GetEventObject() playlist_name = ctrl.GetPageText(ctrl._curpage) @@ -657,148 +509,6 @@ class HookeFrame (wx.Frame): active_file = self.GetActiveFile() active_file.note = self.panelNote.Editor.GetValue() - def _on_panel_visibility(self, _class, method, panel_name, visible): - pane = self._c['manager'].GetPane(panel_name) - print visible - pane.Show(visible) - #if we don't do the following, the Folders pane does not resize properly on hide/show - if pane.caption == 'Folders' and pane.IsShown() and pane.IsDocked(): - #folders_size = pane.GetSize() - self.panelFolders.Fit() - self._c['manager'].Update() - - def _clickize(self, xvector, yvector, index): - ''' - Returns a ClickedPoint() object from an index and vectors of x, y coordinates - ''' - point = lib.clickedpoint.ClickedPoint() - point.index = index - point.absolute_coords = xvector[index], yvector[index] - point.find_graph_coords(xvector, yvector) - return point - - def _delta(self, message='Click 2 points', block=0): - ''' - Calculates the difference between two clicked points - ''' - clicked_points = self._measure_N_points(N=2, message=message, block=block) - - plot = self.GetDisplayedPlotCorrected() - curve = plot.curves[block] - - delta = lib.delta.Delta() - delta.point1.x = clicked_points[0].graph_coords[0] - delta.point1.y = clicked_points[0].graph_coords[1] - delta.point2.x = clicked_points[1].graph_coords[0] - delta.point2.y = clicked_points[1].graph_coords[1] - delta.units.x = curve.units.x - delta.units.y = curve.units.y - - return delta - - def _measure_N_points(self, N, message='', block=0): - ''' - General helper function for N-points measurements - By default, measurements are done on the retraction - ''' - if message: - dialog = wx.MessageDialog(None, message, 'Info', wx.OK) - dialog.ShowModal() - - figure = self.GetActiveFigure() - - xvector = self.displayed_plot.curves[block].x - yvector = self.displayed_plot.curves[block].y - - clicked_points = figure.ginput(N, timeout=-1, show_clicks=True) - - points = [] - for clicked_point in clicked_points: - point = lib.clickedpoint.ClickedPoint() - point.absolute_coords = clicked_point[0], clicked_point[1] - point.dest = 0 - #TODO: make this optional? - #so far, the clicked point is taken, not the corresponding data point - point.find_graph_coords(xvector, yvector) - point.is_line_edge = True - point.is_marker = True - points.append(point) - return points - - def do_copylog(self): - ''' - Copies all files in the current playlist that have a note to the destination folder. - destination: select folder where you want the files to be copied - use_LVDT_folder: when checked, the files will be copied to a folder called 'LVDT' in the destination folder (for MFP-1D files only) - ''' - playlist = self.GetActivePlaylist() - if playlist is not None: - destination = self.GetStringFromConfig('core', 'copylog', 'destination') - if not os.path.isdir(destination): - os.makedirs(destination) - for current_file in playlist.files: - if current_file.note: - shutil.copy(current_file.filename, destination) - if current_file.driver.filetype == 'mfp1d': - filename = current_file.filename.replace('deflection', 'LVDT', 1) - path, name = os.path.split(filename) - filename = os.path.join(path, 'lvdt', name) - use_LVDT_folder = self.GetBoolFromConfig('core', 'copylog', 'use_LVDT_folder') - if use_LVDT_folder: - destination = os.path.join(destination, 'LVDT') - shutil.copy(filename, destination) - - def do_plotmanipulators(self): - ''' - Please select the plotmanipulators you would like to use - and define the order in which they will be applied to the data. - - Click 'Execute' to apply your changes. - ''' - self.UpdatePlot() - - def do_preferences(self): - ''' - Please set general preferences for Hooke here. - hide_curve_extension: hides the extension of the force curve files. - not recommended for 'picoforce' files - ''' - pass - - def do_test(self): - ''' - Use this command for testing purposes. You find do_test in hooke.py. - ''' - pass - - def do_version(self): - ''' - VERSION - ------ - Prints the current version and codename, plus library version. Useful for debugging. - ''' - self.AppendToOutput('Hooke ' + __version__ + ' (' + __codename__ + ')') - self.AppendToOutput('Released on: ' + __releasedate__) - self.AppendToOutput('---') - self.AppendToOutput('Python version: ' + python_version) - self.AppendToOutput('WxPython version: ' + wx_version) - self.AppendToOutput('Matplotlib version: ' + mpl_version) - self.AppendToOutput('SciPy version: ' + scipy_version) - self.AppendToOutput('NumPy version: ' + numpy_version) - self.AppendToOutput('ConfigObj version: ' + configobj_version) - self.AppendToOutput('wxPropertyGrid version: ' + '.'.join([str(PROPGRID_MAJOR), str(PROPGRID_MINOR), str(PROPGRID_RELEASE)])) - self.AppendToOutput('---') - self.AppendToOutput('Platform: ' + str(platform.uname())) - self.AppendToOutput('******************************') - self.AppendToOutput('Loaded plugins') - self.AppendToOutput('---') - - #sort the plugins into alphabetical order - plugins_list = [key for key, value in self.plugins.iteritems()] - plugins_list.sort() - for plugin in plugins_list: - self.AppendToOutput(plugin) - def UpdateNote(self): #update the note for the active file active_file = self.GetActiveFile() @@ -930,6 +640,176 @@ class HookeFrame (wx.Frame): self.Parent.DeleteFromPlaylists(playlist_name) + + # Command panel interface + + def select_command(self, _class, method, command): + self.select_plugin(plugin=command.plugin) + plugin = self.GetItemText(selected_item) + if plugin != 'core': + doc_string = eval('plugins.' + plugin + '.' + plugin + 'Commands.__doc__') + else: + doc_string = 'The module "core" contains Hooke core functionality' + if doc_string is not None: + self.panelAssistant.ChangeValue(doc_string) + else: + self.panelAssistant.ChangeValue('') + panel.propertyeditor.PropertyEditor.Initialize(self.panelProperties, properties) + self.gui.config['selected command'] = command + + + + # Navbar interface + + def _next_curve(self, *args): + """Call the `next curve` command. + """ + results = self.execute_command( + command=self._command_by_name('next curve')) + if isinstance(results[-1], Success): + self.execute_command( + command=self._command_by_name('get curve')) + + def _previous_curve(self, *args): + """Call the `previous curve` command. + """ + self.execute_command( + command=self._command_by_name('previous curve')) + if isinstance(results[-1], Success): + self.execute_command( + command=self._command_by_name('get curve')) + + + + # Panel display handling + + def _on_panel_visibility(self, _class, method, panel_name, visible): + pane = self._c['manager'].GetPane(panel_name) + print visible + pane.Show(visible) + #if we don't do the following, the Folders pane does not resize properly on hide/show + if pane.caption == 'Folders' and pane.IsShown() and pane.IsDocked(): + #folders_size = pane.GetSize() + self.panelFolders.Fit() + self._c['manager'].Update() + + def _setup_perspectives(self): + """Add perspectives to menubar and _perspectives. + """ + self._perspectives = { + 'Default': self._c['manager'].SavePerspective(), + } + path = self.gui.config['perspective path'] + if os.path.isdir(path): + files = sorted(os.listdir(path)) + for fname in files: + name, extension = os.path.splitext(fname) + if extension != self.gui.config['perspective extension']: + continue + fpath = os.path.join(path, fname) + if not os.path.isfile(fpath): + continue + perspective = None + with open(fpath, 'rU') as f: + perspective = f.readline() + if perspective: + self._perspectives[name] = perspective + + 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._restore_perspective(selected_perspective) + self._update_perspective_menu() + + def _update_perspective_menu(self): + self._c['menu bar']._c['perspective'].update( + sorted(self._perspectives.keys()), + self.gui.config['active perspective']) + + def _save_perspective(self, perspective, perspective_dir, name, + extension=None): + path = os.path.join(perspective_dir, name) + if extension != None: + path += extension + if not os.path.isdir(perspective_dir): + os.makedirs(perspective_dir) + with open(path, 'w') as f: + f.write(perspective) + self._perspectives[name] = perspective + self._restore_perspective(name) + self._update_perspective_menu() + + def _delete_perspectives(self, perspective_dir, names, + extension=None): + print 'pop', names + for name in names: + path = os.path.join(perspective_dir, name) + if extension != None: + path += extension + os.remove(path) + del(self._perspectives[name]) + self._update_perspective_menu() + if self.gui.config['active perspective'] in names: + self._restore_perspective('Default') + # TODO: does this bug still apply? + # Unfortunately, there is a bug in wxWidgets for win32 (Ticket #3258 + # http://trac.wxwidgets.org/ticket/3258 + # ) that makes the radio item indicator in the menu disappear. + # The code should be fine once this issue is fixed. + + def _restore_perspective(self, name): + if name != self.gui.config['active perspective']: + print 'restoring perspective:', name + self.gui.config['active perspective'] = name # TODO: push to engine's Hooke + self._c['manager'].LoadPerspective(self._perspectives[name]) + self._c['manager'].Update() + for pane in self._c['manager'].GetAllPanes(): + if pane.name in self._c['menu bar']._c['view']._c.keys(): + pane.Check(pane.window.IsShown()) + + def _on_save_perspective(self, *args): + perspective = self._c['manager'].SavePerspective() + name = self.gui.config['active perspective'] + if name == 'Default': + name = 'New perspective' + name = select_save_file( + directory=self.gui.config['perspective path'], + name=name, + extension=self.gui.config['perspective extension'], + parent=self, + message='Enter a name for the new perspective:', + caption='Save perspective') + if name == None: + return + self._save_perspective( + perspective, self.gui.config['perspective path'], name=name, + extension=self.gui.config['perspective extension']) + + def _on_delete_perspective(self, *args, **kwargs): + options = sorted([p for p in self._perspectives.keys() + if p != 'Default']) + dialog = SelectionDialog( + options=options, + message="\nPlease check the perspectives\n\nyou want to delete and click 'Delete'.\n", + button_id=wx.ID_DELETE, + selection_style='multiple', + parent=self, + title='Delete perspective(s)', + style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) + dialog.CenterOnScreen() + dialog.ShowModal() + 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']) + + def _on_select_perspective(self, _class, method, name): + self._restore_perspective(name) + + + class HookeApp (wx.App): """A :class:`wx.App` wrapper around :class:`HookeFrame`. diff --git a/hooke/ui/gui/dialog/points.py b/hooke/ui/gui/dialog/points.py new file mode 100644 index 0000000..1e86ee1 --- /dev/null +++ b/hooke/ui/gui/dialog/points.py @@ -0,0 +1,33 @@ +# Copyright + +import wx + + +def measure_N_points(hooke_frame, N, message='', block=0): + ''' + General helper function for N-points measurements + By default, measurements are done on the retraction + ''' + if message: + dialog = wx.MessageDialog(None, message, 'Info', wx.OK) + dialog.ShowModal() + + figure = self.GetActiveFigure() + + xvector = self.displayed_plot.curves[block].x + yvector = self.displayed_plot.curves[block].y + + clicked_points = figure.ginput(N, timeout=-1, show_clicks=True) + + points = [] + for clicked_point in clicked_points: + point = lib.clickedpoint.ClickedPoint() + point.absolute_coords = clicked_point[0], clicked_point[1] + point.dest = 0 + #TODO: make this optional? + #so far, the clicked point is taken, not the corresponding data point + point.find_graph_coords(xvector, yvector) + point.is_line_edge = True + point.is_marker = True + points.append(point) + return points -- 2.26.2