comparison Widgets/FlyingFader.py @ 24:548d3aa2660f

physics model fader!
author drewp
date Sun, 07 Jul 2002 08:04:56 +0000
parents 626aa2179630
children f0e1dde35aec
comparison
equal deleted inserted replaced
23:768442c7d023 24:548d3aa2660f
1 from Tkinter import * 1 from Tkinter import *
2 from time import time 2 from time import time,sleep
3 from __future__ import division
4
5 class Mass:
6 def __init__(self):
7 self.x=0 # position
8 self.xgoal=0 # position goal
9
10 self.v=0 # velocity
11 self.maxspeed = .8 # maximum speed, in position/second
12
13 self.maxaccel = 3 # maximum acceleration, in position/second^2
14
15 self.eps = .01 # epsilon - numbers within this much are considered the same
16
17 self._lastupdate=time()
18 self._stopped=1
19
20 def equal(self,a,b):
21 return abs(a-b)<self.eps
22
23 def stop(self):
24 self.v=0
25 self.xgoal=self.x
26 self._stopped=1
27
28 def update(self):
29 t0 = self._lastupdate
30 tnow = time()
31 self._lastupdate = tnow
32
33 dt = tnow-t0
34
35 self.x += self.v*dt
36 # hitting the ends stops the slider
37 if self.x>1: self.v=max(self.v,0); self.x=1
38 if self.x<0: self.v=min(self.v,0); self.x=0
39
40 if self.equal(self.x,self.xgoal):
41 self.x=self.xgoal # clean up value
42 self.stop()
43 return
44
45 self._stopped=0
46 dir = (-1.0,1,0)[self.xgoal>self.x]
47
48 self.v += dir*self.maxaccel*dt # velocity changes with acceleration in the right direction
49 self.v = min(max(self.v,-self.maxspeed),self.maxspeed) # clamp velocity
50
51 print "x=%+.03f v=%+.03f a=%+.03f %f" % (self.x,self.v,self.maxaccel,self.xgoal)
52
53 def goto(self,newx):
54 self.xgoal=newx
55
56 def ismoving(self):
57 return not self._stopped
3 58
4 class FlyingFader(Frame): 59 class FlyingFader(Frame):
5 def __init__(self, master, variable, label, fadedur=1.5, font=('Arial', 8), 60 def __init__(self, master, variable, label, fadedur=1.5, font=('Arial', 8),
6 **kw): 61 **kw):
7 Frame.__init__(self, master) 62 Frame.__init__(self, master)
8 self.name = label 63 self.name = label
9 self.variable = variable 64 self.variable = variable
10 self.fadedur = fadedur
11 self.curfade = None
12 self.fadetimes = 0, 0
13 65
66 self.mass = Mass()
67
14 self.config({'bd':1, 'relief':'raised'}) 68 self.config({'bd':1, 'relief':'raised'})
15 scaleopts = {'variable' : variable, 'showvalue' : 0, 'from' : 1.0, 69 scaleopts = {'variable' : variable, 'showvalue' : 0, 'from' : 1.0,
16 'to' : 0, 'res' : 0.001, 'width' : 20, 'length' : 200} 70 'to' : 0, 'res' : 0.001, 'width' : 20, 'length' : 200}
17 scaleopts.update(kw) 71 scaleopts.update(kw)
18 72
28 82
29 for k in range(1, 10): 83 for k in range(1, 10):
30 self.scale.bind("<Key-%d>" % k, 84 self.scale.bind("<Key-%d>" % k,
31 lambda evt, k=k: self.newfade(k / 10.0, evt)) 85 lambda evt, k=k: self.newfade(k / 10.0, evt))
32 86
33 self.scale.bind("<Key-0>", lambda evt: self.newfade(100, evt)) 87 self.scale.bind("<Key-0>", lambda evt: self.newfade(1.0, evt))
34 self.scale.bind("<grave>", lambda evt: self.newfade(0, evt)) 88 self.scale.bind("<grave>", lambda evt: self.newfade(0, evt))
35 89
36 self.scale.bind("<1>", self.cancelfade) 90 self.scale.bind("<1>", self.cancelfade)
37 self.scale.bind("<2>", self.cancelfade) 91 self.scale.bind("<2>", self.cancelfade)
38 self.scale.bind("<3>", self.mousefade) 92 self.scale.bind("<3>", self.mousefade)
39 93
40 self.variable.trace('w', self.updatelabel) 94 self.variable.trace('w', self.updatelabel)
41 95
42 def cancelfade(self, evt): 96 def cancelfade(self, evt):
43 self.fadetimes = 0, 0 97 self.fadegoal = self.variable.get()
44 self.curfade = 0, self.variable.get() 98 self.fadevel = self.fadeacc = 0
99
45 self.scale['troughcolor'] = self.oldtrough 100 self.scale['troughcolor'] = self.oldtrough
46 101
47 def mousefade(self, evt): 102 def mousefade(self, evt):
48 target = float(self.tk.call(self.scale, 'get', evt.x, evt.y)) 103 target = float(self.tk.call(self.scale, 'get', evt.x, evt.y))
49 self.newfade(target, evt) 104 self.newfade(target, evt)
50 105
51 def isfading(self): 106 def ismoving(self):
52 return self.fadetimes[0] or self.fadetimes[1] 107 return self.fadevel!=0 or self.fadeacc!=0
53 108
54 def newfade(self, newlevel, evt=None, length=None): 109 def newfade(self, newlevel, evt=None, length=None):
55 if length is None: 110
56 length = self.fadedur
57 mult = 1 111 mult = 1
58 112
59 if evt.state & 8 and evt.state & 4: mult = 0.25 # both 113 if evt.state & 8 and evt.state & 4: mult = 0.25 # both
60 elif evt.state & 8: mult = 0.5 # alt 114 elif evt.state & 8: mult = 0.5 # alt
61 elif evt.state & 4: mult = 2 # control 115 elif evt.state & 4: mult = 2 # control
62 116
63 now = time() 117 self.mass.x = self.variable.get()
64 if not self.isfading(): 118 self.mass.goto(newlevel)
65 self.fadetimes = (now, now + (mult * length))
66 self.curfade = (self.variable.get(), newlevel)
67 else:
68 # already fading
69 t1,t2=self.fadetimes
70 v1,v2=self.curfade
71 rate = abs((v2-v1)/(t2-t1))
72
73 vnow=self.variable.get()
74 newdist=abs(newlevel-vnow)
75 newdur=newdist/rate
76
77 self.fadetimes = (now,now+newdur)
78 self.curfade=(vnow,newlevel)
79
80
81 119
82 self.scale['troughcolor'] = 'red' 120 self.scale['troughcolor'] = 'red'
83 121
84 self.gofade() 122 self.gofade()
85 123
86 def gofade(self): 124 def gofade(self):
87 now = time() 125 self.mass.update()
88 start, end = self.fadetimes 126 self.variable.set(self.mass.x)
89 lstart, lend = self.curfade 127
90 if now > end: 128
91 self.fadetimes = 0, 0 129 if not self.mass.ismoving():
92 self.variable.set(lend)
93 self.scale['troughcolor'] = self.oldtrough 130 self.scale['troughcolor'] = self.oldtrough
94 return 131 return
95 percent = (now - start) / (end - start) 132
96 newvalue = (percent * (lend - lstart)) + lstart 133 # colorfade(self.scale, percent)
97 self.variable.set(newvalue)
98 colorfade(self.scale, percent)
99 self.after(30, self.gofade) 134 self.after(30, self.gofade)
100 135
101 def updatelabel(self, *args): 136 def updatelabel(self, *args):
102 self.vlabel['text'] = "%.3f" % self.variable.get() 137 self.vlabel['text'] = "%.3f" % self.variable.get()
103 if self.fadetimes[1] == 0: # no fade 138 # if self.fadetimes[1] == 0: # no fade
104 self.vlabel['fg'] = 'black' 139 # self.vlabel['fg'] = 'black'
105 elif self.curfade[1] > self.curfade[0]: 140 # elif self.curfade[1] > self.curfade[0]:
106 self.vlabel['fg'] = 'red' 141 # self.vlabel['fg'] = 'red'
107 else: 142 # else:
108 self.vlabel['fg'] = 'blue' 143 # self.vlabel['fg'] = 'blue'
109 144
110 def get(self): 145 def get(self):
111 return self.scale.get() 146 return self.scale.get()
112 147
113 def set(self, val): 148 def set(self, val):
120 out = [int(l+lev*(h-l)) for h, l in zip(high,low)] 155 out = [int(l+lev*(h-l)) for h, l in zip(high,low)]
121 col="#%02X%02X%02X" % tuple(out) 156 col="#%02X%02X%02X" % tuple(out)
122 scale.config(troughcolor=col) 157 scale.config(troughcolor=col)
123 158
124 if __name__ == '__main__': 159 if __name__ == '__main__':
160
161
162 # m=Mass()
163 # m.goto(3)
164 # while 1:
165 # m.update()
166 # print "%.03f %.03f" % (m.x, m.v)
167 # sleep(.02)
168
125 root = Tk() 169 root = Tk()
126 root.tk_focusFollowsMouse() 170 root.tk_focusFollowsMouse()
127 171
128 FlyingFader(root, variable=DoubleVar(), label="suck").pack(side=LEFT, 172 FlyingFader(root, variable=DoubleVar(), label="suck").pack(side=LEFT,
129 expand=1, fill=BOTH) 173 expand=1, fill=BOTH)