Skip to content
Snippets Groups Projects
Commit a08cc784 authored by Paul McCarthy's avatar Paul McCarthy
Browse files

Fixed LightBoxPanel scrollbar layout - colour bar is now always flush

with canvas, and scrollbar no longer appears in screenshots.
parent eded900f
No related branches found
No related tags found
No related merge requests found
......@@ -36,8 +36,8 @@ import fsl.fsleyes.controls.clusterpanel as clusterpanel
import fsl.fsleyes.controls.lookuptablepanel as lookuptablepanel
import fsl.fsleyes.controls.shellpanel as shellpanel
import colourbarpanel
import viewpanel
import colourbarpanel
import viewpanel
log = logging.getLogger(__name__)
......@@ -64,10 +64,16 @@ class CanvasPanel(viewpanel.ViewPanel):
Sub-classes of the ``CanvasPanel`` must do the following:
1. Add their content to the panel that is accessible via the
:meth:`getCanvasPanel` method (see the note on
:meth:`getContentPanel` method (see the note on
:ref:`adding content <canvaspanel-adding-content>`).
2. Override the :meth:`getGLCanvases` method.
3. Call the :meth:`centrePanelLayout` method in their ``__init__``
method.
4. Override the :meth:`centrePanelLayout` method if any custom layout is
necessary.
**Actions**
......@@ -104,14 +110,14 @@ class CanvasPanel(viewpanel.ViewPanel):
.. _canvaspanel-adding-content:
**Adding content**
To support colour bar functionality, the ``CanvasPanel`` uses a hierarchy
of ``wx.Panel`` instances, depicted in the following containment
hierarchy diagram:
To support colour bar and screenshot functionality, the ``CanvasPanel``
uses a hierarchy of ``wx.Panel`` instances, depicted in the following
containment hierarchy diagram:
.. graphviz::
......@@ -127,23 +133,49 @@ class CanvasPanel(viewpanel.ViewPanel):
rankdir="BT";
1 [label="CanvasPanel"];
2 [label="Canvas container"];
3 [label="ColourBarPanel"];
4 [label="Centre panel"];
5 [label="Content added by sub-classes"];
2 [label="Centre panel"];
3 [label="Advanced layout"];
4 [label="Container panel"];
5 [label="ColourBarPanel"];
6 [label="Content panel"];
7 [label="Content added by sub-classes"];
2 -> 1;
3 -> 2;
4 -> 2;
5 -> 4;
6 -> 4;
7 -> 6;
}
As depicted in the diagram, sub-classes need to add their content to the
*centre panel*. This panel is accessible via the :meth:`getCanvasPanel`
method. The *container panel* is what gets passed to the
*content panel*. This panel is accessible via the :meth:`getContentPanel`
method.
The *centre panel* is what gets passed to the
:meth:`.ViewPanel.setCentrePanel` method, and is accessible via the
:meth:`getCanvasContainer` method, if necessary.
:meth:`getCentrePanel` method, if necessary. The *container panel* is
also available, via the :meth:`getContainerPanel`. Everything in the
container panel will appear in screenshots (see the :meth:`screenshot`
method).
The :meth:`centrePanelLayout` method lays out the centre panel, using the
:meth:`layoutContainerPanel` method to lay out the colour bar and the
content panel. The ``centrePanelLayout`` method simply adds the canvas
container directly to the centre panel. Sub-classes which have more
advanced layout requirements (e.g. the :class:`.LightBoxPanel` needs a
scrollbar) may override the :meth:`centrePanelLayout` method to implement
their own layout. These sub-class implementations must:
1. Call the :meth:`layoutCanvasContainer` method.
2. Add the container panel (accessed via :meth:`getContainerPanel`)
to the centre panel (:meth:`getCentrePanel`)
3. Add any other custom content to the centre panel.
"""
......@@ -274,10 +306,11 @@ class CanvasPanel(viewpanel.ViewPanel):
self.disableProperty('syncOverlayOrder')
self.disableProperty('syncOverlayDisplay')
self.__canvasContainer = wx.Panel(self)
self.__canvasPanel = wx.Panel(self.__canvasContainer)
self.__centrePanel = wx.Panel(self)
self.__containerPanel = wx.Panel(self.__centrePanel)
self.__contentPanel = wx.Panel(self.__containerPanel)
self.setCentrePanel(self.__canvasContainer)
self.setCentrePanel(self.__centrePanel)
# Stores a reference to a wx.Timer
# when movie mode is enabled
......@@ -291,17 +324,18 @@ class CanvasPanel(viewpanel.ViewPanel):
self.__movieRateChanged)
# Canvas/colour bar layout is managed in
# the _layout/_toggleColourBar methods
self.__canvasSizer = None
self.__colourBar = None
# the layoutColourBarAndCanvas method
self.__colourBar = None
# Use a different listener name so that subclasses
# can register on the same properties with self._name
lName = 'CanvasPanel_{}'.format(self._name)
self.__opts.addListener('colourBarLocation', lName, self.__layout)
self.__opts.addListener('showColourBar', lName, self.__layout)
self.__layout()
self.__opts.addListener('colourBarLocation',
lName,
self.__colourBarPropsChanged)
self.__opts.addListener('showColourBar',
lName,
self.__colourBarPropsChanged)
def destroy(self):
......@@ -337,20 +371,28 @@ class CanvasPanel(viewpanel.ViewPanel):
return self.__opts
def getCanvasPanel(self):
def getCentrePanel(self):
"""Returns the ``wx.Panel`` which is passed to
:meth:`.ViewPanel.setCentrePanel`. See the note on
:ref:`adding content <canvaspanel-adding-content>`.
"""
return self.__centrePanel
def getContentPanel(self):
"""Returns the ``wx.Panel`` to which sub-classes must add their content.
See the note on :ref:`adding content <canvaspanel-adding-content>`.
"""
return self.__canvasPanel
return self.__contentPanel
def getCanvasContainer(self):
def getContainerPanel(self):
"""Returns the ``wx.Panel`` which contains the
:class:`.ColourBarPanel` if it is being displayed, and the canvas
:class:`.ColourBarPanel` if it is being displayed, and the content
panel. See the note on
:ref:`adding content <canvaspanel-adding-content>`.
"""
return self.__canvasContainer
return self.__containerPanel
def getGLCanvases(self):
......@@ -375,11 +417,27 @@ class CanvasPanel(viewpanel.ViewPanel):
return None
def __layout(self, *a):
"""Called when any colour bar display properties are changed (see
:class:`.SceneOpts`). Lays out the container panel, which contains
the :class:`.ColourBarPanel` and all content added by the
``CanvasPanel`` sub-class implementation.
def centrePanelLayout(self):
"""Lays out the centre panel. This method may be overridden by
sub-classes which need more advanced layout logic. See the note on
:ref:`adding content <canvaspanel-adding-content>`
"""
self.layoutContainerPanel()
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.__containerPanel, flag=wx.EXPAND, proportion=1)
self.__centrePanel.SetSizer(sizer)
self.PostSizeEvent()
def layoutContainerPanel(self):
"""Creates a ``wx.Sizer``, and uses it to lay out the colour bar panel
and canvas panel. The sizer object is returned.
This method is used by the default :meth:`centrePanelLayout` method,
and is available for custom sub-class implementations to use.
"""
if not self.__opts.showColourBar:
......@@ -391,19 +449,15 @@ class CanvasPanel(viewpanel.ViewPanel):
self.__colourBar.destroy()
self.__colourBar.Destroy()
self.__colourBar = None
self.__canvasSizer = wx.BoxSizer(wx.HORIZONTAL)
self.__canvasSizer.Add(self.__canvasPanel,
flag=wx.EXPAND,
proportion=1)
self.__canvasContainer.SetSizer(self.__canvasSizer)
self.PostSizeEvent()
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.__contentPanel, flag=wx.EXPAND, proportion=1)
self.__containerPanel.SetSizer(sizer)
return
if self.__colourBar is None:
self.__colourBar = colourbarpanel.ColourBarPanel(
self.__canvasContainer, self._overlayList, self._displayCtx)
self.__containerPanel, self._overlayList, self._displayCtx)
self.__opts.bindProps('colourBarLabelSide',
self.__colourBar,
......@@ -415,23 +469,18 @@ class CanvasPanel(viewpanel.ViewPanel):
self.__colourBar.orientation = 'vertical'
if self.__opts.colourBarLocation in ('top', 'bottom'):
self.__canvasSizer = wx.BoxSizer(wx.VERTICAL)
sizer = wx.BoxSizer(wx.VERTICAL)
else:
self.__canvasSizer = wx.BoxSizer(wx.HORIZONTAL)
self.__canvasContainer.SetSizer(self.__canvasSizer)
sizer = wx.BoxSizer(wx.HORIZONTAL)
if self.__opts.colourBarLocation in ('top', 'left'):
self.__canvasSizer.Add(self.__colourBar, flag=wx.EXPAND)
self.__canvasSizer.Add(self.__canvasPanel, flag=wx.EXPAND,
proportion=1)
sizer.Add(self.__colourBar, flag=wx.EXPAND)
sizer.Add(self.__contentPanel, flag=wx.EXPAND, proportion=1)
else:
self.__canvasSizer.Add(self.__canvasPanel, flag=wx.EXPAND,
proportion=1)
self.__canvasSizer.Add(self.__colourBar, flag=wx.EXPAND)
sizer.Add(self.__contentPanel, flag=wx.EXPAND, proportion=1)
sizer.Add(self.__colourBar, flag=wx.EXPAND)
# Force the canvas panel to resize itself
self.PostSizeEvent()
self.__containerPanel.SetSizer(sizer)
def __movieModeChanged(self, *a):
......@@ -455,6 +504,13 @@ class CanvasPanel(viewpanel.ViewPanel):
self.__movieTimer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.__movieUpdate)
self.__movieTimer.Start(rate)
def __colourBarPropsChanged(self, *a):
"""Called when any colour bar display properties are changed (see
:class:`.SceneOpts`). Calls :meth:`canvasPanelLayout`.
"""
self.centrePanelLayout()
def __movieRateChanged(self, *a):
......@@ -653,7 +709,7 @@ def _screenshot(overlayList, displayCtx, canvasPanel):
# direct parent of the colour bar
# canvas, and an ancestor of the
# other GL canvases
parent = canvasPanel.getCanvasContainer()
parent = canvasPanel.getContainerPanel()
width, height = parent.GetClientSize().Get()
windowDC = wx.WindowDC(parent)
memoryDC = wx.MemoryDC()
......
......@@ -86,11 +86,11 @@ class LightBoxPanel(canvaspanel.CanvasPanel):
actionz)
self.__scrollbar = wx.ScrollBar(
self.getCanvasPanel(),
self.getCentrePanel(),
style=wx.SB_VERTICAL)
self.__lbCanvas = lightboxcanvas.WXGLLightBoxCanvas(
self.getCanvasPanel(),
self.getContentPanel(),
overlayList,
displayCtx)
......@@ -117,10 +117,9 @@ class LightBoxPanel(canvaspanel.CanvasPanel):
sceneOpts.bindProps('zrange', self.__lbCanvas)
self.__canvasSizer = wx.BoxSizer(wx.HORIZONTAL)
self.getCanvasPanel().SetSizer(self.__canvasSizer)
self.getContentPanel().SetSizer(self.__canvasSizer)
self.__canvasSizer.Add(self.__lbCanvas, flag=wx.EXPAND, proportion=1)
self.__canvasSizer.Add(self.__scrollbar, flag=wx.EXPAND)
self.__canvasSizer.Add(self.__lbCanvas, flag=wx.EXPAND, proportion=1)
# When the display context location changes,
# make sure the location is shown on the canvas
......@@ -162,8 +161,9 @@ class LightBoxPanel(canvaspanel.CanvasPanel):
self.__onLightBoxChange()
self.__onZoom()
self.__selectedOverlayChanged()
self.Layout()
self.centrePanelLayout()
self.initProfile()
# The ViewPanel AuiManager seems to
......@@ -204,6 +204,25 @@ class LightBoxPanel(canvaspanel.CanvasPanel):
"""Returns a reference to the :class:`.LightBoxCanvas` instance. """
return self.__lbCanvas
def centrePanelLayout(self):
"""Overrides :meth:`.CanvasPanel.centrePanelLayout`. Adds the
scrollbar to the centre panel.
"""
self.layoutContainerPanel()
centrePanel = self.getCentrePanel()
containerPanel = self.getContainerPanel()
sizer = wx.BoxSizer(wx.HORIZONTAL)
centrePanel.SetSizer(sizer)
sizer.Add(containerPanel, flag=wx.EXPAND, proportion=1)
sizer.Add(self.__scrollbar, flag=wx.EXPAND)
self.PostSizeEvent()
def __selectedOverlayChanged(self, *a):
"""Called when the :attr:`.DisplayContext.selectedOverlay` changes.
......
......@@ -148,19 +148,19 @@ class OrthoPanel(canvaspanel.CanvasPanel):
sceneOpts,
actionz)
canvasPanel = self.getCanvasPanel()
contentPanel = self.getContentPanel()
# The canvases themselves - each one displays a
# slice along each of the three world axes
self.__xcanvas = slicecanvas.WXGLSliceCanvas(canvasPanel,
self.__xcanvas = slicecanvas.WXGLSliceCanvas(contentPanel,
overlayList,
displayCtx,
zax=0)
self.__ycanvas = slicecanvas.WXGLSliceCanvas(canvasPanel,
self.__ycanvas = slicecanvas.WXGLSliceCanvas(contentPanel,
overlayList,
displayCtx,
zax=1)
self.__zcanvas = slicecanvas.WXGLSliceCanvas(canvasPanel,
self.__zcanvas = slicecanvas.WXGLSliceCanvas(contentPanel,
overlayList,
displayCtx,
zax=2)
......@@ -172,9 +172,9 @@ class OrthoPanel(canvaspanel.CanvasPanel):
self.__zLabels = {}
for side in ('left', 'right', 'top', 'bottom'):
self.__xLabels[side] = wx.StaticText(canvasPanel)
self.__yLabels[side] = wx.StaticText(canvasPanel)
self.__zLabels[side] = wx.StaticText(canvasPanel)
self.__xLabels[side] = wx.StaticText(contentPanel)
self.__yLabels[side] = wx.StaticText(contentPanel)
self.__zLabels[side] = wx.StaticText(contentPanel)
self.__xcanvas.bindProps('showCursor', sceneOpts)
self.__ycanvas.bindProps('showCursor', sceneOpts)
......@@ -236,13 +236,14 @@ class OrthoPanel(canvaspanel.CanvasPanel):
# the slice canvases when the canvas
# panel is resized, so aspect ratio
# is maintained
canvasPanel.Bind(wx.EVT_SIZE, self.__onResize)
contentPanel.Bind(wx.EVT_SIZE, self.__onResize)
# Initialise the panel
self.__refreshLayout()
self.__bgColourChanged()
self.__overlayListChanged()
self.__locationChanged()
self.centrePanelLayout()
self.initProfile()
# The ViewPanel AuiManager seems to
......@@ -328,8 +329,8 @@ class OrthoPanel(canvaspanel.CanvasPanel):
bg = [int(round(c * 255)) for c in bg]
fg = [int(round(c * 255)) for c in fg]
self.getCanvasPanel().SetBackgroundColour(bg)
self.getCanvasPanel().SetForegroundColour(fg)
self.getContentPanel().SetBackgroundColour(bg)
self.getContentPanel().SetForegroundColour(fg)
self.__xcanvas.SetBackgroundColour(bg)
self.__ycanvas.SetBackgroundColour(bg)
......@@ -539,7 +540,7 @@ class OrthoPanel(canvaspanel.CanvasPanel):
opts = self.getSceneOptions()
layout = opts.layout
width, height = self.getCanvasPanel().GetClientSize().Get()
width, height = self.getContentPanel().GetClientSize().Get()
show = [opts.showXCanvas, opts.showYCanvas, opts.showZCanvas]
canvases = [self.__xcanvas, self.__ycanvas, self.__zcanvas]
......@@ -765,7 +766,7 @@ class OrthoPanel(canvaspanel.CanvasPanel):
for w in widgets:
self.__canvasSizer.Add(w, flag=flag)
self.getCanvasPanel().SetSizer(self.__canvasSizer)
self.getContentPanel().SetSizer(self.__canvasSizer)
# Calculate/ adjust the appropriate sizes
# for each canvas, such that they are scaled
......@@ -775,7 +776,7 @@ class OrthoPanel(canvaspanel.CanvasPanel):
self.__calcCanvasSizes()
self.Layout()
self.getCanvasPanel().Layout()
self.getContentPanel().Layout()
self.Refresh()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment