Example #1
0
def _Point(parent,
           hasProps,
           propObj,
           propVal,
           labels=None,
           showLimits=True,
           editLimits=False,
           mousewheel=False):
    """Creates and returns a :class:`.SliderSpinPanel` allowing the user to
    edit the low/high values along each dimension of the given
    :class:`.Point` property value.

    :arg labels:     One label for each dimension, to be shown alongside the
                     corresponding controls.

    :arg showLimits: Show labels displaying the point limits.

    :arg editLimits: Show buttons allowing the user to edit the point limits.

    :arg mousewheel: The user can use the mouse wheel to change the point
                     value.

    See the :func:`.widgets._String` documentation for details on the other
    parameters.
    """
    panel = wx.Panel(parent)
    sizer = wx.BoxSizer(wx.VERTICAL)
    panel.SetSizer(sizer)

    ndims = propObj._ndims
    real = propObj._real

    if labels is None:
        labels = [None] * ndims

    for dim in range(len(propVal)):

        style = 0
        if not real: style |= floatslider.SSP_INTEGER
        if showLimits: style |= floatslider.SSP_SHOW_LIMITS
        if editLimits: style |= floatslider.SSP_EDIT_LIMITS
        if mousewheel: style |= floatslider.SSP_MOUSEWHEEL

        slider = floatslider.SliderSpinPanel(panel,
                                             value=propVal[dim],
                                             minValue=propVal.getMin(dim),
                                             maxValue=propVal.getMax(dim),
                                             label=labels[dim],
                                             style=style)

        sizer.Add(slider, flag=wx.EXPAND)

        _pointBind(hasProps, propObj, propVal, slider, dim, editLimits)

    panel.Layout()

    return panel
Example #2
0
def _test_SliderSpinPanel_nolimit():
    frame = wx.GetApp().GetTopWindow()
    panel = floatslider.SliderSpinPanel(frame, style=floatslider.SSP_NO_LIMITS)

    panel.SetRange(0, 100)

    values = [-100, -50, -1, 0, 1, 50, 99, 100, 101, 150, 200]

    for v in values:
        panel.SetValue(v)
        assert panel.GetValue() == v
Example #3
0
def _test_SliderSpinPanel_show_edit_limits():

    sim = wx.UIActionSimulator()
    frame = wx.GetApp().GetTopWindow()
    sizer = wx.BoxSizer(wx.HORIZONTAL)
    panel = floatslider.SliderSpinPanel(frame,
                                        style=floatslider.SSP_SHOW_LIMITS
                                        | floatslider.SSP_EDIT_LIMITS)
    sizer.Add(panel, flag=wx.EXPAND)
    frame.SetSizer(sizer)
    frame.Layout()

    panel.SetRange(0, 100)

    result = [None]

    def handler(ev):
        result[0] = (ev.min, ev.max)

    panel.Bind(floatslider.EVT_SSP_LIMIT, handler)

    numberdlg = mock.MagicMock()
    numberdlg.ShowModal.return_value = wx.ID_OK
    numberdlg.GetValue.return_value = 9

    minbtn = panel._SliderSpinPanel__minButton
    maxbtn = panel._SliderSpinPanel__maxButton

    # limbutton, value, expectedrange, shouldTriggerEvent
    testcases = [
        (minbtn, 50, (50, 100), True),
        (minbtn, 150, (50, 100), False),
        (minbtn, -100, (-100, 100), True),
        (maxbtn, 50, (-100, 50), True),
        (maxbtn, -200, (-100, 50), False),
        (maxbtn, 500, (-100, 500), True),
    ]

    with mock.patch('fsleyes_widgets.numberdialog.NumberDialog',
                    return_value=numberdlg):

        for btn, val, expected, shouldEv in testcases:

            result[0] = None

            numberdlg.GetValue.return_value = val

            realYield()
            simclick(sim, btn)
            assert tuple(panel.GetRange()) == expected

            if shouldEv: assert result[0] == expected
            else: assert result[0] is None
