Merge lp:~andrea.corbellini/a4/clean-player into lp:a4
- clean-player
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 49 |
Proposed branch: | lp:~andrea.corbellini/a4/clean-player |
Merge into: | lp:a4 |
Diff against target: |
451 lines (+139/-143) 3 files modified
a4lib/app.py (+4/-5) a4lib/player.py (+107/-117) a4lib/region.py (+28/-21) |
To merge this branch: | bzr merge lp:~andrea.corbellini/a4/clean-player |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrea Gasparini | Approve | ||
Review via email: mp+29842@code.launchpad.net |
Commit message
Description of the change
Here I've focused my attention of cleaning up the a4lib.player module. Here's what I've done:
* PEP 8 and 257.
* Some optimizations:
1. removed all comparisons with None;
2. replaced lists with tuples when possible;
3. use of local variables when possible;
4. some other minus optimizations.
There's a thing that I've not cleaned up because I would like to have some feedback on the topic. I see there are three classes for just one player: Player, CairoPlayer, GtkCairoPlayer. I'd merge everything into Player if there are no objections.
- 51. By Andrea Corbellini
-
Little fix.
Andrea Corbellini (andrea.corbellini) wrote : | # |
On Wed, 2010-07-14 at 09:15 +0000, Andrea Gasparini wrote:
> Review: Needs Fixing
> Completely agree on the cleaning part.
>
> Just a little fix, these lines:
> 175 + self.area = drawing_area
> 176 + self.drawing_
> have to be:
> 175 + self.area = drawing_area
> 176 + self.area.
> Otherwise it wont work.
Oops, sorry! I thought I had tested everything.
> About *Player class, perhaps it'd be fine to merge CairoPlayer and
> GtkCairoPlayer (let's still think about it a little); although the
> base Player class could be useful, as it could be tested without a
> GUI, and cause it could be subclassed by a future Wx/Qt/web/whatever
> based GUI.
That's fine, I agree.
--
Ubuntu member | http://
BeeSeek member | http://
Andrea Gasparini (gaspa) wrote : | # |
Yay, approving! thanks ;)
Preview Diff
1 | === modified file 'a4lib/app.py' | |||
2 | --- a4lib/app.py 2010-07-08 14:49:06 +0000 | |||
3 | +++ a4lib/app.py 2010-07-14 09:29:23 +0000 | |||
4 | @@ -59,10 +59,9 @@ | |||
5 | 59 | """Open a file inside this window.""" | 59 | """Open a file inside this window.""" |
6 | 60 | self.set_status('Loading {0}...'.format(file_name)) | 60 | self.set_status('Loading {0}...'.format(file_name)) |
7 | 61 | try: | 61 | try: |
9 | 62 | # Try to open a file. | 62 | # Try to open the file. |
10 | 63 | self.player = GtkCairoPlayer( | 63 | self.player = GtkCairoPlayer( |
13 | 64 | self.builder.get_object('drawing_area')) | 64 | file_name, self.builder.get_object('drawing_area')) |
12 | 65 | self.player.load_presentation(file_name) | ||
14 | 66 | except PresentationError as error: | 65 | except PresentationError as error: |
15 | 67 | # The file doesn't exist, or is not an SVG file. Show an error | 66 | # The file doesn't exist, or is not an SVG file. Show an error |
16 | 68 | # dialog and don't do anything else. | 67 | # dialog and don't do anything else. |
17 | @@ -146,12 +145,12 @@ | |||
18 | 146 | def on_zoom_in_clicked(self, widget): | 145 | def on_zoom_in_clicked(self, widget): |
19 | 147 | "The zoom in button has been clicked" | 146 | "The zoom in button has been clicked" |
20 | 148 | if self.player != None: | 147 | if self.player != None: |
22 | 149 | self.player.zoomin() | 148 | self.player.zoom_in() |
23 | 150 | 149 | ||
24 | 151 | def on_zoom_out_clicked(self, widget): | 150 | def on_zoom_out_clicked(self, widget): |
25 | 152 | "The zoom out button has been cliched" | 151 | "The zoom out button has been cliched" |
26 | 153 | if self.player != None: | 152 | if self.player != None: |
28 | 154 | self.player.zoomout() | 153 | self.player.zoom_out() |
29 | 155 | 154 | ||
30 | 156 | def on_drawing_area_expose(self, widget, event): | 155 | def on_drawing_area_expose(self, widget, event): |
31 | 157 | """This method is called everytime the drawing area should be redrawn. | 156 | """This method is called everytime the drawing area should be redrawn. |
32 | 158 | 157 | ||
33 | === modified file 'a4lib/player.py' | |||
34 | --- a4lib/player.py 2010-07-09 13:33:55 +0000 | |||
35 | +++ a4lib/player.py 2010-07-14 09:29:23 +0000 | |||
36 | @@ -1,35 +1,28 @@ | |||
37 | 1 | # Copyright 2010 A4 Developers. This software is licensed under the | 1 | # Copyright 2010 A4 Developers. This software is licensed under the |
38 | 2 | # GNU General Public License version 3 (see the file COPYING). | 2 | # GNU General Public License version 3 (see the file COPYING). |
39 | 3 | 3 | ||
40 | 4 | import cairo | ||
41 | 5 | import glib | 4 | import glib |
42 | 6 | import gtk | 5 | import gtk |
44 | 7 | from a4lib.presentation import Presentation, PresentationError | 6 | from a4lib.presentation import Presentation |
45 | 8 | from a4lib.region import Region, Animation, linear_interpolation | 7 | from a4lib.region import Region, Animation, linear_interpolation |
46 | 9 | 8 | ||
47 | 10 | 9 | ||
48 | 11 | class Player(object): | 10 | class Player(object): |
61 | 12 | """ This class handle moving the frame generically from a position to | 11 | """Handle the frame moving generically from a position to another.""" |
62 | 13 | another """ | 12 | |
63 | 14 | 13 | def __init__(self, file_name): | |
52 | 15 | def __init__(self): | ||
53 | 16 | ## each zoom call Region.scle_of with this factor | ||
54 | 17 | self.zoom_factor = 1.4 | ||
55 | 18 | self.current_region = None | ||
56 | 19 | self.view_status = None | ||
57 | 20 | self.current_animation = None | ||
58 | 21 | |||
59 | 22 | def load_presentation(self, file_name): | ||
60 | 23 | """ Set the presentation file, and try to load it """ | ||
64 | 24 | image = Presentation(file_name) | 14 | image = Presentation(file_name) |
65 | 25 | self.presentation = image | 15 | self.presentation = image |
66 | 26 | self.current_region = Region.whole_image(image) | 16 | self.current_region = Region.whole_image(image) |
67 | 17 | self.current_animation = None | ||
68 | 18 | # Each zoom call Region.scale_of with this factor. | ||
69 | 19 | self.zoom_factor = 1.4 | ||
70 | 20 | self.view_status = -1 | ||
71 | 27 | 21 | ||
72 | 28 | def _set_animation_to(self, target): | 22 | def _set_animation_to(self, target): |
77 | 29 | """ Calculate Animation given the id of two point of a presentation """ | 23 | """Calculate `Animation` given the id of two point of a presentation. |
78 | 30 | if not self.current_region: | 24 | """ |
79 | 31 | return | 25 | if target < 0: |
76 | 32 | if target == None: | ||
80 | 33 | target_region = Region.whole_image(self.presentation) | 26 | target_region = Region.whole_image(self.presentation) |
81 | 34 | else: | 27 | else: |
82 | 35 | image = self.presentation | 28 | image = self.presentation |
83 | @@ -39,68 +32,56 @@ | |||
84 | 39 | self.current_animation = Animation(self.current_region, target_region) | 32 | self.current_animation = Animation(self.current_region, target_region) |
85 | 40 | 33 | ||
86 | 41 | def next(self): | 34 | def next(self): |
95 | 42 | """ Send the frame to the next presentation region """ | 35 | """Send the frame to the next presentation region.""" |
96 | 43 | start = self.view_status | 36 | self.view_status = min( |
97 | 44 | if self.view_status == None: | 37 | self.view_status + 1, len(self.presentation.get_path()) - 1) |
90 | 45 | self.view_status = 0 | ||
91 | 46 | else: | ||
92 | 47 | self.view_status += 1 | ||
93 | 48 | if self.view_status >= len(self.presentation.get_path()): | ||
94 | 49 | self.view_status = len(self.presentation.get_path()) - 1 | ||
98 | 50 | self._set_animation_to(self.view_status) | 38 | self._set_animation_to(self.view_status) |
99 | 51 | 39 | ||
100 | 52 | def previous(self): | 40 | def previous(self): |
133 | 53 | """ Send the frame to the previous presentation region """ | 41 | """Send the frame to the previous presentation region.""" |
134 | 54 | start = self.view_status | 42 | self.view_status -= 1 |
135 | 55 | if not self.view_status: | 43 | self._set_animation_to(self.view_status) |
136 | 56 | self.view_status = None | 44 | |
137 | 57 | else: | 45 | def go_to(self, position): |
138 | 58 | self.view_status -= 1 | 46 | self.view_status = min( |
139 | 59 | self._set_animation_to(self.view_status) | 47 | position, len(self.presentation.get_path()) - 1) |
140 | 60 | 48 | self._set_animation_to(self.view_status) | |
141 | 61 | def goto(self, position): | 49 | |
142 | 62 | start = self.view_status | 50 | def zoom_in(self, translation=(0, 0)): |
143 | 63 | if position >= len(self.presentation.get_path()): | 51 | if self.current_region is None: |
144 | 64 | position = len(self.presentation.get_path()) - 1 | 52 | return |
145 | 65 | self.view_status = position | 53 | factor = 1.0 / self.zoom_factor |
146 | 66 | self._set_animation_to(position) | 54 | region = self.current_region.scale_of( |
147 | 67 | 55 | factor, factor).move(*translation) | |
148 | 68 | def zoomin(self, translation=(0, 0)): | 56 | self.current_animation = Animation( |
149 | 69 | if self.current_region != None: | 57 | self.current_region, region, 0.2, linear_interpolation) |
150 | 70 | factor = 1.0 / self.zoom_factor | 58 | |
151 | 71 | region = self.current_region.scale_of(factor, | 59 | def zoom_out(self, translation=(0, 0)): |
152 | 72 | factor).move(*translation) | 60 | if self.current_region is None: |
153 | 73 | self.current_animation = Animation(self.current_region, | 61 | return |
154 | 74 | region, 0.2, linear_interpolation) | 62 | region = self.current_region.scale_of( |
155 | 75 | 63 | self.zoom_factor, self.zoom_factor).move(*translation) | |
156 | 76 | def zoomout(self, translation=(0, 0)): | 64 | self.current_animation = Animation( |
157 | 77 | if self.current_region != None: | 65 | self.current_region, region, 0.2, linear_interpolation) |
158 | 78 | region = self.current_region.scale_of(self.zoom_factor, | 66 | |
159 | 79 | self.zoom_factor).move(*translation) | 67 | def move(self, step_x, step_y): |
160 | 80 | self.current_animation = Animation(self.current_region, | 68 | if self.current_animation and self.current_animation.status != 'ended': |
129 | 81 | region, 0.2, linear_interpolation) | ||
130 | 82 | |||
131 | 83 | def move(self, stepx, stepy): | ||
132 | 84 | if self.current_animation and self.current_animation.status != "ended": | ||
161 | 85 | self.current_animation = None | 69 | self.current_animation = None |
163 | 86 | self.current_region = self.current_region.move(stepx, stepy) | 70 | self.current_region = self.current_region.move(step_x, step_y) |
164 | 87 | 71 | ||
165 | 88 | 72 | ||
166 | 89 | class CairoPlayer(Player): | 73 | class CairoPlayer(Player): |
168 | 90 | """ This class extends Player with the cairo rendering functions """ | 74 | """This class extends `Player` with the cairo rendering functions.""" |
169 | 91 | 75 | ||
173 | 92 | def __init__(self, drawingarea): | 76 | def __init__(self, file_name, drawing_area): |
174 | 93 | Player.__init__(self) | 77 | Player.__init__(self, file_name) |
175 | 94 | self.area = drawingarea | 78 | self.area = drawing_area |
176 | 79 | drawing_area.queue_draw() | ||
177 | 95 | 80 | ||
178 | 96 | def _set_timer(self, interval=100): | 81 | def _set_timer(self, interval=100): |
179 | 97 | self.area.queue_draw() | 82 | self.area.queue_draw() |
180 | 98 | self.timer = glib.timeout_add(interval, self.tick) | 83 | self.timer = glib.timeout_add(interval, self.tick) |
181 | 99 | 84 | ||
182 | 100 | def load_presentation(self, file_name): | ||
183 | 101 | Player.load_presentation(self, file_name) | ||
184 | 102 | self.area.queue_draw() | ||
185 | 103 | |||
186 | 104 | def next(self): | 85 | def next(self): |
187 | 105 | Player.next(self) | 86 | Player.next(self) |
188 | 106 | self._set_timer() | 87 | self._set_timer() |
189 | @@ -110,23 +91,22 @@ | |||
190 | 110 | self._set_timer() | 91 | self._set_timer() |
191 | 111 | 92 | ||
192 | 112 | def tick(self): | 93 | def tick(self): |
194 | 113 | if self.current_animation and self.current_animation.status != "ended": | 94 | if self.current_animation and self.current_animation.status != 'ended': |
195 | 114 | self.area.queue_draw() | 95 | self.area.queue_draw() |
196 | 115 | return True | 96 | return True |
211 | 116 | else: | 97 | self.current_animation = None |
212 | 117 | self.current_animation = None | 98 | glib.source_remove(self.timer) |
213 | 118 | glib.source_remove(self.timer) | 99 | |
214 | 119 | 100 | def go_to(self, position): | |
215 | 120 | def goto(self, position): | 101 | Player.go_to(self, position) |
216 | 121 | Player.goto(self, position) | 102 | self._set_timer() |
217 | 122 | self._set_timer() | 103 | |
218 | 123 | 104 | def zoom_in(self, translation=(0, 0)): | |
219 | 124 | def zoomin(self, translation=(0, 0)): | 105 | Player.zoom_in(self, translation) |
220 | 125 | Player.zoomin(self, translation) | 106 | self._set_timer() |
221 | 126 | self._set_timer() | 107 | |
222 | 127 | 108 | def zoom_out(self, translation=(0, 0)): | |
223 | 128 | def zoomout(self, translation=(0, 0)): | 109 | Player.zoom_out(self, translation) |
210 | 129 | Player.zoomout(self, translation) | ||
224 | 130 | self._set_timer() | 110 | self._set_timer() |
225 | 131 | 111 | ||
226 | 132 | def move(self, stepx, stepy): | 112 | def move(self, stepx, stepy): |
227 | @@ -138,21 +118,21 @@ | |||
228 | 138 | self.area.queue_draw() | 118 | self.area.queue_draw() |
229 | 139 | 119 | ||
230 | 140 | def render(self, context): | 120 | def render(self, context): |
232 | 141 | """ render a frame, considering the current point of an animation """ | 121 | """Render a frame, considering the current point of an animation.""" |
233 | 142 | if not self.presentation: | 122 | if not self.presentation: |
234 | 143 | return | 123 | return |
236 | 144 | if self.current_animation and self.current_animation.status != "ended": | 124 | if self.current_animation and self.current_animation.status != 'ended': |
237 | 145 | self.current_region = self.current_animation.get_next_region() | 125 | self.current_region = self.current_animation.get_next_region() |
238 | 146 | 126 | ||
241 | 147 | self.current_region.render(context, self.presentation, | 127 | self.current_region.render( |
242 | 148 | self.area.window.get_size()) | 128 | context, self.presentation, self.area.window.get_size()) |
243 | 149 | 129 | ||
244 | 150 | 130 | ||
245 | 151 | class GtkCairoPlayer(CairoPlayer): | 131 | class GtkCairoPlayer(CairoPlayer): |
247 | 152 | """ This class extends CairoPlayer with the handling of gtk events """ | 132 | """This class extends `CairoPlayer` with the handling of GTK events.""" |
248 | 153 | 133 | ||
251 | 154 | def __init__(self, area): | 134 | def __init__(self, file_name, area): |
252 | 155 | CairoPlayer.__init__(self, area) | 135 | CairoPlayer.__init__(self, file_name, area) |
253 | 156 | area.connect('button_press_event', self.on_area_button_press_event) | 136 | area.connect('button_press_event', self.on_area_button_press_event) |
254 | 157 | area.connect('button_release_event', self.on_area_button_release_event) | 137 | area.connect('button_release_event', self.on_area_button_release_event) |
255 | 158 | area.connect('scroll_event', self.on_area_scroll_event) | 138 | area.connect('scroll_event', self.on_area_scroll_event) |
256 | @@ -163,19 +143,24 @@ | |||
257 | 163 | self.mouse_position = (0, 0) | 143 | self.mouse_position = (0, 0) |
258 | 164 | 144 | ||
259 | 165 | def _mouse_step_factor(self, factor): | 145 | def _mouse_step_factor(self, factor): |
273 | 166 | #resize factor, between gtk window and the svg images | 146 | # Resize factor, between GTK window and the SVG images. |
274 | 167 | resize_factor = self.current_region.width / ( | 147 | current_region = self.current_region |
275 | 168 | self.area.window.get_size()[0]) | 148 | resize_factor = current_region.width / self.area.window.get_size()[0] |
276 | 169 | #pointer position adaptation | 149 | |
277 | 170 | mouse_step = [self.mouse_position[0] * resize_factor, | 150 | # Pointer position adaptation. |
278 | 171 | self.mouse_position[1] * resize_factor] | 151 | mouse_step = ( |
279 | 172 | mouse_step_out = [mouse_step[0] - (mouse_step[0] * factor), | 152 | self.mouse_position[0] * resize_factor, |
280 | 173 | mouse_step[1] - (mouse_step[1] * factor)] | 153 | self.mouse_position[1] * resize_factor) |
281 | 174 | #zoom view and move to the mouse positions. Zoom also compensate the delta if center is false | 154 | mouse_step_out = [ |
282 | 175 | mouse_step_out[0] += ((self.current_region.width * factor - | 155 | mouse_step[0] - (mouse_step[0] * factor), |
283 | 176 | self.current_region.width) / 2) | 156 | mouse_step[1] - (mouse_step[1] * factor)] |
284 | 177 | mouse_step_out[1] += ((self.current_region.height * factor - | 157 | |
285 | 178 | self.current_region.height) / 2) | 158 | # Zoom view and move to the mouse positions. Zoom also compensate the |
286 | 159 | # delta if center is False. | ||
287 | 160 | mouse_step_out[0] += ( | ||
288 | 161 | (current_region.width * factor - current_region.width) / 2) | ||
289 | 162 | mouse_step_out[1] += ( | ||
290 | 163 | (current_region.height * factor - current_region.height) / 2) | ||
291 | 179 | return mouse_step_out | 164 | return mouse_step_out |
292 | 180 | 165 | ||
293 | 181 | def on_area_button_press_event(self, widget, event): | 166 | def on_area_button_press_event(self, widget, event): |
294 | @@ -189,30 +174,35 @@ | |||
295 | 189 | 174 | ||
296 | 190 | def on_area_motion_notify_event(self, widget, event): | 175 | def on_area_motion_notify_event(self, widget, event): |
297 | 191 | if self.mouse_pressed: | 176 | if self.mouse_pressed: |
300 | 192 | self.move(self.mouse_position[0] - event.x, | 177 | self.move( |
301 | 193 | self.mouse_position[1] - event.y) | 178 | self.mouse_position[0] - event.x, |
302 | 179 | self.mouse_position[1] - event.y) | ||
303 | 194 | self.mouse_position = (event.x, event.y) | 180 | self.mouse_position = (event.x, event.y) |
304 | 195 | 181 | ||
305 | 196 | def on_area_scroll_event(self, widget, event): | 182 | def on_area_scroll_event(self, widget, event): |
307 | 197 | """ callback for the scroll mouse event """ | 183 | """Callback for the scroll mouse event.""" |
308 | 198 | if event.direction == gtk.gdk.SCROLL_UP: | 184 | if event.direction == gtk.gdk.SCROLL_UP: |
309 | 199 | factor = 1.0 / self.zoom_factor | 185 | factor = 1.0 / self.zoom_factor |
310 | 200 | mouse_step = self._mouse_step_factor(factor) | 186 | mouse_step = self._mouse_step_factor(factor) |
312 | 201 | self.zoomin(mouse_step) | 187 | self.zoom_in(mouse_step) |
313 | 202 | elif event.direction == gtk.gdk.SCROLL_DOWN: | 188 | elif event.direction == gtk.gdk.SCROLL_DOWN: |
314 | 203 | mouse_step = self._mouse_step_factor(self.zoom_factor) | 189 | mouse_step = self._mouse_step_factor(self.zoom_factor) |
316 | 204 | self.zoomout(mouse_step) | 190 | self.zoom_out(mouse_step) |
317 | 205 | 191 | ||
318 | 206 | def on_area_keypress(self, widget, event): | 192 | def on_area_keypress(self, widget, event): |
321 | 207 | """ callback for the key press event """ | 193 | """Callback for the key press event.""" |
322 | 208 | if "Left" == gtk.gdk.keyval_name(event.keyval): | 194 | key = gtk.gdk.keyval_name(event.keyval) |
323 | 195 | if key == 'Left': | ||
324 | 209 | self.previous() | 196 | self.previous() |
326 | 210 | if "Right" == gtk.gdk.keyval_name(event.keyval): | 197 | elif key == 'Right': |
327 | 211 | self.next() | 198 | self.next() |
335 | 212 | numkeys = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] | 199 | elif key in '0123456789': |
336 | 213 | if gtk.gdk.keyval_name(event.keyval) in numkeys: | 200 | # XXX I think most of the presentation will have more than 10 |
337 | 214 | self.goto(int(gtk.gdk.keyval_name(event.keyval))) | 201 | # regions. Probably it would be better to give the user the ability |
338 | 215 | if "minus" == gtk.gdk.keyval_name(event.keyval): | 202 | # to decide which keys to associate to a given presentation. |
339 | 216 | self.zoomout() | 203 | # [bug=605310] |
340 | 217 | if "plus" == gtk.gdk.keyval_name(event.keyval): | 204 | self.go_to(int(key)) |
341 | 218 | self.zoomin() | 205 | elif key == 'minus': |
342 | 206 | self.zoom_out() | ||
343 | 207 | elif key == 'plus': | ||
344 | 208 | self.zoom_in() | ||
345 | 219 | 209 | ||
346 | === modified file 'a4lib/region.py' | |||
347 | --- a4lib/region.py 2010-07-09 13:33:55 +0000 | |||
348 | +++ a4lib/region.py 2010-07-14 09:29:23 +0000 | |||
349 | @@ -30,22 +30,25 @@ | |||
350 | 30 | def from_obj_props(cls, obj_props): | 30 | def from_obj_props(cls, obj_props): |
351 | 31 | """Initialize from a given object's properties.""" | 31 | """Initialize from a given object's properties.""" |
352 | 32 | o = obj_props | 32 | o = obj_props |
358 | 33 | return cls((o['x'] + o['translate'][0]) * o['scale'][0], | 33 | return cls( |
359 | 34 | (o['y'] + o['translate'][1]) * o['scale'][1], | 34 | (o['x'] + o['translate'][0]) * o['scale'][0], |
360 | 35 | o['width'] * o['scale'][0], | 35 | (o['y'] + o['translate'][1]) * o['scale'][1], |
361 | 36 | o['height'] * o['scale'][1], | 36 | o['width'] * o['scale'][0], |
362 | 37 | o['rotation']) | 37 | o['height'] * o['scale'][1], |
363 | 38 | o['rotation']) | ||
364 | 38 | 39 | ||
365 | 39 | def scale_of(self, scalex, scaley=1.0): | 40 | def scale_of(self, scalex, scaley=1.0): |
367 | 40 | """ returns a Region that's a scaled version of self """ | 41 | """Returns a `Region` that's a scaled version of self.""" |
368 | 41 | deltax = (self.width * scalex - self.width) / 2 | 42 | deltax = (self.width * scalex - self.width) / 2 |
369 | 42 | deltay = (self.height * scaley - self.height) / 2 | 43 | deltay = (self.height * scaley - self.height) / 2 |
372 | 43 | return Region(self.x - deltax, self.y - deltay, self.width * scalex, | 44 | return Region( |
373 | 44 | self.height * scaley, self.rotate) | 45 | self.x - deltax, self.y - deltay, self.width * scalex, |
374 | 46 | self.height * scaley, self.rotate) | ||
375 | 45 | 47 | ||
376 | 46 | def move(self, stepx, stepy): | 48 | def move(self, stepx, stepy): |
379 | 47 | return Region(self.x + stepx, self.y + stepy, self.width, | 49 | return Region( |
380 | 48 | self.height, self.rotate) | 50 | self.x + stepx, self.y + stepy, self.width, self.height, |
381 | 51 | self.rotate) | ||
382 | 49 | 52 | ||
383 | 50 | def render(self, context, svg_image, window_size): | 53 | def render(self, context, svg_image, window_size): |
384 | 51 | """Render the region of interest to the given Cairo context.""" | 54 | """Render the region of interest to the given Cairo context.""" |
385 | @@ -64,16 +67,18 @@ | |||
386 | 64 | 67 | ||
387 | 65 | 68 | ||
388 | 66 | def linear_interpolation(fraction): | 69 | def linear_interpolation(fraction): |
390 | 67 | """Constant speed interpolation""" | 70 | """Constant speed interpolation.""" |
391 | 68 | return fraction | 71 | return fraction |
392 | 69 | 72 | ||
393 | 70 | 73 | ||
394 | 71 | def quadratic_interpolation(fraction): | 74 | def quadratic_interpolation(fraction): |
396 | 72 | """Create an elastic movement animation""" | 75 | """Create an elastic movement animation.""" |
397 | 73 | now0 = fraction * 2 | 76 | now0 = fraction * 2 |
399 | 74 | if now0 < 1: #Manage the ease-in acceleration | 77 | if now0 < 1: |
400 | 78 | # Manage the ease-in acceleration. | ||
401 | 75 | out = now0 * now0 / 2 | 79 | out = now0 * now0 / 2 |
403 | 76 | else: #Manage the ease-out deceleration | 80 | else: |
404 | 81 | # Manage the ease-out deceleration. | ||
405 | 77 | now0 -= 1 | 82 | now0 -= 1 |
406 | 78 | out = -(now0 * (now0 - 2) - 1) / 2 | 83 | out = -(now0 * (now0 - 2) - 1) / 2 |
407 | 79 | return out | 84 | return out |
408 | @@ -81,23 +86,25 @@ | |||
409 | 81 | 86 | ||
410 | 82 | class Animation(object): | 87 | class Animation(object): |
411 | 83 | 88 | ||
414 | 84 | def __init__(self, startregion, endregion, deltatime=1.0, | 89 | def __init__( |
415 | 85 | interpolation_type=quadratic_interpolation): | 90 | self, startregion, endregion, deltatime=1.0, |
416 | 91 | interpolation_type=quadratic_interpolation): | ||
417 | 86 | self.startregion = startregion | 92 | self.startregion = startregion |
418 | 87 | self.endregion = endregion | 93 | self.endregion = endregion |
419 | 88 | self.time = deltatime | 94 | self.time = deltatime |
420 | 89 | self.interpolator = interpolation_type | 95 | self.interpolator = interpolation_type |
422 | 90 | self.status = "stopped" | 96 | self.status = 'stopped' |
423 | 91 | 97 | ||
424 | 92 | def _interpolate(self, now): | 98 | def _interpolate(self, now): |
425 | 93 | fraction = (now - self.starttime) / self.time | 99 | fraction = (now - self.starttime) / self.time |
426 | 94 | fraction = self.interpolator(fraction) | 100 | fraction = self.interpolator(fraction) |
427 | 95 | kargs = {} | 101 | kargs = {} |
429 | 96 | for attrname in ['x', 'y', 'width', 'height']: | 102 | for attrname in ('x', 'y', 'width', 'height'): |
430 | 97 | start = getattr(self.startregion, attrname) | 103 | start = getattr(self.startregion, attrname) |
431 | 98 | end = getattr(self.endregion, attrname) | 104 | end = getattr(self.endregion, attrname) |
432 | 99 | out = start + fraction * (end - start) | 105 | out = start + fraction * (end - start) |
433 | 100 | kargs[attrname] = out | 106 | kargs[attrname] = out |
434 | 107 | |||
435 | 101 | deltarot = self.endregion.rotate - self.startregion.rotate | 108 | deltarot = self.endregion.rotate - self.startregion.rotate |
436 | 102 | deltarot %= 2 * math.pi | 109 | deltarot %= 2 * math.pi |
437 | 103 | if deltarot > math.pi: | 110 | if deltarot > math.pi: |
438 | @@ -107,10 +114,10 @@ | |||
439 | 107 | 114 | ||
440 | 108 | def get_next_region(self): | 115 | def get_next_region(self): |
441 | 109 | now = time.time() | 116 | now = time.time() |
443 | 110 | if self.status == "stopped": | 117 | if self.status == 'stopped': |
444 | 111 | self.starttime = now | 118 | self.starttime = now |
446 | 112 | self.status = "started" | 119 | self.status = 'started' |
447 | 113 | if now > (self.starttime + self.time): | 120 | if now > (self.starttime + self.time): |
449 | 114 | self.status = "ended" | 121 | self.status = 'ended' |
450 | 115 | return self.endregion | 122 | return self.endregion |
451 | 116 | return self._interpolate(now) | 123 | return self._interpolate(now) |
Completely agree on the cleaning part.
Just a little fix, these lines: area.queue_ draw() queue_draw( )
175 + self.area = drawing_area
176 + self.drawing_
have to be:
175 + self.area = drawing_area
176 + self.area.
Otherwise it wont work.
About *Player class, perhaps it'd be fine to merge CairoPlayer and GtkCairoPlayer (let's still think about it a little); although the base Player class could be useful, as it could be tested without a GUI, and cause it could be subclassed by a future Wx/Qt/web/whatever based GUI.