From: W. Trevor King Date: Sat, 24 Jul 2010 18:06:50 +0000 (-0400) Subject: Cleaning up hooke.ui.gui. Can initialize, but without most bindings. X-Git-Url: http://git.tremily.us/?p=hooke.git;a=commitdiff_plain;h=86f7d4277dbae62efc73b59576fa10ad00bc2987 Cleaning up hooke.ui.gui. Can initialize, but without most bindings. Following the wxPython style guide: http://wiki.wxpython.org/wxPython%20Style%20Guide Most of removing IDs and breaking out GUI elements into their own classes. --- diff --git a/hooke/ui/gui/__init__.py b/hooke/ui/gui/__init__.py index db64594..5fcfb14 100644 --- a/hooke/ui/gui/__init__.py +++ b/hooke/ui/gui/__init__.py @@ -3,7 +3,7 @@ """Defines :class:`GUI` providing a wxWindows interface to Hooke. """ -WX_GOOD=['2.6','2.8'] +WX_GOOD=['2.8'] import wxversion wxversion.select(WX_GOOD) @@ -25,272 +25,264 @@ import wx.lib.evtmgr as evtmgr from matplotlib.ticker import FuncFormatter -from ..command import CommandExit, Exit, Command, Argument, StoreValue -from ..interaction import Request, BooleanRequest, ReloadUserInterfaceConfig -from ..ui import UserInterface, CommandMessage +from ... import version +from ...command import CommandExit, Exit, Command, Argument, StoreValue +from ...config import Setting +from ...interaction import Request, BooleanRequest, ReloadUserInterfaceConfig +from ...ui import UserInterface, CommandMessage +from . import panel as panel +from . import prettyformat as prettyformat -import lib.prettyformat -import .panel as panel +class Notebook (aui.AuiNotebook): + def __init__(self, *args, **kwargs): + super(Notebook, self).__init__(*args, **kwargs) + self.SetArtProvider(aui.AuiDefaultTabArt()) + #uncomment if we find a nice icon + #page_bmp = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16, 16)) + self.AddPage(self._welcome_window(), 'Welcome') + + def _welcome_window(self): + #TODO: move into panel.welcome + ctrl = wx.html.HtmlWindow(parent=self, size=wx.Size(400, 300)) + lines = [ + '

Welcome to Hooke

', + '

Features

', + '', + '

See the DocumentationIndex' + % 'http://code.google.com/p/hooke/wiki/DocumentationIndex', + 'for more information

