Mercurial > code > home > repos > light9
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) |