diff --git a/Widgets/FlyingFader.py b/Widgets/FlyingFader.py new file mode 100644 --- /dev/null +++ b/Widgets/FlyingFader.py @@ -0,0 +1,191 @@ +from Tix import * +from time import time,sleep +from __future__ import division + +class Mass: + def __init__(self): + self.x=0 # position + self.xgoal=0 # position goal + + self.v=0 # velocity + self.maxspeed = .8 # maximum speed, in position/second + self.maxaccel = 3 # maximum acceleration, in position/second^2 + self.eps = .03 # epsilon - numbers within this much are considered the same + + self._lastupdate=time() + self._stopped=1 + + def equal(self,a,b): + return abs(a-b)1: self.v=max(self.v,0); self.x=1 + if self.x<0: self.v=min(self.v,0); self.x=0 + + if self.equal(self.x,self.xgoal): + self.x=self.xgoal # clean up value + self.stop() + return + + self._stopped=0 + dir = (-1.0,1,0)[self.xgoal>self.x] + + if abs(self.xgoal-self.x) < abs(self.v*5*dt): + # apply the brakes on the last 5 steps + dir *= -.5 + + self.v += dir*self.maxaccel*dt # velocity changes with acceleration in the right direction + self.v = min(max(self.v,-self.maxspeed),self.maxspeed) # clamp velocity + + #print "x=%+.03f v=%+.03f a=%+.03f %f" % (self.x,self.v,self.maxaccel,self.xgoal) + + def goto(self,newx): + self.xgoal=newx + + def ismoving(self): + return not self._stopped + +class FlyingFader(Frame): + def __init__(self, master, variable, label, fadedur=1.5, font=('Arial', 8), labelwidth=12, + **kw): + Frame.__init__(self, master) + self.name = label + self.variable = variable + + self.mass = Mass() + + self.config({'bd':1, 'relief':'raised'}) + scaleopts = {'variable' : variable, 'showvalue' : 0, 'from' : 1.0, + 'to' : 0, 'res' : 0.001, 'width' : 20, 'length' : 200, 'orient':'vert'} + scaleopts.update(kw) + if scaleopts['orient']=='vert': + side1=TOP + side2=BOTTOM + else: + side1=RIGHT + side2=LEFT + + self.scale = Scale(self, **scaleopts) + self.vlabel = Label(self, text="0.0", width=6, font=font) + self.label = Label(self, text=label, font=font, anchor='w',width=labelwidth) #wraplength=40, ) + + self.oldtrough = self.scale['troughcolor'] + + self.scale.pack(side=side2, expand=1, fill=BOTH, anchor='c') + self.vlabel.pack(side=side2, expand=0, fill=X) + self.label.pack(side=side2, expand=0, fill=X) + + for k in range(1, 10): + self.scale.bind("" % k, + lambda evt, k=k: self.newfade(k / 10.0, evt)) + + self.scale.bind("", lambda evt: self.newfade(1.0, evt)) + self.scale.bind("", lambda evt: self.newfade(0, evt)) + + self.scale.bind("<1>", self.cancelfade) + self.scale.bind("<2>", self.cancelfade) + self.scale.bind("<3>", self.mousefade) + + self.trace_ret = self.variable.trace('w', self.updatelabel) + self.bind("",self.ondestroy) + + def ondestroy(self,*ev): + self.variable.trace_vdelete('w',self.trace_ret) + + def cancelfade(self, evt): + self.fadegoal = self.variable.get() + self.fadevel = self.fadeacc = 0 + + self.scale['troughcolor'] = self.oldtrough + + def mousefade(self, evt): + target = float(self.tk.call(self.scale, 'get', evt.x, evt.y)) + self.newfade(target, evt) + + def ismoving(self): + return self.fadevel!=0 or self.fadeacc!=0 + + def newfade(self, newlevel, evt=None, length=None): + + # these are currently unused-- Mass needs to accept a speed input + mult = 1 + if evt.state & 8 and evt.state & 4: mult = 0.25 # both + elif evt.state & 8: mult = 0.5 # alt + elif evt.state & 4: mult = 2 # control + + + self.mass.x = self.variable.get() + self.mass.goto(newlevel) + + self.gofade() + + def gofade(self): + self.mass.update() + self.variable.set(self.mass.x) + + if not self.mass.ismoving(): + self.scale['troughcolor'] = self.oldtrough + return + + # blink the trough while the thing's moving + if time()%.4>.2: + # self.scale.config(troughcolor=self.oldtrough) + self.scale.config(troughcolor='orange') + else: + # self.scale.config(troughcolor='white') + self.scale.config(troughcolor='yellow') + +# colorfade(self.scale, percent) + self.after(30, self.gofade) + + def updatelabel(self, *args): + if self.variable: + self.vlabel['text'] = "%.3f" % self.variable.get() +# if self.fadetimes[1] == 0: # no fade +# self.vlabel['fg'] = 'black' +# elif self.curfade[1] > self.curfade[0]: +# self.vlabel['fg'] = 'red' +# else: +# self.vlabel['fg'] = 'blue' + + def get(self): + return self.scale.get() + + def set(self, val): + self.scale.set(val) + +def colorfade(scale, lev): + low = (255, 255, 255) + high = (0, 0, 0) + out = [int(l+lev*(h-l)) for h, l in zip(high,low)] + col="#%02X%02X%02X" % tuple(out) + scale.config(troughcolor=col) + +if __name__ == '__main__': + root = Tk() + root.tk_focusFollowsMouse() + + FlyingFader(root, variable=DoubleVar(), label="suck").pack(side=LEFT, + expand=1, fill=BOTH) + FlyingFader(root, variable=DoubleVar(), label="moof").pack(side=LEFT, + expand=1, fill=BOTH) + FlyingFader(root, variable=DoubleVar(), label="zarf").pack(side=LEFT, + expand=1, fill=BOTH) + FlyingFader(root, variable=DoubleVar(), + label="long name goes here. got it?").pack(side=LEFT, expand=1, + fill=BOTH) + + root.mainloop()