', + ] + ctrl.SetPage('\n'.join(lines)) + return ctrl -ID_About = wx.NewId() -ID_Next = wx.NewId() -ID_Previous = wx.NewId() - -ID_ViewAssistant = wx.NewId() -ID_ViewCommands = wx.NewId() -ID_ViewFolders = wx.NewId() -ID_ViewNote = wx.NewId() -ID_ViewOutput = wx.NewId() -ID_ViewPlaylists = wx.NewId() -ID_ViewProperties = wx.NewId() -ID_ViewResults = wx.NewId() - -ID_DeletePerspective = wx.NewId() -ID_SavePerspective = wx.NewId() - -ID_FirstPerspective = ID_SavePerspective + 1000 -#I hope we'll never have more than 1000 perspectives -ID_FirstPlot = ID_SavePerspective + 2000 - -class Hooke(wx.App): - - def OnInit(self): - self.SetAppName('Hooke') - self.SetVendorName('') - - window_height = config['main']['height'] - window_left= config['main']['left'] - window_top = config['main']['top'] - window_width = config['main']['width'] - - #sometimes, the ini file gets confused and sets 'left' - #and 'top' to large negative numbers - #let's catch and fix this - #keep small negative numbers, the user might want those - if window_left < -window_width: - window_left = 0 - if window_top < -window_height: - window_top = 0 - window_position = (window_left, window_top) - window_size = (window_width, window_height) - - #setup the splashscreen - if config['splashscreen']['show']: - filename = lh.get_file_path('hooke.jpg', ['resources']) - if os.path.isfile(filename): - bitmap = wx.Image(filename).ConvertToBitmap() - splashStyle = wx.SPLASH_CENTRE_ON_SCREEN|wx.SPLASH_TIMEOUT - splashDuration = config['splashscreen']['duration'] - wx.SplashScreen(bitmap, splashStyle, splashDuration, None, -1) - wx.Yield() - ''' - we need for the splash screen to disappear - for whatever reason splashDuration and sleep do not correspond to each other - at least not on Windows - maybe it's because duration is in milliseconds and sleep in seconds - thus we need to increase the sleep time a bit - a factor of 1.2 seems to work quite well - ''' - sleepFactor = 1.2 - time.sleep(sleepFactor * splashDuration / 1000) - - plugin_objects = [] - for plugin in config['plugins']: - if config['plugins'][plugin]: - filename = ''.join([plugin, '.py']) - path = lh.get_file_path(filename, ['plugins']) - if os.path.isfile(path): - #get the corresponding filename and path - plugin_name = ''.join(['plugins.', plugin]) - #import the module - __import__(plugin_name) - #get the file that contains the plugin - class_file = getattr(plugins, plugin) - #get the class that contains the commands - class_object = getattr(class_file, plugin + 'Commands') - plugin_objects.append(class_object) - - def make_command_class(*bases): - #create metaclass with plugins and plotmanipulators - return type(HookeFrame)("HookeFramePlugged", bases + (HookeFrame,), {}) - frame = make_command_class(*plugin_objects)(parent=None, id=wx.ID_ANY, title='Hooke', pos=window_position, size=window_size) - frame.Show(True) - self.SetTopWindow(frame) +class NavBar (wx.ToolBar): + def __init__(self, *args, **kwargs): + super(NavBar, self).__init__(*args, **kwargs) + self.SetToolBitmapSize(wx.Size(16,16)) + self._c = { + 'previous': self.AddLabelTool( + id=wx.ID_ANY, + label='Previous', + bitmap=wx.ArtProvider_GetBitmap( + wx.ART_GO_BACK, wx.ART_OTHER, wx.Size(16, 16)), + shortHelp='Previous curve'), + 'next': self.AddLabelTool( + id=wx.ID_ANY, + label='Next', + bitmap=wx.ArtProvider_GetBitmap( + wx.ART_GO_FORWARD, wx.ART_OTHER, wx.Size(16, 16)), + shortHelp='Next curve'), + } + self.Realize() + + +class FileMenu (wx.Menu): + def __init__(self, *args, **kwargs): + super(FileMenu, self).__init__(*args, **kwargs) + self._c = {'exit': self.Append(wx.ID_EXIT, 'Exit\tCtrl-Q')} + + +class ViewMenu (wx.Menu): + def __init__(self, *args, **kwargs): + super(ViewMenu, self).__init__(*args, **kwargs) + self._c = { + 'folders': self.AppendCheckItem(id=wx.ID_ANY, text='Folders\tF5'), + 'playlist': self.AppendCheckItem( + id=wx.ID_ANY, text='Playlists\tF6'), + 'commands': self.AppendCheckItem( + id=wx.ID_ANY, text='Commands\tF7'), + 'assistant': self.AppendCheckItem( + id=wx.ID_ANY, text='Assistant\tF9'), + 'properties': self.AppendCheckItem( + id=wx.ID_ANY, text='Properties\tF8'), + 'results': self.AppendCheckItem(id=wx.ID_ANY, text='Results\tF10'), + 'output': self.AppendCheckItem(id=wx.ID_ANY, text='Output\tF11'), + 'note': self.AppendCheckItem(id=wx.ID_ANY, text='Note\tF12'), + } + + +class PerspectivesMenu (wx.Menu): + def __init__(self, *args, **kwargs): + super(PerspectivesMenu, self).__init__(*args, **kwargs) + self._c = {} + + def update(self, perspectives, selected): + """Rebuild the perspectives menu. + """ + for item in self.GetMenuItems(): + self.DeleteItem(item) + self._c = { + 'save': self.Append(item='Save Perspective'), + 'delete': self.Append(item='Delete Perspective'), + } + self.AppendSeparator() + for label in perspectives: + self._c[label] = menu.AppendRadioItem(item=label) + if label == selected_perspective: + self._c[label].Check(True) + + +class HelpMenu (wx.Menu): + def __init__(self, *args, **kwargs): + super(HelpMenu, self).__init__(*args, **kwargs) + self._c = {'about':self.Append(id=wx.ID_ANY, text='About Hooke')} + + +class MenuBar (wx.MenuBar): + def __init__(self, *args, **kwargs): + super(MenuBar, self).__init__(*args, **kwargs) + self._c = { + 'file': FileMenu(), + 'view': ViewMenu(), + 'perspectives': PerspectivesMenu(), + 'help': HelpMenu(), + } + self.Append(self._c['file'], 'File') + self.Append(self._c['view'], 'View') + self.Append(self._c['perspectives'], 'Perspectives') + self.Append(self._c['help'], 'Help') + + +class StatusBar (wx.StatusBar): + def __init__(self, *args, **kwargs): + super(StatusBar, self).__init__(*args, **kwargs) + self.SetStatusWidths([-2, -3]) + self.SetStatusText('Ready', 0) + self.SetStatusText(u'Welcome to Hooke (version %s)' % version(), 1) + + +class HookeFrame (wx.Frame): + def __init__(self, gui, commands, *args, **kwargs): + super(HookeFrame, self).__init__(*args, **kwargs) + self.gui = gui + self.commands = commands + self._perspectives = {} # {name: perspective_str} + self._c = {} + + self.SetIcon(wx.Icon(self.gui.config['icon image'], wx.BITMAP_TYPE_ICO)) + + # setup frame manager + self._c['manager'] = aui.AuiManager() + self._c['manager'].SetManagedWindow(self) + + # set the gradient and drag styles + self._c['manager'].GetArtProvider().SetMetric( + aui.AUI_DOCKART_GRADIENT_TYPE, aui.AUI_GRADIENT_NONE) + self._c['manager'].SetFlags( + self._c['manager'].GetFlags() ^ aui.AUI_MGR_TRANSPARENT_DRAG) + + # Min size for the frame itself isn't completely done. See + # the end of FrameManager::Update() for the test code. For + # now, just hard code a frame minimum size. + self.SetMinSize(wx.Size(500, 500)) - return True + self._setup_panels() + self._setup_toolbars() + self._c['manager'].Update() # commit pending changes - def OnExit(self): - return True + # Create the menubar after the panes so that the default + # perspective is created with all panes open + self._c['menu bar'] = MenuBar() + self.SetMenuBar(self._c['menu bar']) + self._c['status bar'] = StatusBar(self, style=wx.ST_SIZEGRIP) -class HookeFrame(wx.Frame): - - def __init__(self, parent, id=-1, title='', pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE|wx.SUNKEN_BORDER|wx.CLIP_CHILDREN): - #call parent constructor - wx.Frame.__init__(self, parent, id, title, pos, size, style) - self.config = config - self.CreateApplicationIcon() - #self.configs contains: {the name of the Commands file: corresponding ConfigObj} - self.configs = {} - #self.displayed_plot holds the currently displayed plot - self.displayed_plot = None - #self.playlists contains: {the name of the playlist: [playlist, tabIndex, plotID]} - self.playlists = {} - #list of all plotmanipulators - self.plotmanipulators = [] - #self.plugins contains: {the name of the plugin: [caption, function]} - self.plugins = {} - #self.results_str contains the type of results we want to display - self.results_str = 'wlc' - - #tell FrameManager to manage this frame - self._mgr = aui.AuiManager() - self._mgr.SetManagedWindow(self) - #set the gradient style - self._mgr.GetArtProvider().SetMetric(aui.AUI_DOCKART_GRADIENT_TYPE, aui.AUI_GRADIENT_NONE) - #set transparent drag - self._mgr.SetFlags(self._mgr.GetFlags() ^ aui.AUI_MGR_TRANSPARENT_DRAG) - - # set up default notebook style - self._notebook_style = aui.AUI_NB_DEFAULT_STYLE | aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER - self._notebook_theme = 0 - - #holds the perspectives: {name, perspective_str} - self._perspectives = {} + self._bind_events() - # min size for the frame itself isn't completely done. - # see the end up FrameManager::Update() for the test - # code. For now, just hard code a frame minimum size - self.SetMinSize(wx.Size(500, 500)) - #define the list of active drivers - self.drivers = [] - for driver in self.config['drivers']: - if self.config['drivers'][driver]: - #get the corresponding filename and path - filename = ''.join([driver, '.py']) - path = lh.get_file_path(filename, ['drivers']) - #the driver is active for driver[1] == 1 - if os.path.isfile(path): - #driver files are located in the 'drivers' subfolder - driver_name = ''.join(['drivers.', driver]) - __import__(driver_name) - class_file = getattr(drivers, driver) - for command in dir(class_file): - if command.endswith('Driver'): - self.drivers.append(getattr(class_file, command)) - #import all active plugins and plotmanips - #add 'core.ini' to self.configs (this is not a plugin and thus must be imported separately) - ini_path = lh.get_file_path('core.ini', ['plugins']) - plugin_config = ConfigObj(ini_path) - #self.config.merge(plugin_config) - self.configs['core'] = plugin_config - #existing_commands contains: {command: plugin} - existing_commands = {} - #make sure we execute _plug_init() for every command line plugin we import - for plugin in self.config['plugins']: - if self.config['plugins'][plugin]: - filename = ''.join([plugin, '.py']) - path = lh.get_file_path(filename, ['plugins']) - if os.path.isfile(path): - #get the corresponding filename and path - plugin_name = ''.join(['plugins.', plugin]) - try: - #import the module - module = __import__(plugin_name) - #prepare the ini file for inclusion - ini_path = path.replace('.py', '.ini') - #include ini file - plugin_config = ConfigObj(ini_path) - #self.config.merge(plugin_config) - self.configs[plugin] = plugin_config - #add to plugins - commands = eval('dir(module.' + plugin+ '.' + plugin + 'Commands)') - #keep only commands (ie names that start with 'do_') - commands = [command for command in commands if command.startswith('do_')] - if commands: - for command in commands: - if existing_commands.has_key(command): - message_str = 'Adding "' + command + '" in plugin "' + plugin + '".\n\n' - message_str += '"' + command + '" already exists in "' + str(existing_commands[command]) + '".\n\n' - message_str += 'Only "' + command + '" in "' + str(existing_commands[command]) + '" will work.\n\n' - message_str += 'Please rename one of the commands in the source code and restart Hooke or disable one of the plugins.' - dialog = wx.MessageDialog(self, message_str, 'Warning', wx.OK|wx.ICON_WARNING|wx.CENTER) - dialog.ShowModal() - dialog.Destroy() - existing_commands[command] = plugin - self.plugins[plugin] = commands - try: - #initialize the plugin - eval('module.' + plugin+ '.' + plugin + 'Commands._plug_init(self)') - except AttributeError: - pass - except ImportError: - pass - #add commands from hooke.py i.e. 'core' commands - commands = dir(HookeFrame) - commands = [command for command in commands if command.startswith('do_')] - if commands: - self.plugins['core'] = commands - #create panels here - self.panelAssistant = self.CreatePanelAssistant() - self.panelCommands = self.CreatePanelCommands() - self.panelFolders = self.CreatePanelFolders() - self.panelPlaylists = self.CreatePanelPlaylists() - self.panelProperties = self.CreatePanelProperties() - self.panelNote = self.CreatePanelNote() - self.panelOutput = self.CreatePanelOutput() - self.panelResults = self.CreatePanelResults() - self.plotNotebook = self.CreateNotebook() - - # add panes - self._mgr.AddPane(self.panelFolders, aui.AuiPaneInfo().Name('Folders').Caption('Folders').Left().CloseButton(True).MaximizeButton(False)) - self._mgr.AddPane(self.panelPlaylists, aui.AuiPaneInfo().Name('Playlists').Caption('Playlists').Left().CloseButton(True).MaximizeButton(False)) - self._mgr.AddPane(self.panelNote, aui.AuiPaneInfo().Name('Note').Caption('Note').Left().CloseButton(True).MaximizeButton(False)) - self._mgr.AddPane(self.plotNotebook, aui.AuiPaneInfo().Name('Plots').CenterPane().PaneBorder(False)) - self._mgr.AddPane(self.panelCommands, aui.AuiPaneInfo().Name('Commands').Caption('Settings and commands').Right().CloseButton(True).MaximizeButton(False)) - self._mgr.AddPane(self.panelProperties, aui.AuiPaneInfo().Name('Properties').Caption('Properties').Right().CloseButton(True).MaximizeButton(False)) - self._mgr.AddPane(self.panelAssistant, aui.AuiPaneInfo().Name('Assistant').Caption('Assistant').Right().CloseButton(True).MaximizeButton(False)) - self._mgr.AddPane(self.panelOutput, aui.AuiPaneInfo().Name('Output').Caption('Output').Bottom().CloseButton(True).MaximizeButton(False)) - self._mgr.AddPane(self.panelResults, aui.AuiPaneInfo().Name('Results').Caption('Results').Bottom().CloseButton(True).MaximizeButton(False)) - #self._mgr.AddPane(self.textCtrlCommandLine, aui.AuiPaneInfo().Name('CommandLine').CaptionVisible(False).Fixed().Bottom().Layer(2).CloseButton(False).MaximizeButton(False)) - #self._mgr.AddPane(panelBottom, aui.AuiPaneInfo().Name("panelCommandLine").Bottom().Position(1).CloseButton(False).MaximizeButton(False)) - - # add the toolbars to the manager - #self.toolbar=self.CreateToolBar() - self.toolbarNavigation=self.CreateToolBarNavigation() - #self._mgr.AddPane(self.toolbar, aui.AuiPaneInfo().Name('toolbar').Caption('Toolbar').ToolbarPane().Top().Layer(1).Row(1).LeftDockable(False).RightDockable(False)) - self._mgr.AddPane(self.toolbarNavigation, aui.AuiPaneInfo().Name('toolbarNavigation').Caption('Navigation').ToolbarPane().Top().Layer(1).Row(1).LeftDockable(False).RightDockable(False)) - # "commit" all changes made to FrameManager - self._mgr.Update() - #create the menubar after the panes so that the default perspective - #is created with all panes open - self.CreateMenuBar() - self.statusbar = self.CreateStatusbar() - self._BindEvents() - - name = self.config['perspectives']['active'] + self._update_perspectives() + name = self.gui.config['active perspective'] + return # TODO: cleanup menu_item = self.GetPerspectiveMenuItem(name) if menu_item is not None: self.OnRestorePerspective(menu_item) #TODO: config setting to remember playlists from last session - self.playlists = self.panelPlaylists.Playlists - #initialize the commands tree - self.panelCommands.Initialize(self.plugins) - for command in dir(self): - if command.startswith('plotmanip_'): - self.plotmanipulators.append(lib.plotmanipulator.Plotmanipulator(method=getattr(self, command), command=command)) - + self.playlists = self._c['playlists'].Playlists + self._displayed_plot = None #load default list, if possible self.do_loadlist(self.GetStringFromConfig('core', 'preferences', 'playlist')) - def _BindEvents(self): - #TODO: figure out if we can use the eventManager for menu ranges - #and events of 'self' without raising an assertion fail error + def _setup_panels(self): + client_size = self.GetClientSize() + for label,p,style in [ + ('folders', wx.GenericDirCtrl( + parent=self, + dir=self.gui.config['folders-workdir'], + size=(200, 250), + style=wx.DIRCTRL_SHOW_FILTERS, + filter=self.gui.config['folders-filters'], + defaultFilter=int(self.gui.config['folders-filter-index'])), 'left'), #HACK: config should convert + ('playlists', panel.playlist.Playlist(self), 'left'), + ('note', panel.note.Note(self), 'left'), + ('notebook', Notebook( + parent=self, + pos=wx.Point(client_size.x, client_size.y), + size=wx.Size(430, 200), + style=aui.AUI_NB_DEFAULT_STYLE + | aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER), 'center'), + ('commands', panel.commands.Commands( + commands=self.commands, + selected=self.gui.config['selected command'], + parent=self, + style=wx.WANTS_CHARS|wx.NO_BORDER, + # WANTS_CHARS so the panel doesn't eat the Return key. + size=(160, 200)), 'right'), + #('properties', panel.propertyeditor.PropertyEditor(self),'right'), + ('assistant', wx.TextCtrl( + parent=self, + pos=wx.Point(0, 0), + size=wx.Size(150, 90), + style=wx.NO_BORDER|wx.TE_MULTILINE), 'right'), + ('output', wx.TextCtrl( + parent=self, + pos=wx.Point(0, 0), + size=wx.Size(150, 90), + style=wx.NO_BORDER|wx.TE_MULTILINE), 'bottom'), + ('results', panel.results.Results(self), 'bottom'), + ]: + self._add_panel(label, p, style) + self._c['assistant'].SetEditable(False) + + def _add_panel(self, label, panel, style): + self._c[label] = panel + cap_label = label.capitalize() + info = aui.AuiPaneInfo().Name(cap_label).Caption(cap_label) + if style == 'left': + info.Left().CloseButton(True).MaximizeButton(False) + elif style == 'center': + info.CenterPane().PaneBorder(False) + elif style == 'right': + info.Right().CloseButton(True).MaximizeButton(False) + else: + assert style == 'bottom', style + info.Bottom().CloseButton(True).MaximizeButton(False) + self._c['manager'].AddPane(panel, info) + + def _setup_toolbars(self): + self._c['navbar'] = NavBar(self, style=wx.TB_FLAT | wx.TB_NODIVIDER) + + self._c['manager'].AddPane( + self._c['navbar'], + aui.AuiPaneInfo().Name('Navigation').Caption('Navigation' + ).ToolbarPane().Top().Layer(1).Row(1).LeftDockable(False + ).RightDockable(False)) + + def _bind_events(self): + # TODO: figure out if we can use the eventManager for menu + # ranges and events of 'self' without raising an assertion + # fail error. self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_CLOSE, self.OnClose) + return # TODO: cleanup # Show How To Use The Closing Panes Event self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPaneClose) self.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnNotebookPageClose) @@ -313,12 +305,12 @@ class HookeFrame(wx.Frame): #tree.Bind(wx.EVT_LEFT_DOWN, self.OnGenericDirCtrl1LeftDown) treeCtrl.Bind(wx.EVT_LEFT_DCLICK, self.OnDirCtrlLeftDclick) #playlist tree - self.panelPlaylists.PlaylistsTree.Bind(wx.EVT_LEFT_DOWN, self.OnPlaylistsLeftDown) - self.panelPlaylists.PlaylistsTree.Bind(wx.EVT_LEFT_DCLICK, self.OnPlaylistsLeftDclick) + self._c['playlists'].PlaylistsTree.Bind(wx.EVT_LEFT_DOWN, self.OnPlaylistsLeftDown) + self._c['playlists'].PlaylistsTree.Bind(wx.EVT_LEFT_DCLICK, self.OnPlaylistsLeftDclick) #commands tree - evtmgr.eventManager.Register(self.OnExecute, wx.EVT_BUTTON, self.panelCommands.ExecuteButton) - evtmgr.eventManager.Register(self.OnTreeCtrlCommandsSelectionChanged, wx.EVT_TREE_SEL_CHANGED, self.panelCommands.CommandsTree) - evtmgr.eventManager.Register(self.OnTreeCtrlItemActivated, wx.EVT_TREE_ITEM_ACTIVATED, self.panelCommands.CommandsTree) + evtmgr.eventManager.Register(self.OnExecute, wx.EVT_BUTTON, self._c['commands'].ExecuteButton) + evtmgr.eventManager.Register(self.OnTreeCtrlCommandsSelectionChanged, wx.EVT_TREE_SEL_CHANGED, self._c['commands']._c['tree']) + evtmgr.eventManager.Register(self.OnTreeCtrlItemActivated, wx.EVT_TREE_ITEM_ACTIVATED, self._c['commands']._c['tree']) evtmgr.eventManager.Register(self.OnUpdateNote, wx.EVT_BUTTON, self.panelNote.UpdateButton) #property editor self.panelProperties.pg.Bind(wxpg.EVT_PG_CHANGED, self.OnPropGridChanged) @@ -328,20 +320,20 @@ class HookeFrame(wx.Frame): def _GetActiveFileIndex(self): lib.playlist.Playlist = self.GetActivePlaylist() #get the selected item from the tree - selected_item = self.panelPlaylists.PlaylistsTree.GetSelection() + selected_item = self._c['playlists'].PlaylistsTree.GetSelection() #test if a playlist or a curve was double-clicked - if self.panelPlaylists.PlaylistsTree.ItemHasChildren(selected_item): + if self._c['playlists'].PlaylistsTree.ItemHasChildren(selected_item): return -1 else: count = 0 - selected_item = self.panelPlaylists.PlaylistsTree.GetPrevSibling(selected_item) + selected_item = self._c['playlists'].PlaylistsTree.GetPrevSibling(selected_item) while selected_item.IsOk(): count += 1 - selected_item = self.panelPlaylists.PlaylistsTree.GetPrevSibling(selected_item) + selected_item = self._c['playlists'].PlaylistsTree.GetPrevSibling(selected_item) return count def _GetPlaylistTab(self, name): - for index, page in enumerate(self.plotNotebook._tabs._pages): + for index, page in enumerate(self._c['notebook']._tabs._pages): if page.caption == name: return index return -1 @@ -355,10 +347,10 @@ class HookeFrame(wx.Frame): return playlist_name def _RestorePerspective(self, name): - self._mgr.LoadPerspective(self._perspectives[name]) - self.config['perspectives']['active'] = name - self._mgr.Update() - all_panes = self._mgr.GetAllPanes() + self._c['manager'].LoadPerspective(self._perspectives[name]) + self.gui.config['active perspective'] = name + self._c['manager'].Update() + all_panes = self._c['manager'].GetAllPanes() for pane in all_panes: if not pane.name.startswith('toolbar'): if pane.name == 'Assistant': @@ -417,8 +409,8 @@ class HookeFrame(wx.Frame): def AddToPlaylists(self, playlist): if playlist.count > 0: #setup the playlist in the Playlist tree - tree_root = self.panelPlaylists.PlaylistsTree.GetRootItem() - playlist_root = self.panelPlaylists.PlaylistsTree.AppendItem(tree_root, playlist.name, 0) + tree_root = self._c['playlists'].PlaylistsTree.GetRootItem() + playlist_root = self._c['playlists'].PlaylistsTree.AppendItem(tree_root, playlist.name, 0) #add all files to the Playlist tree # files = {} hide_curve_extension = self.GetBoolFromConfig('core', 'preferences', 'hide_curve_extension') @@ -426,18 +418,18 @@ class HookeFrame(wx.Frame): #optionally remove the extension from the name of the curve if hide_curve_extension: file_to_add.name = lh.remove_extension(file_to_add.name) - file_ID = self.panelPlaylists.PlaylistsTree.AppendItem(playlist_root, file_to_add.name, 1) + file_ID = self._c['playlists'].PlaylistsTree.AppendItem(playlist_root, file_to_add.name, 1) if index == playlist.index: - self.panelPlaylists.PlaylistsTree.SelectItem(file_ID) + self._c['playlists'].PlaylistsTree.SelectItem(file_ID) playlist.reset() #create the plot tab and add playlist to the dictionary - plotPanel = panels.plot.PlotPanel(self, ID_FirstPlot + len(self.playlists)) - notebook_tab = self.plotNotebook.AddPage(plotPanel, playlist.name, True) - #tab_index = self.plotNotebook.GetSelection() + 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.panelPlaylists.PlaylistsTree.Expand(playlist_root) + self._c['playlists'].PlaylistsTree.Expand(playlist_root) self.statusbar.SetStatusText(playlist.get_status_string(), 0) self.UpdateNote() self.UpdatePlot() @@ -463,136 +455,19 @@ class HookeFrame(wx.Frame): manipulated_plot = plotmanipulator.method(manipulated_plot, plot_file) return manipulated_plot - def CreateApplicationIcon(self): - iconFile = 'resources' + os.sep + 'microscope.ico' - icon = wx.Icon(iconFile, wx.BITMAP_TYPE_ICO) - self.SetIcon(icon) - - def CreateCommandLine(self): - return wx.TextCtrl(self, -1, '', style=wx.NO_BORDER|wx.EXPAND) - - def CreatePanelAssistant(self): - panel = wx.TextCtrl(self, -1, '', wx.Point(0, 0), wx.Size(150, 90), wx.NO_BORDER|wx.TE_MULTILINE) - panel.SetEditable(False) - return panel - - def CreatePanelCommands(self): - return panels.commands.Commands(self) - - def CreatePanelFolders(self): - #set file filters - filters = self.config['folders']['filters'] - index = self.config['folders'].as_int('filterindex') - #set initial directory - folder = self.GetStringFromConfig('core', 'preferences', 'workdir') - return wx.GenericDirCtrl(self, -1, dir=folder, size=(200, 250), style=wx.DIRCTRL_SHOW_FILTERS, filter=filters, defaultFilter=index) - - def CreatePanelNote(self): - return panels.note.Note(self) - - def CreatePanelOutput(self): - return wx.TextCtrl(self, -1, '', wx.Point(0, 0), wx.Size(150, 90), wx.NO_BORDER|wx.TE_MULTILINE) - - def CreatePanelPlaylists(self): - return panels.playlist.Playlists(self) - - def CreatePanelProperties(self): - return panels.propertyeditor.PropertyEditor(self) - - def CreatePanelResults(self): - return panels.results.Results(self) - - def CreatePanelWelcome(self): - #TODO: move into panels.welcome - ctrl = wx.html.HtmlWindow(self, -1, wx.DefaultPosition, wx.Size(400, 300)) - introStr = '

