Made the red a little brighter, to differentiate it from the orange (Salmonish color was too close). Also checked to make sure that the pygauge preferences default colors matched what we were actually using.
519 lines
14 KiB
Python
519 lines
14 KiB
Python
# --------------------------------------------------------------------------------- #
|
|
# PYFAGAUGE wxPython IMPLEMENTATION
|
|
#
|
|
# Darriele, @ 08/30/2010
|
|
# Updated: 09/07/2010
|
|
# Based on AWG : pygauge code
|
|
# --------------------------------------------------------------------------------- #
|
|
|
|
"""
|
|
PyfaGauge is a generic Gauge implementation tailored for PYFA (Python Fitting Assistant)
|
|
It uses the easeOutQuad equation from caurina.transitions.Tweener to do the animation stuff
|
|
"""
|
|
|
|
import wx
|
|
import copy
|
|
import math
|
|
|
|
class PyGauge(wx.PyWindow):
|
|
"""
|
|
This class provides a visual alternative for `wx.Gauge`. It currently
|
|
only support determinant mode (see SetValue and SetRange)
|
|
"""
|
|
|
|
def __init__(self, parent, id=wx.ID_ANY, range=100, pos=wx.DefaultPosition,
|
|
size=(-1,30), style=0):
|
|
"""
|
|
Default class constructor.
|
|
|
|
:param `parent`: parent window. Must not be ``None``;
|
|
:param `id`: window identifier. A value of -1 indicates a default value;
|
|
:param `pos`: the control position. A value of (-1, -1) indicates a default position,
|
|
chosen by either the windowing system or wxPython, depending on platform;
|
|
:param `size`: the control size. A value of (-1, -1) indicates a default size,
|
|
chosen by either the windowing system or wxPython, depending on platform.
|
|
"""
|
|
|
|
wx.PyWindow.__init__(self, parent, id, pos, size, style)
|
|
|
|
self._size = size
|
|
|
|
self._border_colour = wx.BLACK
|
|
self._barColour = self._barColourSorted = [wx.Colour(212,228,255)]
|
|
self._barGradient = self._barGradientSorted = None
|
|
|
|
self._border_padding = 0
|
|
self._range = range
|
|
self._value = 0
|
|
|
|
self._fractionDigits = 0
|
|
|
|
self._timerId = wx.NewId()
|
|
self._timer = None
|
|
|
|
self._oldValue = 0
|
|
|
|
self._animDuration = 700
|
|
self._animStep = 0
|
|
self._period = 20
|
|
self._animValue = 0
|
|
self._animDirection = 0
|
|
|
|
self.transitionsColors = [( (191, 191, 191, 255) , (96, 191, 0, 255) ),
|
|
( (191, 167, 96, 255) , (255, 191, 0, 255) ),
|
|
( (255, 191, 0, 255) , (255, 128, 0, 255) ),
|
|
( (255, 128, 0, 255) , (255, 0, 0, 255) )]
|
|
self.gradientEffect = 95
|
|
|
|
self._percentage = 0
|
|
self._oldPercentage = 0
|
|
|
|
self.font = wx.FontFromPixelSize((0,14),wx.SWISS, wx.NORMAL, wx.NORMAL, False)
|
|
|
|
self.SetBarGradient((wx.Colour(119,119,119),wx.Colour(153,153,153)))
|
|
self.SetBackgroundColour(wx.Colour(51,51,51))
|
|
self._tooltip = wx.ToolTip("")
|
|
self.SetToolTip(self._tooltip)
|
|
self._tooltip.SetTip("0/0")
|
|
|
|
self.Bind(wx.EVT_PAINT, self.OnPaint)
|
|
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
|
|
self.Bind(wx.EVT_TIMER, self.OnTimer)
|
|
|
|
|
|
def DoGetBestSize(self):
|
|
"""
|
|
Overridden base class virtual. Determines the best size of the
|
|
button based on the label and bezel size.
|
|
"""
|
|
|
|
return wx.Size(self._size[0], self._size[1])
|
|
|
|
|
|
def GetBorderColour(self):
|
|
return self._border_colour
|
|
|
|
def SetBorderColour(self, colour):
|
|
self._border_colour = colour
|
|
|
|
SetBorderColor = SetBorderColour
|
|
GetBorderColor = GetBorderColour
|
|
|
|
def GetBarColour(self):
|
|
return self._barColour[0]
|
|
|
|
def SetBarColour(self, colour):
|
|
if type(colour) != type([]):
|
|
self._barColour = [colour]
|
|
else:
|
|
self._barColour = list(colour)
|
|
|
|
SetBarColor = SetBarColour
|
|
GetBarColor = GetBarColour
|
|
|
|
def SetFractionDigits(self, digits):
|
|
self._fractionDigits=digits
|
|
|
|
def GetBarGradient(self):
|
|
""" Returns a tuple containing the gradient start and end colours. """
|
|
|
|
if self._barGradient == None:
|
|
return None
|
|
|
|
return self._barGradient[0]
|
|
|
|
def SetBarGradient(self, gradient = None):
|
|
"""
|
|
Sets the bar gradient. This overrides the BarColour.
|
|
|
|
:param `gradient`: a tuple containing the gradient start and end colours.
|
|
"""
|
|
if gradient == None:
|
|
self._barGradient = None
|
|
else:
|
|
if type(gradient) != type([]):
|
|
self._barGradient = [gradient]
|
|
else:
|
|
self._barGradient = list(gradient)
|
|
|
|
|
|
def GetBorderPadding(self):
|
|
""" Gets the border padding. """
|
|
|
|
return self._border_padding
|
|
|
|
def SetBorderPadding(self, padding):
|
|
"""
|
|
Sets the border padding.
|
|
|
|
:param `padding`: pixels between the border and the progress bar.
|
|
"""
|
|
|
|
self._border_padding = padding
|
|
|
|
|
|
def GetRange(self):
|
|
""" Returns the maximum value of the gauge. """
|
|
|
|
return self._range
|
|
|
|
def Animate(self):
|
|
if not self._timer:
|
|
self._timer = wx.Timer(self, self._timerId)
|
|
self._animStep = 0
|
|
self._timer.Start(self._period)
|
|
|
|
def SetRange(self, range, reinit = False):
|
|
"""
|
|
Sets the range of the gauge. The gauge length is its
|
|
value as a proportion of the range.
|
|
|
|
:param `range`: The maximum value of the gauge.
|
|
"""
|
|
|
|
if self._range == range:
|
|
return
|
|
|
|
range = float(range)
|
|
|
|
if range <= 0:
|
|
self._range = 0.01
|
|
else:
|
|
self._range = range
|
|
|
|
if reinit is False:
|
|
self._oldPercentage = self._percentage
|
|
self._percentage = (self._value/self._range) * 100
|
|
else:
|
|
self._oldPercentage = self._percentage
|
|
self._percentage = 0
|
|
self._value = 0
|
|
|
|
self.Animate()
|
|
|
|
|
|
self._tooltip.SetTip("%.2f/%.2f" % (self._value, self._range if self._range >0.01 else 0))
|
|
|
|
|
|
def GetValue(self):
|
|
""" Returns the current position of the gauge. """
|
|
|
|
return self._value
|
|
|
|
def SetValue(self, value):
|
|
""" Sets the current position of the gauge. """
|
|
if self._value == value:
|
|
return
|
|
|
|
value = float(value)
|
|
self._oldPercentage = self._percentage
|
|
self._value = value
|
|
if value < 0:
|
|
self._value = 0
|
|
self._percentage = (self._value/self._range) * 100
|
|
|
|
self.Animate()
|
|
|
|
self._tooltip.SetTip("%.2f/%.2f" % (self._value, self._range))
|
|
|
|
def SetValueRange(self, value, range, reinit = False):
|
|
if self._value == value and self._range == range:
|
|
return
|
|
|
|
range = float(range)
|
|
|
|
if range <= 0:
|
|
self._range = 0.01
|
|
else:
|
|
self._range = range
|
|
|
|
value = float(value)
|
|
|
|
self._value = value
|
|
if value < 0:
|
|
self._value = float(0)
|
|
|
|
if reinit is False:
|
|
self._oldPercentage = self._percentage
|
|
self._percentage = (self._value/self._range) * 100
|
|
|
|
else:
|
|
self._oldPercentage = self._percentage
|
|
self._percentage = 0
|
|
|
|
|
|
self.Animate()
|
|
self._tooltip.SetTip("%.2f/%.2f" % (self._value, self._range if self._range >0.01 else 0))
|
|
|
|
def OnEraseBackground(self, event):
|
|
"""
|
|
Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{PyGauge}.
|
|
|
|
:param `event`: a `wx.EraseEvent` event to be processed.
|
|
|
|
:note: This method is intentionally empty to reduce flicker.
|
|
"""
|
|
|
|
pass
|
|
|
|
def CalculateGColor(self, color, delta):
|
|
bkR ,bkG , bkB = color
|
|
scale = delta
|
|
|
|
r = bkR + scale
|
|
g = bkG + scale
|
|
b = bkB + scale
|
|
|
|
r = min(max(r,0),255)
|
|
b = min(max(b,0),255)
|
|
g = min(max(g,0),255)
|
|
|
|
return wx.Colour(r,g,b,255)
|
|
|
|
def CalculateTransitionColor(self, startColor, endColor, delta):
|
|
sR,sG,sB,_ = startColor
|
|
eR,eG,eB,_ = endColor
|
|
|
|
tR = sR + (eR - sR) * delta
|
|
tG = sG + (eG - sG) * delta
|
|
tB = sB + (eB - sB) * delta
|
|
|
|
return (tR, tG, tB)
|
|
|
|
def OnPaint(self, event):
|
|
"""
|
|
Handles the ``wx.EVT_PAINT`` event for L{PyGauge}.
|
|
|
|
:param `event`: a `wx.PaintEvent` event to be processed.
|
|
"""
|
|
|
|
dc = wx.BufferedPaintDC(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.DrawRectangleRect(rect)
|
|
|
|
value = self._percentage
|
|
if self._timer:
|
|
if self._timer.IsRunning():
|
|
value = self._animValue
|
|
|
|
if self._border_colour:
|
|
dc.SetPen(wx.Pen(self.GetBorderColour()))
|
|
dc.DrawRectangleRect(rect)
|
|
pad = 1 + self.GetBorderPadding()
|
|
rect.Deflate(pad,pad)
|
|
|
|
if self.GetBarGradient():
|
|
|
|
if value > 100:
|
|
w = rect.width
|
|
else:
|
|
w = rect.width * (float(value) / 100)
|
|
r = copy.copy(rect)
|
|
r.width = w
|
|
r.height = r.height/2+1
|
|
|
|
pv = value
|
|
xv=1
|
|
transition = 0
|
|
|
|
if pv <= 100:
|
|
xv = pv/100
|
|
transition = 0
|
|
|
|
elif pv <=101:
|
|
xv = pv -100
|
|
transition = 1
|
|
|
|
elif pv <= 103:
|
|
xv = (pv -101)/2
|
|
transition = 2
|
|
|
|
elif pv <= 105:
|
|
xv = (pv -103)/2
|
|
transition = 3
|
|
|
|
else:
|
|
pv = 106
|
|
xv = pv -100
|
|
transition = -1
|
|
|
|
if transition != -1:
|
|
colorS,colorE = self.transitionsColors[transition]
|
|
color = self.CalculateTransitionColor(colorS, colorE, xv)
|
|
else:
|
|
color = wx.Colour(191,48,48)
|
|
|
|
gcolor = self.CalculateGColor(color, -self.gradientEffect)
|
|
|
|
dc.GradientFillLinear(r, gcolor, color, wx.SOUTH)
|
|
r.top = r.height
|
|
dc.GradientFillLinear(r, gcolor, color, wx.NORTH)
|
|
else:
|
|
colour=self.GetBarColour()
|
|
dc.SetBrush(wx.Brush(colour))
|
|
dc.SetPen(wx.Pen(colour))
|
|
if value > 100:
|
|
w = rect.width
|
|
else:
|
|
w = rect.width * (float(value) / 100)
|
|
r = copy.copy(rect)
|
|
r.width = w
|
|
dc.DrawRectangleRect(r)
|
|
|
|
dc.SetFont(self.font)
|
|
|
|
r = copy.copy(rect)
|
|
r.left +=1
|
|
r.top +=1
|
|
if self._range == 0.01 and self._value > 0:
|
|
formatStr = u'\u221e'
|
|
dc.SetTextForeground(wx.Colour(80,80,80))
|
|
dc.DrawLabel(formatStr, r, wx.ALIGN_CENTER)
|
|
|
|
dc.SetTextForeground(wx.Colour(255,255,255))
|
|
dc.DrawLabel(formatStr, rect, wx.ALIGN_CENTER)
|
|
else:
|
|
formatStr = "{0:." + str(self._fractionDigits) + "f}%"
|
|
dc.SetTextForeground(wx.Colour(80,80,80))
|
|
dc.DrawLabel(formatStr.format(value), r, wx.ALIGN_CENTER)
|
|
|
|
dc.SetTextForeground(wx.Colour(255,255,255))
|
|
dc.DrawLabel(formatStr.format(value), rect, wx.ALIGN_CENTER)
|
|
|
|
def OUT_CIRC (self, t, b, c, d):
|
|
t=float(t)
|
|
b=float(b)
|
|
c=float(c)
|
|
d=float(d)
|
|
t = t/d -1
|
|
return c * math.sqrt(1 - t*t) + b;
|
|
|
|
def OUT_QUART(self, t, b, c, d):
|
|
t=float(t)
|
|
b=float(b)
|
|
c=float(c)
|
|
d=float(d)
|
|
t = t/d -1
|
|
return -c * ((t)*t*t*t - 1) + b;
|
|
|
|
def INOUT_CIRC(self, t, b, c, d):
|
|
t=float(t)
|
|
b=float(b)
|
|
c=float(c)
|
|
d=float(d)
|
|
t1 = t / (d / 2)
|
|
|
|
if ((t / (d/2)) < 1):
|
|
return -c/2 * (math.sqrt(1 - (t/(d/2))**2) - 1) + b
|
|
return c/2 * (math.sqrt(1 - (t1-2)**2) + 1) + b;
|
|
|
|
def IN_CUBIC (self, t, b, c, d):
|
|
t=float(t)
|
|
b=float(b)
|
|
c=float(c)
|
|
d=float(d)
|
|
t = t/d
|
|
return c*t*t*t + b
|
|
|
|
def OUT_QUAD (self, t, b, c, d):
|
|
t=float(t)
|
|
b=float(b)
|
|
c=float(c)
|
|
d=float(d)
|
|
|
|
t/=d
|
|
|
|
return -c *(t)*(t-2) + b
|
|
|
|
def OUT_BOUNCE (self, t, b, c, d):
|
|
t=float(t)
|
|
b=float(b)
|
|
c=float(c)
|
|
d=float(d)
|
|
|
|
t/=d
|
|
|
|
if ((t) < (1/2.75)):
|
|
return c*(7.5625*t*t) + b
|
|
else:
|
|
if (t < (2/2.75)):
|
|
t-=(1.5/2.75)
|
|
return c*(7.5625*t*t + .75) + b
|
|
else:
|
|
if (t < (2.5/2.75)):
|
|
t-=(2.25/2.75)
|
|
return c*(7.5625*(t)*t + .9375) + b
|
|
else:
|
|
t-=(2.625/2.75)
|
|
return c*(7.5625*(t)*t + .984375) + b
|
|
|
|
def INOUT_EXP(self, t, b, c, d):
|
|
t=float(t)
|
|
b=float(b)
|
|
c=float(c)
|
|
d=float(d)
|
|
t1 = t / (d/2)
|
|
if t==0:
|
|
return b
|
|
if t==d:
|
|
return b+c
|
|
if (t1) < 1:
|
|
return c/2 * math.pow(2, 10 * (t1 - 1)) + b - c * 0.0005
|
|
return c/2 * 1.0005 * (-math.pow(2, -10 * (t1-1)) + 2) + b
|
|
|
|
|
|
def OnTimer(self,event):
|
|
"""
|
|
Handles the ``wx.EVT_TIMER`` event for L{PyfaGauge}.
|
|
|
|
:param `event`: a timer event
|
|
"""
|
|
oldValue=self._oldPercentage
|
|
value=self._percentage
|
|
|
|
if oldValue < value:
|
|
direction = 1
|
|
start = 0
|
|
end = value-oldValue
|
|
else:
|
|
direction = -1
|
|
start = 0
|
|
end = oldValue - value
|
|
self._animDirection = direction
|
|
step=self.OUT_QUAD(self._animStep, start, end, self._animDuration)
|
|
|
|
self._animStep += self._period
|
|
|
|
if self._timerId == event.GetId():
|
|
stop_timer = False
|
|
|
|
if self._animStep > self._animDuration:
|
|
stop_timer = True
|
|
|
|
if direction == 1:
|
|
if (oldValue+step) < value:
|
|
self._animValue = oldValue+step
|
|
else:
|
|
stop_timer = True
|
|
else:
|
|
if (oldValue-step) > value:
|
|
self._animValue = oldValue-step
|
|
|
|
else:
|
|
stop_timer = True
|
|
|
|
if stop_timer:
|
|
self._timer.Stop()
|
|
|
|
self.Refresh()
|
|
|