def __init__(self, parent, baseValue, minValue, maxValue, inverse=False, id=-1): wx.Panel.__init__(self, parent, id=id) self.parent = parent self.base_value = baseValue self.UserMinValue = minValue self.UserMaxValue = maxValue print(self.UserMinValue, self.UserMaxValue) self.inverse = inverse def getStep(valRange): """ Find step for the passed range, which is based on 1, 2 or 5. Step returned will make sure that range fits 10..50 of them, as close to 10 as possible. """ steps = {1: None, 2: None, 5: None} for baseInc in steps: baseIncAmount = valRange / baseInc incScale = math.floor(math.log10(baseIncAmount) - 1) steps[baseInc] = baseInc * 10 ** incScale chosenBase = min(steps, key=lambda base: valRange / steps[base]) chosenStep = steps[chosenBase] if inverse: chosenStep *= -1 return chosenStep def getDigitPlaces(minValue, maxValue): minDigits = 3 maxDigits = 5 currentDecision = minDigits for value in (floatUnerr(minValue), floatUnerr(maxValue)): for currentDigit in range(minDigits, maxDigits + 1): if round(value, currentDigit) == value: if currentDigit > currentDecision: currentDecision = currentDigit break # Max decimal places we can afford to show was not enough else: return maxDigits return currentDecision self.ctrl = wx.SpinCtrlDouble(self, min=minValue, max=maxValue, inc=getStep(maxValue - minValue)) self.ctrl.SetDigits(getDigitPlaces(minValue, maxValue)) self.ctrl.Bind(wx.EVT_SPINCTRLDOUBLE, self.UpdateValue) self.slider = AttributeGauge(self, size=(-1, 8)) b = 4 vsizer1 = wx.BoxSizer(wx.VERTICAL) vsizer1.Add(self.ctrl, 0, wx.LEFT | wx.RIGHT | wx.CENTER, b) vsizer1.Add(self.slider, 0, wx.EXPAND | wx.ALL , b) self.SetSizerAndFit(vsizer1) self.parent.SetClientSize((500, vsizer1.GetSize()[1]))
def __init__(self, parent, baseValue, minMod, maxMod, inverse=False, id=-1): wx.Panel.__init__(self, parent, id=id) self.parent = parent self.inverse = inverse self.base_value = baseValue self.UserMinValue = minMod self.UserMaxValue = maxMod # The internal slider basically represents the percentage towards the end of the range. It has to be normalized # in this way, otherwise when we start off with a base, if the range is skewed to one side, the base value won't # be centered. We use a range of -100,100 so that we can depend on the SliderValue to contain the percentage # toward one end # Additionally, since we want the slider to be accurate to 3 decimal places, we need to blow out the two ends here # (if we have a slider that needs to land on 66.66% towards the right, it will actually be converted to 66%. Se we need it to support 6,666) self.SliderMinValue = -100 self.SliderMaxValue = 100 self.SliderValue = 0 range = [(self.UserMinValue * self.base_value), (self.UserMaxValue * self.base_value)] self.ctrl = wx.SpinCtrlDouble(self, min=min(range), max=max(range)) self.ctrl.SetDigits(3) self.ctrl.Bind(wx.EVT_SPINCTRLDOUBLE, self.UpdateValue) self.slider = AttributeGauge(self, size=(-1, 8)) b = 4 vsizer1 = wx.BoxSizer(wx.VERTICAL) vsizer1.Add(self.ctrl, 0, wx.LEFT | wx.RIGHT | wx.CENTER, b) vsizer1.Add(self.slider, 0, wx.EXPAND | wx.ALL, b) self.SetSizerAndFit(vsizer1) self.parent.SetClientSize((500, vsizer1.GetSize()[1]))
class AttributeSlider(wx.Panel): # Slider which abstracts users values from internal values (because the built in slider does not deal with floats # and the like), based on http://wxpython-users.wxwidgets.narkive.com/ekgBzA7u/anyone-ever-thought-of-a-floating-point-slider def __init__(self, parent, baseValue, minValue, maxValue, inverse=False, id=-1): wx.Panel.__init__(self, parent, id=id) self.parent = parent self.base_value = baseValue self.UserMinValue = minValue self.UserMaxValue = maxValue self.inverse = inverse # The internal slider basically represents the percentage towards the end of the range. It has to be normalized # in this way, otherwise when we start off with a base, if the range is skewed to one side, the base value won't # be centered. We use a range of -100,100 so that we can depend on the SliderValue to contain the percentage # toward one end # Additionally, since we want the slider to be accurate to 3 decimal places, we need to blow out the two ends here # (if we have a slider that needs to land on 66.66% towards the right, it will actually be converted to 66%. Se we need it to support 6,666) # # self.SliderMinValue = -100 # self.SliderMaxValue = 100 # self.SliderValue = 0 range = [self.UserMinValue, self.UserMaxValue] self.ctrl = wx.SpinCtrlDouble(self, min=min(range), max=max(range)) self.ctrl.SetDigits(3) self.ctrl.Bind(wx.EVT_SPINCTRLDOUBLE, self.UpdateValue) self.slider = AttributeGauge(self, size=(-1, 8)) b = 4 vsizer1 = wx.BoxSizer(wx.VERTICAL) vsizer1.Add(self.ctrl, 0, wx.LEFT | wx.RIGHT | wx.CENTER, b) vsizer1.Add(self.slider, 0, wx.EXPAND | wx.ALL , b) self.SetSizerAndFit(vsizer1) self.parent.SetClientSize((500, vsizer1.GetSize()[1])) def UpdateValue(self, evt): self.SetValue(self.ctrl.GetValue()) evt.Skip() def SetValue(self, value, post_event=True): self.ctrl.SetValue(value) invert_factor = -1 if self.inverse else 1 if value >= self.base_value: slider_percentage = (value - self.base_value) / (self.UserMaxValue - self.base_value) * 100 * invert_factor else: slider_percentage = (value - self.base_value) / (self.base_value - self.UserMinValue) * 100 * invert_factor self.slider.SetValue(slider_percentage) if post_event: wx.PostEvent(self, ValueChanged(self, None, value, None, slider_percentage))
class AttributeSlider(wx.Panel): # Slider which abstracts users values from internal values (because the built in slider does not deal with floats # and the like), based on http://wxpython-users.wxwidgets.narkive.com/ekgBzA7u/anyone-ever-thought-of-a-floating-point-slider def __init__(self, parent, baseValue, minValue, maxValue, inverse=False, id=-1): wx.Panel.__init__(self, parent, id=id) self.parent = parent self.base_value = baseValue self.UserMinValue = minValue self.UserMaxValue = maxValue self.inverse = inverse def getStep(valRange): """ Find step for the passed range, which is based on 1, 2 or 5. Step returned will make sure that range fits 10..50 of them, as close to 10 as possible. """ steps = {1: None, 2: None, 5: None} for baseInc in steps: baseIncAmount = valRange / baseInc incScale = math.floor(math.log10(baseIncAmount) - 1) steps[baseInc] = baseInc * 10**incScale chosenBase = min(steps, key=lambda base: valRange / steps[base]) chosenStep = steps[chosenBase] if inverse: chosenStep *= -1 return chosenStep def getDigitPlaces(minValue, maxValue): minDigits = 3 maxDigits = 5 currentDecision = minDigits for value in (floatUnerr(minValue), floatUnerr(maxValue)): for currentDigit in range(minDigits, maxDigits + 1): if round(value, currentDigit) == value: if currentDigit > currentDecision: currentDecision = currentDigit break # Max decimal places we can afford to show was not enough else: return maxDigits return currentDecision self.ctrl = wx.SpinCtrlDouble(self, min=minValue, max=maxValue, inc=getStep(maxValue - minValue)) self.ctrl.SetDigits(getDigitPlaces(minValue, maxValue)) self.ctrl.Bind(wx.EVT_SPINCTRLDOUBLE, self.UpdateValue) # GTK scrolls spinboxes with mousewheel, others do not if "wxGTK" not in wx.PlatformInfo: self.ctrl.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel) self.slider = AttributeGauge(self, size=(-1, 8)) b = 4 vsizer1 = wx.BoxSizer(wx.VERTICAL) vsizer1.Add(self.ctrl, 0, wx.LEFT | wx.RIGHT | wx.CENTER, b) vsizer1.Add(self.slider, 0, wx.EXPAND | wx.ALL, b) self.SetSizerAndFit(vsizer1) self.parent.SetClientSize((500, vsizer1.GetSize()[1])) def UpdateValue(self, evt): self.SetValue(self.ctrl.GetValue()) evt.Skip() def SetValue(self, value, post_event=True): self.ctrl.SetValue(value) invert_factor = -1 if self.inverse else 1 if value >= self.base_value: slider_percentage = (value - self.base_value) / ( self.UserMaxValue - self.base_value) * 100 * invert_factor else: slider_percentage = (value - self.base_value) / ( self.base_value - self.UserMinValue) * 100 * invert_factor self.slider.SetValue(slider_percentage) if post_event: wx.PostEvent( self, ValueChanged(self, None, value, None, slider_percentage)) def OnMouseWheel(self, evt): if evt.GetWheelRotation() > 0 and evt.GetWheelAxis( ) == wx.MOUSE_WHEEL_VERTICAL: self.ctrl.Value = self.ctrl.Value + self.ctrl.Increment self.SetValue(self.ctrl.GetValue()) elif evt.GetWheelRotation() < 0 and evt.GetWheelAxis( ) == wx.MOUSE_WHEEL_VERTICAL: self.ctrl.Value = self.ctrl.Value - self.ctrl.Increment self.SetValue(self.ctrl.GetValue()) else: evt.Skip()