diff --git a/fsl/fsleyes/displaycontext/__init__.py b/fsl/fsleyes/displaycontext/__init__.py index af2bf65fa03c6efdf152d431f20411cea4aedb2c..b23ab8178a38cfc3bf07aa093983ed8baae1d2aa 100644 --- a/fsl/fsleyes/displaycontext/__init__.py +++ b/fsl/fsleyes/displaycontext/__init__.py @@ -103,18 +103,33 @@ Scene options Independent of the ``DisplayContext``, ``Display`` and ``DisplayOpts`` classes, the ``displaycontext`` package is also home to a few classes which -define *scene* options. Every :class:`.CanvasPanel` instance uses a -:class:`.SceneOpts` sub-class to control the scene configuration. For example, -the :attr:`.LightBoxOpts.ncols` property controls how many columns of slices -the :class:`.LightBoxPanel` should display. The following scene option -classes exist: +define *scene* options:: + .. autosummary:: :nosignatures: + ~fsl.fsleyes.displaycontext.canvasopts.SliceCanvasOpts + ~fsl.fsleyes.displaycontext.canvasopts.LightBoxCanvasOpts ~fsl.fsleyes.displaycontext.sceneopts.SceneOpts ~fsl.fsleyes.displaycontext.orthoopts.OrthoOpts ~fsl.fsleyes.displaycontext.lightboxopts.LightBoxOpts + + +.. note:: Aside from an increase in code modularity and cleanliness, another + reason that all of these scene display settings are separated from + the things that use them is so they can be imported, queried, and + set without having to import the modules that use them. + + For example, the :mod:`.fsleyes_parseargs` module needs to be able + to access all of the display settings in order to print out the + corresponding help documentation. This process would take much + longer if ``fsleyes_parseargs`` had to import, e.g. + :class:`.OrthoPanel`, which would result in importing both :mod:`wx` + and :mod:`.OpenGL`. + + Keeping these display settings separate allows us to avoid these + time-consuming imports in situations where they are not needed. """ diff --git a/fsl/fsleyes/displaycontext/display.py b/fsl/fsleyes/displaycontext/display.py index 8a2ceffe834bb6b5255f470c7d7b4324d9ec2713..6fa4ce49a5e5bdbeb1e7b81d1dc073fe84f9e624 100644 --- a/fsl/fsleyes/displaycontext/display.py +++ b/fsl/fsleyes/displaycontext/display.py @@ -4,14 +4,8 @@ # # Author: Paul McCarthy <pauldmccarthy@gmail.com> # -"""This module provides definitions of an important class - the -:class:`Display` class. - -A ``Display`` contains a specification for the way in which any overlays is to -be displayed. - -..note:: Put a description of the three coordinate systems which - exist in the system. +"""This module provides the :class:`Display` and :class:`DisplayOpts` classes, +which encapsulate overlay display settings. """ import logging @@ -26,96 +20,15 @@ import fsl.fsleyes.actions as actions log = logging.getLogger(__name__) -class DisplayOpts(actions.ActionProvider): - - - bounds = props.Bounds(ndims=3) - """Specifies a bounding box (in display coordinates) which is big enough - to contain the overlay described by this ``DisplayOpts`` instance. The - values in this ``bounds`` property must be maintained by subclass - implementations. - - Whenever the spatial representation of this overlay changes, but the - bounds do not change, subclass implementations should force notification - on this property (via the :meth:`.HasProperties.notify` method). - """ - - def __init__( - self, - overlay, - display, - overlayList, - displayCtx, - **kwargs): - - actions.ActionProvider.__init__( - self, - overlayList, - displayCtx, - **kwargs) - - self.overlay = overlay - self.display = display - self.overlayList = overlayList - self.displayCtx = displayCtx - self.overlayType = display.overlayType - self.name = '{}_{}'.format(type(self).__name__, id(self)) - - log.memory('{}.init ({})'.format(type(self).__name__, id(self))) - - - def __del__(self): - log.memory('{}.del ({})'.format(type(self).__name__, id(self))) - - - def destroy(self): - """If overridden, this method should be called by the subclass - implementation. - """ - actions.ActionProvider.destroy(self) - - self.overlay = None - self.display = None - self.overlayList = None - self.displayCtx = None - - - def getReferenceImage(self): - """Some non-volumetric overlay types (e.g. the :class:`.Model` - see - :class:`.ModelOpts`) may have a 'reference' :class:`.Image` instance - associated with them, allowing the overlay to be localised in the - coordinate space defined by the :class:`.Image`. The - :class:`.DisplayOpts` class which corresponds to such non-volumetric - overlays should override this method to return the reference image. - - :class:`.DisplayOpts` subclasses which are associated with volumetric - overlays (i.e. :class:`.Image` instances) do not need to override - this method. - """ - - if isinstance(self.overlay, fslimage.Image): - return self.overlay - return None - - - def transformDisplayLocation(self, coords): - """This method may be called after the overlay :attr:`bounds` have - changed. - - If the bounds were changed as a result of a change to the spatial - representation of the overlay (e.g. the :attr:`.ImageOpts.transform` - property for :class:`.Image` overlays), this method should return - a copy of the given coordinates which has been transformed into the - new space. - - If the bounds were changed for some other reason, this method can - just return the ``coords`` unchanged. - """ - return coords - - class Display(props.SyncableHasProperties): - """ + """The ``Display`` class contains display settings which are common to + all overlay types. + + A ``Display`` instance is also responsible for managing a single + :class:`DisplayOpts` instance, which contains overlay type specific + display options. Whenever the :attr:`overlayType` property of a + ``Display`` instance changes, the old ``DisplayOpts`` instance (if any) + is destroyed, and a new one, of the correct type, created. """ @@ -128,11 +41,12 @@ class Display(props.SyncableHasProperties): displayed. The options for this property are populated in the :meth:`__init__` - method. See the :attr:`OVERLAY_TYPES` dictionary. + method, from the :attr:`OVERLAY_TYPES` dictionary. A :class:`DisplayOpts` + sub-class exists for every possible value that this property may take. """ enabled = props.Boolean(default=True) - """Should this overlay be displayed at all?""" + """Should this overlay be displayed at all? """ alpha = props.Percentage(default=100.0) @@ -140,19 +54,19 @@ class Display(props.SyncableHasProperties): brightness = props.Percentage() + """Brightness - 50% is normal brightness.""" contrast = props.Percentage() + """Contrast - 50% is normal contrast.""" softwareMode = props.Boolean(default=False) - """If possible, optimise for software-based rendering.""" + """If possible, optimise for a low-performance rendering environment + (e.g. a software-based OpenGL renderer). + """ - def getOverlay(self): - return self.__overlay - - def __init__(self, overlay, overlayList, @@ -172,7 +86,8 @@ class Display(props.SyncableHasProperties): :arg parent: A parent ``Display`` instance - see :mod:`props.syncable`. - :arg overlayType: Initial overlay type. + :arg overlayType: Initial overlay type - see the :attr:`overlayType` + property. """ self.__overlay = overlay @@ -227,7 +142,7 @@ class Display(props.SyncableHasProperties): # # The structure of the dictionary is: # - # { type(DIsplayOpts), propName : propValue } + # { (type(DisplayOpts), propName) : propValue } # # This also applies to the case where the # overlay type is changed from one type to @@ -251,8 +166,7 @@ class Display(props.SyncableHasProperties): # Display instance's parent (so it can # subsequently access a parent for the # new DisplayOpts instance). Therefore, - # we do this after calling - # Syncable.__init__. + # we do this after calling Syncable.__init__. self.__displayOpts = None self.__overlayTypeChanged() @@ -260,12 +174,21 @@ class Display(props.SyncableHasProperties): def __del__(self): + """Prints a log message.""" log.memory('{}.del ({})'.format(type(self).__name__, id(self))) - + + + def getOverlay(self): + """Returns the overlay associated with this ``Display`` instance.""" + return self.__overlay + def destroy(self): - """This method should be called when this ``Display`` instance + """This method must be called when this ``Display`` instance is no longer needed. + + When a ``Display`` instance is destroyed, the corresponding + :class:`DisplayOpts` instance is also destroyed. """ if self.__displayOpts is not None: @@ -276,11 +199,21 @@ class Display(props.SyncableHasProperties): self.detachFromParent() self.__displayOpts = None + self.__overlayList = None + self.__displayCtx = None self.__overlay = None def getDisplayOpts(self): - """ + """Return the :class:`.DisplayOpts` instance associated with this + ``Display``, which contains overlay type specific display settings. + + If a ``DisplayOpts`` instance has not yet been created, or the + :attr:`overlayType` property no longer matches the type of the + existing ``DisplayOpts`` instance, a new ``DisplayOpts`` instance + is created (and the old one destroyed if necessary). + + See the :meth:`__makeDisplayOpts` method. """ if (self.__displayOpts is None) or \ @@ -295,7 +228,12 @@ class Display(props.SyncableHasProperties): def __makeDisplayOpts(self): - """ + """Creates a new :class:`DisplayOpts` instance. The specific + ``DisplayOpts`` sub-class that is created is dictated by the current + value of the :attr:`overlayType` property. + + The :data:`DISPLAY_OPTS_MAP` dictionary defines the mapping between + :attr:`overlayType` values, and ``DisplayOpts`` sub-class types. """ if self.getParent() is None: @@ -351,8 +289,8 @@ class Display(props.SyncableHasProperties): def __saveOldDisplayOpts(self): """Saves the value of every property on the current - :class:`DisplayOpts` instance, so they can be restored - later if needed. + :class:`DisplayOpts` instance, so they can be restored later if + needed. """ opts = self.__displayOpts @@ -367,8 +305,8 @@ class Display(props.SyncableHasProperties): def __restoreOldDisplayOpts(self): - """Restores any cached values for all of the properties on the - current ``DisplayOpts`` instance. + """Restores any cached values for all of the properties on the + current :class:`DisplayOpts` instance. """ opts = self.__displayOpts @@ -386,16 +324,158 @@ class Display(props.SyncableHasProperties): def __overlayTypeChanged(self, *a): + """Called when the :attr:`overlayType` property changes. Makes sure + that the :class:`DisplayOpts` instance is of the correct type. """ - """ - - # make sure that the display - # options instance is up to date self.__saveOldDisplayOpts() self.getDisplayOpts() self.__restoreOldDisplayOpts() +class DisplayOpts(actions.ActionProvider): + """The ``DisplayOpts`` class contains overlay type specific display + settings. ``DisplayOpts`` instances are managed by :class:`Display` + instances. + + + The ``DisplayOpts`` class is not meant to be created directly - it is a + base class for type specific implementations (e.g. the :class:`.ImageOpts` + class). + + + The following attributes are available on all ``DisplayOpts`` instances: + + + =============== ====================================================== + ``overlay`` The overlay object + ``display`` The :class:`Display` instance that created this + ``DisplayOpts`` instance. + ``overlayType`` The value of the :attr:`Display.overlayType` property + corresponding to the type of this ``DisplayOpts`` + instance. + ``overlayList`` The :class:`.OverlayList` instance, which contains all + overlays. + ``displayCtx`` The :class:`.DisplayContext` instance which is + responsible for all ``Display`` and ``DisplayOpts`` + instances. + ``name`` A unique name for this ``DIsplayOpts`` instance. + =============== ====================================================== + """ + + + bounds = props.Bounds(ndims=3) + """Specifies a bounding box in the display coordinate system which is big + enough to contain the overlay described by this ``DisplayOpts`` + instance. The values in this ``bounds`` property must be updated by + ``DisplayOpts`` subclasses. + + Whenever the spatial representation of this overlay changes, but the + bounds do not change, subclass implementations should force notification + on this property (via the :meth:`.HasProperties.notify` method). + """ + + + def __init__( + self, + overlay, + display, + overlayList, + displayCtx, + **kwargs): + """Create a ``DisplayOpts`` object. + + :arg overlay: The overlay associated with this ``DisplayOpts`` + instance. + + :arg display: The :class:`Display` instance which owns this + ``DisplayOpts`` instance. + + :arg overlayList: The :class:`.OverlayList` which contains all + overlays. + + :arg displayCtx: A :class:`.DisplayContext` instance describing + how the overlays are to be displayed. + + :arg kwargs: Passed through to the + :meth:`.ActionProvider.__init__` constructor. + """ + + actions.ActionProvider.__init__( + self, + overlayList, + displayCtx, + **kwargs) + + self.overlay = overlay + self.display = display + self.overlayList = overlayList + self.displayCtx = displayCtx + self.overlayType = display.overlayType + self.name = '{}_{}'.format(type(self).__name__, id(self)) + + log.memory('{}.init ({})'.format(type(self).__name__, id(self))) + + + def __del__(self): + """Prints a log message.""" + log.memory('{}.del ({})'.format(type(self).__name__, id(self))) + + + def destroy(self): + """This method must be called when this ``DisplayOpts`` instance + is no longer needed. + + If a subclass overrides this method, the subclass implementation + must call this method, **after** performing its own clean up. + """ + actions.ActionProvider.destroy(self) + + self.overlay = None + self.display = None + self.overlayList = None + self.displayCtx = None + + + def getReferenceImage(self): + """Return the reference image associated with this ``DisplayOpts`` + instance. + + Some non-volumetric overlay types (e.g. the :class:`.Model` - see + :class:`.ModelOpts`) may have a *reference* :class:`.Image` instance + associated with them, allowing the overlay to be localised in the + coordinate space defined by the :class:`.Image`. The + :class:`.DisplayOpts` sub-class which corresponds to + such non-volumetric overlays should override this method to return + that reference image. + + :class:`.DisplayOpts` sub-classes which are associated with volumetric + overlays (i.e. :class:`.Image` instances) do not need to override + this method - in this case, the overlay itself is considered to be + its own reference image, and is returned by the base-class + implementation of this this method. + """ + + if isinstance(self.overlay, fslimage.Image): + return self.overlay + return None + + + def transformDisplayLocation(self, coords): + """This method may be called after the overlay :attr:`bounds` have + changed. + + If the bounds were changed as a result of a change to the spatial + representation of the overlay (e.g. the :attr:`.ImageOpts.transform` + property for :class:`.Image` overlays), this method should return + a copy of the given coordinates which has been transformed into the + new space. + + If the bounds were changed for some other reason, this method can + just return the ``coords`` unchanged. + """ + return coords + + import volumeopts import vectoropts import maskopts @@ -408,8 +488,9 @@ OVERLAY_TYPES = td.TypeDict({ 'Image' : ['volume', 'mask', 'rgbvector', 'linevector', 'label'], 'Model' : ['model'] }) -"""This dictionary provides a mapping between the overlay classes, and -the way in which they may be represented. +"""This dictionary provides a mapping between all overlay classes, +and the possible values that the :attr:`Display.overlayType` property +may take for each of them. For each overlay class, the first entry in the corresponding overlay type list is used as the default overlay type. diff --git a/fsl/fsleyes/displaycontext/displaycontext.py b/fsl/fsleyes/displaycontext/displaycontext.py index b591eb54ff320db96ddce60c54f40d3169d49f8f..73c69bc965edbe38b12db0224efb80bdb361895c 100644 --- a/fsl/fsleyes/displaycontext/displaycontext.py +++ b/fsl/fsleyes/displaycontext/displaycontext.py @@ -1,9 +1,13 @@ #!/usr/bin/env python # -# displaycontext.py - +# displaycontext.py - The DisplayContext class. # # Author: Paul McCarthy <pauldmccarthy@gmail.com> # +"""This module provides the :class:`DisplayContext` class, which defines +general display settings for displaying the overlays in a +:class:`.OverlayList`. +""" import sys import logging @@ -25,36 +29,59 @@ class InvalidOverlayError(Exception): class DisplayContext(props.SyncableHasProperties): - """Contains a number of properties defining how an :class:`.OverlayList` - is to be displayed. + """A ``DisplayContext`` instance contains a number of properties defining + how the overlays in an :class:`.OverlayList` are to be displayed, and + related contextual information. + + + A ``DisplayContext`` instance is responsible for creating and destroying + :class:`.Display` instances for every overlay in the ``OverlayList``. These + ``Display`` instances, and the corresponding ``DisplayOpts`` instances + (which, in turn, are created/destroyed by ``Display`` instances) can be + accessed with the :meth:`getDisplay` and :meth:`getOpts` method + respectively. + + + A number of other useful methods are provided by a ``DisplayContext`` + instance: + + .. autosummary:: + :nosignatures: + + getReferenceImage + selectOverlay + getSelectedOverlay + getOverlayOrder + getOrderedOverlays """ selectedOverlay = props.Int(minval=0, default=0, clamped=True) """Index of the currently 'selected' overlay. - Note that this index is in relation to the - :class:`.OverlayList`, rather than to the :attr:`overlayOrder` - list. + .. note:: The value of this index is in relation to the + :class:`.OverlayList`, rather than to the :attr:`overlayOrder` + list. - If you're interested in the currently selected overlay, you must also - listen for changes to the :attr:`.OverlayList.images` list as, if the list - changes, the :attr:`selectedOverlay` index may not change, but the overlay - to which it points may be different. + If you're interested in the currently selected overlay, you must + also listen for changes to the :attr:`.OverlayList.images` list + as, if the list changes, the :attr:`selectedOverlay` index may + not change, but the overlay to which it points may be different. """ location = props.Point(ndims=3) - """The location property contains the currently selected - 3D location (xyz) in the current display coordinate system. + """The location property contains the currently selected 3D location (xyz) + in the display coordinate system. """ bounds = props.Bounds(ndims=3) """This property contains the min/max values of a bounding box (in display coordinates) which is big enough to contain all of the overlays in the - :attr:`overlays` list. This property shouid be read-only, but I don't have - a way to enforce it (yet). + :attr:`overlays` list. + + .. warning:: This property shouid be treated as read-only. """ @@ -74,25 +101,26 @@ class DisplayContext(props.SyncableHasProperties): syncOverlayDisplay = props.Boolean(default=True) """If this ``DisplayContext`` instance has a parent (see - :mod:`props.syncable`), and this is ``True``, the properties of the - :class:`.Display` and :class:`.DisplayOpts` for every overlay managed - by this ``DisplayContext`` instance will be synchronised to those of - the parent instance. Otherwise, the display properties for every overlay - will be unsynchronised from the parent. - - This property is accessed by the :class:`.Display` class, in its - :meth:`.Display.__init__` method, and when it creates new - :class:`.DisplayOpts` instances, to set initial sync states. + :mod:`props.syncable`), and this property is ``True``, the properties of + the :class:`.Display` and :class:`.DisplayOpts` instances for every + overlay managed by this ``DisplayContext`` instance will be synchronised + to those of the parent instance. Otherwise, the display properties for + every overlay will be unsynchronised from the parent. + + .. note:: This property is accessed by the :class:`.Display` class, in its + :meth:`.Display.__init__` method, and when it creates new + :class:`.DisplayOpts` instances, to set initial sync states. """ def __init__(self, overlayList, parent=None): - """Create a :class:`DisplayContext` object. + """Create a ``DisplayContext``. - :arg overlayList: A :class:`.OverlayList` instance. + :arg overlayList: An :class:`.OverlayList` instance. - :arg parent: Another :class`DisplayContext` instance to be used - as the parent of this instance. + :arg parent: Another ``DisplayContext`` instance to be used + as the parent of this instance, passed to the + :meth:`.SyncableHasProperties.__init__` constructor. """ props.SyncableHasProperties.__init__( @@ -104,9 +132,9 @@ class DisplayContext(props.SyncableHasProperties): self.__overlayList = overlayList self.__name = '{}_{}'.format(self.__class__.__name__, id(self)) - # Keep track of the overlay list - # length so we can do some things in the - # _overlayListChanged method. This if/else + # Keep track of the overlay list length so + # we can do some things in the + # __overlayListChanged method. This if/else # is a bit hacky .... # # If the __overlayListChanged method detects @@ -145,10 +173,17 @@ class DisplayContext(props.SyncableHasProperties): def __del__(self): + """Prints a log message.""" log.memory('{}.del ({})'.format(type(self).__name__, id(self))) def destroy(self): + """This method must be called when this ``DisplayContext`` is no + longer needed. + + When a ``DisplayContext`` is destroyed, all of the :class:`.Display` + instances managed by it are destroyed as well. + """ self.__overlayList.removeListener('overlays', self.__name) @@ -159,19 +194,21 @@ class DisplayContext(props.SyncableHasProperties): def getDisplay(self, overlay, overlayType=None): - """Returns the display property object (e.g. a :class:`.Display` - object) for the specified overlay (or overlay index). + """Returns the :class:`.Display` instance for the specified overlay + (or overlay index). - If a :class:`Display` object does not exist for the given overlay, - one is created. + If the overlay is not in the ``OverlayList``, an + :exc:`InvalidOverlayError` is raised. Otheriwse, if a + :class:`Display` object does not exist for the given overlay, one is + created. - :arg overlay: The overlay to retrieve a ``Display`` - instance for. + :arg overlay: The overlay to retrieve a ``Display`` instance for, + or an index into the ``OverlayList``. :arg overlayType: If a ``Display`` instance for the specified - ``overlay`` does not exist, one is created - the - specified ``overlayType`` is passed to the - :meth:`.Display.__init__` method. + ``overlay`` does not exist, one is created - in + this case, the specified ``overlayType`` is passed + to the :meth:`.Display.__init__` method. """ if overlay is None: @@ -208,9 +245,8 @@ class DisplayContext(props.SyncableHasProperties): def getOpts(self, overlay, overlayType=None): """Returns the :class:`.DisplayOpts` instance associated with the - specified overlay. - - See :meth:`.Display.getDisplayOpts` and :meth:`getDisplay`. + specified overlay. See :meth:`getDisplay` and + :meth:`.Display.getDisplayOpts` for more details, """ if overlay is None: @@ -236,8 +272,11 @@ class DisplayContext(props.SyncableHasProperties): def selectOverlay(self, overlay): - """Selects the specified ``overlay``. Raises an ``IndexError`` if + """Selects the specified ``overlay``. Raises an :exc:`IndexError` if the overlay is not in the list. + + If you want to select an overlay by its index in the ``OverlayList``, + you can just assign to the :attr:`selectedOverlay` property directly. """ self.selectedOverlay = self.__overlayList.index(overlay) @@ -247,15 +286,16 @@ class DisplayContext(props.SyncableHasProperties): or ``None`` if there are no overlays. """ if len(self.__overlayList) == 0: return None + return self.__overlayList[self.selectedOverlay] def getOverlayOrder(self, overlay): """Returns the order in which the given overlay (or an index into the :class:`.OverlayList` list) should be displayed - (see the :attr:`overlayOrder property). + (see the :attr:`overlayOrder` property). - Raises an ``IndexError`` if the overlay is not in the list. + Raises an :exc:`IndexError` if the overlay is not in the list. """ self.__syncOverlayOrder() @@ -266,11 +306,12 @@ class DisplayContext(props.SyncableHasProperties): def getOrderedOverlays(self): - """Returns a list of overlay objects from - the :class:`.OverlayList` list, sorted into the order - that they are to be displayed. + """Returns a list of overlay objects from the :class:`.OverlayList` + list, sorted into the order that they should be displayed, as defined + by the :attr:`overlayOrder` property. """ self.__syncOverlayOrder() + return [self.__overlayList[idx] for idx in self.overlayOrder] @@ -300,9 +341,8 @@ class DisplayContext(props.SyncableHasProperties): # opts instance, so we don't do it here display.destroy() - # Ensure that a Display object - # exists for every overlay in - # the list + # Ensure that a Display object exists + # for every overlay in the list for overlay in self.__overlayList: # The getDisplay method @@ -313,18 +353,18 @@ class DisplayContext(props.SyncableHasProperties): # Register a listener on the overlay type, # because when it changes, the DisplayOpts - # instance will change, and we will need to - # re-register the next listener + # instance will change, and we will need + # to re-register the DisplayOpts.bounds + # listener (see the next statement) display.addListener('overlayType', self.__name, self.__overlayListChanged, overwrite=True) - # Register a listener on the DisplayOpts - # object for every overlay - if any - # DisplayOpts properties change, the - # overlay display bounds may have changed, - # so we need to know when this happens. + # Register a listener on the DisplayOpts.bounds + # property for every overlay - if the display + # bounds for any overlay changes, we need to + # update our own bounds property. opts.addListener('bounds', self.__name, self.__overlayBoundsChanged, @@ -337,9 +377,10 @@ class DisplayContext(props.SyncableHasProperties): # Ensure that the bounds property is accurate self.__updateBounds() - # If the overlay list was empty, - # and is now non-empty, centre - # the currently selected location + # If the overlay list was empty, and is + # now non-empty, centre the currently + # selected location (but see the comments + # in __init__ about this). if (self.__prevOverlayListLen == 0) and (len(self.__overlayList) > 0): # initialise the location to be @@ -430,7 +471,7 @@ class DisplayContext(props.SyncableHasProperties): def __overlayBoundsChanged(self, value, valid, opts, name): """Called when the :attr:`.DisplayOpts.bounds` property of any overlay changes. Updates the :attr:`bounds` property and preserves - the display :attr:`location` in terms of hte currently selected + the display :attr:`location` in terms of the currently selected overlay. """ @@ -465,9 +506,9 @@ class DisplayContext(props.SyncableHasProperties): # # So this test is in place to prevent this horrible # circular loop behaviour from occurring. If the - # location properties are synced, and contain the - # same value, we assume that they don't need to be - # updated again, and escape from ths system. + # location properties are synced, we assume that + # they don't need to be updated again, and escape + # from ths system. if self.getParent() is not None and self.isSyncedToParent('location'): return @@ -491,7 +532,7 @@ class DisplayContext(props.SyncableHasProperties): # currently selected overlay, when the overlay # bounds have changed. We don't care about changes # to the options for other overlays. - if (overlay != self.getSelectedOverlay()): + if overlay != self.getSelectedOverlay(): self.notify('location') return @@ -542,7 +583,9 @@ class DisplayContext(props.SyncableHasProperties): def __updateBounds(self, *a): """Called when the overlay list changes, or when any overlay display - transform is changed. Updates the :attr:`bounds` property. + transform is changed. Updates the :attr:`bounds` property so that it + is big enough to contain all of the overlays (as defined by their + :attr:`.DisplayOpts.bounds` properties). """ if len(self.__overlayList) == 0: