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. """
[docs]def _targetImageName(image): if image is None: return 'None' else: return image.name
_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. """