Example #4
0
def _test_SliderSpinPanel_events():

    sim = wx.UIActionSimulator()
    frame = wx.GetApp().GetTopWindow()
    panel = floatslider.SliderSpinPanel(frame, label='Value', style=0)
    sizer = wx.BoxSizer(wx.HORIZONTAL)
    sizer.Add(panel, flag=wx.EXPAND, proportion=1)
    frame.SetSizer(sizer)
    frame.Layout()

    ncalls = [0]
    called = [None]

    def handler(ev):
        ncalls[0] += 1
        called[0] = ev.value

    panel.Bind(floatslider.EVT_SSP_VALUE, handler)

    panel.SetRange(0, 100)

    realYield()
    simclick(sim, panel.slider, pos=[0.5, 0.5])

    assert abs(panel.spinCtrl.GetValue() - 50) < 5
    assert abs(panel.slider.GetValue() - 50) < 5
    assert abs(panel.GetValue() - 50) < 5
    assert called[0] - 50 < 5
    assert ncalls[0] == 1

    called[0] = None
    ncalls[0] = 0
    simtext(sim, panel.spinCtrl.textCtrl, '75')

    assert np.isclose(panel.spinCtrl.GetValue(), 75)
    assert np.isclose(panel.slider.GetValue(), 75)
    assert np.isclose(panel.GetValue(), 75)
    assert np.isclose(called[0], 75)
    assert ncalls[0] == 1
