1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import copy
24 import gobject
25
27 '''
28 Linear interpolator
29
30 @param factor: the current factor
31 @param lower: the init lower value
32 @param lower: the init upper value
33 @return: the calculated value
34 '''
35 return factor * (upper - lower)
37 '''
38 Random interpolator
39
40 @param base: the base value used to calculate result value
41 @param offset: the offset apply to base.
42 @return: the random value based on 'base' and 'offset'
43 '''
44
45 import random
46 return random.randint(base-offset/2, base+offset/2)
47
48
50 '''
51 The animation class used to convenient production special effects.
52
53 @undocumented: init
54 @undocumented: init_all
55 @undocumented: compute
56 '''
57 - def __init__(self,
58 widgets,
59 property,
60 duration,
61 ranges,
62 interpolator=LinerInterpolator,
63 stop_callback=None):
64 '''
65 Initialize Animation class.
66
67 @param widgets: the widgets apply to this animation. the type of
68 this param is an gtk.Widget or an list of gtk.Widget.
69
70 @param property: the gtk.Widget's property used to do effect or an function to change the actual effect.
71 @param duration: the time of this effect to continued, the unit of time
72 is millisecond
73 @param ranges: the range of the property's value. the type of this param
74 is an [lower,upper] or ([lower, upper], [lower,upper]), this is decsion by the parameter of the 'widget' or 'widgets'.
75 @param interpolator: this is an function used to calculate the property value by the current time and value range.
76 @param stop_callback: the callback when this animation stop.
77 '''
78 self.stop_callback = stop_callback
79 self.delay = 50
80 try:
81 widgets[0]
82
83 self.widgets = widgets
84
85 except:
86 self.widgets = [copy.weakref.ref(widgets)]
87
88 if isinstance(ranges, tuple):
89 self.ranges = ranges
90 else:
91 self.ranges = (ranges,)
92
93
94 self.duration = duration
95 self.interpolator = interpolator
96 self.time = 0
97 self.animation_id = None
98 self.start_id = None
99 self.other_concurent = []
100 self.other_after = []
101
102 def set_method1(*values):
103 for widget in self.widgets:
104 if isinstance(widget, copy.weakref.ref):
105 property(widget(), *values)
106 else:
107 property(widget, *values)
108
109 def set_method2(*values):
110 for widget in self.widgets:
111 if isinstance(widget, copy.weakref.ref):
112 widget().set_property(property, *values)
113 else:
114 widget.set_property(property, *values)
115
116
117 if callable(property):
118 self.set_method = set_method1
119 else:
120 self.set_method = set_method2
121
123 '''
124 Set the delay time of before the start do effect.
125
126 @param delay: the time of dealy, unit of time is millisecond
127 '''
128 self.delay = delay
129
130 - def init(self, values=None):
131 if isinstance(values, list):
132 self.set_method(*values)
133 else:
134 self.set_method(values)
135 self.time = 0
136
138 if isinstance(values, list):
139 values.reverse()
140 self.init(values.pop())
141 for o in self.other_concurent:
142 value = values.pop()
143 o.init(value)
144 else:
145 raise Warning("init_all should init multi animation")
146
148 '''
149 Start the animation after the dealy time.
150 or you can use Animation.set_delay function.
151
152 @param time: the time of dealy, unit of time is millisecond
153 '''
154 if self.start_id:
155 gobject.source_remove(self.start_id)
156 self.start_id = gobject.timeout_add(time, self.start)
157 for o in self.other_concurent:
158 o.start_after(time)
159
161 '''
162 Start the animation object.
163 '''
164 self.time = 0
165 self.animation_id = gobject.timeout_add(self.delay, self.compute)
166 for o in self.other_concurent:
167 o.start()
168 return False
169
171 '''
172 stop immediately the animation object
173 '''
174 if self.animation_id:
175 gobject.source_remove(self.animation_id)
176 if self.start_id:
177 gobject.source_remove(self.start_id)
178
179 for o in self.other_concurent:
180 o.stop()
181
182
183 if self.stop_callback:
184 self.stop_callback()
185
187 if self.time >= self.duration+self.delay:
188
189 if self.stop_callback:
190 self.stop_callback()
191 return False
192
193 values = []
194 for r in self.ranges:
195 factor = float(self.time) / self.duration
196 value = self.interpolator(factor, r[0], r[1])
197 values.append(r[0]+value)
198
199 self.set_method(*values)
200
201 for o in self.other_concurent:
202 o.compute()
203
204 self.time += self.delay
205
206 return True
207
209 '''
210 Overload the '*' operator to link two or more animation object.
211 the animation's effect is happend parallel.
212 @param other: the right hand side animation class.
213 @return: the new animation class with the two operator animation's effect.
214 '''
215 r = copy.deepcopy(self)
216 r.other_concurent.append(other)
217 return r
218
221
222 if __name__ == "__main__":
223 import gtk
224 win = gtk.Window()
225 win.set_position(gtk.WIN_POS_CENTER)
226
227 box = gtk.VBox()
228
229 ani1 = Animation(win, lambda widget, v1, v2: widget.move(int(v1), int(v2)), 1000, ([200, 400], [200, 400]))
230 b1 = gtk.Button("moving....(set multip value)")
231 b1.connect('clicked', lambda w: ani1.start())
232 box.add(b1)
233
234 ani2 = Animation(win, "opacity", 1000, [0, 1])
235 b2 = gtk.Button("opacity(set single value)")
236 b2.connect('clicked', lambda w: ani2.start())
237 box.add(b2)
238
239 ani3 = ani2 * ani1
240 b3 = gtk.Button("composited animation")
241 b3.connect('clicked', lambda w: ani3.start())
242 box.add(b3)
243
244 ani4 = Animation(win,
245 lambda w, v1, v2: w.move(w.get_position()[0]+int(v1), w.get_position()[1]+int(v2)),
246 800, ([0, 0], [0,0]), lambda *args : RandomInterpolator(00, 20))
247 b4 = gtk.Button("vibration")
248 b4.connect('clicked', lambda w: ani4.start())
249 box.add(b4)
250
251 ani5 = Animation(win, lambda w, v1, v2: w.resize(int(v1), int(v2)), 300, ([20, 300], [20, 300]))
252 b5 = gtk.Button("smaller")
253 b5.connect('clicked', lambda w: ani5.start())
254 box.add(b5)
255
256 win.add(box)
257 win.show_all()
258 win.connect('destroy', gtk.main_quit)
259 win.connect_after('show', lambda w: ani3.start())
260
261 gtk.main()
262