Welcome to Hooke

' + \ - '

Features

' + \ - '' + \ - '

See the DocumentationIndex for more information

' - ctrl.SetPage(introStr) - return ctrl - - def CreateMenuBar(self): - menu_bar = wx.MenuBar() - self.SetMenuBar(menu_bar) - #file - file_menu = wx.Menu() - file_menu.Append(wx.ID_EXIT, 'Exit\tCtrl-Q') -# edit_menu.AppendSeparator(); -# edit_menu.Append(ID_Config, 'Preferences') - #view - view_menu = wx.Menu() - view_menu.AppendCheckItem(ID_ViewFolders, 'Folders\tF5') - view_menu.AppendCheckItem(ID_ViewPlaylists, 'Playlists\tF6') - view_menu.AppendCheckItem(ID_ViewCommands, 'Commands\tF7') - view_menu.AppendCheckItem(ID_ViewProperties, 'Properties\tF8') - view_menu.AppendCheckItem(ID_ViewAssistant, 'Assistant\tF9') - view_menu.AppendCheckItem(ID_ViewResults, 'Results\tF10') - view_menu.AppendCheckItem(ID_ViewOutput, 'Output\tF11') - view_menu.AppendCheckItem(ID_ViewNote, 'Note\tF12') - #perspectives - perspectives_menu = wx.Menu() - - #help - help_menu = wx.Menu() - help_menu.Append(wx.ID_ABOUT, 'About Hooke') - #put it all together - menu_bar.Append(file_menu, 'File') - menu_bar.Append(view_menu, 'View') - menu_bar.Append(perspectives_menu, "Perspectives") - self.UpdatePerspectivesMenu() - menu_bar.Append(help_menu, 'Help') - - def CreateNotebook(self): - # create the notebook off-window to avoid flicker - client_size = self.GetClientSize() - ctrl = aui.AuiNotebook(self, -1, wx.Point(client_size.x, client_size.y), wx.Size(430, 200), self._notebook_style) - arts = [aui.AuiDefaultTabArt, aui.AuiSimpleTabArt, aui.VC71TabArt, aui.FF2TabArt, aui.VC8TabArt, aui.ChromeTabArt] - art = arts[self._notebook_theme]() - ctrl.SetArtProvider(art) - #uncomment if we find a nice icon - #page_bmp = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16, 16)) - ctrl.AddPage(self.CreatePanelWelcome(), "Welcome", False) - return ctrl - - def CreateStatusbar(self): - statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) - statusbar.SetStatusWidths([-2, -3]) - statusbar.SetStatusText('Ready', 0) - welcomeString=u'Welcome to Hooke (version '+__version__+', '+__release_name__+')!' - statusbar.SetStatusText(welcomeString, 1) - return statusbar - - def CreateToolBarNavigation(self): - toolbar = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER) - toolbar.SetToolBitmapSize(wx.Size(16,16)) - toolbar_bmpBack = wx.ArtProvider_GetBitmap(wx.ART_GO_BACK, wx.ART_OTHER, wx.Size(16, 16)) - toolbar_bmpForward = wx.ArtProvider_GetBitmap(wx.ART_GO_FORWARD, wx.ART_OTHER, wx.Size(16, 16)) - toolbar.AddLabelTool(ID_Previous, 'Previous', toolbar_bmpBack, shortHelp='Previous curve') - toolbar.AddLabelTool(ID_Next, 'Next', toolbar_bmpForward, shortHelp='Next curve') - toolbar.Realize() - return toolbar - def DeleteFromPlaylists(self, name): if name in self.playlists: del self.playlists[name] - tree_root = self.panelPlaylists.PlaylistsTree.GetRootItem() - item, cookie = self.panelPlaylists.PlaylistsTree.GetFirstChild(tree_root) + tree_root = self._c['playlists'].PlaylistsTree.GetRootItem() + item, cookie = self._c['playlists'].PlaylistsTree.GetFirstChild(tree_root) while item.IsOk(): - playlist_name = self.panelPlaylists.PlaylistsTree.GetItemText(item) + playlist_name = self._c['playlists'].PlaylistsTree.GetItemText(item) if playlist_name == name: try: - self.panelPlaylists.PlaylistsTree.Delete(item) + self._c['playlists'].PlaylistsTree.Delete(item) except: pass - item = self.panelPlaylists.PlaylistsTree.GetNextSibling(item) + item = self._c['playlists'].PlaylistsTree.GetNextSibling(item) def GetActiveFigure(self): playlist_name = self.GetActivePlaylistName() @@ -615,15 +490,15 @@ class HookeFrame(wx.Frame): def GetActivePlaylistName(self): #get the selected item from the tree - selected_item = self.panelPlaylists.PlaylistsTree.GetSelection() + selected_item = self._c['playlists'].PlaylistsTree.GetSelection() #test if a playlist or a curve was double-clicked - if self.panelPlaylists.PlaylistsTree.ItemHasChildren(selected_item): + if self._c['playlists'].PlaylistsTree.ItemHasChildren(selected_item): playlist_item = selected_item else: #get the name of the playlist - playlist_item = self.panelPlaylists.PlaylistsTree.GetItemParent(selected_item) + playlist_item = self._c['playlists'].PlaylistsTree.GetItemParent(selected_item) #now we have a playlist - return self.panelPlaylists.PlaylistsTree.GetItemText(playlist_item) + return self._c['playlists'].PlaylistsTree.GetItemText(playlist_item) def GetActivePlot(self): playlist = self.GetActivePlaylist() @@ -650,79 +525,7 @@ class HookeFrame(wx.Frame): return plot def GetDockArt(self): - return self._mgr.GetArtProvider() - - def GetBoolFromConfig(self, *args): - if len(args) == 2: - plugin = args[0] - section = args[0] - key = args[1] - elif len(args) == 3: - plugin = args[0] - section = args[1] - key = args[2] - if self.configs.has_key(plugin): - config = self.configs[plugin] - return config[section][key].as_bool('value') - return None - - def GetColorFromConfig(self, *args): - if len(args) == 2: - plugin = args[0] - section = args[0] - key = args[1] - elif len(args) == 3: - plugin = args[0] - section = args[1] - key = args[2] - if self.configs.has_key(plugin): - config = self.configs[plugin] - color_tuple = eval(config[section][key]['value']) - color = [value / 255.0 for value in color_tuple] - return color - return None - - def GetFloatFromConfig(self, *args): - if len(args) == 2: - plugin = args[0] - section = args[0] - key = args[1] - elif len(args) == 3: - plugin = args[0] - section = args[1] - key = args[2] - if self.configs.has_key(plugin): - config = self.configs[plugin] - return config[section][key].as_float('value') - return None - - def GetIntFromConfig(self, *args): - if len(args) == 2: - plugin = args[0] - section = args[0] - key = args[1] - elif len(args) == 3: - plugin = args[0] - section = args[1] - key = args[2] - if self.configs.has_key(plugin): - config = self.configs[plugin] - return config[section][key].as_int('value') - return None - - def GetStringFromConfig(self, *args): - if len(args) == 2: - plugin = args[0] - section = args[0] - key = args[1] - elif len(args) == 3: - plugin = args[0] - section = args[1] - key = args[2] - if self.configs.has_key(plugin): - config = self.configs[plugin] - return config[section][key]['value'] - return None + return self._c['manager'].GetArtProvider() def GetPlotmanipulator(self, name): ''' @@ -764,31 +567,45 @@ class HookeFrame(wx.Frame): dialog.Destroy() def OnClose(self, event): - #apply changes - self.config['main']['height'] = str(self.GetSize().GetHeight()) - self.config['main']['left'] = str(self.GetPosition()[0]) - self.config['main']['top'] = str(self.GetPosition()[1]) - self.config['main']['width'] = str(self.GetSize().GetWidth()) - #save the configuration file to 'config/hooke.ini' - self.config.write() - #save all plugin config files - for config in self.configs: - plugin_config = self.configs[config] - plugin_config.write() + # 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._UnbindEvents() - self._mgr.UnInit() - del self._mgr + self._c['manager'].UnInit() + del self._c['manager'] self.Destroy() def OnDeletePerspective(self, event): - dialog = panels.perspectives.Perspectives(self, -1, 'Delete perspective(s)') + dialog = panel.selection.Selection( + options=sorted(os.listdir(self.gui.config['perspective-path'])), + message="\nPlease check the perspectives\n\nyou want to delete and click 'Delete'.\n", + button_id=wx.ID_DELETE, + button_callback=self._on_delete_perspective, + parent=self, + label='Delete perspective(s)', + style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) dialog.CenterOnScreen() dialog.ShowModal() dialog.Destroy() - self.UpdatePerspectivesMenu() - #unfortunately, there is a bug in wxWidgets (Ticket #3258) that - #makes the radio item indicator in the menu disappear - #the code should be fine once this issue is fixed + self._c['menu bar']['perspectives'].update( + sorted(self._perspectives.keys), + self.gui.config['active perspective']) + # 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 _on_delete_perspective(self, event, items, selected_items): + for item in selected_items: + self._perspectives.remove(item) + if item == self.gui.config['active perspective']: + self.gui.config['active perspective'] = 'Default' + path = os.path.join(self.gui.config['perspective-path'], + item+'.txt') + remove(path) def OnDirCtrlLeftDclick(self, event): file_path = self.panelFolders.GetPath() @@ -801,10 +618,10 @@ class HookeFrame(wx.Frame): event.Skip() def OnExecute(self, event): - item = self.panelCommands.CommandsTree.GetSelection() + item = self._c['commands']._c['tree'].GetSelection() if item.IsOk(): - if not self.panelCommands.CommandsTree.ItemHasChildren(item): - item_text = self.panelCommands.CommandsTree.GetItemText(item) + if not self._c['commands']._c['tree'].ItemHasChildren(item): + item_text = self._c['commands']._c['tree'].GetItemText(item) command = ''.join(['self.do_', item_text, '()']) #self.AppendToOutput(command + '\n') exec(command) @@ -820,20 +637,20 @@ class HookeFrame(wx.Frame): ----- Syntax: next, n ''' - selected_item = self.panelPlaylists.PlaylistsTree.GetSelection() - if self.panelPlaylists.PlaylistsTree.ItemHasChildren(selected_item): + selected_item = self._c['playlists'].PlaylistsTree.GetSelection() + if self._c['playlists'].PlaylistsTree.ItemHasChildren(selected_item): #GetFirstChild returns a tuple #we only need the first element - next_item = self.panelPlaylists.PlaylistsTree.GetFirstChild(selected_item)[0] + next_item = self._c['playlists'].PlaylistsTree.GetFirstChild(selected_item)[0] else: - next_item = self.panelPlaylists.PlaylistsTree.GetNextSibling(selected_item) + next_item = self._c['playlists'].PlaylistsTree.GetNextSibling(selected_item) if not next_item.IsOk(): - parent_item = self.panelPlaylists.PlaylistsTree.GetItemParent(selected_item) + parent_item = self._c['playlists'].PlaylistsTree.GetItemParent(selected_item) #GetFirstChild returns a tuple #we only need the first element - next_item = self.panelPlaylists.PlaylistsTree.GetFirstChild(parent_item)[0] - self.panelPlaylists.PlaylistsTree.SelectItem(next_item, True) - if not self.panelPlaylists.PlaylistsTree.ItemHasChildren(selected_item): + next_item = self._c['playlists'].PlaylistsTree.GetFirstChild(parent_item)[0] + self._c['playlists'].PlaylistsTree.SelectItem(next_item, True) + if not self._c['playlists'].PlaylistsTree.ItemHasChildren(selected_item): playlist = self.GetActivePlaylist() if playlist.count > 1: playlist.next() @@ -850,20 +667,20 @@ class HookeFrame(wx.Frame): event.Skip() def OnPlaylistsLeftDclick(self, event): - if self.panelPlaylists.PlaylistsTree.Count > 0: + if self._c['playlists'].PlaylistsTree.Count > 0: playlist_name = self.GetActivePlaylistName() #if that playlist already exists #we check if it is the active playlist (ie selected in panelPlaylists) #and switch to it if necessary if playlist_name in self.playlists: - index = self.plotNotebook.GetSelection() - current_playlist = self.plotNotebook.GetPageText(index) + index = self._c['notebook'].GetSelection() + current_playlist = self._c['notebook'].GetPageText(index) if current_playlist != playlist_name: index = self._GetPlaylistTab(playlist_name) - self.plotNotebook.SetSelection(index) + self._c['notebook'].SetSelection(index) #if a curve was double-clicked - item = self.panelPlaylists.PlaylistsTree.GetSelection() - if not self.panelPlaylists.PlaylistsTree.ItemHasChildren(item): + item = self._c['playlists'].PlaylistsTree.GetSelection() + if not self._c['playlists'].PlaylistsTree.ItemHasChildren(item): index = self._GetActiveFileIndex() else: index = 0 @@ -877,14 +694,14 @@ class HookeFrame(wx.Frame): #event.Skip() def OnPlaylistsLeftDown(self, event): - hit_item, hit_flags = self.panelPlaylists.PlaylistsTree.HitTest(event.GetPosition()) + hit_item, hit_flags = self._c['playlists'].PlaylistsTree.HitTest(event.GetPosition()) if (hit_flags & wx.TREE_HITTEST_ONITEM) != 0: - self.panelPlaylists.PlaylistsTree.SelectItem(hit_item) + self._c['playlists'].PlaylistsTree.SelectItem(hit_item) playlist_name = self.GetActivePlaylistName() playlist = self.GetActivePlaylist() #if a curve was clicked - item = self.panelPlaylists.PlaylistsTree.GetSelection() - if not self.panelPlaylists.PlaylistsTree.ItemHasChildren(item): + item = self._c['playlists'].PlaylistsTree.GetSelection() + if not self._c['playlists'].PlaylistsTree.ItemHasChildren(item): index = self._GetActiveFileIndex() if index >= 0: playlist.index = index @@ -902,15 +719,15 @@ class HookeFrame(wx.Frame): #playlist = self.playlists[self.GetActivePlaylistName()][0] #select the previous curve and tell the user if we wrapped around #self.AppendToOutput(playlist.previous()) - selected_item = self.panelPlaylists.PlaylistsTree.GetSelection() - if self.panelPlaylists.PlaylistsTree.ItemHasChildren(selected_item): - previous_item = self.panelPlaylists.PlaylistsTree.GetLastChild(selected_item) + selected_item = self._c['playlists'].PlaylistsTree.GetSelection() + if self._c['playlists'].PlaylistsTree.ItemHasChildren(selected_item): + previous_item = self._c['playlists'].PlaylistsTree.GetLastChild(selected_item) else: - previous_item = self.panelPlaylists.PlaylistsTree.GetPrevSibling(selected_item) + previous_item = self._c['playlists'].PlaylistsTree.GetPrevSibling(selected_item) if not previous_item.IsOk(): - parent_item = self.panelPlaylists.PlaylistsTree.GetItemParent(selected_item) - previous_item = self.panelPlaylists.PlaylistsTree.GetLastChild(parent_item) - self.panelPlaylists.PlaylistsTree.SelectItem(previous_item, True) + parent_item = self._c['playlists'].PlaylistsTree.GetItemParent(selected_item) + previous_item = self._c['playlists'].PlaylistsTree.GetLastChild(parent_item) + self._c['playlists'].PlaylistsTree.SelectItem(previous_item, True) playlist = self.GetActivePlaylist() if playlist.count > 1: playlist.previous() @@ -922,10 +739,10 @@ class HookeFrame(wx.Frame): prop = event.GetProperty() if prop: item_section = self.panelProperties.SelectedTreeItem - item_plugin = self.panelCommands.CommandsTree.GetItemParent(item_section) - plugin = self.panelCommands.CommandsTree.GetItemText(item_plugin) - config = self.configs[plugin] - property_section = self.panelCommands.CommandsTree.GetItemText(item_section) + 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() @@ -968,10 +785,11 @@ class HookeFrame(wx.Frame): else: done = True - perspective = self._mgr.SavePerspective() + perspective = self._c['manager'].SavePerspective() self._SavePerspectiveToFile(name, perspective) - self.config['perspectives']['active'] = name - self.UpdatePerspectivesMenu() + self.gui.config['active perspectives'] = name + self._c['menu bar']['perspectives'].update( + sorted(self._perspectives.keys), name) # if nameExists(name): # #check the corresponding menu item # menu_item = self.GetPerspectiveMenuItem(name) @@ -1011,25 +829,25 @@ class HookeFrame(wx.Frame): section = '' #deregister/register the listener to avoid infinite loop evtmgr.eventManager.DeregisterListener(self.OnTreeCtrlCommandsSelectionChanged) - self.panelCommands.CommandsTree.SelectItem(selected_item) - evtmgr.eventManager.Register(self.OnTreeCtrlCommandsSelectionChanged, wx.EVT_TREE_SEL_CHANGED, self.panelCommands.CommandsTree) + self._c['commands']._c['tree'].SelectItem(selected_item) + evtmgr.eventManager.Register(self.OnTreeCtrlCommandsSelectionChanged, wx.EVT_TREE_SEL_CHANGED, self._c['commands']._c['tree']) self.panelProperties.SelectedTreeItem = selected_item #if a command was clicked properties = [] - if not self.panelCommands.CommandsTree.ItemHasChildren(selected_item): - item_plugin = self.panelCommands.CommandsTree.GetItemParent(selected_item) - plugin = self.panelCommands.CommandsTree.GetItemText(item_plugin) - if self.configs.has_key(plugin): - #config = self.panelCommands.CommandsTree.GetPyData(item_plugin) - config = self.configs[plugin] - section = self.panelCommands.CommandsTree.GetItemText(selected_item) + if not self._c['commands']._c['tree'].ItemHasChildren(selected_item): + item_plugin = self._c['commands']._c['tree'].GetItemParent(selected_item) + plugin = self._c['commands']._c['tree'].GetItemText(item_plugin) + if self.gui.config.has_key(plugin): + #config = self._c['commands']._c['tree'].GetPyData(item_plugin) + config = self.gui.config[plugin] + section = self._c['commands']._c['tree'].GetItemText(selected_item) #display docstring in help window doc_string = eval('self.do_' + section + '.__doc__') if section in config: for option in config[section]: properties.append([option, config[section][option]]) else: - plugin = self.panelCommands.CommandsTree.GetItemText(selected_item) + plugin = self._c['commands']._c['tree'].GetItemText(selected_item) if plugin != 'core': doc_string = eval('plugins.' + plugin + '.' + plugin + 'Commands.__doc__') else: @@ -1038,10 +856,10 @@ class HookeFrame(wx.Frame): self.panelAssistant.ChangeValue(doc_string) else: self.panelAssistant.ChangeValue('') - panels.propertyeditor.PropertyEditor.Initialize(self.panelProperties, properties) + panel.propertyeditor.PropertyEditor.Initialize(self.panelProperties, properties) #save the currently selected command/plugin to the config file - self.config['command']['command'] = section - self.config['command']['plugin'] = plugin + self.gui.config['command']['command'] = section + self.gui.config['command']['plugin'] = plugin def OnTreeCtrlItemActivated(self, event): self.OnExecute(event) @@ -1058,13 +876,13 @@ class HookeFrame(wx.Frame): menu_item = self.MenuBar.FindItemById(menu_id) menu_label = menu_item.GetLabel() - pane = self._mgr.GetPane(menu_label) + pane = self._c['manager'].GetPane(menu_label) pane.Show(not pane.IsShown()) #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._mgr.Update() + self._c['manager'].Update() def _clickize(self, xvector, yvector, index): ''' @@ -1076,14 +894,14 @@ class HookeFrame(wx.Frame): point.find_graph_coords(xvector, yvector) return point - def _delta(self, message='Click 2 points', whatset=lh.RETRACTION): + 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, whatset=whatset) + clicked_points = self._measure_N_points(N=2, message=message, block=block) plot = self.GetDisplayedPlotCorrected() - curve = plot.curves[whatset] + curve = plot.curves[block] delta = lib.delta.Delta() delta.point1.x = clicked_points[0].graph_coords[0] @@ -1095,7 +913,7 @@ class HookeFrame(wx.Frame): return delta - def _measure_N_points(self, N, message='', whatset=lh.RETRACTION): + def _measure_N_points(self, N, message='', block=0): ''' General helper function for N-points measurements By default, measurements are done on the retraction @@ -1106,8 +924,8 @@ class HookeFrame(wx.Frame): figure = self.GetActiveFigure() - xvector = self.displayed_plot.curves[whatset].x - yvector = self.displayed_plot.curves[whatset].y + xvector = self.displayed_plot.curves[block].x + yvector = self.displayed_plot.curves[block].y clicked_points = figure.ginput(N, timeout=-1, show_clicks=True) @@ -1204,10 +1022,10 @@ class HookeFrame(wx.Frame): if active_file is not None: self.panelNote.Editor.SetValue(active_file.note) - def UpdatePerspectivesMenu(self): - #add perspectives to menubar and _perspectives - perspectivesDirectory = os.path.join(lh.hookeDir, 'perspectives') + def _update_perspectives(self): + # add perspectives to menubar and _perspectives self._perspectives = {} + return # TODO: cleanup if os.path.isdir(perspectivesDirectory): perspectiveFileNames = os.listdir(perspectivesDirectory) for perspectiveFilename in perspectiveFileNames: @@ -1223,34 +1041,20 @@ class HookeFrame(wx.Frame): #in case there are no perspectives if not self._perspectives: - perspective = self._mgr.SavePerspective() + perspective = self._c['manager'].SavePerspective() self._perspectives['Default'] = perspective self._SavePerspectiveToFile('Default', perspective) - selected_perspective = self.config['perspectives']['active'] + selected_perspective = self.gui.config['active perspective'] if not self._perspectives.has_key(selected_perspective): - self.config['perspectives']['active'] = 'Default' + self.gui.config['active perspective'] = 'Default' selected_perspective = 'Default' - perspectives_list = [key for key, value in self._perspectives.iteritems()] - perspectives_list.sort() - - #get the Perspectives menu - menu_position = self.MenuBar.FindMenu('Perspectives') - menu = self.MenuBar.GetMenu(menu_position) - #delete all menu items - for item in menu.GetMenuItems(): - menu.DeleteItem(item) - #rebuild the menu by adding the standard menu items - menu.Append(ID_SavePerspective, 'Save Perspective') - menu.Append(ID_DeletePerspective, 'Delete Perspective') - menu.AppendSeparator() - #add all previous perspectives - for index, label in enumerate(perspectives_list): - menu_item = menu.AppendRadioItem(ID_FirstPerspective + index, label) - if label == selected_perspective: - self._RestorePerspective(label) - menu_item.Check(True) + self._c['menu']._c['perspectives'].update( + sorted(self._perspectives.keys()), selected_perspective) + + self._RestorePerspective(selected_perspective) + def UpdatePlaylistsTreeSelection(self): playlist = self.GetActivePlaylist() @@ -1346,24 +1150,66 @@ class HookeFrame(wx.Frame): #refresh the plot figure.canvas.draw() -if __name__ == '__main__': - ## now, silence a deprecation warning for py2.3 - import warnings - warnings.filterwarnings("ignore", "integer", DeprecationWarning, "wxPython.gdi") - redirect = True - if __debug__: - redirect=False +class HookeApp (wx.App): + def __init__(self, gui, commands, inqueue, outqueue, *args, **kwargs): + self.gui = gui + self.commands = commands + self.inqueue = inqueue + self.outqueue = outqueue + super(HookeApp, self).__init__(*args, **kwargs) - app = Hooke(redirect=redirect) + def OnInit(self): + self.SetAppName('Hooke') + self.SetVendorName('') + self._setup_splash_screen() + + height = int(self.gui.config['main height']) # HACK: config should convert + width = int(self.gui.config['main width']) + top = int(self.gui.config['main top']) + left = int(self.gui.config['main left']) + + # Sometimes, the ini file gets confused and sets 'left' and + # 'top' to large negative numbers. Here we catch and fix + # this. Keep small negative numbers, the user might want + # those. + if left < -width: + left = 0 + if top < -height: + top = 0 + + self._c = { + 'frame': HookeFrame( + self.gui, self.commands, parent=None, title='Hooke', + pos=(left, top), size=(width, height), + style=wx.DEFAULT_FRAME_STYLE|wx.SUNKEN_BORDER|wx.CLIP_CHILDREN), + } + self._c['frame'].Show(True) + self.SetTopWindow(self._c['frame']) + return True - app.MainLoop() + def _setup_splash_screen(self): + if self.gui.config['show splash screen']: + path = self.gui.config['splash screen image'] + if os.path.isfile(path): + duration = int(self.gui.config['splash screen duration']) # HACK: config should decode types + wx.SplashScreen( + bitmap=wx.Image(path).ConvertToBitmap(), + splashStyle=wx.SPLASH_CENTRE_ON_SCREEN|wx.SPLASH_TIMEOUT, + milliseconds=duration, + parent=None) + wx.Yield() + # For some reason splashDuration and sleep do not + # correspond to each other at least not on Windows. + # Maybe it's because duration is in milliseconds and + # sleep in seconds. Thus we need to increase the + # sleep time a bit. A factor of 1.2 seems to work. + sleepFactor = 1.2 + time.sleep(sleepFactor * duration / 1000) -from ..command import CommandExit, Exit, Command, Argument, StoreValue -from ..interaction import Request, BooleanRequest, ReloadUserInterfaceConfig -from ..ui import UserInterface, CommandMessage -from ..util.encoding import get_input_encoding, get_output_encoding + def OnExit(self): + return True class GUI (UserInterface): @@ -1380,17 +1226,63 @@ class GUI (UserInterface): Setting(section=self.setting_section, help=self.__doc__) """ - return [] - - def reload_config(self): - pass + return [ + Setting(section=self.setting_section, help=self.__doc__), + Setting(section=self.setting_section, option='icon image', + value=os.path.join('doc', 'img', 'microscope.ico'), + help='Path to the hooke icon image.'), + Setting(section=self.setting_section, option='show splash screen', + value=True, + help='Enable/disable the splash screen'), + Setting(section=self.setting_section, option='splash screen image', + value=os.path.join('doc', 'img', 'hooke.jpg'), + help='Path to the Hooke splash screen image.'), + Setting(section=self.setting_section, option='splash screen duration', + value=1000, + help='Duration of the splash screen in milliseconds.'), + Setting(section=self.setting_section, option='perspective-path', + value=os.path.join('resources', 'gui', 'perspectives'), + help='Directory containing perspective files.'), # TODO: allow colon separated list, like $PATH. + Setting(section=self.setting_section, option='folders-workdir', + value='.', + help='This should probably go...'), + Setting(section=self.setting_section, option='folders-filters', + value='.', + help='This should probably go...'), + Setting(section=self.setting_section, option='active perspective', + value='Default', + help='Name of active perspective file (or "Default").'), + Setting(section=self.setting_section, option='folders-filter-index', + value='0', + help='This should probably go...'), + Setting(section=self.setting_section, option='main height', + value=500, + help='Height of main window in pixels.'), + Setting(section=self.setting_section, option='main width', + value=500, + help='Width of main window in pixels.'), + Setting(section=self.setting_section, option='main top', + value=0, + help='Pixels from screen top to top of main window.'), + Setting(section=self.setting_section, option='main left', + value=0, + help='Pixels from screen left to left of main window.'), + Setting(section=self.setting_section, option='selected command', + value='load playlist', + help='Name of the initially selected command.'), + ] + + def _app(self, commands, ui_to_command_queue, command_to_ui_queue): + redirect = True + if __debug__: + redirect=False + app = HookeApp(gui=self, + commands=commands, + inqueue=ui_to_command_queue, + outqueue=command_to_ui_queue, + redirect=redirect) + return app def run(self, commands, ui_to_command_queue, command_to_ui_queue): - self._initialize() - cmd = self._cmd(commands, ui_to_command_queue, command_to_ui_queue) - cmd.cmdloop(self._splash_text()) - - def run_lines(self, commands, ui_to_command_queue, command_to_ui_queue, - lines): - raise NotImplementedError( - 'Use the command line interface for run_lines()') + app = self._app(commands, ui_to_command_queue, command_to_ui_queue) + app.MainLoop() diff --git a/hooke/ui/gui/panel/__init__.py b/hooke/ui/gui/panel/__init__.py index 26664e8..c5a77e6 100644 --- a/hooke/ui/gui/panel/__init__.py +++ b/hooke/ui/gui/panel/__init__.py @@ -1,12 +1,12 @@ # Copyright -import .commands as commands -import .note as note -import .perspectives as perspectives -import .playlist as playlist -import .plot as plot -import .propertyeditor as propertyeditor -import .results as results +from . import commands as commands +from . import note as note +from . import playlist as playlist +from . import plot as plot +#from . import propertyeditor as propertyeditor +from . import results as results +from . import selection as selection -__all__ = [commands, note, perspectives, playlist, plot, propertyeditor, - results] +__all__ = [commands, note, playlist, plot, #propertyeditor, + results, selection] diff --git a/hooke/ui/gui/panel/commands.py b/hooke/ui/gui/panel/commands.py index 52db8a4..d26d5b0 100644 --- a/hooke/ui/gui/panel/commands.py +++ b/hooke/ui/gui/panel/commands.py @@ -1,93 +1,76 @@ #!/usr/bin/env python -''' -commands.py +"""Commands and settings panel for Hooke. +""" -Commands and settings panel for Hooke. - -Copyright 2009 by Dr. Rolf Schmidt (Concordia University, Canada) - -This program is released under the GNU General Public License version 2. -''' - -from configobj import ConfigObj import os.path -import wx - -import lib.libhooke as lh -class Commands(wx.Panel): - - def __init__(self, parent): - # Use the WANTS_CHARS style so the panel doesn't eat the Return key. - wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS|wx.NO_BORDER, size=(160, 200)) - - self.CommandsTree = wx.TreeCtrl(self, -1, wx.Point(0, 0), wx.Size(160, 250), wx.TR_DEFAULT_STYLE|wx.NO_BORDER|wx.TR_HIDE_ROOT) - imglist = wx.ImageList(16, 16, True, 2) - imglist.Add(wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, wx.Size(16, 16))) - imglist.Add(wx.ArtProvider.GetBitmap(wx.ART_EXECUTABLE_FILE, wx.ART_OTHER, wx.Size(16, 16))) - self.CommandsTree.AssignImageList(imglist) - self.CommandsTree.AddRoot('Commands and Settings', 0) +import wx - self.ExecuteButton = wx.Button(self, -1, 'Execute') +class Tree (wx.TreeCtrl): + def __init__(self, commands, selected, *args, **kwargs): + super(Tree, self).__init__(*args, **kwargs) + imglist = wx.ImageList(width=16, height=16, mask=True, initialCount=2) + imglist.Add(wx.ArtProvider.GetBitmap( + wx.ART_FOLDER, wx.ART_OTHER, wx.Size(16, 16))) + imglist.Add(wx.ArtProvider.GetBitmap( + wx.ART_EXECUTABLE_FILE, wx.ART_OTHER, wx.Size(16, 16))) + self.AssignImageList(imglist) + self.image = { + 'root': 0, + 'plugin': 0, + 'command': 1, + } + self.AddRoot(text='Commands and Settings', image=self.image['root']) + + self._setup_commands(commands, selected) + + def _setup_commands(self, commands, selected): + self._commands = commands + selected = None + tree_root = self.GetRootItem() + + plugin_roots = {} + plugins = sorted(set([c.plugin for c in commands]), + key=lambda p:p.name) + for plugin in plugins: + plugin_roots[plugin.name] = self.AppendItem( + parent=tree_root, + text=plugin.name, + image=self.image['plugin'], + data=wx.TreeItemData(plugin)) + + for command in sorted(commands, key=lambda c:c.name): + item = self.AppendItem( + parent=plugin_roots[command.plugin.name], + text=command.name, + image=self.image['command']) + if command.name == selected: + selected = item + for key,value in plugin_roots.items(): + self.Expand(value) + #make sure the selected command/plugin is visible in the tree + if selected is not None: + self.SelectItem(selected, True) + self.EnsureVisible(selected) + + +class Commands (wx.Panel): + def __init__(self, commands, selected, *args, **kwargs): + super(Commands, self).__init__(*args, **kwargs) + self._c = { + 'tree': Tree( + commands=commands, + selected=selected, + parent=self, + pos=wx.Point(0, 0), + size=wx.Size(160, 250), + style=wx.TR_DEFAULT_STYLE|wx.NO_BORDER|wx.TR_HIDE_ROOT), + 'execute': wx.Button(self, label='Execute'), + } sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(self.CommandsTree, 1, wx.EXPAND) - sizer.Add(self.ExecuteButton, 0, wx.EXPAND) - + sizer.Add(self._c['execute'], 0, wx.EXPAND) + sizer.Add(self._c['tree'], 1, wx.EXPAND) self.SetSizer(sizer) sizer.Fit(self) - - def Initialize(self, plugins): - selected = None - tree_root = self.CommandsTree.GetRootItem() - path = lh.get_file_path('hooke.ini', ['config']) - config = ConfigObj() - if os.path.isfile(path): - config.filename = path - config.reload() - #get the selected command/plugin from the config file - command_str = config['command']['command'] - module_str = config['command']['plugin'] - - #sort the plugins into alphabetical order - plugins_list = [key for key, value in plugins.iteritems()] - plugins_list.sort() - for plugin in plugins_list: - filename = ''.join([plugin, '.ini']) - path = lh.get_file_path(filename, ['plugins']) - config = ConfigObj() - if os.path.isfile(path): - config.filename = path - config.reload() - #append the ini file to the plugin - plugin_root = self.CommandsTree.AppendItem(tree_root, plugin, 0, data=wx.TreeItemData(config)) - else: - plugin_root = self.CommandsTree.AppendItem(tree_root, plugin, 0) - #select the plugin according to the config file - if plugin == module_str: - selected = plugin_root - - #add all commands to the tree - for command in plugins[plugin]: - command_label = command.replace('do_', '') - #do not add the ini file to the command (we'll access the ini file of the plugin (ie parent) instead, see above) - item = self.CommandsTree.AppendItem(plugin_root, command_label, 1) - #select the command according to the config file - if plugin == module_str and command_label == command_str: - selected = item - #e = wx.MouseEvent() - #e.SetEventType(wx.EVT_LEFT_DOWN.typeId) - #e.SetEventObject(self.CommandsTree) - - ##e.SetSelection(page) - #self.Parent.OnTreeCtrlCommandsLeftDown(e) - #wx.PostEvent(self, e) - - #self.CommandsTree.SelectItem(item, True) - - self.CommandsTree.Expand(plugin_root) - #make sure the selected command/plugin is visible in the tree - if selected is not None: - self.CommandsTree.SelectItem(selected, True) - self.CommandsTree.EnsureVisible(selected) diff --git a/hooke/ui/gui/panel/note.py b/hooke/ui/gui/panel/note.py index 2257d88..ff92cfe 100644 --- a/hooke/ui/gui/panel/note.py +++ b/hooke/ui/gui/panel/note.py @@ -1,14 +1,8 @@ #!/usr/bin/env python -''' -note.py +"""Note panel for Hooke. +""" -Note panel for Hooke. - -Copyright 2010 by Dr. Rolf Schmidt (Concordia University, Canada) - -This program is released under the GNU General Public License version 2. -''' import wx class Note(wx.Panel): diff --git a/hooke/ui/gui/panel/perspectives.py b/hooke/ui/gui/panel/perspectives.py deleted file mode 100644 index 75eab72..0000000 --- a/hooke/ui/gui/panel/perspectives.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python - -''' -perspectives.py - -Perspectives panel for deletion. - -Copyright 2010 by Dr. Rolf Schmidt (Concordia University, Canada) - -This program is released under the GNU General Public License version 2. -''' - -from os import remove -import wx - -import lib.libhooke as lh - -class Perspectives(wx.Dialog): - - def __init__(self, parent, ID, title): - wx.Dialog.__init__(self, parent, ID, title, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) - - # contents - sizer_vertical = wx.BoxSizer(wx.VERTICAL) - - message_str = "\nPlease check the perspectives\n\nyou want to delete and click 'Delete'.\n" - text = wx.StaticText(self, -1, message_str, wx.DefaultPosition, style=wx.ALIGN_CENTRE) - sizer_vertical.Add(text, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - - perspectives_list = [item[0] for item in self.Parent._perspectives.items() if item[0] != 'Default'] - perspectives_list.sort() - listbox = wx.CheckListBox(self, -1, wx.DefaultPosition, wx.Size(175, 200), perspectives_list) - self.Bind(wx.EVT_CHECKLISTBOX, self.EvtCheckListBox, listbox) - listbox.SetSelection(0) - sizer_vertical.Add(listbox, 1, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - self.listbox = listbox - - horizontal_line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL) - sizer_vertical.Add(horizontal_line, 0, wx.GROW, 5) - - sizer_buttons = wx.BoxSizer(wx.HORIZONTAL) - - button_delete = wx.Button(self, wx.ID_DELETE) - self.Bind(wx.EVT_BUTTON, self.OnButtonDelete, button_delete) - button_delete.SetDefault() - sizer_buttons.Add(button_delete, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - - button_close = wx.Button(self, wx.ID_CLOSE) - self.Bind(wx.EVT_BUTTON, self.OnButtonClose, button_close) - sizer_buttons.Add(button_close, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - - sizer_vertical.Add(sizer_buttons, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5) - - self.SetSizer(sizer_vertical) - sizer_vertical.Fit(self) - - def EvtCheckListBox(self, event): - index = event.GetSelection() - self.listbox.SetSelection(index) # so that (un)checking also selects (moves the highlight) - - def OnButtonClose(self, event): - self.EndModal(wx.ID_CLOSE) - - def OnButtonDelete(self, event): - items = self.listbox.GetItems() - selected_perspective = self.Parent.config['perspectives']['active'] - for index in reversed(self.listbox.GetChecked()): - self.listbox.Delete(index) - if items[index] == selected_perspective: - self.Parent.config['perspectives']['active'] = 'Default' - - filename = lh.get_file_path(items[index] + '.txt', ['perspectives']) - remove(filename) diff --git a/hooke/ui/gui/panel/playlist.py b/hooke/ui/gui/panel/playlist.py index 3868a4f..022950d 100644 --- a/hooke/ui/gui/panel/playlist.py +++ b/hooke/ui/gui/panel/playlist.py @@ -1,18 +1,11 @@ -#!/usr/bin/env python +# Copyright -''' -playlist.py - -Playlist panel for Hooke. - -Copyright 2009 by Dr. Rolf Schmidt (Concordia University, Canada) - -This program is released under the GNU General Public License version 2. -''' +"""Playlist panel for Hooke. +""" import wx -class Playlists(wx.Panel): +class Playlist(wx.Panel): def __init__(self, parent): # Use the WANTS_CHARS style so the panel doesn't eat the Return key. diff --git a/hooke/ui/gui/panel/plot.py b/hooke/ui/gui/panel/plot.py index 7a1515e..b1c7f78 100644 --- a/hooke/ui/gui/panel/plot.py +++ b/hooke/ui/gui/panel/plot.py @@ -1,25 +1,16 @@ -#!/usr/bin/env python +# Copyright -''' -plot.py - -Plot panel for Hooke. - -Copyright 2009 by Dr. Rolf Schmidt (Concordia University, Canada) - -This program is released under the GNU General Public License version 2. -''' +"""Plot panel for Hooke. +""" from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas - from matplotlib.backends.backend_wx import NavigationToolbar2Wx - from matplotlib.figure import Figure import wx -#there are many comments in here from the demo app -#they should come in handy to expand the functionality in the future +# There are many comments in here from the demo app. +# They should come in handy to expand the functionality in the future. class HookeCustomToolbar(NavigationToolbar2Wx): diff --git a/hooke/ui/gui/panel/propertyeditor.py b/hooke/ui/gui/panel/propertyeditor.py index 40eecaf..edf0968 100644 --- a/hooke/ui/gui/panel/propertyeditor.py +++ b/hooke/ui/gui/panel/propertyeditor.py @@ -1,50 +1,35 @@ -#!/usr/bin/env python +# Copyright -''' -propertyeditor.py - -Property editor panel for Hooke. - -Copyright 2009 by Dr. Rolf Schmidt (Concordia University, Canada) - -This program is released under the GNU General Public License version 2. -''' +"""Property editor panel for Hooke. +""" import sys import os.path import wx import wx.propgrid as wxpg -#import wx.stc -from string import split -#there are many comments and code fragments in here from the demo app -#they should come in handy to expand the functionality in the future +# There are many comments and code fragments in here from the demo app. +# They should come in handy to expand the functionality in the future. -class Display: +class Display (object): property_descriptor = [] def __init__(self): pass - -class ValueObject: +class ValueObject (object): def __init__(self): pass -class IntProperty2(wxpg.PyProperty): - """\ - This is a simple re-implementation of wxIntProperty. +class IntProperty2 (wxpg.PyProperty): + """This is a simple re-implementation of wxIntProperty. """ def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=0): wxpg.PyProperty.__init__(self, label, name) self.SetValue(value) def GetClassName(self): - """\ - This is not 100% necessary and in future is probably going to be - automated to return class name. - """ return "IntProperty2" def GetEditor(self): diff --git a/hooke/ui/gui/panel/results.py b/hooke/ui/gui/panel/results.py index c53de11..1588dbd 100644 --- a/hooke/ui/gui/panel/results.py +++ b/hooke/ui/gui/panel/results.py @@ -1,16 +1,10 @@ -#!/usr/bin/env python +# Copyright -''' -results.py - -Fitting results panel for Hooke. - -Copyright 2009 by Dr. Rolf Schmidt (Concordia University, Canada) - -This program is released under the GNU General Public License version 2. -''' +"""Fitting results panel for Hooke. +""" import sys + import wx from wx.lib.mixins.listctrl import CheckListCtrlMixin diff --git a/hooke/ui/gui/panel/selection.py b/hooke/ui/gui/panel/selection.py new file mode 100644 index 0000000..4979ad4 --- /dev/null +++ b/hooke/ui/gui/panel/selection.py @@ -0,0 +1,86 @@ +# Copyright + +"""Selection dialog. +""" + +from os import remove + +import wx + + +class Selection (wx.Dialog): + """A selection dialog box. + + Lists options and two buttons. The first button is setup by the + caller. The second button cancels the dialog. + + The button appearance can be specified by selecting one of the + `standard wx IDs`_. + + .. _standard wx IDs: + http://docs.wxwidgets.org/stable/wx_stdevtid.html#stdevtid + """ + def __init__(self, options, message, button_id, button_callback, *args, **kwargs): + super(Selection, self).__init__(*args, **kwargs) + + self._button_callback = button_callback + + self._c = { + 'text': wx.StaticText( + parent=self, label=message, style=wx.ALIGN_CENTRE), + 'listbox': wx.CheckListBox( + parent=self, size=wx.Size(175, 200), list=options), + 'button': wx.Button(parent=self, id=button_id), + 'cancel': wx.Button(self, wx.ID_CANCEL), + } + self.Bind(wx.EVT_CHECKLISTBOX, self._on_check, self._c['listbox']) + self.Bind(wx.EVT_BUTTON, self._on_button, self._c['button']) + self.Bind(wx.EVT_BUTTON, self._on_cancel, self._c['cancel']) + + border_width = 5 + + b = wx.BoxSizer(wx.HORIZONTAL) + b.Add(window=self._c['button'], + flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, + border=border_width) + b.Add(window=self._c['cancel'], + flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, + border=border_width) + + v = wx.BoxSizer(wx.VERTICAL) + v.Add(window=self._c['text'], + flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, + border=border_width) + v.Add(window=self._c['listbox'], + proportion=1, + flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, + border=border_width) + v.Add(window=wx.StaticLine( + parent=self, size=(20,-1), style=wx.LI_HORIZONTAL), + flag=wx.GROW, + border=border_width) + v.Add(window=b, + flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, + border=border_width) + self.SetSizer(v) + v.Fit(self) + + def _on_check(self, event): + """Refocus on the first checked item. + """ + index = event.GetSelection() + self.listbox.SetSelection(index) + + def _on_cancel(self, event): + """Close the dialog. + """ + self.EndModal(wx.ID_CANCEL) + + def _on_button(self, event): + """Call ._button_callback() and close the dialog. + """ + self._button_callback( + event=event, + items=self._c['listbox'].GetItems(), + selected_items=self._c['listbox'].GetChecked()) + self.EndModal(wx.ID_CLOSE)