Example #5
0
    def __init__(self, parent, overlayList, displayCtx, frame, ortho):
        """Create an ``EditTransformPanel``.

        :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.
        """

        fslpanel.FSLeyesPanel.__init__(self, parent, overlayList, displayCtx,
                                       frame)

        self.__ortho = ortho

        # A ref to the currently selected
        # (compatible) overlay is kept here.
        # The __extraXform attribute is used
        # to store a FLIRT transform if the
        # user has loaded one. This 'extra'
        # matrix is used in place of the
        # image voxToWorldMat (i.e. its sform);
        # the scale/offset/ rotate transform
        # defined by the widgets on this panel
        # is still applied.
        #
        # In the future, I might allow the
        # user to load/apply an arbitrary
        # (non-FLIRT) transform.
        self.__overlay = None
        self.__extraXform = None

        # When the selected overlay is changed, the
        # transform settings for the previously selected
        # overlay are cached in this dict, so they can be
        # restored if/when the overlay is re-selected.
        #
        # { overlay : (scales, offsets, rotations, extraXform) }
        self.__cachedXforms = {}

        scArgs = {
            'value': 0,
            'minValue': 0.001,
            'maxValue': 3,
            'style': fslider.SSP_NO_LIMITS
        }

        offArgs = {
            'value': 0,
            'minValue': -250,
            'maxValue': 250,
            'style': fslider.SSP_NO_LIMITS
        }

        rotArgs = {'value': 0, 'minValue': -180, 'maxValue': 180, 'style': 0}

        self.__overlayName = wx.StaticText(self)
        self.__dsWarning = dswarning.DisplaySpaceWarning(
            self, overlayList, displayCtx, frame,
            strings.labels[self, 'dsWarning'], 'overlay', 'world')

        self.__xscale = fslider.SliderSpinPanel(self, label='X', **scArgs)
        self.__yscale = fslider.SliderSpinPanel(self, label='Y', **scArgs)
        self.__zscale = fslider.SliderSpinPanel(self, label='Z', **scArgs)

        self.__xoffset = fslider.SliderSpinPanel(self, label='X', **offArgs)
        self.__yoffset = fslider.SliderSpinPanel(self, label='Y', **offArgs)
        self.__zoffset = fslider.SliderSpinPanel(self, label='Z', **offArgs)

        self.__xrotate = fslider.SliderSpinPanel(self, label='X', **rotArgs)
        self.__yrotate = fslider.SliderSpinPanel(self, label='Y', **rotArgs)
        self.__zrotate = fslider.SliderSpinPanel(self, label='Z', **rotArgs)

        self.__scaleLabel = wx.StaticText(self)
        self.__offsetLabel = wx.StaticText(self)
        self.__rotateLabel = wx.StaticText(self)

        self.__oldXformLabel = wx.StaticText(self)
        self.__oldXform = wx.StaticText(self)
        self.__newXformLabel = wx.StaticText(self)
        self.__newXform = wx.StaticText(self)

        self.__apply = wx.Button(self)
        self.__reset = wx.Button(self)
        self.__loadFlirt = wx.Button(self)
        self.__saveFlirt = wx.Button(self)
        self.__cancel = wx.Button(self)

        self.__overlayName.SetLabel(strings.labels[self, 'noOverlay'])
        self.__scaleLabel.SetLabel(strings.labels[self, 'scale'])
        self.__offsetLabel.SetLabel(strings.labels[self, 'offset'])
        self.__rotateLabel.SetLabel(strings.labels[self, 'rotate'])
        self.__apply.SetLabel(strings.labels[self, 'apply'])
        self.__reset.SetLabel(strings.labels[self, 'reset'])
        self.__loadFlirt.SetLabel(strings.labels[self, 'loadFlirt'])
        self.__saveFlirt.SetLabel(strings.labels[self, 'saveFlirt'])
        self.__cancel.SetLabel(strings.labels[self, 'cancel'])
        self.__oldXformLabel.SetLabel(strings.labels[self, 'oldXform'])
        self.__newXformLabel.SetLabel(strings.labels[self, 'newXform'])

        # Populate the xform labels with a
        # dummy xform, so an appropriate
        # minimum size will get calculated
        # below
        self.__formatXform(np.eye(4), self.__oldXform)
        self.__formatXform(np.eye(4), self.__newXform)

        self.__primarySizer = wx.BoxSizer(wx.VERTICAL)
        self.__secondarySizer = wx.BoxSizer(wx.HORIZONTAL)
        self.__controlSizer = wx.BoxSizer(wx.VERTICAL)
        self.__xformSizer = wx.BoxSizer(wx.VERTICAL)
        self.__buttonSizer = wx.BoxSizer(wx.HORIZONTAL)

        self.__primarySizer.Add((1, 10), flag=wx.EXPAND)
        self.__primarySizer.Add(self.__overlayName, flag=wx.CENTRE)
        self.__primarySizer.Add(self.__dsWarning, flag=wx.CENTRE)
        self.__primarySizer.Add((1, 10), flag=wx.EXPAND)
        self.__primarySizer.Add(self.__secondarySizer)
        self.__primarySizer.Add((1, 10), flag=wx.EXPAND)
        self.__primarySizer.Add(self.__buttonSizer, flag=wx.EXPAND)
        self.__primarySizer.Add((1, 10), flag=wx.EXPAND)

        self.__secondarySizer.Add((10, 1), flag=wx.EXPAND)
        self.__secondarySizer.Add(self.__controlSizer)
        self.__secondarySizer.Add((10, 1), flag=wx.EXPAND)
        self.__secondarySizer.Add(self.__xformSizer, flag=wx.EXPAND)
        self.__secondarySizer.Add((10, 1), flag=wx.EXPAND)

        self.__controlSizer.Add(self.__scaleLabel)
        self.__controlSizer.Add(self.__xscale)
        self.__controlSizer.Add(self.__yscale)
        self.__controlSizer.Add(self.__zscale)
        self.__controlSizer.Add(self.__offsetLabel)
        self.__controlSizer.Add(self.__xoffset)
        self.__controlSizer.Add(self.__yoffset)
        self.__controlSizer.Add(self.__zoffset)
        self.__controlSizer.Add(self.__rotateLabel)
        self.__controlSizer.Add(self.__xrotate)
        self.__controlSizer.Add(self.__yrotate)
        self.__controlSizer.Add(self.__zrotate)

        self.__xformSizer.Add((1, 1), flag=wx.EXPAND, proportion=1)
        self.__xformSizer.Add(self.__oldXformLabel)
        self.__xformSizer.Add(self.__oldXform)
        self.__xformSizer.Add((1, 1), flag=wx.EXPAND, proportion=1)
        self.__xformSizer.Add(self.__newXformLabel)
        self.__xformSizer.Add(self.__newXform)
        self.__xformSizer.Add((1, 1), flag=wx.EXPAND, proportion=1)

        self.__buttonSizer.Add((10, 1), flag=wx.EXPAND, proportion=1)
        self.__buttonSizer.Add(self.__apply, flag=wx.EXPAND)
        self.__buttonSizer.Add((10, 1), flag=wx.EXPAND)
        self.__buttonSizer.Add(self.__reset, flag=wx.EXPAND)
        self.__buttonSizer.Add((10, 1), flag=wx.EXPAND)
        self.__buttonSizer.Add(self.__loadFlirt, flag=wx.EXPAND)
        self.__buttonSizer.Add((10, 1), flag=wx.EXPAND)
        self.__buttonSizer.Add(self.__saveFlirt, flag=wx.EXPAND)
        self.__buttonSizer.Add((10, 1), flag=wx.EXPAND)
        self.__buttonSizer.Add(self.__cancel, flag=wx.EXPAND)
        self.__buttonSizer.Add((10, 1), flag=wx.EXPAND, proportion=1)

        self.SetSizer(self.__primarySizer)
        self.SetMinSize(self.__primarySizer.GetMinSize())

        self.__xscale.Bind(fslider.EVT_SSP_VALUE, self.__xformChanged)
        self.__yscale.Bind(fslider.EVT_SSP_VALUE, self.__xformChanged)
        self.__zscale.Bind(fslider.EVT_SSP_VALUE, self.__xformChanged)
        self.__xoffset.Bind(fslider.EVT_SSP_VALUE, self.__xformChanged)
        self.__yoffset.Bind(fslider.EVT_SSP_VALUE, self.__xformChanged)
        self.__zoffset.Bind(fslider.EVT_SSP_VALUE, self.__xformChanged)
        self.__xrotate.Bind(fslider.EVT_SSP_VALUE, self.__xformChanged)
        self.__yrotate.Bind(fslider.EVT_SSP_VALUE, self.__xformChanged)
        self.__zrotate.Bind(fslider.EVT_SSP_VALUE, self.__xformChanged)

        self.__apply.Bind(wx.EVT_BUTTON, self.__onApply)
        self.__reset.Bind(wx.EVT_BUTTON, self.__onReset)
        self.__loadFlirt.Bind(wx.EVT_BUTTON, self.__onLoadFlirt)
        self.__saveFlirt.Bind(wx.EVT_BUTTON, self.__onSaveFlirt)
        self.__cancel.Bind(wx.EVT_BUTTON, self.__onCancel)

        displayCtx.addListener('selectedOverlay', self.name,
                               self.__selectedOverlayChanged)
        overlayList.addListener('overlays', self.name,
                                self.__selectedOverlayChanged)

        self.__selectedOverlayChanged()
