Changes to attribute slider, and thinking about dropping it in support of a modified pyfa gauge
This commit is contained in:
344
gui/attribute_gauge.py
Normal file
344
gui/attribute_gauge.py
Normal file
@@ -0,0 +1,344 @@
|
||||
# ===============================================================================
|
||||
# PyfaGauge is a generic Gauge implementation tailored for pyfa (the Python
|
||||
# Fitting Assistant). It uses the easeOutQuad equation from
|
||||
# caurina.transitions.Tweener to do animations
|
||||
#
|
||||
# ToDo: make SetGradient(<value, colour start, colour end)
|
||||
# ToDo: make a solid gradient (not to->from and not dependant on value)
|
||||
# ToDo: fix 0 range (currently resets range to 0.01, but this causes problems if
|
||||
# we really set range at 0.01). Perhaps make it -1 and test percentage as
|
||||
# a negativeor something.
|
||||
# ToDo: possibly devise a way to determine transition percents on init
|
||||
# (currently hardcoded)
|
||||
#
|
||||
# ===============================================================================
|
||||
|
||||
import copy
|
||||
import wx
|
||||
|
||||
from gui.utils import color as color_utils
|
||||
from gui.utils import draw, anim_effects
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
class AttributeGauge(wx.Window):
|
||||
def __init__(self, parent, max_range=100, size=(-1, 30), *args,
|
||||
**kargs):
|
||||
|
||||
super().__init__(parent, size=size, *args, **kargs)
|
||||
|
||||
self._size = size
|
||||
|
||||
self._border_colour = wx.BLACK
|
||||
self._bar_colour = None
|
||||
self._bar_gradient = None
|
||||
|
||||
self._border_padding = 0
|
||||
self._max_range = max_range
|
||||
self._value = 0
|
||||
|
||||
self._fraction_digits = 0
|
||||
|
||||
self._timer_id = wx.NewId()
|
||||
self._timer = None
|
||||
|
||||
self._oldValue = 0
|
||||
|
||||
self._anim_duration = 500
|
||||
self._anim_step = 0
|
||||
self._period = 20
|
||||
self._anim_value = 0
|
||||
self._anim_direction = 0
|
||||
self.anim_effect = anim_effects.OUT_QUAD
|
||||
|
||||
# transition colors used based on how full (or overfilled) the gauge is.
|
||||
self.transition_colors = [
|
||||
(wx.Colour(191, 191, 191), wx.Colour(96, 191, 0)), # < 0-100%
|
||||
(wx.Colour(191, 167, 96), wx.Colour(255, 191, 0)), # < 100-101%
|
||||
(wx.Colour(255, 191, 0), wx.Colour(255, 128, 0)), # < 101-103%
|
||||
(wx.Colour(255, 128, 0), wx.Colour(255, 0, 0)) # < 103-105%
|
||||
]
|
||||
|
||||
self.gradient_effect = -35
|
||||
|
||||
self._percentage = 0
|
||||
self._old_percentage = 0
|
||||
self._show_remaining = False
|
||||
|
||||
self.SetBackgroundColour(wx.Colour(51, 51, 51))
|
||||
|
||||
self._tooltip = wx.ToolTip("0.00/100.00")
|
||||
self.SetToolTip(self._tooltip)
|
||||
|
||||
self.Bind(wx.EVT_PAINT, self.OnPaint)
|
||||
self.Bind(wx.EVT_TIMER, self.OnTimer)
|
||||
self.Bind(wx.EVT_ENTER_WINDOW, self.OnWindowEnter)
|
||||
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnWindowLeave)
|
||||
self.SetBackgroundStyle(wx.BG_STYLE_PAINT)
|
||||
|
||||
def OnEraseBackground(self, event):
|
||||
pass
|
||||
|
||||
def OnWindowEnter(self, event):
|
||||
self._show_remaining = True
|
||||
self.Refresh()
|
||||
|
||||
def OnWindowLeave(self, event):
|
||||
self._show_remaining = False
|
||||
self.Refresh()
|
||||
|
||||
def GetBorderColour(self):
|
||||
return self._border_colour
|
||||
|
||||
def SetBorderColour(self, colour):
|
||||
self._border_colour = colour
|
||||
|
||||
def GetBarColour(self):
|
||||
return self._bar_colour
|
||||
|
||||
def SetBarColour(self, colour):
|
||||
self._bar_colour = colour
|
||||
|
||||
def SetFractionDigits(self, digits):
|
||||
self._fraction_digits = digits
|
||||
|
||||
def GetBarGradient(self):
|
||||
if self._bar_gradient is None:
|
||||
return None
|
||||
|
||||
return self._bar_gradient[0]
|
||||
|
||||
def SetBarGradient(self, gradient=None):
|
||||
if gradient is None:
|
||||
self._bar_gradient = None
|
||||
else:
|
||||
if not isinstance(gradient, list):
|
||||
self._bar_gradient = [gradient]
|
||||
else:
|
||||
self._bar_gradient = list(gradient)
|
||||
|
||||
def GetBorderPadding(self):
|
||||
return self._border_padding
|
||||
|
||||
def SetBorderPadding(self, padding):
|
||||
self._border_padding = padding
|
||||
|
||||
def GetRange(self):
|
||||
""" Returns the maximum value of the gauge. """
|
||||
return self._max_range
|
||||
|
||||
def Animate(self):
|
||||
#sFit = Fit.getInstance()
|
||||
if False:
|
||||
if not self._timer:
|
||||
self._timer = wx.Timer(self, self._timer_id)
|
||||
|
||||
self._anim_step = 0
|
||||
self._timer.Start(self._period)
|
||||
else:
|
||||
self._anim_value = self._percentage
|
||||
self.Refresh()
|
||||
|
||||
def SetRange(self, range, reinit=False, animate=True):
|
||||
"""
|
||||
Sets the range of the gauge. The gauge length is its
|
||||
value as a proportion of the range.
|
||||
"""
|
||||
|
||||
if self._max_range == range:
|
||||
return
|
||||
|
||||
# we cannot have a range of zero (laws of physics, etc), so we set it
|
||||
if range <= 0:
|
||||
self._max_range = 0.01
|
||||
else:
|
||||
self._max_range = range
|
||||
|
||||
if reinit is False:
|
||||
self._old_percentage = self._percentage
|
||||
self._percentage = (self._value / self._max_range) * 100
|
||||
else:
|
||||
self._old_percentage = self._percentage
|
||||
self._percentage = 0
|
||||
self._value = 0
|
||||
|
||||
if animate:
|
||||
self.Animate()
|
||||
|
||||
self._tooltip.SetTip("%.2f/%.2f" % (self._value, self._max_range if self._max_range > 0.01 else 0))
|
||||
|
||||
def GetValue(self):
|
||||
return self._value
|
||||
|
||||
def SetValue(self, value, animate=True):
|
||||
""" Sets the current position of the gauge. """
|
||||
if self._value == value:
|
||||
return
|
||||
|
||||
self._old_percentage = self._percentage
|
||||
self._value = value
|
||||
|
||||
self._percentage = (self._value / self._max_range) * 100
|
||||
|
||||
if animate:
|
||||
self.Animate()
|
||||
|
||||
self._tooltip.SetTip("%.2f/%.2f" % (self._value, self._max_range))
|
||||
|
||||
def SetValueRange(self, value, range, reinit=False):
|
||||
""" Set both value and range of the gauge. """
|
||||
range_ = float(range)
|
||||
|
||||
if range_ <= 0:
|
||||
self._max_range = 0.01
|
||||
else:
|
||||
self._max_range = range_
|
||||
|
||||
value = float(value)
|
||||
|
||||
self._value = value
|
||||
if value < 0:
|
||||
self._value = float(0)
|
||||
|
||||
if reinit is False:
|
||||
self._old_percentage = self._percentage
|
||||
self._percentage = (self._value / self._max_range) * 100
|
||||
|
||||
else:
|
||||
self._old_percentage = self._percentage
|
||||
self._percentage = 0
|
||||
|
||||
self.Animate()
|
||||
self._tooltip.SetTip("%.2f/%.2f" %
|
||||
(self._value, self._max_range if float(self._max_range) > 0.01 else 0))
|
||||
|
||||
def OnPaint(self, event):
|
||||
dc = wx.AutoBufferedPaintDC(self)
|
||||
rect = self.GetClientRect()
|
||||
|
||||
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
|
||||
dc.Clear()
|
||||
|
||||
colour = self.GetBackgroundColour()
|
||||
|
||||
dc.SetBrush(wx.Brush(colour))
|
||||
dc.SetPen(wx.Pen(colour))
|
||||
|
||||
dc.DrawRectangle(rect)
|
||||
|
||||
value = abs(self._percentage)
|
||||
|
||||
if self._timer:
|
||||
if self._timer.IsRunning():
|
||||
value = self._anim_value
|
||||
|
||||
if self._border_colour:
|
||||
dc.SetPen(wx.Pen(self.GetBorderColour()))
|
||||
dc.DrawRectangle(rect)
|
||||
pad = 1 + self.GetBorderPadding()
|
||||
rect.Deflate(pad, pad)
|
||||
|
||||
if self.GetBarColour():
|
||||
# if we have a bar color set, then we will use this
|
||||
|
||||
colour = self.GetBarColour()
|
||||
dc.SetBrush(wx.Brush(colour))
|
||||
dc.SetPen(wx.Pen(colour))
|
||||
|
||||
half = (rect.width / 2)
|
||||
# calculate width of bar and draw it
|
||||
w = (rect.width * (value / 100)) / 2
|
||||
w = min(w, half)
|
||||
|
||||
print(half, w)
|
||||
|
||||
if self._percentage >= 0:
|
||||
padding = half
|
||||
else:
|
||||
padding = min(half-w, half)
|
||||
|
||||
#r = copy.copy(rect)
|
||||
dc.DrawRectangle(padding+1, 1, w, rect.height)
|
||||
|
||||
def OnTimer(self, event):
|
||||
old_value = self._old_percentage
|
||||
value = self._percentage
|
||||
start = 0
|
||||
|
||||
# -1 = left direction, 1 = right direction
|
||||
direction = 1 if old_value < value else -1
|
||||
|
||||
end = direction * (value - old_value)
|
||||
|
||||
self._anim_direction = direction
|
||||
step = self.anim_effect(self._anim_step, start, end, self._anim_duration)
|
||||
|
||||
self._anim_step += self._period
|
||||
|
||||
if self._timer_id == event.GetId():
|
||||
stop_timer = False
|
||||
|
||||
if self._anim_step > self._anim_duration:
|
||||
stop_timer = True
|
||||
|
||||
# add new value to the animation if we haven't reached our goal
|
||||
# otherwise, stop animation
|
||||
if direction == 1:
|
||||
if old_value + step < value:
|
||||
self._anim_value = old_value + step
|
||||
else:
|
||||
stop_timer = True
|
||||
else:
|
||||
if old_value - step > value:
|
||||
self._anim_value = old_value - step
|
||||
else:
|
||||
stop_timer = True
|
||||
|
||||
if stop_timer:
|
||||
self._timer.Stop()
|
||||
|
||||
self.Refresh()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
def frange(x, y, jump):
|
||||
while x < y:
|
||||
yield x
|
||||
x += jump
|
||||
|
||||
class MyPanel(wx.Panel):
|
||||
def __init__(self, parent, size=(500, 500)):
|
||||
wx.Panel.__init__(self, parent, size=size)
|
||||
box = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
font = wx.Font(9, wx.SWISS, wx.NORMAL, wx.NORMAL, False)
|
||||
|
||||
gauge = AttributeGauge(self, size=(100, 25))
|
||||
gauge.SetBackgroundColour(wx.Colour(52, 86, 98))
|
||||
gauge.SetBarColour(wx.Colour(255, 128, 0))
|
||||
gauge.SetValue(-25)
|
||||
gauge.SetFractionDigits(1)
|
||||
box.Add(gauge, 0, wx.ALL, 2)
|
||||
|
||||
self.SetSizer(box)
|
||||
self.Layout()
|
||||
|
||||
# see animation going backwards with last gauge
|
||||
#wx.CallLater(2000, self.ChangeValues)
|
||||
|
||||
def ChangeValues(self):
|
||||
self.gauge.SetValueRange(4, 100)
|
||||
|
||||
class Frame(wx.Frame):
|
||||
def __init__(self, title, size=(500, 800)):
|
||||
wx.Frame.__init__(self, None, title=title, size=size)
|
||||
self.statusbar = self.CreateStatusBar()
|
||||
main_sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
panel = MyPanel(self, size=size)
|
||||
main_sizer.Add(panel)
|
||||
self.SetSizer(main_sizer)
|
||||
|
||||
app = wx.App(redirect=False) # Error messages go to popup window
|
||||
top = Frame("Test Chrome Tabs")
|
||||
top.Show()
|
||||
app.MainLoop()
|
||||
@@ -19,8 +19,11 @@ class AttributeSlider(wx.Panel):
|
||||
# be centered. We use a range of -100,100 so that we can depend on the SliderValue to contain the percentage
|
||||
# toward one end
|
||||
|
||||
self.SliderMinValue = -100
|
||||
self.SliderMaxValue = 100
|
||||
# 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_000
|
||||
self.SliderMaxValue = 100_000
|
||||
self.SliderValue = 0
|
||||
|
||||
self.statxt1 = wx.StaticText(self, wx.ID_ANY, 'left',
|
||||
@@ -70,10 +73,10 @@ class AttributeSlider(wx.Panel):
|
||||
slider_percentage = 0
|
||||
if mod < 1:
|
||||
modEnd = -1 * self.UserMinValue
|
||||
slider_percentage = (modEnd / mod) * 100
|
||||
slider_percentage = (modEnd / mod) * 10_000
|
||||
elif mod > 1:
|
||||
modEnd = self.UserMaxValue
|
||||
slider_percentage = ((mod-1)/(modEnd-1)) * 100
|
||||
slider_percentage = ((mod-1)/(modEnd-1)) * 100_000
|
||||
|
||||
self.slider.SetValue(slider_percentage)
|
||||
self.CalculateUserValue()
|
||||
@@ -90,19 +93,19 @@ class AttributeSlider(wx.Panel):
|
||||
mod = self.UserMaxValue
|
||||
|
||||
# Get the slider value percentage as an absolute value
|
||||
slider_mod = abs(self.SliderValue) / 100
|
||||
slider_mod = abs(self.SliderValue/1_000) / 100
|
||||
|
||||
# Gets our new mod by use the slider's percentage to determine where in the spectrum it is
|
||||
new_mod = mod + ((1 - mod) - ((1 - mod) * slider_mod))
|
||||
|
||||
# Modifies our base vale, to get out modified value
|
||||
# Modifies our base value, to get out modified value
|
||||
newValue = new_mod * self.base_value
|
||||
|
||||
if mod == 1:
|
||||
self.statxt2.SetLabel("{0:.3f}".format(newValue))
|
||||
else:
|
||||
self.statxt2.SetLabel("{0:.3f} ({1:+.3f})".format(newValue, newValue - self.base_value, ))
|
||||
self.statxt2.SetToolTip("{0:+f}%".format(newValue))
|
||||
self.statxt2.SetToolTip("{0:+f}%".format(new_mod*100))
|
||||
|
||||
|
||||
class TestAttributeSlider(wx.Frame):
|
||||
@@ -114,8 +117,8 @@ class TestAttributeSlider(wx.Frame):
|
||||
sty = wx.DEFAULT_FRAME_STYLE
|
||||
wx.Frame.__init__(self, parent, id, title, pos, size, sty)
|
||||
|
||||
self.panel = AttributeSlider(self, 200, .80, 2.5)
|
||||
self.panel.SetValue(400)
|
||||
self.panel = AttributeSlider(self, 10, .80, 1.5)
|
||||
self.panel.SetValue(8.805)
|
||||
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
|
||||
@@ -130,8 +130,8 @@ class PyGauge(wx.Window):
|
||||
return self._max_range
|
||||
|
||||
def Animate(self):
|
||||
sFit = Fit.getInstance()
|
||||
if sFit.serviceFittingOptions["enableGaugeAnimation"]:
|
||||
#sFit = Fit.getInstance()
|
||||
if True:
|
||||
if not self._timer:
|
||||
self._timer = wx.Timer(self, self._timer_id)
|
||||
|
||||
@@ -425,6 +425,13 @@ if __name__ == "__main__":
|
||||
gauge.SetFractionDigits(1)
|
||||
box.Add(gauge, 0, wx.ALL, 2)
|
||||
|
||||
gauge = PyGauge(self, font, size=(100, 5))
|
||||
gauge.SetBackgroundColour(wx.Colour(52, 86, 98))
|
||||
gauge.SetBarColour(wx.Colour(255, 128, 0))
|
||||
gauge.SetValue(59)
|
||||
gauge.SetFractionDigits(1)
|
||||
box.Add(gauge, 0, wx.ALL, 2)
|
||||
|
||||
self.SetSizer(box)
|
||||
self.Layout()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user