From 1e404801b2424be634ecd4ebd4856e03357f4262 Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauld.mccarthy@gmail.com> Date: Mon, 20 Jul 2015 17:53:42 +0100 Subject: [PATCH] Re-vamped overlay display panel so it now uses the WidgetList. --- fsl/data/strings.py | 20 +- fsl/fslview/controls/overlaydisplaypanel.py | 242 ++++++++++++++------ fsl/fslview/controls/overlaylistpanel.py | 1 + fsl/fslview/gl/glvector.py | 2 +- fsl/fslview/layouts.py | 108 ++++----- 5 files changed, 236 insertions(+), 137 deletions(-) diff --git a/fsl/data/strings.py b/fsl/data/strings.py index 1c4526027..46a006691 100644 --- a/fsl/data/strings.py +++ b/fsl/data/strings.py @@ -257,6 +257,15 @@ labels = TypeDict({ 'ClusterPanel.addZStats' : 'Add Z statistics', 'ClusterPanel.addClusterMask' : 'Add cluster mask', + + + 'OverlayDisplayPanel.Display' : 'General display settings', + 'OverlayDisplayPanel.VolumeOpts' : 'Volume settings', + 'OverlayDisplayPanel.MaskOpts' : 'Mask settings', + 'OverlayDisplayPanel.LabelOpts' : 'Label settings', + 'OverlayDisplayPanel.RGBVectorOpts' : 'RGB vector settings', + 'OverlayDisplayPanel.LineVectorOpts' : 'Line vector settings', + 'OverlayDisplayPanel.ModelOpts' : 'Model settings', }) @@ -377,11 +386,12 @@ properties = TypeDict({ 'LineVectorOpts.directed' : 'Interpret vectors as directed', 'LineVectorOpts.lineWidth' : 'Line width', - 'ModelOpts.colour' : 'Colour', - 'ModelOpts.outline' : 'Show outline only', - 'ModelOpts.refImage' : 'Reference image', - 'ModelOpts.coordSpace' : 'Model coordinate space', - 'ModelOpts.showName' : 'Show model name', + 'ModelOpts.colour' : 'Colour', + 'ModelOpts.outline' : 'Show outline only', + 'ModelOpts.outlineWidth' : 'Outline width', + 'ModelOpts.refImage' : 'Reference image', + 'ModelOpts.coordSpace' : 'Model coordinate space', + 'ModelOpts.showName' : 'Show model name', 'LabelOpts.lut' : 'Look-up table', 'LabelOpts.outline' : 'Show outline only', diff --git a/fsl/fslview/controls/overlaydisplaypanel.py b/fsl/fslview/controls/overlaydisplaypanel.py index 1d6c4738a..ed3fc8363 100644 --- a/fsl/fslview/controls/overlaydisplaypanel.py +++ b/fsl/fslview/controls/overlaydisplaypanel.py @@ -14,13 +14,92 @@ import logging import wx import props +import pwidgets.widgetlist as widgetlist + +import fsl.utils.typedict as td +import fsl.data.strings as strings import fsl.fslview.panel as fslpanel -import fsl.fslview.displaycontext as fsldisplay -import overlayselectpanel as overlayselect +import fsl.fslview.displaycontext as displayctx + log = logging.getLogger(__name__) + +_DISPLAY_PROPS = td.TypeDict({ + 'Display' : [ + props.Widget('name'), + props.Widget('overlayType'), + props.Widget('enabled'), + props.Widget('alpha', showLimits=False), + props.Widget('brightness', showLimits=False), + props.Widget('contrast', showLimits=False)], + + 'VolumeOpts' : [ + props.Widget('resolution', showLimits=False), + props.Widget('transform'), + props.Widget('volume', showLimits=False), + props.Widget('interpolation'), + props.Widget('cmap'), + props.Widget('invert'), + props.Widget('invertClipping'), + props.Widget('displayRange', showLimits=False, slider=True), + props.Widget('clippingRange', showLimits=False, slider=True)], + + 'MaskOpts' : [ + props.Widget('resolution', showLimits=False), + props.Widget('transform'), + props.Widget('volume', showLimits=False), + props.Widget('colour'), + props.Widget('invert'), + props.Widget('threshold', showLimits=False)], + + 'RGBVectorOpts' : [ + props.Widget('resolution', showLimits=False), + props.Widget('transform'), + props.Widget('interpolation'), + props.Widget('xColour'), + props.Widget('yColour'), + props.Widget('zColour'), + props.Widget('suppressX'), + props.Widget('suppressY'), + props.Widget('suppressZ'), + props.Widget('modulate'), + props.Widget('modThreshold', showLimits=False, spin=False)], + + 'LineVectorOpts' : [ + props.Widget('resolution', showLimits=False), + props.Widget('transform'), + props.Widget('xColour'), + props.Widget('yColour'), + props.Widget('zColour'), + props.Widget('suppressX'), + props.Widget('suppressY'), + props.Widget('suppressZ'), + props.Widget('directed'), + props.Widget('lineWidth', showLimits=False), + props.Widget('modulate'), + props.Widget('modThreshold', showLimits=False, spin=False)], + + 'ModelOpts' : [ + props.Widget('colour'), + props.Widget('outline'), + props.Widget('outlineWidth', showLimits=False), + props.Widget('refImage'), + # props.Widget('showName'), + props.Widget('coordSpace', + enabledWhen=lambda o: o.refImage != 'none')], + + 'LabelOpts' : [ + props.Widget('lut'), + props.Widget('outline'), + props.Widget('outlineWidth', showLimits=False), + # props.Widget('showNames'), + props.Widget('resolution', showLimits=False), + props.Widget('transform'), + props.Widget('volume', showLimits=False)] +}) + class OverlayDisplayPanel(fslpanel.FSLViewPanel): @@ -28,40 +107,17 @@ class OverlayDisplayPanel(fslpanel.FSLViewPanel): """ """ - # TODO Ability to link properties across images - fslpanel.FSLViewPanel.__init__(self, parent, overlayList, displayCtx) - self.overlaySelect = overlayselect.OverlaySelectPanel( - self, overlayList, displayCtx) + self.__overlayName = wx.StaticText(self, style=wx.ALIGN_CENTRE) + self.__widgets = widgetlist.WidgetList(self) + self.__sizer = wx.BoxSizer(wx.VERTICAL) - self.propPanel = wx.ScrolledWindow(self) - self.propPanel.SetScrollRate(0, 5) - self.dispPanel = wx.Panel(self.propPanel) - self.optsPanel = wx.Panel(self.propPanel) + self.SetSizer(self.__sizer) - self.divider = wx.StaticLine( - self.propPanel, size=(-1, -1), style=wx.LI_HORIZONTAL) + self.__sizer.Add(self.__overlayName, flag=wx.EXPAND) + self.__sizer.Add(self.__widgets, flag=wx.EXPAND, proportion=1) - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.propSizer = wx.BoxSizer(wx.VERTICAL) - self.dispSizer = wx.BoxSizer(wx.VERTICAL) - self.optsSizer = wx.BoxSizer(wx.VERTICAL) - - self .SetSizer(self.sizer) - self.propPanel.SetSizer(self.propSizer) - self.dispPanel.SetSizer(self.dispSizer) - self.optsPanel.SetSizer(self.optsSizer) - - self.sizer.Add(self.overlaySelect, flag=wx.EXPAND) - self.sizer.Add(self.propPanel, flag=wx.EXPAND, proportion=1) - - flags = wx.EXPAND | wx.ALIGN_CENTRE | wx.ALL - - self.propSizer.Add(self.dispPanel, border=20, flag=flags) - self.propSizer.Add(self.divider, flag=flags) - self.propSizer.Add(self.optsPanel, border=20, flag=flags) - displayCtx .addListener('selectedOverlay', self._name, self.__selectedOverlayChanged) @@ -69,71 +125,108 @@ class OverlayDisplayPanel(fslpanel.FSLViewPanel): self._name, self.__selectedOverlayChanged) - self.__lastOverlay = None + self.__currentOverlay = None self.__selectedOverlayChanged() - self.propSizer.Layout() self.Layout() - - pSize = self.propSizer.GetMinSize().Get() - size = self.sizer .GetMinSize().Get() - self.SetMinSize((max(pSize[0], size[0]), max(pSize[1], size[1]) + 20)) + self.SetMinSize((100, 50)) def destroy(self): self._displayCtx .removeListener('selectedOverlay', self._name) self._overlayList.removeListener('overlays', self._name) - self.overlaySelect.destroy() - for ovl in self._overlayList: - display = self._displayCtx.getDisplay(ovl) + if self.__currentOverlay is not None and \ + self.__currentOverlay in self._overlayList: + + display = self._displayCtx.getDisplay(self.__currentOverlay) + opts = display.getDisplayOpts() + display.removeListener('overlayType', self._name) + display.removeListener('name', self._name) + if isinstance(opts, displayctx.VolumeOpts): + opts.removeListener('transform', self._name) + + self.__currentOverlay = None fslpanel.FSLViewPanel.destroy(self) def __selectedOverlayChanged(self, *a): overlay = self._displayCtx.getSelectedOverlay() - lastOverlay = self.__lastOverlay + lastOverlay = self.__currentOverlay if overlay is None: - self.__lastOverlay = None - self.dispPanel.DestroyChildren() - self.optsPanel.DestroyChildren() + self.__currentOverlay = None + self.__overlayName.SetLabel('') + self.__widgets.Clear() self.Layout() return if overlay is lastOverlay: return - if lastOverlay is not None: + self.__currentOverlay = overlay + + if lastOverlay is not None and \ + lastOverlay in self._overlayList: + lastDisplay = self._displayCtx.getDisplay(lastOverlay) lastOpts = lastDisplay.getDisplayOpts() + lastDisplay.removeListener('overlayType', self._name) + lastDisplay.removeListener('name', self._name) - if isinstance(lastOpts, fsldisplay.VolumeOpts): + if isinstance(lastOpts, displayctx.VolumeOpts): lastOpts.removeListener('transform', self._name) + if lastOverlay is not None: + displayExpanded = self.__widgets.IsExpanded('display') + optsExpanded = self.__widgets.IsExpanded('opts') + else: + displayExpanded = True + optsExpanded = True + display = self._displayCtx.getDisplay(overlay) opts = display.getDisplayOpts() - display.addListener('overlayType', - self._name, - self.__overlayTypeChanged) + display.addListener('overlayType', self._name, self.__ovlTypeChanged) + display.addListener('name', self._name, self.__ovlNameChanged) - if isinstance(opts, fsldisplay.VolumeOpts): + if isinstance(opts, displayctx.VolumeOpts): opts.addListener('transform', self._name, self.__transformChanged) - self.__lastOverlay = overlay - self.__updateProps(self.dispPanel, False) - self.__updateProps(self.optsPanel, True) + self.__widgets.Clear() + self.__widgets.AddGroup('display', strings.labels[self, display]) + self.__widgets.AddGroup('opts', strings.labels[self, opts]) - def __overlayTypeChanged(self, *a): - self.__updateProps(self.optsPanel, True) + self.__overlayName.SetLabel(display.name) + self.__updateWidgets(display, 'display') + self.__updateWidgets(opts, 'opts') + + self.__widgets.Expand('display', displayExpanded) + self.__widgets.Expand('opts', optsExpanded) + + self.Layout() + + + def __ovlNameChanged(self, *a): + + display = self._displayCtx.getDisplay(self.__currentOverlay) + self.__overlayName.SetLabel(display.name) + self.Layout() + + + def __ovlTypeChanged(self, *a): + + opts = self._displayCtx.getOpts(self.__currentOverlay) + self.__updateWidgets(opts, 'opts') + self.Layout() + def __transformChanged(self, *a): """Called when the transform setting of the currently selected overlay changes. @@ -147,7 +240,7 @@ class OverlayDisplayPanel(fslpanel.FSLViewPanel): display = self._displayCtx.getDisplay(overlay) opts = display.getDisplayOpts() - if not isinstance(opts, fsldisplay.VolumeOpts): + if not isinstance(opts, displayctx.VolumeOpts): return choices = opts.getProp('interpolation').getChoices(display) @@ -160,21 +253,24 @@ class OverlayDisplayPanel(fslpanel.FSLViewPanel): else: opts.interpolation = 'linear' - def __updateProps(self, parent, opts): - - import fsl.fslview.layouts as layouts - - overlay = self._displayCtx.getSelectedOverlay() - display = self._displayCtx.getDisplay(overlay) - - if opts: optObj = display.getDisplayOpts() - else: optObj = display - - parent.DestroyChildren() - - panel = props.buildGUI( - parent, optObj, view=layouts.layouts[self, optObj]) + def __updateWidgets(self, target, groupName): + + self.__widgets.ClearGroup(groupName) + + widgets = _DISPLAY_PROPS[target] + if isinstance(target, displayctx.RGBVectorOpts): + print 'bah' + labels = [strings.properties[target, w.key] for w in widgets] + widgets = [props.buildGUI(self.__widgets, + target, + w, + showUnlink=False) + for w in widgets] + + for label, widget in zip(labels, widgets): + self.__widgets.AddWidget( + widget, + label, + groupName=groupName) - parent.GetSizer().Add(panel, flag=wx.EXPAND, proportion=1) - panel .Layout() - parent.Layout() + self.Layout() diff --git a/fsl/fslview/controls/overlaylistpanel.py b/fsl/fslview/controls/overlaylistpanel.py index 76f44f211..530cc7d03 100644 --- a/fsl/fslview/controls/overlaylistpanel.py +++ b/fsl/fslview/controls/overlaylistpanel.py @@ -74,6 +74,7 @@ class ListItemWidget(wx.Panel): self.lockButton.Bind(wx.EVT_TOGGLEBUTTON, self.__onLockButton) self .Bind(wx.EVT_WINDOW_DESTROY, self.__onDestroy) + self.__overlayGroupChanged() self.__vizChanged() self.__saveStateChanged() diff --git a/fsl/fslview/gl/glvector.py b/fsl/fslview/gl/glvector.py index cdcb16091..d026d3457 100644 --- a/fsl/fslview/gl/glvector.py +++ b/fsl/fslview/gl/glvector.py @@ -253,7 +253,7 @@ class GLVector(globject.GLImageObject): modImage = self.displayOpts.modulate - if modImage == 'none': + if modImage is None or modImage == 'none': textureData = np.zeros((5, 5, 5), dtype=np.uint8) textureData[:] = 255 modImage = fslimage.Image(textureData) diff --git a/fsl/fslview/layouts.py b/fsl/fslview/layouts.py index 5797956db..d16cb5835 100644 --- a/fsl/fslview/layouts.py +++ b/fsl/fslview/layouts.py @@ -181,90 +181,82 @@ LabelOptsToolBarLayout = [ actions.ActionButton(OverlayDisplayToolBar, 'more')] -DisplayLayout = props.VGroup( - (widget(Display, 'name'), - widget(Display, 'overlayType'), - widget(Display, 'enabled'), - widget(Display, 'alpha', showLimits=False, editLimits=False), - widget(Display, 'brightness', showLimits=False, editLimits=False), - widget(Display, 'contrast', showLimits=False, editLimits=False))) - - -VolumeOptsLayout = props.VGroup( - (widget(VolumeOpts, 'resolution', showLimits=False), - widget(VolumeOpts, 'transform'), - widget(VolumeOpts, 'volume', showLimits=False), - widget(VolumeOpts, 'interpolation'), - widget(VolumeOpts, 'cmap'), - widget(VolumeOpts, 'invert'), - widget(VolumeOpts, 'invertClipping'), - widget(VolumeOpts, 'displayRange', showLimits=False, slider=True), - widget(VolumeOpts, 'clippingRange', showLimits=False, slider=True))) - - -MaskOptsLayout = props.VGroup( - (widget(MaskOpts, 'resolution', showLimits=False), - widget(MaskOpts, 'transform'), - widget(MaskOpts, 'volume', showLimits=False), - widget(MaskOpts, 'colour'), - widget(MaskOpts, 'invert'), - widget(MaskOpts, 'threshold', showLimits=False))) - - -RGBVectorOptsLayout = props.VGroup(( +DisplayLayout = [ + widget(Display, 'name'), + widget(Display, 'overlayType'), + widget(Display, 'enabled'), + widget(Display, 'alpha', showLimits=False, editLimits=False), + widget(Display, 'brightness', showLimits=False, editLimits=False), + widget(Display, 'contrast', showLimits=False, editLimits=False)] + + +VolumeOptsLayout = [ + widget(VolumeOpts, 'resolution', showLimits=False), + widget(VolumeOpts, 'transform'), + widget(VolumeOpts, 'volume', showLimits=False), + widget(VolumeOpts, 'interpolation'), + widget(VolumeOpts, 'cmap'), + widget(VolumeOpts, 'invert'), + widget(VolumeOpts, 'invertClipping'), + widget(VolumeOpts, 'displayRange', showLimits=False, slider=True), + widget(VolumeOpts, 'clippingRange', showLimits=False, slider=True)] + + +MaskOptsLayout = [ + widget(MaskOpts, 'resolution', showLimits=False), + widget(MaskOpts, 'transform'), + widget(MaskOpts, 'volume', showLimits=False), + widget(MaskOpts, 'colour'), + widget(MaskOpts, 'invert'), + widget(MaskOpts, 'threshold', showLimits=False)] + + +RGBVectorOptsLayout = [ widget(RGBVectorOpts, 'resolution', showLimits=False), widget(RGBVectorOpts, 'transform'), widget(RGBVectorOpts, 'interpolation'), - props.HGroup(( - widget(RGBVectorOpts, 'xColour'), - widget(RGBVectorOpts, 'yColour'), - widget(RGBVectorOpts, 'zColour')), - vertLabels=True), - props.HGroup(( - widget(RGBVectorOpts, 'suppressX'), - widget(RGBVectorOpts, 'suppressY'), - widget(RGBVectorOpts, 'suppressZ')), - vertLabels=True), + widget(RGBVectorOpts, 'xColour'), + widget(RGBVectorOpts, 'yColour'), + widget(RGBVectorOpts, 'zColour'), + widget(RGBVectorOpts, 'suppressX'), + widget(RGBVectorOpts, 'suppressY'), + widget(RGBVectorOpts, 'suppressZ'), widget(RGBVectorOpts, 'modulate'), - widget(RGBVectorOpts, 'modThreshold', showLimits=False, spin=False))) + widget(RGBVectorOpts, 'modThreshold', showLimits=False, spin=False)] -LineVectorOptsLayout = props.VGroup(( +LineVectorOptsLayout = [ widget(LineVectorOpts, 'resolution', showLimits=False), widget(LineVectorOpts, 'transform'), - props.HGroup(( - widget(LineVectorOpts, 'xColour'), - widget(LineVectorOpts, 'yColour'), - widget(LineVectorOpts, 'zColour')), - vertLabels=True), - props.HGroup(( - widget(LineVectorOpts, 'suppressX'), - widget(LineVectorOpts, 'suppressY'), - widget(LineVectorOpts, 'suppressZ')), - vertLabels=True), + widget(LineVectorOpts, 'xColour'), + widget(LineVectorOpts, 'yColour'), + widget(LineVectorOpts, 'zColour'), + widget(LineVectorOpts, 'suppressX'), + widget(LineVectorOpts, 'suppressY'), + widget(LineVectorOpts, 'suppressZ'), widget(LineVectorOpts, 'directed'), widget(LineVectorOpts, 'lineWidth', showLimits=False), widget(LineVectorOpts, 'modulate'), - widget(LineVectorOpts, 'modThreshold', showLimits=False, spin=False))) + widget(LineVectorOpts, 'modThreshold', showLimits=False, spin=False)] -ModelOptsLayout = props.VGroup(( +ModelOptsLayout = [ widget(ModelOpts, 'colour'), widget(ModelOpts, 'outline'), widget(ModelOpts, 'outlineWidth', showLimits=False), widget(ModelOpts, 'refImage'), # widget(ModelOpts, 'showName'), widget(ModelOpts, 'coordSpace', - visibleWhen=lambda o: o.refImage != 'none'))) + visibleWhen=lambda o: o.refImage != 'none')] -LabelOptsLayout = props.VGroup(( +LabelOptsLayout = [ widget(LabelOpts, 'lut'), widget(LabelOpts, 'outline'), widget(LabelOpts, 'outlineWidth', showLimits=False), # widget(LabelOpts, 'showNames'), widget(LabelOpts, 'resolution', showLimits=False), widget(LabelOpts, 'transform'), - widget(LabelOpts, 'volume', showLimits=False))) + widget(LabelOpts, 'volume', showLimits=False)] -- GitLab