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
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
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
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
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()
def _test_SliderSpinPanel_changeRange(): frame = wx.GetApp().GetTopWindow() panel = floatslider.SliderSpinPanel(frame) _test_widget_changeRange(panel)
def _test_SliderSpinPanel_logic_integer(): frame = wx.GetApp().GetTopWindow() panel = floatslider.SliderSpinPanel(frame, style=floatslider.SSP_INTEGER) _test_widget_logic_integer(panel)
def _test_SliderSpinPanel_logic(): frame = wx.GetApp().GetTopWindow() panel = floatslider.SliderSpinPanel(frame) _test_widget_logic(panel)
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