diff --git a/fsl/fsleyes/frame.py b/fsl/fsleyes/frame.py index fa25c8afe35d2c5da7fca10462e42e9a9bd2da28..ea6675c3d4412f6bc566897a1470f7746b5d2461 100644 --- a/fsl/fsleyes/frame.py +++ b/fsl/fsleyes/frame.py @@ -86,7 +86,8 @@ class FSLEyesFrame(wx.Frame): parent, overlayList, displayCtx, - restore=False): + restore=False, + save=True): """Create a ``FSLEyesFrame``. .. note:: The ``restore`` functionality is not currently implemented. @@ -101,6 +102,8 @@ class FSLEyesFrame(wx.Frame): :arg restore: Restores previous saved layout. If ``False``, no view panels will be displayed. + + :arg save: Save current layout when closed. """ wx.Frame.__init__(self, parent, title='FSLeyes') @@ -163,10 +166,7 @@ class FSLEyesFrame(wx.Frame): self.__makeMenuBar() self.__restoreState(restore) - # If we have not restored the previous - # layout, we are not going to save the - # layout on exit. - self.__saveLayout = restore + self.__saveLayout = save self.__auiManager.Bind(aui.EVT_AUI_PANE_CLOSE, self.__onViewPanelClose) self .Bind(wx.EVT_CLOSE, self.__onClose) @@ -468,6 +468,11 @@ class FSLEyesFrame(wx.Frame): size = self.GetSize().Get() position = self.GetScreenPosition().Get() layout = perspectives.serialisePerspective(self) + + + log.debug('Saving size: {}' .format(size)) + log.debug('Saving position: {}'.format(position)) + log.debug('Saving layout: {}' .format(layout)) fslsettings.write('framesize', str(size)) fslsettings.write('frameposition', str(position)) @@ -592,6 +597,7 @@ class FSLEyesFrame(wx.Frame): if layout is None: perspectives.loadPerspective(self, 'default') else: + log.debug('Restoring previous layout: {}'.format(layout)) perspectives.applyPerspective( self, 'framelayout', diff --git a/fsl/fsleyes/fsleyes_parseargs.py b/fsl/fsleyes/fsleyes_parseargs.py index 7d67acf4d61c0006a326181bfbec87a471c979ba..83be91f828c5df8679f7cd751ac12e019ba71427 100644 --- a/fsl/fsleyes/fsleyes_parseargs.py +++ b/fsl/fsleyes/fsleyes_parseargs.py @@ -416,14 +416,14 @@ defines descriptions for ecah command line group. # Descriptions for each group GROUPDESCS = td.TypeDict({ - 'SceneOpts' : 'These settings are only applied if the \'--scene\' ' - 'option is set to \'lightbox\' or \'ortho\'.', + 'SceneOpts' : 'These settings are applied to every ' + 'orthographic and lightbox view.', - 'OrthoOpts' : 'These settings are only applied if the \'--scene\' ' - 'option is set to \'ortho\'.', + 'OrthoOpts' : 'These settings are applied to every ' + 'ortho view.', - 'LightBoxOpts' : 'These settings are only applied if the \'--scene\' ' - 'option is set to \'lightbox\'.', + 'LightBoxOpts' : 'These settings are applied to every ' + 'lightbox view.', 'Display' : 'Each display option will be applied to the ' 'overlay which is listed before that option. ' diff --git a/fsl/fsleyes/perspectives.py b/fsl/fsleyes/perspectives.py index 5c1e83d4b4024963873db200858b4b4dd63de896..6ddda36fc0c00f113e3f334cfa4044aa20e5c653 100644 --- a/fsl/fsleyes/perspectives.py +++ b/fsl/fsleyes/perspectives.py @@ -252,7 +252,32 @@ def serialisePerspective(frame): # AuiManager, and makes sure that the order of the # child pane layout specifications in the string is # the same as the order of the children in the list. - def patchLayoutString(auiMgr, panels): + # + # If the 'rename' argument is True, this function + # performs an additional step. + # + # The FSLEyesFrame gives each of its view panels a + # unique name of the form "ClassName index", where + # the 'index' is a sequentially increasing identifier + # number (so that multiple views of the same type can + # be differentiated). If the 'rename' argument to + # this function is True, these names are adjusted so + # that they begin at 1 and increase sequentially. This + # is done by the patchPanelName function, defined + # below. + # + # This name adjustment is required to handle + # situations where the indices of existing view panels + # are not sequential, as when a layout is applied, the + # view panel names given by the FSLEyesFrame must + # match the names that are specified in the layout + # perspective string. + # + # In addition to patching the name of each panel, + # the 'rename' argument will also cause the panel + # caption (its display title) to be adjusted so that + # it is in line with the name. + def patchLayoutString(auiMgr, panels, rename=False): layoutStr = auiMgr.SavePerspective() @@ -276,12 +301,48 @@ def serialisePerspective(frame): pi += 1 sections[si] = panelLayout + if rename: + sections[si] = patchPanelName(sections[si], pi) + # Now the panel layouts in our layout string # are in the same order as our list of view # panels - we can re-join the layout string # sections, and we're done. return '|'.join(sections) + '|' + # The purpose of this function is described above. + def patchPanelName(layoutString, index): + # In each AUI layout section, 'key=value' + # pairs are separated with a semi-colon + kvps = layoutString.split(';') + + # And each 'key=value' pair is separated + # with an equals character + kvps = [kvp.split('=') for kvp in kvps] + kvps = collections.OrderedDict(kvps) + + # We need to update the indices contained + # in the 'name' and 'caption' values + name = kvps['name'] + caption = kvps['caption'] + + # Strip off the old index + name = ' '.join(name .split()[:-1]) + caption = ' '.join(caption.split()[:-1]) + + # Patch in the new index + name = '{} {}'.format(name, index) + caption = '{} {}'.format(caption, index) + + kvps['name'] = name + kvps['caption'] = caption + + # Reconstruct the layout string + kvps = ['='.join((k, v)) for k, v in kvps.items()] + kvps = ';'.join(kvps) + + return kvps + # Now we can start extracting the layout information. # We start with the FSLEyesFrame layout. auiMgr = frame.getAuiManager() @@ -289,7 +350,7 @@ def serialisePerspective(frame): # Generate the frame layout string, and a # list of the children of the frame - frameLayout = patchLayoutString(auiMgr, viewPanels) + frameLayout = patchLayoutString(auiMgr, viewPanels, True) frameChildren = [type(vp).__name__ for vp in viewPanels] frameChildren = ','.join(frameChildren) diff --git a/fsl/tools/fsleyes.py b/fsl/tools/fsleyes.py index 3c7aa894d006a1e8a3946d627ac684b8665480f3..bf9aa73afab04279f3dd11d0ea51f7290aa4d458 100644 --- a/fsl/tools/fsleyes.py +++ b/fsl/tools/fsleyes.py @@ -178,14 +178,16 @@ def interface(parent, args, ctx): # If a scene or perspective has not been # specified, the default behaviour is to - # restore the previous frame layout. - if args.scene is None and args.perspective is None: restore = True - else: restore = False + # restore the previous frame layout. And + # if a scene is specified, the layout is + # not saved on exit. + restore = args.scene is None and args.perspective is None + save = args.scene is None status.update('Creating FSLeyes interface...') frame = fsleyesframe.FSLEyesFrame( - parent, overlayList, displayCtx, restore) + parent, overlayList, displayCtx, restore, save) # Make sure the new frame is shown # before destroying the splash screen