Source code for fsleyes.controls.orthoedittoolbar
#
# orthoedittoolbar.py - The OrthoEditToolBar
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides the :class:`OrthoEditToolBar`, a
:class:`.ControlToolBar` which displays controls for editing :class:`.Image`
instances in an :class:`.OrthoPanel`.
"""
import logging
import wx
import fsleyes_props as props
import fsleyes.controls.controlpanel as ctrlpanel
import fsleyes.toolbar as fsltoolbar
import fsleyes.icons as fslicons
import fsleyes.tooltips as fsltooltips
import fsleyes.strings as strings
import fsleyes.controls.displayspacewarning as dswarning
from fsleyes.profiles.orthoeditprofile import OrthoEditProfile
log = logging.getLogger(__name__)
[docs]class OrthoEditToolBar(ctrlpanel.ControlToolBar):
"""The ``OrthoEditToolBar`` is a :class:`.ControlToolBar` which displays
controls for editing :class:`.Image` instances in an :class:`.OrthoPanel`.
An ``OrthoEditToolBar`` looks something like this:
.. image:: images/orthoedittoolbar.png
:scale: 50%
:align: center
The ``OrthoEditToolBar`` exposes properties and actions which are defined
on the :class:`.OrthoEditProfile` class, and allows the user to:
- Change the :class:`.OrthoPanel` profile between ``view`` and ``edit``
mode (see the :attr:`.ViewPanel.profile` property). When in ``view``
mode, all of the other controls are hidden.
- Undo/redo changes to the selection and to :class:`.Image` instances.
- Clear and fill the current selection.
- Switch between a 2D and 3D selection cursor.
- Change the selection cursor size.
- Create a new mask/ROI :class:`.Image` from the current selection.
- Switch between regular *select* mode, and *select by intensity* mode,
and adjust the select by intensity mode settings.
All of the controls shown on an ``OrthoEditToolBar`` instance are defined
in the :attr:`_TOOLBAR_SPECS` dictionary.
"""
selint = props.Boolean(default=False)
"""This property allows the user to change the :class:`.OrthoEditProfile`
between ``sel`` mode, and ``selint`` mode.
"""
[docs] def __init__(self, parent, overlayList, displayCtx, frame, ortho):
"""Create an ``OrthoEditToolBar``.
:arg parent: The :mod:`wx` parent object.
:arg overlayList: The :class:`.OverlayList` instance.
:arg displayCtx: The :class:`.DisplayContext` instance.
:arg frame: The :class:`.FSLeyesFrame` instance.
:arg ortho: The :class:`.OrthoPanel` instance.
"""
ctrlpanel.ControlToolBar.__init__(self,
parent,
overlayList,
displayCtx,
frame,
height=24,
kbFocus=True)
self.__orthoPanel = ortho
self.__dsWarning = dswarning.DisplaySpaceWarning(
self,
self.overlayList,
self.displayCtx,
self.frame,
strings.messages[self, 'dsWarning'],
'not like overlay',
'overlay')
ortho.addListener('profile', self.name, self.__profileChanged)
self.__profileChanged()
[docs] def destroy(self):
"""Must be called when this ``OrthoEditToolBar`` is no longer
needed. Removes property listeners, and calls the
:meth:`.ControlToolBar.destroy` method.
"""
self.__orthoPanel.removeListener('profile', self.name)
self.__dsWarning.destroy()
self.__orthoPanel = None
self.__dsWarning = None
ctrlpanel.ControlToolBar.destroy(self)
[docs] @staticmethod
def supportedViews():
"""Overrides :meth:`.ControlMixin.supportedViews`. The
``OrthoEditToolBar`` is only intended to be added to
:class:`.OrthoPanel` views.
"""
from fsleyes.views.orthopanel import OrthoPanel
return [OrthoPanel]
def __profileChanged(self, *a):
"""Called when the :attr:`.ViewPanel.profile` property of the
:class:`.OrthoPanel` changes. Shows/hides edit controls accordingly.
"""
self.ClearTools(destroy=True, postevent=False)
ortho = self.__orthoPanel
profile = ortho.profile
profileObj = ortho.getCurrentProfile()
if profile != 'edit':
self.__dsWarning.Show(False)
return
allTools = []
allWidgets = []
for specGroup in _TOOLBAR_SPECS:
if specGroup == 'div':
allTools.append(fsltoolbar.ToolBarDivider(self,
height=24,
orient=wx.VERTICAL))
continue
groupWidgets = []
isGroup = isinstance(specGroup, list)
if isGroup:
parent = wx.Panel(self)
else:
parent = self
specGroup = [specGroup]
for spec in specGroup:
widget = props.buildGUI(parent, profileObj, spec)
if not isGroup and spec.label is not None:
widget = self.MakeLabelledTool(widget, spec.label)
allWidgets .append(widget)
groupWidgets.append(widget)
# Assuming here that all
# widgets have labels
if isGroup:
sizer = wx.FlexGridSizer(2, 2, 0, 0)
parent.SetSizer(sizer)
labels = [s.label for s in specGroup]
labels = [wx.StaticText(parent, label=l) for l in labels]
for w, l in zip(groupWidgets, labels):
sizer.Add(l, flag=wx.ALIGN_CENTRE_VERTICAL | wx.ALIGN_RIGHT)
sizer.Add(w, flag=wx.ALIGN_CENTRE_VERTICAL | wx.ALIGN_RIGHT)
allTools.append(parent)
else:
allTools.append(groupWidgets[0])
self.SetTools( [self.__dsWarning] + allTools)
self.setNavOrder(allWidgets)
_LABELS = {
'selectionCursorColour' : strings.properties[OrthoEditProfile,
'selectionCursorColour'],
'selectionOverlayColour' : strings.properties[OrthoEditProfile,
'selectionOverlayColour'],
'selectionSize' : strings.properties[OrthoEditProfile,
'selectionSize'],
'intensityThres' : strings.properties[OrthoEditProfile,
'intensityThres'],
'searchRadius' : strings.properties[OrthoEditProfile,
'searchRadius'],
'fillValue' : strings.properties[OrthoEditProfile,
'fillValue'],
'targetImage' : strings.properties[OrthoEditProfile,
'targetImage'],
}
"""This dictionary contains labels for some :class:`OrthoEditToolBar`
controls. It is referenced in the :attr:`_TOOLBAR_SPECS` dictionary.
"""
_ICONS = {
'drawMode' : [fslicons.findImageFile('drawModeHighlight24'),
fslicons.findImageFile('drawMode24'),
fslicons.findImageFile('selectModeHighlight24'),
fslicons.findImageFile('selectMode24')],
'mode' : {
'nav' : [
fslicons.findImageFile('addHighlight24'),
fslicons.findImageFile('add24'),
],
'sel' : [
fslicons.findImageFile('pencilHighlight24'),
fslicons.findImageFile('pencil24'),
],
'desel' : [
fslicons.findImageFile('eraserHighlight24'),
fslicons.findImageFile('eraser24'),
],
'fill' : [
fslicons.findImageFile('bucketHighlight24'),
fslicons.findImageFile('bucket24'),
],
'selint' : [
fslicons.findImageFile('selectByIntensityHighlight24'),
fslicons.findImageFile('selectByIntensity24'),
],
},
'selectionIs3D' : [
fslicons.findImageFile('selection3DHighlight24'),
fslicons.findImageFile('selection3D24'),
fslicons.findImageFile('selection2DHighlight24'),
fslicons.findImageFile('selection2D24')],
'limitToRadius' : [
fslicons.findImageFile('radiusHighlight24'),
fslicons.findImageFile('radius24')],
'localFill' : [
fslicons.findImageFile('localsearchHighlight24'),
fslicons.findImageFile('localsearch24')],
'selint' : [
fslicons.findImageFile('selectByIntensityHighlight24'),
fslicons.findImageFile('selectByIntensity24')],
}
"""This dictionary contains icons for some :class:`OrthoEditToolBar`
controls. It is referenced in the :attr:`_TOOLBAR_SPECS` dictionary.
"""
_TOOLTIPS = {
'drawMode' : fsltooltips.properties['OrthoEditProfile.'
'drawMode'],
'mode' : fsltooltips.properties['OrthoEditProfile.mode'],
'selectionIs3D' : fsltooltips.properties['OrthoEditProfile.'
'selectionIs3D'],
'limitToRadius' : fsltooltips.properties['OrthoEditProfile.'
'limitToRadius'],
'searchRadius' : fsltooltips.properties['OrthoEditProfile.'
'searchRadius'],
'localFill' : fsltooltips.properties['OrthoEditProfile.localFill'],
'selectionSize' : fsltooltips.properties['OrthoEditProfile.'
'selectionSize'],
'fillValue' : fsltooltips.properties['OrthoEditProfile.fillValue'],
'intensityThres' : fsltooltips.properties['OrthoEditProfile.'
'intensityThres'],
'targetImage' : fsltooltips.properties['OrthoEditProfile.targetImage'],
}
"""This dictionary contains tooltips for some :class:`OrthoEditToolBar`
controls. It is referenced in the :attr:`_TOOLBAR_SPECS` dictionary.
"""
_TOOLBAR_SPECS = [
props.Widget(
'drawMode',
toggle=False,
icon=_ICONS['drawMode'],
tooltip=_TOOLTIPS['drawMode'],
style=wx.HORIZONTAL),
'div',
props.Widget(
'mode',
icons=_ICONS['mode'],
tooltip=_TOOLTIPS['mode'],
fixChoices=['nav', 'sel', 'desel', 'fill', 'selint']),
'div',
props.Widget(
'selectionIs3D',
icon=_ICONS['selectionIs3D'],
tooltip=_TOOLTIPS['selectionIs3D'],
toggle=False,
dependencies=['mode'],
enabledWhen=lambda p, m: m != 'fill'),
props.Widget(
'limitToRadius',
icon=_ICONS['limitToRadius'],
tooltip=_TOOLTIPS['limitToRadius'],
dependencies=['mode'],
enabledWhen=lambda p, m: m == 'selint'),
props.Widget(
'localFill',
icon=_ICONS['localFill'],
tooltip=_TOOLTIPS['localFill'],
dependencies=['mode'],
enabledWhen=lambda p, m: m == 'selint'),
[props.Widget(
'selectionSize',
spin=True,
slider=False,
showLimits=False,
spinWidth=3,
label=_LABELS['selectionSize'],
tooltip=_TOOLTIPS['selectionSize']),
props.Widget(
'fillValue',
label=_LABELS['fillValue'],
tooltip=_TOOLTIPS['fillValue'],
slider=False,
spinWidth=3,
increment=1)],
[props.Widget(
'intensityThres',
slider=True,
spin=True,
showLimits=False,
spinWidth=6,
label=_LABELS['intensityThres'],
tooltip=_TOOLTIPS['intensityThres'],
dependencies=['mode'],
enabledWhen=lambda p, m: m == 'selint'),
props.Widget(
'searchRadius',
slider=True,
spin=True,
showLimits=False,
spinWidth=6,
label=_LABELS['searchRadius'],
tooltip=_TOOLTIPS['searchRadius'],
dependencies=['mode', 'limitToRadius'],
enabledWhen=lambda p, m, r: m == 'selint' and r)],
props.Widget('targetImage',
label=_LABELS['targetImage'],
tooltip=_TOOLTIPS['targetImage'],
labels=_targetImageName,
dependencies=['drawMode'],
enabledWhen=lambda p, dm: not dm)
]
"""This list contains specifications for all of the tools shown in an
:class:`OrthoEditToolBar`, in the order that they are shown.
Some specs are grouped together into sub-lists - these will be laid out
vertically on the toolbar.
"""