Example #6
0
def _test_SliderSpinPanel_changeRange():
    frame = wx.GetApp().GetTopWindow()
    panel = floatslider.SliderSpinPanel(frame)
    _test_widget_changeRange(panel)
Example #7
0
def _test_SliderSpinPanel_logic_integer():
    frame = wx.GetApp().GetTopWindow()
    panel = floatslider.SliderSpinPanel(frame, style=floatslider.SSP_INTEGER)
    _test_widget_logic_integer(panel)
Example #8
0
def _test_SliderSpinPanel_logic():
    frame = wx.GetApp().GetTopWindow()
    panel = floatslider.SliderSpinPanel(frame)
    _test_widget_logic(panel)
Example #9
0
def _makeSlider(parent, hasProps, propObj, propVal, showSpin, showLimits,
                editLimits, mousewheel, spinWidth):
    """Used by the :func:`_Number` function.

    Creates and returns a :class:`.FloatSlider` or :class:`.SliderSpinPanel`,
    and binds it to the given :class:`.PropertyValue` instance.

    See :func:`_Number` for details on the parameters.
    """

    value = propVal.get()
    minval = propVal.getAttribute('minval')
    maxval = propVal.getAttribute('maxval')
    limited = propVal.getAttribute('clamped')

    if isinstance(propObj, ptypes.Int): real = False
    elif isinstance(propObj, ptypes.Real): real = True

    if not showSpin:

        if mousewheel: style = floatslider.FS_MOUSEWHEEL
        else: style = 0

        if not real:
            style |= floatslider.FS_INTEGER

        evt = wx.EVT_SLIDER
        slider = floatslider.FloatSlider(parent,
                                         value=value,
                                         minValue=minval,
                                         maxValue=maxval,
                                         style=style)

    else:
        evt = floatslider.EVT_SSP_VALUE
        style = 0

        if not real: style |= floatslider.SSP_INTEGER
        if not limited: style |= floatslider.SSP_NO_LIMITS
        if showLimits: style |= floatslider.SSP_SHOW_LIMITS
        if editLimits: style |= floatslider.SSP_EDIT_LIMITS
        if mousewheel: style |= floatslider.SSP_MOUSEWHEEL

        slider = floatslider.SliderSpinPanel(parent,
                                             value=value,
                                             minValue=minval,
                                             maxValue=maxval,
                                             style=style,
                                             spinWidth=spinWidth)

    # bind the slider value to the property value
    widgets._propBind(hasProps, propObj, propVal, slider, evt)

    # Update slider min/max bounds and labels
    # whenever the property attributes change.
    def updateSliderRange(*a):
        minval = propVal.getAttribute('minval')
        maxval = propVal.getAttribute('maxval')

        log.debug('Updating {} range from {}.{}: {} - {}'.format(
            type(slider).__name__,
            type(hasProps).__name__, propVal._name, minval, maxval))

        slider.SetRange(minval, maxval)
        # TODO check that value has changed due to the range change?

    listenerName = 'widgets_number_py_updateRange_{}'.format(id(slider))
    propVal.addAttributeListener(listenerName, updateSliderRange, weak=False)

    # remove the listener when the slider is destroyed
    def onDestroy(ev):
        propVal.removeAttributeListener(listenerName)
        ev.Skip()

    slider.Bind(wx.EVT_WINDOW_DESTROY, onDestroy)

    if editLimits:

        # When the user edits the slider bounds,
        # update the property attributes
        def updatePropRange(ev):
            propVal.setAttribute('minval', ev.min)
            propVal.setAttribute('maxval', ev.max)

        slider.Bind(floatslider.EVT_SSP_LIMIT, updatePropRange)

    return slider