From e46718dda5d3b64d67e1c8d391e9e956da18ce5c Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauld.mccarthy@gmail.com> Date: Thu, 26 Mar 2015 14:33:04 +0000 Subject: [PATCH] GLVolume code was assuming the presence of a 'clippingRange' property - was failing for GLMask types. Hack to make image display panel size more useful. DisplayOpts instances have a 'destroy' method, so listeners can be de-registered --- fsl/data/strings.py | 2 +- fsl/fslview/controls/imagedisplaypanel.py | 7 +++---- fsl/fslview/displaycontext/display.py | 7 +++++++ fsl/fslview/displaycontext/maskopts.py | 16 +++++++++++----- fsl/fslview/displaycontext/volumeopts.py | 6 ++++++ fsl/fslview/gl/glmask.py | 8 ++++---- fsl/fslview/layouts.py | 6 +++--- fsl/tools/fslview_parseargs.py | 14 +++++++------- 8 files changed, 42 insertions(+), 24 deletions(-) diff --git a/fsl/data/strings.py b/fsl/data/strings.py index 85d9f5ae9..d2b71fa42 100644 --- a/fsl/data/strings.py +++ b/fsl/data/strings.py @@ -203,7 +203,7 @@ properties = TypeDict({ 'MaskOpts.colour' : 'Colour', 'MaskOpts.invert' : 'Invert', - 'MaskOpts.threshold' : 'Threshold', + 'MaskOpts.clippingRange' : 'Threshold', 'VectorOpts.displayMode' : 'Display mode', 'VectorOpts.xColour' : 'X Colour', diff --git a/fsl/fslview/controls/imagedisplaypanel.py b/fsl/fslview/controls/imagedisplaypanel.py index 8e60c04ad..1581294fd 100644 --- a/fsl/fslview/controls/imagedisplaypanel.py +++ b/fsl/fslview/controls/imagedisplaypanel.py @@ -70,13 +70,12 @@ class ImageDisplayPanel(fslpanel.FSLViewPanel): self._lastImage = None self._selectedImageChanged() + 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]) / 4.0)) + self.SetMinSize((max(pSize[0], size[0]), max(pSize[1], size[1]) + 20)) def destroy(self): diff --git a/fsl/fslview/displaycontext/display.py b/fsl/fslview/displaycontext/display.py index ba4e18cee..81367cac7 100644 --- a/fsl/fslview/displaycontext/display.py +++ b/fsl/fslview/displaycontext/display.py @@ -50,6 +50,10 @@ class DisplayOpts(props.SyncableHasProperties): self.imageType = image.imageType self.name = '{}_{}'.format(type(self).__name__, id(self)) + + def destroy(self): + pass + class Display(props.SyncableHasProperties): """ @@ -323,6 +327,9 @@ class Display(props.SyncableHasProperties): if (self.__displayOpts is None) or \ (self.__displayOpts.imageType != self.imageType): + + if self.__displayOpts is not None: + self.__displayOpts.destroy() self.__displayOpts = self.__makeDisplayOpts() diff --git a/fsl/fslview/displaycontext/maskopts.py b/fsl/fslview/displaycontext/maskopts.py index f6e7a3994..4b011d55e 100644 --- a/fsl/fslview/displaycontext/maskopts.py +++ b/fsl/fslview/displaycontext/maskopts.py @@ -18,7 +18,8 @@ class MaskOpts(fsldisplay.DisplayOpts): colour = props.Colour() invert = props.Boolean(default=False) - threshold = props.Bounds( + + clippingRange = props.Bounds( ndims=1, labels=[strings.choices['VolumeOpts.displayRange.min'], strings.choices['VolumeOpts.displayRange.max']]) @@ -36,10 +37,15 @@ class MaskOpts(fsldisplay.DisplayOpts): dRangeLen = abs(self.dataMax - self.dataMin) dMinDistance = dRangeLen / 10000.0 - self.threshold.setMin( 0, self.dataMin - 0.5 * dRangeLen) - self.threshold.setMax( 0, self.dataMax + 0.5 * dRangeLen) - self.threshold.setRange(0, 0.1, self.dataMax + 0.1) - self.setConstraint('threshold', 'minDistance', dMinDistance) + self.clippingRange.xmin = self.dataMin - dMinDistance + self.clippingRange.xmax = self.dataMax + dMinDistance + + # By default, the lowest values + # in the image are clipped + self.clippingRange.xlo = self.dataMin + dMinDistance + self.clippingRange.xhi = self.dataMax + dMinDistance + + self.setConstraint('clippingRange', 'minDistance', dMinDistance) fsldisplay.DisplayOpts.__init__(self, image, diff --git a/fsl/fslview/displaycontext/volumeopts.py b/fsl/fslview/displaycontext/volumeopts.py index 2a981c930..9b0a1d0db 100644 --- a/fsl/fslview/displaycontext/volumeopts.py +++ b/fsl/fslview/displaycontext/volumeopts.py @@ -90,6 +90,7 @@ class VolumeOpts(fsldisplay.DisplayOpts): _propHelp = _tooltips + def __init__(self, image, display, imageList, displayCtx, parent=None): """Create an :class:`ImageDisplay` for the specified image. @@ -168,6 +169,11 @@ class VolumeOpts(fsldisplay.DisplayOpts): self.name, self.displayRangeChanged) + def destroy(self): + self.display.removeListener('brightness', self.name) + self.display.removeListener('contrast', self.name) + self .removeListener('displayRange', self.name) + def briconChanged(self, *a): """Called when the ``brightness``/``contrast`` properties of the diff --git a/fsl/fslview/gl/glmask.py b/fsl/fslview/gl/glmask.py index 36231c7c0..d347bd496 100644 --- a/fsl/fslview/gl/glmask.py +++ b/fsl/fslview/gl/glmask.py @@ -59,7 +59,7 @@ class GLMask(glvolume.GLVolume): self.display .addListener('transform', lnrName, vertexUpdate) self.display .addListener('alpha', lnrName, colourUpdate) self.displayOpts.addListener('colour', lnrName, colourUpdate) - self.displayOpts.addListener('threshold', lnrName, colourUpdate) + self.displayOpts.addListener('clippingRange', lnrName, colourUpdate) self.displayOpts.addListener('invert', lnrName, colourUpdate) @@ -79,7 +79,7 @@ class GLMask(glvolume.GLVolume): self.display .removeListener('volume', lnrName) self.image .removeListener('data', lnrName) self.displayOpts.removeListener('colour', lnrName) - self.displayOpts.removeListener('threshold', lnrName) + self.displayOpts.removeListener('clippingRange', lnrName) self.displayOpts.removeListener('invert', lnrName) @@ -98,8 +98,8 @@ class GLMask(glvolume.GLVolume): opts = self.displayOpts colour = opts.colour - imin = opts.threshold[0] - imax = opts.threshold[1] + imin = opts.clippingRange[0] + imax = opts.clippingRange[1] colour[3] = 1.0 diff --git a/fsl/fslview/layouts.py b/fsl/fslview/layouts.py index 7a97c2a0b..83c3be965 100644 --- a/fsl/fslview/layouts.py +++ b/fsl/fslview/layouts.py @@ -182,14 +182,14 @@ DisplayLayout = props.VGroup( VolumeOptsLayout = props.VGroup( (widget(VolumeOpts, 'cmap'), widget(VolumeOpts, 'invert'), - widget(VolumeOpts, 'displayRange', slider=True), - widget(VolumeOpts, 'clippingRange', slider=True))) + widget(VolumeOpts, 'displayRange', slider=True, showLimits=False), + widget(VolumeOpts, 'clippingRange', slider=True, showLimits=False))) MaskOptsLayout = props.VGroup( (widget(MaskOpts, 'colour'), widget(MaskOpts, 'invert'), - widget(MaskOpts, 'threshold'))) + widget(MaskOpts, 'clippingRange', showLimits=False))) VectorOptsLayout = props.VGroup(( diff --git a/fsl/tools/fslview_parseargs.py b/fsl/tools/fslview_parseargs.py index a484a2135..2a3de481d 100644 --- a/fsl/tools/fslview_parseargs.py +++ b/fsl/tools/fslview_parseargs.py @@ -128,7 +128,7 @@ OPTIONS = td.TypeDict({ 'cmap'], 'MaskOpts' : ['colour', 'invert', - 'threshold'], + 'clippingRange'], 'VectorOpts' : ['displayMode', 'xColour', 'yColour', @@ -210,9 +210,9 @@ ARGUMENTS = td.TypeDict({ 'VolumeOpts.cmap' : ('cm', 'cmap'), 'VolumeOpts.invert' : ('ci', 'cmapInvert'), - 'MaskOpts.colour' : ('co', 'colour'), - 'MaskOpts.invert' : ('mi', 'maskInvert'), - 'MaskOpts.threshold' : ('t', 'threshold'), + 'MaskOpts.colour' : ('co', 'colour'), + 'MaskOpts.invert' : ('mi', 'maskInvert'), + 'MaskOpts.clippingRange' : ('t', 'threshold'), 'VectorOpts.displayMode' : ('d', 'displayMode'), 'VectorOpts.xColour' : ('xc', 'xColour'), @@ -280,9 +280,9 @@ HELP = td.TypeDict({ 'VolumeOpts.cmap' : 'Colour map', 'VolumeOpts.invert' : 'Invert colour map', - 'MaskOpts.colour' : 'Colour', - 'MaskOpts.invert' : 'Invert', - 'MaskOpts.threshold' : 'Threshold', + 'MaskOpts.colour' : 'Colour', + 'MaskOpts.invert' : 'Invert', + 'MaskOpts.clippingRange' : 'Threshold', 'VectorOpts.displayMode' : 'Display mode', 'VectorOpts.xColour' : 'X colour', -- GitLab