1 #!/usr/bin/env python
\r
4 HOOKE - A force spectroscopy review & analysis tool
\r
6 Copyright (C) 2008-2010 Massimo Sandal (University of Bologna, Italy).
\r
7 Rolf Schmidt (Concordia University, Canada).
\r
9 This program is released under the GNU General Public License version 2.
\r
12 from libhooke import WX_GOOD
\r
15 wxversion.select(WX_GOOD)
\r
29 import wx.lib.agw.aui as aui
\r
30 import wx.propgrid as wxpg
\r
32 import libhooke as lh
\r
33 from config import config
\r
36 import hookecommands
\r
37 import hookeplaylist
\r
38 import hookepropertyeditor
\r
44 __version__ = lh.HOOKE_VERSION[0]
\r
45 __release_name__ = lh.HOOKE_VERSION[1]
\r
47 #TODO: order menu items, get rid of all unused IDs
\r
48 ID_ExportText = wx.NewId()
\r
49 ID_ExportImage = wx.NewId()
\r
50 ID_Config = wx.NewId()
\r
51 ID_About = wx.NewId()
\r
52 ID_Next = wx.NewId()
\r
53 ID_Previous = wx.NewId()
\r
55 ID_ViewAssistant = wx.NewId()
\r
56 ID_ViewCommands = wx.NewId()
\r
57 ID_ViewFolders = wx.NewId()
\r
58 ID_ViewOutput = wx.NewId()
\r
59 ID_ViewPlaylists = wx.NewId()
\r
60 ID_ViewProperties = wx.NewId()
\r
61 ID_ViewResults = wx.NewId()
\r
63 ID_CommandsList = wx.NewId()
\r
64 ID_CommandsListBox = wx.NewId()
\r
66 ID_TextContent = wx.NewId()
\r
67 ID_TreeContent = wx.NewId()
\r
68 ID_HTMLContent = wx.NewId()
\r
69 ID_SizeReportContent = wx.NewId()
\r
70 ID_DeletePerspective = wx.NewId()
\r
71 ID_SavePerspective = wx.NewId()
\r
73 ID_FirstPerspective = ID_SavePerspective + 1000
\r
74 #I hope we'll never have more than 1000 perspectives
\r
75 ID_FirstPlot = ID_SavePerspective + 2000
\r
77 class Hooke(wx.App):
\r
80 self.SetAppName('Hooke')
\r
81 self.SetVendorName('')
\r
83 #set the Hooke directory
\r
84 lh.hookeDir = os.path.abspath(os.path.dirname(__file__))
\r
86 windowPosition = (config['main']['left'], config['main']['top'])
\r
87 windowSize = (config['main']['width'], config['main']['height'])
\r
89 #setup the splashscreen
\r
90 if config['splashscreen']['show']:
\r
91 filename = lh.get_file_path('hooke.jpg', ['resources'])
\r
92 if os.path.isfile(filename):
\r
93 bitmap = wx.Image(filename).ConvertToBitmap()
\r
94 splashStyle = wx.SPLASH_CENTRE_ON_SCREEN|wx.SPLASH_TIMEOUT
\r
95 splashDuration = config['splashscreen']['duration']
\r
96 wx.SplashScreen(bitmap, splashStyle, splashDuration, None, -1)
\r
99 we need for the splash screen to disappear
\r
100 for whatever reason splashDuration and sleep do not correspond to each other
\r
101 at least not on Windows
\r
102 maybe it's because duration is in milliseconds and sleep in seconds
\r
103 thus we need to increase the sleep time a bit
\r
104 a factor of 1.2 seems to work quite well
\r
107 time.sleep(sleepFactor * splashDuration / 1000)
\r
109 plugin_objects = []
\r
110 for plugin in config['plugins']:
\r
111 if config['plugins'][plugin]:
\r
112 filename = ''.join([plugin, '.py'])
\r
113 path = lh.get_file_path(filename, ['plugins'])
\r
114 if os.path.isfile(path):
\r
115 #get the corresponding filename and path
\r
116 plugin_name = ''.join(['plugins.', plugin])
\r
117 module = __import__(plugin_name)
\r
118 #get the file that contains the plugin
\r
119 class_file = getattr(plugins, plugin)
\r
120 #get the class that contains the commands
\r
121 class_object = getattr(class_file, plugin + 'Commands')
\r
122 plugin_objects.append(class_object)
\r
124 def make_command_class(*bases):
\r
125 #create metaclass with plugins and plotmanipulators
\r
126 return type(HookeFrame)("HookeFramePlugged", bases + (HookeFrame,), {})
\r
127 frame = make_command_class(*plugin_objects)(parent=None, id=wx.ID_ANY, title='Hooke', pos=windowPosition, size=windowSize)
\r
129 self.SetTopWindow(frame)
\r
134 #TODO: write values to ini file if necessary
\r
138 class HookeFrame(wx.Frame):
\r
140 def __init__(self, parent, id=-1, title='', pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE|wx.SUNKEN_BORDER|wx.CLIP_CHILDREN):
\r
141 #call parent constructor
\r
142 wx.Frame.__init__(self, parent, id, title, pos, size, style)
\r
143 self.config = config
\r
144 self.CreateApplicationIcon()
\r
145 #self.configs contains: {the name of the Commands file: corresponding ConfigObj}
\r
147 ##self.playlists contains: {the name of the playlist: [playlist, tabIndex, plotID]}
\r
148 #self.playlists = {}
\r
149 #self.plugins contains: {the name of the plugin: [caption, function]}
\r
151 #self.plotmanipulators list contains: [the name of the plotmanip, function, name of the module]
\r
152 self.plotmanipulators = []
\r
154 #tell FrameManager to manage this frame
\r
155 self._mgr = aui.AuiManager()
\r
156 self._mgr.SetManagedWindow(self)
\r
157 #set the gradient style
\r
158 self._mgr.GetArtProvider().SetMetric(aui.AUI_DOCKART_GRADIENT_TYPE, aui.AUI_GRADIENT_NONE)
\r
159 #set transparent drag
\r
160 self._mgr.SetFlags(self._mgr.GetFlags() ^ aui.AUI_MGR_TRANSPARENT_DRAG)
\r
162 # set up default notebook style
\r
163 self._notebook_style = aui.AUI_NB_DEFAULT_STYLE | aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER
\r
164 self._notebook_theme = 0
\r
166 #holds the perspectives: {name, [index, perspectiveStr]}
\r
167 self._perspectives = {}
\r
169 # min size for the frame itself isn't completely done.
\r
170 # see the end up FrameManager::Update() for the test
\r
171 # code. For now, just hard code a frame minimum size
\r
172 self.SetMinSize(wx.Size(400, 300))
\r
173 #create panels here
\r
174 self.panelAssistant = self.CreatePanelAssistant()
\r
175 self.panelCommands = self.CreatePanelCommands()
\r
176 self.panelFolders = self.CreatePanelFolders()
\r
177 self.panelPlaylists = self.CreatePanelPlaylists()
\r
178 self.panelProperties = self.CreatePanelProperties()
\r
179 self.panelOutput = self.CreatePanelOutput()
\r
180 self.panelResults = self.CreatePanelResults()
\r
181 self.plotNotebook = self.CreateNotebook()
\r
182 #self.textCtrlCommandLine=self.CreateCommandLine()
\r
185 self._mgr.AddPane(self.panelFolders, aui.AuiPaneInfo().Name('Folders').Caption('Folders').Left().CloseButton(True).MaximizeButton(False))
\r
186 self._mgr.AddPane(self.panelPlaylists, aui.AuiPaneInfo().Name('Playlists').Caption('Playlists').Left().CloseButton(True).MaximizeButton(False))
\r
187 self._mgr.AddPane(self.plotNotebook, aui.AuiPaneInfo().Name('Plots').CenterPane().PaneBorder(False))
\r
188 self._mgr.AddPane(self.panelCommands, aui.AuiPaneInfo().Name('Commands').Caption('Settings and commands').Right().CloseButton(True).MaximizeButton(False))
\r
189 self._mgr.AddPane(self.panelProperties, aui.AuiPaneInfo().Name('Properties').Caption('Properties').Right().CloseButton(True).MaximizeButton(False))
\r
190 self._mgr.AddPane(self.panelAssistant, aui.AuiPaneInfo().Name('Assistant').Caption('Assistant').Right().CloseButton(True).MaximizeButton(False))
\r
191 self._mgr.AddPane(self.panelOutput, aui.AuiPaneInfo().Name('Output').Caption('Output').Bottom().CloseButton(True).MaximizeButton(False))
\r
192 self._mgr.AddPane(self.panelResults, aui.AuiPaneInfo().Name('Results').Caption('Results').Bottom().CloseButton(True).MaximizeButton(False))
\r
193 #self._mgr.AddPane(self.textCtrlCommandLine, aui.AuiPaneInfo().Name('CommandLine').CaptionVisible(False).Fixed().Bottom().Layer(2).CloseButton(False).MaximizeButton(False))
\r
194 #self._mgr.AddPane(panelBottom, aui.AuiPaneInfo().Name("panelCommandLine").Bottom().Position(1).CloseButton(False).MaximizeButton(False))
\r
196 # add the toolbars to the manager
\r
197 self.toolbar=self.CreateToolBar()
\r
198 self.toolbarNavigation=self.CreateToolBarNavigation()
\r
199 self._mgr.AddPane(self.toolbar, aui.AuiPaneInfo().Name('toolbar').Caption('Toolbar').ToolbarPane().Top().Layer(1).Row(1).LeftDockable(False).RightDockable(False))
\r
200 self._mgr.AddPane(self.toolbarNavigation, aui.AuiPaneInfo().Name('toolbarNavigation').Caption('Navigation').ToolbarPane().Top().Layer(1).Row(1).LeftDockable(False).RightDockable(False))
\r
201 # "commit" all changes made to FrameManager
\r
203 #create the menubar after the panes so that the default perspective
\r
204 #is created with all panes open
\r
205 self.CreateMenuBar()
\r
206 self.statusbar = self.CreateStatusBar()
\r
208 #TODO: select item on startup (whatever item)
\r
209 #self.listCtrlCommands.Select(0)
\r
210 #self.OnListboxSelect(None)
\r
211 name = self.config['perspectives']['active']
\r
212 menu_item = self.GetPerspectiveMenuItem(name)
\r
213 self.OnRestorePerspective(menu_item)
\r
214 self.playlists = self.panelPlaylists.Playlists
\r
215 #define the list of active drivers
\r
217 for driver in self.config['drivers']:
\r
218 if self.config['drivers'][driver]:
\r
219 #get the corresponding filename and path
\r
220 filename = ''.join([driver, '.py'])
\r
221 path = lh.get_file_path(filename, ['drivers'])
\r
222 #the driver is active for driver[1] == 1
\r
223 if os.path.isfile(path):
\r
224 #driver files are located in the 'drivers' subfolder
\r
225 driver_name = ''.join(['drivers.', driver])
\r
226 module = __import__(driver_name)
\r
227 class_file = getattr(drivers, driver)
\r
228 for command in dir(class_file):
\r
229 if command.endswith('Driver'):
\r
230 self.drivers.append(getattr(class_file, command))
\r
231 #import all active plugins and plotmanips
\r
232 #the plotmanip_functions contains: {the name of the plotmanip: [method, class_object]}
\r
233 plotmanip_functions = {}
\r
234 #add 'general.ini' to self.configs (this is not a plugin and thus must be imported seperately)
\r
235 ini_path = lh.get_file_path('general.ini', ['plugins'])
\r
236 plugin_config = ConfigObj(ini_path)
\r
237 #self.config.merge(plugin_config)
\r
238 self.configs['general'] = plugin_config
\r
239 #make sure we execute _plug_init() for every command line plugin we import
\r
240 for plugin in self.config['plugins']:
\r
241 if self.config['plugins'][plugin]:
\r
242 filename = ''.join([plugin, '.py'])
\r
243 path = lh.get_file_path(filename, ['plugins'])
\r
244 if os.path.isfile(path):
\r
245 #get the corresponding filename and path
\r
246 plugin_name = ''.join(['plugins.', plugin])
\r
249 module = __import__(plugin_name)
\r
250 #prepare the ini file for inclusion
\r
251 ini_path = path.replace('.py', '.ini')
\r
253 plugin_config = ConfigObj(ini_path)
\r
254 #self.config.merge(plugin_config)
\r
255 self.configs[plugin] = plugin_config
\r
257 commands = eval('dir(module.' + plugin+ '.' + plugin + 'Commands)')
\r
258 #keep only commands (ie names that start with 'do_')
\r
259 commands = [command for command in commands if command.startswith('do_')]
\r
261 self.plugins[plugin] = commands
\r
263 #initialize the plugin
\r
264 eval('module.' + plugin+ '.' + plugin + 'Commands._plug_init(self)')
\r
265 except AttributeError:
\r
267 except ImportError:
\r
269 #initialize the commands tree
\r
270 commands = dir(HookeFrame)
\r
271 commands = [command for command in commands if command.startswith('do_')]
\r
273 self.plugins['general'] = commands
\r
274 self.panelCommands.Initialize(self.plugins)
\r
275 for command in dir(self):
\r
276 if command.startswith('plotmanip_'):
\r
277 plotmanip_functions[command] = [command, getattr(self, command)]
\r
278 for name in self.config['plotmanipulators']['names']:
\r
279 if self.config['plotmanipulators'].as_bool(name):
\r
280 command_name = ''.join(['plotmanip_', name])
\r
281 if command_name in plotmanip_functions:
\r
282 self.plotmanipulators.append(plotmanip_functions[command_name])
\r
283 #load default list, if possible
\r
284 self.do_loadlist(self.config['general']['list'])
\r
286 def _BindEvents(self):
\r
287 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
\r
288 self.Bind(wx.EVT_SIZE, self.OnSize)
\r
289 self.Bind(wx.EVT_CLOSE, self.OnClose)
\r
290 # Show How To Use The Closing Panes Event
\r
291 self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPaneClose)
\r
292 self.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnNotebookPageClose)
\r
294 self.Bind(wx.EVT_MENU, self.OnClose, id=wx.ID_EXIT)
\r
295 self.Bind(wx.EVT_MENU, self.OnAbout, id=wx.ID_ABOUT)
\r
297 self.Bind(wx.EVT_MENU_RANGE, self.OnView, id=ID_ViewAssistant, id2=ID_ViewResults)
\r
299 self.Bind(wx.EVT_MENU, self.OnDeletePerspective, id=ID_DeletePerspective)
\r
300 self.Bind(wx.EVT_MENU, self.OnSavePerspective, id=ID_SavePerspective)
\r
301 self.Bind(wx.EVT_MENU_RANGE, self.OnRestorePerspective, id=ID_FirstPerspective, id2=ID_FirstPerspective+1000)
\r
303 self.Bind(wx.EVT_TOOL, self.OnExportImage, id=ID_ExportImage)
\r
304 self.Bind(wx.EVT_TOOL, self.OnNext, id=ID_Next)
\r
305 self.Bind(wx.EVT_TOOL, self.OnPrevious, id=ID_Previous)
\r
306 #self.Bind(.EVT_AUITOOLBAR_TOOL_DROPDOWN, self.OnDropDownToolbarItem, id=ID_DropDownToolbarItem)
\r
308 treeCtrl = self.panelFolders.GetTreeCtrl()
\r
309 #tree.Bind(wx.EVT_LEFT_UP, self.OnDirCtrl1LeftUp)
\r
310 #tree.Bind(wx.EVT_LEFT_DOWN, self.OnGenericDirCtrl1LeftDown)
\r
311 treeCtrl.Bind(wx.EVT_LEFT_DCLICK, self.OnDirCtrlLeftDclick)
\r
313 self.panelPlaylists.PlaylistsTree.Bind(wx.EVT_LEFT_DOWN, self.OnPlaylistsLeftDown)
\r
314 self.panelPlaylists.PlaylistsTree.Bind(wx.EVT_LEFT_DCLICK, self.OnPlaylistsLeftDclick)
\r
316 self.panelCommands.ExecuteButton.Bind(wx.EVT_BUTTON, self.OnExecute)
\r
317 self.panelCommands.CommandsTree.Bind(wx.EVT_LEFT_DOWN, self.OnTreeCtrlCommandsLeftDown)
\r
319 self.panelProperties.pg.Bind(wxpg.EVT_PG_CHANGED, self.OnPropGridChanged)
\r
320 self.panelProperties.pg.Bind(wxpg.EVT_PG_SELECTED, self.OnPropGridSelect)
\r
322 self.panelResults.results_list.OnCheckItem = self.OnResultsCheck
\r
324 def _GetActiveCurveIndex(self):
\r
325 playlist = self.GetActivePlaylist()
\r
326 #get the selected item from the tree
\r
327 selected_item = self.panelPlaylists.PlaylistsTree.GetSelection()
\r
328 #test if a playlist or a curve was double-clicked
\r
329 if self.panelPlaylists.PlaylistsTree.ItemHasChildren(selected_item):
\r
333 selected_item = self.panelPlaylists.PlaylistsTree.GetPrevSibling(selected_item)
\r
334 while selected_item.IsOk():
\r
336 selected_item = self.panelPlaylists.PlaylistsTree.GetPrevSibling(selected_item)
\r
339 def _GetActivePlaylistName(self):
\r
340 #get the selected item from the tree
\r
341 selected_item = self.panelPlaylists.PlaylistsTree.GetSelection()
\r
342 #test if a playlist or a curve was double-clicked
\r
343 if self.panelPlaylists.PlaylistsTree.ItemHasChildren(selected_item):
\r
344 playlist_item = selected_item
\r
346 #get the name of the playlist
\r
347 playlist_item = self.panelPlaylists.PlaylistsTree.GetItemParent(selected_item)
\r
348 #now we have a playlist
\r
349 return self.panelPlaylists.PlaylistsTree.GetItemText(playlist_item)
\r
351 def _GetPlaylistTab(self, name):
\r
352 for index, page in enumerate(self.plotNotebook._tabs._pages):
\r
353 if page.caption == name:
\r
357 def _GetUniquePlaylistName(self, name):
\r
358 playlist_name = name
\r
360 while playlist_name in self.playlists:
\r
361 playlist_name = ''.join([name, str(count)])
\r
363 return playlist_name
\r
365 def _SavePerspectiveToFile(self, name, perspective):
\r
366 filename = ''.join([name, '.txt'])
\r
367 filename = lh.get_file_path(filename, ['perspectives'])
\r
368 perspectivesFile = open(filename, 'w')
\r
369 perspectivesFile.write(perspective)
\r
370 perspectivesFile.close()
\r
372 def AddPlaylist(self, playlist=None, name='Untitled'):
\r
373 #TODO: change cursor or progressbar (maybe in statusbar)
\r
374 #self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
\r
375 if playlist and playlist.count > 0:
\r
376 playlist.name = self._GetUniquePlaylistName(name)
\r
378 self.AddToPlaylists(playlist)
\r
380 def AddPlaylistFromFiles(self, files=[], name='Untitled'):
\r
381 #TODO: change cursor or progressbar (maybe in statusbar)
\r
382 #self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
\r
384 playlist = Playlist.Playlist(self.drivers)
\r
386 playlist.add_curve(item)
\r
387 if playlist.count > 0:
\r
388 playlist.name = self._GetUniquePlaylistName(name)
\r
390 self.AddToPlaylists(playlist)
\r
392 def AddToPlaylists(self, playlist):
\r
393 if playlist.has_curves:
\r
394 #setup the playlist in the Playlist tree
\r
395 tree_root = self.panelPlaylists.PlaylistsTree.GetRootItem()
\r
396 playlist_root = self.panelPlaylists.PlaylistsTree.AppendItem(tree_root, playlist.name, 0)
\r
397 #add all curves to the Playlist tree
\r
399 for index, curve in enumerate(playlist.curves):
\r
400 ##remove the extension from the name of the curve
\r
402 #item_text, extension = os.path.splitext(curve.name)
\r
403 #curve_ID = self.panelPlaylists.PlaylistsTree.AppendItem(playlist_root, item_text, 1)
\r
404 curve_ID = self.panelPlaylists.PlaylistsTree.AppendItem(playlist_root, curve.name, 1)
\r
405 if index == playlist.index:
\r
406 self.panelPlaylists.PlaylistsTree.SelectItem(curve_ID)
\r
408 #create the plot tab and add playlist to the dictionary
\r
409 plotPanel = wxmpl.PlotPanel(self, ID_FirstPlot + len(self.playlists))
\r
410 notebook_tab = self.plotNotebook.AddPage(plotPanel, playlist.name, True)
\r
411 tab_index = self.plotNotebook.GetSelection()
\r
412 figure = plotPanel.get_figure()
\r
413 self.playlists[playlist.name] = [playlist, figure]
\r
414 self.panelPlaylists.PlaylistsTree.Expand(playlist_root)
\r
415 self.statusbar.SetStatusText(playlist.get_status_string(), 0)
\r
418 def AppendToOutput(self, text):
\r
419 self.panelOutput.AppendText(''.join([text, '\n']))
\r
421 def CreateApplicationIcon(self):
\r
422 iconFile = 'resources' + os.sep + 'microscope.ico'
\r
423 icon = wx.Icon(iconFile, wx.BITMAP_TYPE_ICO)
\r
426 def CreateCommandLine(self):
\r
427 return wx.TextCtrl(self, -1, '', style=wx.NO_BORDER|wx.EXPAND)
\r
429 def CreatePanelAssistant(self):
\r
430 panel = wx.TextCtrl(self, -1, '', wx.Point(0, 0), wx.Size(150, 90), wx.NO_BORDER|wx.TE_MULTILINE)
\r
431 panel.SetEditable(False)
\r
434 def CreatePanelCommands(self):
\r
435 return hookecommands.Commands(self)
\r
437 def CreatePanelFolders(self):
\r
439 filters = self.config['folders']['filters']
\r
440 index = self.config['folders'].as_int('filterindex')
\r
441 #set initial directory
\r
442 folder = self.config['general']['workdir']
\r
443 return wx.GenericDirCtrl(self, -1, dir=folder, size=(200, 250), style=wx.DIRCTRL_SHOW_FILTERS, filter=filters, defaultFilter=index)
\r
445 def CreatePanelOutput(self):
\r
446 return wx.TextCtrl(self, -1, '', wx.Point(0, 0), wx.Size(150, 90), wx.NO_BORDER|wx.TE_MULTILINE)
\r
448 def CreatePanelPlaylists(self):
\r
449 return hookeplaylist.Playlists(self)
\r
451 def CreatePanelProperties(self):
\r
452 return hookepropertyeditor.PropertyEditor(self)
\r
454 def CreatePanelResults(self):
\r
455 return hookeresults.Results(self)
\r
457 def CreatePanelWelcome(self):
\r
458 ctrl = wx.html.HtmlWindow(self, -1, wx.DefaultPosition, wx.Size(400, 300))
\r
459 introStr = '<h1>Welcome to Hooke</h1>' + \
\r
460 '<h3>Features</h3>' + \
\r
462 '<li>View, annotate, measure force curves</li>' + \
\r
463 '<li>Worm-like chain fit of force peaks</li>' + \
\r
464 '<li>Automatic convolution-based filtering of empty curves</li>' + \
\r
465 '<li>Automatic fit and measurement of multiple force peaks</li>' + \
\r
466 '<li>Handles force-clamp force experiments (experimental)</li>' + \
\r
467 '<li>It is extensible by users by means of plugins and drivers</li>' + \
\r
469 '<p>See the <a href="/p/hooke/wiki/DocumentationIndex">DocumentationIndex</a> for more information</p>'
\r
470 ctrl.SetPage(introStr)
\r
473 def CreateMenuBar(self):
\r
474 menu_bar = wx.MenuBar()
\r
476 file_menu = wx.Menu()
\r
477 file_menu.Append(wx.ID_OPEN, '&Open playlist\tCtrl-O')
\r
478 file_menu.Append(wx.ID_SAVE, 'Save playlist\tCtrl-S')
\r
479 file_menu.AppendSeparator()
\r
480 file_menu.Append(wx.ID_EXIT, 'Exit\tCtrl-Q')
\r
482 edit_menu = wx.Menu()
\r
483 edit_menu.Append(ID_ExportText, 'Export text...')
\r
484 edit_menu.Append(ID_ExportImage, 'Export image...')
\r
485 edit_menu.AppendSeparator();
\r
486 edit_menu.Append(ID_Config, 'Preferences')
\r
488 view_menu = wx.Menu()
\r
489 view_menu.AppendCheckItem(ID_ViewFolders, 'Folders\tF5')
\r
490 view_menu.AppendCheckItem(ID_ViewPlaylists, 'Playlists\tF6')
\r
491 view_menu.AppendCheckItem(ID_ViewCommands, 'Commands\tF7')
\r
492 view_menu.AppendCheckItem(ID_ViewProperties, 'Properties\tF8')
\r
493 view_menu.AppendCheckItem(ID_ViewAssistant, 'Assistant\tF9')
\r
494 view_menu.AppendCheckItem(ID_ViewResults, 'Results\tF10')
\r
495 view_menu.AppendCheckItem(ID_ViewOutput, 'Output\tF11')
\r
497 self._perspectives_menu = self.CreatePerspectivesMenu()
\r
499 help_menu = wx.Menu()
\r
500 help_menu.Append(wx.ID_ABOUT, 'About Hooke')
\r
501 #put it all together
\r
502 menu_bar.Append(file_menu, 'File')
\r
503 menu_bar.Append(edit_menu, 'Edit')
\r
504 menu_bar.Append(view_menu, 'View')
\r
505 menu_bar.Append(self._perspectives_menu, "Perspectives")
\r
506 menu_bar.Append(help_menu, 'Help')
\r
508 self.SetMenuBar(menu_bar)
\r
510 def CreateNotebook(self):
\r
511 # create the notebook off-window to avoid flicker
\r
512 client_size = self.GetClientSize()
\r
513 ctrl = aui.AuiNotebook(self, -1, wx.Point(client_size.x, client_size.y), wx.Size(430, 200), self._notebook_style)
\r
514 arts = [aui.AuiDefaultTabArt, aui.AuiSimpleTabArt, aui.VC71TabArt, aui.FF2TabArt, aui.VC8TabArt, aui.ChromeTabArt]
\r
515 art = arts[self._notebook_theme]()
\r
516 ctrl.SetArtProvider(art)
\r
517 #uncomment if we find a nice icon
\r
518 #page_bmp = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16, 16))
\r
519 ctrl.AddPage(self.CreatePanelWelcome(), "Welcome", False)
\r
522 def CreatePerspectivesMenu(self):
\r
524 menu.Append(ID_SavePerspective, "Save Perspective")
\r
525 menu.Append(ID_DeletePerspective, "Delete Perspective")
\r
526 menu.AppendSeparator()
\r
527 #add perspectives to menubar and _perspectives
\r
528 perspectivesDirectory = os.path.join(lh.hookeDir, 'perspectives')
\r
529 if os.path.isdir(perspectivesDirectory):
\r
530 perspectiveFileNames = os.listdir(perspectivesDirectory)
\r
531 for perspectiveFilename in perspectiveFileNames:
\r
532 filename = lh.get_file_path(perspectiveFilename, ['perspectives'])
\r
533 if os.path.isfile(filename):
\r
534 perspectiveFile = open(filename, 'rU')
\r
535 perspective = perspectiveFile.readline()
\r
536 perspectiveFile.close()
\r
537 if perspective != '':
\r
538 name, extension = os.path.splitext(perspectiveFilename)
\r
539 if extension == '.txt':
\r
540 menuItem = menu.AppendRadioItem(ID_FirstPerspective + len(self._perspectives), name)
\r
541 self._perspectives[name] = [len(self._perspectives), perspective]
\r
542 if self.config['perspectives']['active'] == name:
\r
544 #in case there are no perspectives
\r
545 if not self._perspectives:
\r
546 perspective = self._mgr.SavePerspective()
\r
547 self.config['perspectives']['default'] = 'Default'
\r
548 self._perspectives['Default'] = [0, perspective]
\r
549 menuItem = menu.AppendRadioItem(ID_FirstPerspective, 'Default')
\r
551 self._SavePerspectiveToFile('Default', perspective)
\r
554 def CreateStatusbar(self):
\r
555 statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP)
\r
556 statusbar.SetStatusWidths([-2, -3])
\r
557 statusbar.SetStatusText('Ready', 0)
\r
558 welcomeString=u'Welcome to Hooke (version '+__version__+', '+__release_name__+')!'
\r
559 statusbar.SetStatusText(welcomeString, 1)
\r
562 def CreateToolBar(self):
\r
563 toolbar = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER)
\r
564 toolbar.SetToolBitmapSize(wx.Size(16,16))
\r
565 toolbar_bmp1 = wx.ArtProvider_GetBitmap(wx.ART_QUESTION, wx.ART_OTHER, wx.Size(16, 16))
\r
566 toolbar_bmpOpen = wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, wx.Size(16, 16))
\r
567 toolbar_bmpSave = wx.ArtProvider_GetBitmap(wx.ART_FILE_SAVE, wx.ART_OTHER, wx.Size(16, 16))
\r
568 toolbar_bmpExportText = wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16, 16))
\r
569 toolbar_bmpExportImage = wx.ArtProvider_GetBitmap(wx.ART_MISSING_IMAGE, wx.ART_OTHER, wx.Size(16, 16))
\r
570 toolbar.AddLabelTool(101, 'Open', toolbar_bmpOpen)
\r
571 toolbar.AddLabelTool(102, 'Save', toolbar_bmpSave)
\r
572 toolbar.AddSeparator()
\r
573 toolbar.AddLabelTool(ID_ExportText, 'Export text...', toolbar_bmpExportText)
\r
574 toolbar.AddLabelTool(ID_ExportImage, 'Export image...', toolbar_bmpExportImage)
\r
578 def CreateToolBarNavigation(self):
\r
579 toolbar = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER)
\r
580 toolbar.SetToolBitmapSize(wx.Size(16,16))
\r
581 toolbar_bmpBack = wx.ArtProvider_GetBitmap(wx.ART_GO_BACK, wx.ART_OTHER, wx.Size(16, 16))
\r
582 toolbar_bmpForward = wx.ArtProvider_GetBitmap(wx.ART_GO_FORWARD, wx.ART_OTHER, wx.Size(16, 16))
\r
583 toolbar.AddLabelTool(ID_Previous, 'Previous', toolbar_bmpBack, shortHelp='Previous curve')
\r
584 toolbar.AddLabelTool(ID_Next, 'Next', toolbar_bmpForward, shortHelp='Next curve')
\r
588 def DeleteFromPlaylists(self, name):
\r
589 if name in self.playlists:
\r
590 del self.playlists[name]
\r
591 tree_root = self.panelPlaylists.PlaylistsTree.GetRootItem()
\r
592 item, cookie = self.panelPlaylists.PlaylistsTree.GetFirstChild(tree_root)
\r
594 playlist_name = self.panelPlaylists.PlaylistsTree.GetItemText(item)
\r
595 if playlist_name == name:
\r
597 self.panelPlaylists.PlaylistsTree.Delete(item)
\r
600 item = self.panelPlaylists.PlaylistsTree.GetNextSibling(item)
\r
601 self.OnPlaylistsLeftDclick(None)
\r
603 def DeletePlotPage(self, name):
\r
604 index = self._GetPlaylistTab(name)
\r
605 plot = self.playlists[name][1]
\r
607 self.plotNotebook.RemovePage(index)
\r
608 self.DeleteFromPlaylists(name)
\r
610 def GetActiveCurve(self):
\r
611 playlist = self.GetActivePlaylist()
\r
612 if playlist is not None:
\r
613 return playlist.get_active_curve()
\r
616 def GetActivePlaylist(self):
\r
617 playlist_name = self._GetActivePlaylistName()
\r
618 if playlist_name in self.playlists:
\r
619 return self.playlists[playlist_name][0]
\r
622 def GetActivePlot(self):
\r
623 curve = self.GetActiveCurve()
\r
624 if curve is not None:
\r
625 return curve.plots[0]
\r
628 def GetDockArt(self):
\r
629 return self._mgr.GetArtProvider()
\r
631 def GetBoolFromConfig(self, *args):
\r
636 elif len(args) == 3:
\r
640 if self.configs.has_key(plugin):
\r
641 config = self.configs[plugin]
\r
642 return config[section][key].as_bool('value')
\r
645 def GetFloatFromConfig(self, *args):
\r
650 elif len(args) == 3:
\r
654 if self.configs.has_key(plugin):
\r
655 config = self.configs[plugin]
\r
656 return config[section][key].as_float('value')
\r
659 def GetIntFromConfig(self, *args):
\r
664 elif len(args) == 3:
\r
668 if self.configs.has_key(plugin):
\r
669 config = self.configs[plugin]
\r
670 return config[section][key].as_int('value')
\r
673 def GetStringFromConfig(self, *args):
\r
678 elif len(args) == 3:
\r
682 if self.configs.has_key(plugin):
\r
683 config = self.configs[plugin]
\r
684 return config[section][key]['value']
\r
687 def GetPerspectiveMenuItem(self, name):
\r
688 index = self._perspectives[name][0]
\r
689 perspective_Id = ID_FirstPerspective + index
\r
690 menu_item = self.MenuBar.FindItemById(perspective_Id)
\r
693 def HasPlotmanipulator(self, name):
\r
695 returns True if the plotmanipulator 'name' is loaded, False otherwise
\r
697 for plotmanipulator in self.plotmanipulators:
\r
698 if plotmanipulator[0] == name:
\r
702 def OnAbout(self, event):
\r
703 msg = 'Hooke\n\n'+\
\r
704 'A free, open source data analysis platform\n'+\
\r
705 '(c) 2006-2008 Massimo Sandal\n\n'+\
\r
706 '(c) 2009 Dr. Rolf Schmidt\n\n'+\
\r
707 'Released under the GNU GPL v2'
\r
708 dialog = wx.MessageDialog(self, msg, "About Hooke", wx.OK | wx.ICON_INFORMATION)
\r
712 def OnClose(self, event):
\r
714 self.config['main']['height'] = str(self.GetSize().GetHeight())
\r
715 self.config['main']['left'] = str(self.GetPosition()[0])
\r
716 self.config['main']['top'] = str(self.GetPosition()[1])
\r
717 self.config['main']['width'] = str(self.GetSize().GetWidth())
\r
718 # Writing the configuration file to 'hooke.ini'
\r
719 self.config.write()
\r
724 def OnDeletePerspective(self, event):
\r
727 def OnDirCtrlLeftDclick(self, event):
\r
728 file_path = self.panelFolders.GetPath()
\r
729 if os.path.isfile(file_path):
\r
730 if file_path.endswith('.hkp'):
\r
731 self.do_loadlist(file_path)
\r
736 def OnEraseBackground(self, event):
\r
739 def OnExecute(self, event):
\r
740 item = self.panelCommands.CommandsTree.GetSelection()
\r
742 if self.panelCommands.CommandsTree.ItemHasChildren(item):
\r
746 parent = self.panelCommands.CommandsTree.GetItemParent(item)
\r
747 if not self.panelCommands.CommandsTree.ItemHasChildren(item):
\r
748 parent_text = self.panelCommands.CommandsTree.GetItemText(parent)
\r
749 item_text = self.panelCommands.CommandsTree.GetItemText(item)
\r
750 if item_text in ['genlist', 'loadlist', 'savelist']:
\r
751 property_values = self.panelProperties.GetPropertyValues()
\r
753 for item in property_values:
\r
754 arg_str = ''.join([arg_str, item, '=r"', str(property_values[item]), '", '])
\r
755 command = ''.join(['self.do_', item_text, '(', arg_str, ')'])
\r
757 command = ''.join(['self.do_', item_text, '()'])
\r
761 def OnExit(self, event):
\r
764 def OnExportImage(self, event):
\r
767 def OnNext(self, event):
\r
770 Go to the next curve in the playlist.
\r
771 If we are at the last curve, we come back to the first.
\r
775 selected_item = self.panelPlaylists.PlaylistsTree.GetSelection()
\r
776 if self.panelPlaylists.PlaylistsTree.ItemHasChildren(selected_item):
\r
777 #GetFirstChild returns a tuple
\r
778 #we only need the first element
\r
779 next_item = self.panelPlaylists.PlaylistsTree.GetFirstChild(selected_item)[0]
\r
781 next_item = self.panelPlaylists.PlaylistsTree.GetNextSibling(selected_item)
\r
782 if not next_item.IsOk():
\r
783 parent_item = self.panelPlaylists.PlaylistsTree.GetItemParent(selected_item)
\r
784 #GetFirstChild returns a tuple
\r
785 #we only need the first element
\r
786 next_item = self.panelPlaylists.PlaylistsTree.GetFirstChild(parent_item)[0]
\r
787 self.panelPlaylists.PlaylistsTree.SelectItem(next_item, True)
\r
788 playlist = self.playlists[self._GetActivePlaylistName()][0]
\r
789 if playlist.count > 1:
\r
791 self.statusbar.SetStatusText(playlist.get_status_string(), 0)
\r
794 def OnNotebookPageClose(self, event):
\r
795 ctrl = event.GetEventObject()
\r
796 playlist_name = ctrl.GetPageText(ctrl._curpage)
\r
797 self.DeleteFromPlaylists(playlist_name)
\r
799 def OnPaneClose(self, event):
\r
802 def OnPlaylistsLeftDclick(self, event):
\r
803 playlist_name = self._GetActivePlaylistName()
\r
804 #if that playlist already exists
\r
805 #we check if it is the active playlist (ie selected in panelPlaylists)
\r
806 #and switch to it if necessary
\r
807 if playlist_name in self.playlists:
\r
808 index = self.plotNotebook.GetSelection()
\r
809 current_playlist = self.plotNotebook.GetPageText(index)
\r
810 #new_playlist = self.playlists[playlist_name][0]
\r
811 #if current_playlist != new_playlist:
\r
812 if current_playlist != playlist_name:
\r
813 index = self._GetPlaylistTab(playlist_name)
\r
814 self.plotNotebook.SetSelection(index)
\r
815 #if a curve was double-clicked
\r
816 item = self.panelPlaylists.PlaylistsTree.GetSelection()
\r
817 #TODO: fix with get_active_curve
\r
818 if not self.panelPlaylists.PlaylistsTree.ItemHasChildren(item):
\r
819 index = self._GetActiveCurveIndex()
\r
823 playlist = self.playlists[playlist_name][0]
\r
824 playlist.index = index
\r
825 self.statusbar.SetStatusText(playlist.get_status_string(), 0)
\r
827 #if you uncomment the following line, the tree will collapse/expand as well
\r
830 def OnPlaylistsLeftDown(self, event):
\r
831 hit_item, hit_flags = self.panelPlaylists.PlaylistsTree.HitTest(event.GetPosition())
\r
832 if (hit_flags & wx.TREE_HITTEST_ONITEM) != 0:
\r
834 self.panelPlaylists.PlaylistsTree.SelectItem(hit_item)
\r
835 playlist_name = self._GetActivePlaylistName()
\r
836 playlist = self.playlists[playlist_name][0]
\r
837 #if a curve was clicked
\r
838 item = self.panelPlaylists.PlaylistsTree.GetSelection()
\r
839 if not self.panelPlaylists.PlaylistsTree.ItemHasChildren(item):
\r
840 #TODO: fix with get_active_curve
\r
841 index = self._GetActiveCurveIndex()
\r
843 #playlist = self.playlists[playlist_name][0]
\r
844 playlist.index = index
\r
845 #self.playlists[playlist_name][0].index = index
\r
847 ##self.playlists[playlist_name][0].index = 0
\r
848 #playlist.index = index
\r
849 self.playlists[playlist_name][0] = playlist
\r
852 def OnPrevious(self, event):
\r
855 Go to the previous curve in the playlist.
\r
856 If we are at the first curve, we jump to the last.
\r
858 Syntax: previous, p
\r
860 #playlist = self.playlists[self._GetActivePlaylistName()][0]
\r
861 #select the previous curve and tell the user if we wrapped around
\r
862 #self.AppendToOutput(playlist.previous())
\r
863 selected_item = self.panelPlaylists.PlaylistsTree.GetSelection()
\r
864 if self.panelPlaylists.PlaylistsTree.ItemHasChildren(selected_item):
\r
865 previous_item = self.panelPlaylists.PlaylistsTree.GetLastChild(selected_item)
\r
867 previous_item = self.panelPlaylists.PlaylistsTree.GetPrevSibling(selected_item)
\r
868 if not previous_item.IsOk():
\r
869 parent_item = self.panelPlaylists.PlaylistsTree.GetItemParent(selected_item)
\r
870 previous_item = self.panelPlaylists.PlaylistsTree.GetLastChild(parent_item)
\r
871 self.panelPlaylists.PlaylistsTree.SelectItem(previous_item, True)
\r
872 playlist = self.playlists[self._GetActivePlaylistName()][0]
\r
873 if playlist.count > 1:
\r
874 playlist.previous()
\r
875 self.statusbar.SetStatusText(playlist.get_status_string(), 0)
\r
878 def OnPropGridChanged (self, event):
\r
879 prop = event.GetProperty()
\r
881 item_section = self.panelProperties.SelectedTreeItem
\r
882 item_plugin = self.panelCommands.CommandsTree.GetItemParent(item_section)
\r
883 plugin = self.panelCommands.CommandsTree.GetItemText(item_plugin)
\r
884 config = self.configs[plugin]
\r
885 property_section = self.panelCommands.CommandsTree.GetItemText(item_section)
\r
886 property_key = prop.GetName()
\r
887 property_value = prop.GetValue()
\r
888 config[property_section][property_key]['value'] = property_value
\r
890 def OnPropGridSelect(self, event):
\r
893 def OnRestorePerspective(self, event):
\r
894 name = self.MenuBar.FindItemById(event.GetId()).GetLabel()
\r
895 self._mgr.LoadPerspective(self._perspectives[name][1])
\r
896 self.config['perspectives']['active'] = name
\r
898 all_panes = self._mgr.GetAllPanes()
\r
899 for pane in all_panes:
\r
900 if not pane.name.startswith('toolbar'):
\r
901 if pane.name == 'Assistant':
\r
902 self.MenuBar.FindItemById(ID_ViewAssistant).Check(pane.window.IsShown())
\r
903 if pane.name == 'Folders':
\r
904 self.MenuBar.FindItemById(ID_ViewFolders).Check(pane.window.IsShown())
\r
905 if pane.name == 'Playlists':
\r
906 self.MenuBar.FindItemById(ID_ViewPlaylists).Check(pane.window.IsShown())
\r
907 if pane.name == 'Commands':
\r
908 self.MenuBar.FindItemById(ID_ViewCommands).Check(pane.window.IsShown())
\r
909 if pane.name == 'Properties':
\r
910 self.MenuBar.FindItemById(ID_ViewProperties).Check(pane.window.IsShown())
\r
911 if pane.name == 'Output':
\r
912 self.MenuBar.FindItemById(ID_ViewOutput).Check(pane.window.IsShown())
\r
913 if pane.name == 'Results':
\r
914 self.MenuBar.FindItemById(ID_ViewResults).Check(pane.window.IsShown())
\r
916 def OnResultsCheck(self, index, flag):
\r
917 curve = self.GetActiveCurve()
\r
918 result = curve.data['results'][index]['visible'] = flag
\r
921 def OnSavePerspective(self, event):
\r
922 def nameExists(name):
\r
923 for item in self._perspectives_menu.GetMenuItems():
\r
924 if item.GetText() == name:
\r
930 dialog = wx.TextEntryDialog(self, 'Enter a name for the new perspective:', 'Save perspective')
\r
931 dialog.SetValue('New perspective')
\r
932 if dialog.ShowModal() != wx.ID_OK:
\r
935 name = dialog.GetValue()
\r
937 if nameExists(name):
\r
938 dialogConfirm = wx.MessageDialog(self, 'A file with this name already exists.\n\nDo you want to replace it?', 'Confirm', wx.YES_NO|wx.ICON_QUESTION|wx.CENTER)
\r
939 if dialogConfirm.ShowModal() == wx.ID_YES:
\r
944 perspective = self._mgr.SavePerspective()
\r
946 if nameExists(name):
\r
947 #check the corresponding menu item
\r
948 menuItem = self.GetPerspectiveMenuItem(name)
\r
949 #replace the perspectiveStr in _pespectives
\r
950 index = self._perspectives[name][0]
\r
951 self._perspectives[name] = [index, perspective]
\r
953 #simply add the new perspective to _perspectives
\r
954 index = len(self._perspectives)
\r
955 self._perspectives[name] = [len(self._perspectives), perspective]
\r
956 menuItem = self._perspectives_menu.AppendRadioItem(ID_FirstPerspective + len(self._perspectives), name)
\r
959 self._SavePerspectiveToFile(name, perspective)
\r
960 #uncheck all perspective menu items
\r
961 #as these are radio items, one item has to be checked at all times
\r
962 #the line 'menuItem.Check()' above actually checks a second item
\r
963 #but does not toggle
\r
964 #so we need to uncheck all other items afterwards
\r
965 #weirdly enough, menuitem.Toggle() doesn't do this properly either
\r
966 for item in self._perspectives_menu.GetMenuItems():
\r
967 if item.IsCheckable():
\r
968 if item.GetLabel() != name:
\r
971 def OnView(self, event):
\r
972 menu_id = event.GetId()
\r
973 menu_item = self.MenuBar.FindItemById(menu_id)
\r
974 menu_label = menu_item.GetLabel()
\r
976 pane = self._mgr.GetPane(menu_label)
\r
977 pane.Show(not pane.IsShown())
\r
978 #if we don't do the following, the Folders pane does not resize properly on hide/show
\r
979 if pane.caption == 'Folders' and pane.IsShown() and pane.IsDocked():
\r
980 #folders_size = pane.GetSize()
\r
981 self.panelFolders.Fit()
\r
984 def OnSize(self, event):
\r
987 def OnTreeCtrlCommandsLeftDown(self, event):
\r
988 hit_item, hit_flags = self.panelCommands.CommandsTree.HitTest(event.GetPosition())
\r
989 if (hit_flags & wx.TREE_HITTEST_ONITEM) != 0:
\r
990 self.panelCommands.CommandsTree.SelectItem(hit_item)
\r
991 self.panelProperties.SelectedTreeItem = hit_item
\r
992 #if a command was clicked
\r
994 if not self.panelCommands.CommandsTree.ItemHasChildren(hit_item):
\r
995 item_plugin = self.panelCommands.CommandsTree.GetItemParent(hit_item)
\r
996 plugin = self.panelCommands.CommandsTree.GetItemText(item_plugin)
\r
997 if self.configs.has_key(plugin):
\r
998 #config = self.panelCommands.CommandsTree.GetPyData(item_plugin)
\r
999 config = self.configs[plugin]
\r
1000 section = self.panelCommands.CommandsTree.GetItemText(hit_item)
\r
1001 #display docstring in help window
\r
1002 doc_string = eval('self.do_' + section + '.__doc__')
\r
1003 if section in config:
\r
1004 for option in config[section]:
\r
1005 properties.append([option, config[section][option]])
\r
1007 module = self.panelCommands.CommandsTree.GetItemText(hit_item)
\r
1008 if module != 'general':
\r
1009 doc_string = eval('plugins.' + module + '.' + module + 'Commands.__doc__')
\r
1011 doc_string = 'The module "general" contains Hooke core functionality'
\r
1012 if doc_string is not None:
\r
1013 self.panelAssistant.ChangeValue(doc_string)
\r
1014 hookepropertyeditor.PropertyEditor.Initialize(self.panelProperties, properties)
\r
1017 def UpdatePlaylists(self):
\r
1018 #setup the playlist in the Playlist tree
\r
1019 tree_root = self.panelPlaylists.PlaylistsTree.GetRootItem()
\r
1020 playlist_root = self.panelPlaylists.PlaylistsTree.AppendItem(tree_root, playlist.name, 0)
\r
1021 #add all curves to the Playlist tree
\r
1023 for index, curve in enumerate(playlist.curves):
\r
1024 ##remove the extension from the name of the curve
\r
1026 #item_text, extension = os.path.splitext(curve.name)
\r
1027 #curve_ID = self.panelPlaylists.PlaylistsTree.AppendItem(playlist_root, item_text, 1)
\r
1028 curve_ID = self.panelPlaylists.PlaylistsTree.AppendItem(playlist_root, curve.name, 1)
\r
1029 if index == playlist.index:
\r
1030 self.panelPlaylists.PlaylistsTree.SelectItem(curve_ID)
\r
1031 #create the plot tab and add playlist to the dictionary
\r
1032 plotPanel = wxmpl.PlotPanel(self, ID_FirstPlot + len(self.playlists))
\r
1033 notebook_tab = self.plotNotebook.AddPage(plotPanel, playlist.name, True)
\r
1034 #tab_index = self.plotNotebook.GetSelection()
\r
1035 figure = plotPanel.get_figure()
\r
1036 #self.playlists[playlist.name] = [playlist, tab_index, figure]
\r
1037 self.playlists[playlist.name] = [playlist, figure]
\r
1038 self.panelPlaylists.PlaylistsTree.Expand(playlist_root)
\r
1039 self.statusbar.SetStatusText(playlist.get_status_string(), 0)
\r
1043 #Everything sending an event should be here
\r
1044 def _measure_N_points(self, N, whatset=1):
\r
1046 general helper function for N-points measures
\r
1048 wx.PostEvent(self.frame,self.list_of_events['measure_points'](num_of_points=N, set=whatset))
\r
1051 points=self.frame.events_from_gui.get()
\r
1057 def _clickize(self, xvector, yvector, index):
\r
1059 returns a ClickedPoint() object from an index and vectors of x, y coordinates
\r
1061 point = lh.ClickedPoint()
\r
1062 point.index = index
\r
1063 point.absolute_coords = xvector[index], yvector[index]
\r
1064 point.find_graph_coords(xvector, yvector)
\r
1067 #PLAYLIST INTERACTION COMMANDS
\r
1068 #-------------------------------
\r
1069 def do_genlist(self, folder=lh.hookeDir, filemask='*.*'):
\r
1072 Generates a file playlist.
\r
1073 Note it doesn't *save* it: see savelist for this.
\r
1075 If [input files] is a directory, it will use all files in the directory for playlist.
\r
1081 are all equivalent syntax.
\r
1083 Syntax: genlist [input files]
\r
1085 #args list is: input folder, file mask
\r
1086 if os.path.isdir(folder):
\r
1087 path = os.path.join(folder, filemask)
\r
1088 #expanding correctly the input list with the glob module :)
\r
1089 files = glob.glob(path)
\r
1091 #TODO: change cursor or progressbar (maybe in statusbar)
\r
1092 #self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
\r
1093 playlist = playlist.Playlist(self.drivers)
\r
1094 for item in files:
\r
1095 curve = playlist.add_curve(item)
\r
1096 plot = copy.deepcopy(curve.plots[0])
\r
1097 #add the 'raw' data
\r
1098 curve.add_data('raw', plot.vectors[0][0], plot.vectors[0][1], color=plot.colors[0], style='plot')
\r
1099 curve.add_data('raw', plot.vectors[1][0], plot.vectors[1][1], color=plot.colors[1], style='plot')
\r
1100 #apply all active plotmanipulators and add the 'manipulated' data
\r
1101 for plotmanipulator in self.plotmanipulators:
\r
1102 plot = plotmanipulator[1](plot, curve)
\r
1103 curve.set_data('manipulated', plot.vectors[0][0], plot.vectors[0][1], color=plot.colors[0], style='plot')
\r
1104 curve.add_data('manipulated', plot.vectors[1][0], plot.vectors[1][1], color=plot.colors[1], style='plot')
\r
1105 if playlist.count > 0:
\r
1106 playlist.name = self._GetUniquePlaylistName(os.path.basename(folder))
\r
1108 self.AddToPlaylists(playlist)
\r
1109 self.AppendToOutput(playlist.get_status_string())
\r
1111 self.AppendToOutput(''.join(['Cannot find folder ', folder]))
\r
1113 def do_loadlist(self, filename):
\r
1116 Loads a file playlist
\r
1118 Syntax: loadlist [playlist file]
\r
1120 #TODO: check for duplicate playlists, ask the user for a unique name
\r
1121 #if self.playlist_name in self.playlists:
\r
1123 #add hkp extension if necessary
\r
1124 if not filename.endswith('.hkp'):
\r
1125 filename = ''.join([filename, '.hkp'])
\r
1126 #prefix with 'hookeDir' if just a filename or a relative path
\r
1127 filename = lh.get_file_path(filename)
\r
1128 if os.path.isfile(filename):
\r
1129 #TODO: change cursor
\r
1130 #self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
\r
1131 playlist_new = playlist.Playlist(self.drivers)
\r
1132 playlist_new.load(filename)
\r
1133 if playlist_new.count > 0:
\r
1134 for curve in playlist_new.curves:
\r
1135 plot = copy.deepcopy(curve.plots[0])
\r
1136 for plotmanip in self.plotmanipulators:
\r
1137 #to_plot = plotmanip[1](to_plot, curve)
\r
1138 plot = plotmanip[1](plot, curve)
\r
1139 curve.set_data('manipulated', plot.vectors[0][0], plot.vectors[0][1], color=plot.colors[0], style='plot')
\r
1140 curve.add_data('manipulated', plot.vectors[1][0], plot.vectors[1][1], color=plot.colors[1], style='plot')
\r
1141 self.AddToPlaylists(playlist_new)
\r
1143 ##TODO: display dialog
\r
1144 self.AppendToOutput(playlist_new.get_status_string())
\r
1145 #TODO: change cursor
\r
1146 #self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
\r
1148 #TODO: display dialog
\r
1149 self.AppendToOutput(''.join['File ', filename, ' not found.\n'])
\r
1152 def do_savelist(self, filename):
\r
1155 Saves the current file playlist on disk.
\r
1157 Syntax: savelist [filename]
\r
1160 #self.playlist_generics['pointer'] = self._GetActiveCurveIndex
\r
1161 pointer = self._GetActiveCurveIndex()
\r
1162 #autocomplete filename if not specified
\r
1163 if not filename.endswith('.hkp'):
\r
1164 filename = filename.join(['.hkp'])
\r
1166 playlist = self.GetActivePlaylist()
\r
1167 playlist.set_XML()
\r
1168 playlist.save(filename)
\r
1170 #PLOT INTERACTION COMMANDS
\r
1171 #-------------------------------
\r
1172 def UpdatePlot(self):
\r
1173 def add_plot(plot):
\r
1174 if plot['visible'] and plot['x'] and plot['y']:
\r
1175 color = plot['color']
\r
1176 style = plot['style']
\r
1177 if style == 'plot':
\r
1178 axes.plot(plot['x'], plot['y'], color=color, zorder=1)
\r
1179 if style == 'scatter':
\r
1180 axes.scatter(plot['x'], plot['y'], color=color, s=0.5, zorder=2)
\r
1182 def add_plot2(plot):
\r
1183 if plot.visible and plot.x and plot.y:
\r
1184 if plot.style == 'plot':
\r
1185 axes.plot(plot.x, plot.y, color=plot.color, zorder=1)
\r
1186 if plot.style == 'scatter':
\r
1187 axes.scatter(plot.x, plot.y, color=plot.color, s=0.5, zorder=2)
\r
1189 playlist_name = self._GetActivePlaylistName()
\r
1190 index = self._GetActiveCurveIndex()
\r
1191 playlist = self.playlists[playlist_name][0]
\r
1192 curve = playlist.get_active_curve()
\r
1193 plot = playlist.get_active_plot()
\r
1194 figure = self.playlists[playlist_name][1]
\r
1198 if curve.data.has_key('manipulated'):
\r
1200 elif curve.data.has_key('raw'):
\r
1201 exclude = 'manipulated'
\r
1203 if exclude is not None:
\r
1204 #TODO: what is this good for?
\r
1205 if not hasattr(self, 'subplot'):
\r
1206 axes = figure.add_subplot(111)
\r
1208 axes.set_title(plot.title)
\r
1209 axes.set_xlabel(plot.units[0])
\r
1210 axes.set_ylabel(plot.units[1])
\r
1212 for set_of_plots in curve.data:
\r
1213 if set_of_plots != exclude:
\r
1214 plots = curve.data[set_of_plots]
\r
1215 for each_plot in plots:
\r
1216 add_plot(each_plot)
\r
1218 #TODO: add multiple results support
\r
1219 #for fit in curve.fits:
\r
1220 if curve.fits.has_key('wlc'):
\r
1221 for plot in curve.fits['wlc'].results:
\r
1223 self.panelResults.DisplayResults(curve.fits['wlc'])
\r
1225 self.panelResults.ClearResults()
\r
1227 axes.figure.canvas.draw()
\r
1229 self.AppendToOutput('Not able to plot.')
\r
1232 ID_PaneBorderSize = wx.ID_HIGHEST + 1
\r
1233 ID_SashSize = ID_PaneBorderSize + 1
\r
1234 ID_CaptionSize = ID_PaneBorderSize + 2
\r
1235 ID_BackgroundColor = ID_PaneBorderSize + 3
\r
1236 ID_SashColor = ID_PaneBorderSize + 4
\r
1237 ID_InactiveCaptionColor = ID_PaneBorderSize + 5
\r
1238 ID_InactiveCaptionGradientColor = ID_PaneBorderSize + 6
\r
1239 ID_InactiveCaptionTextColor = ID_PaneBorderSize + 7
\r
1240 ID_ActiveCaptionColor = ID_PaneBorderSize + 8
\r
1241 ID_ActiveCaptionGradientColor = ID_PaneBorderSize + 9
\r
1242 ID_ActiveCaptionTextColor = ID_PaneBorderSize + 10
\r
1243 ID_BorderColor = ID_PaneBorderSize + 11
\r
1244 ID_GripperColor = ID_PaneBorderSize + 12
\r
1247 #----------------------------------------------------------------------
\r
1249 if __name__ == '__main__':
\r
1251 ## now, silence a deprecation warning for py2.3
\r
1253 #warnings.filterwarnings("ignore", "integer", DeprecationWarning, "wxPython.gdi")
\r
1258 app = Hooke(redirect=redirect)
\r