| ... | ... |
@@ -25,7 +25,7 @@ from gi.repository import GLib |
| 25 | 25 |
|
| 26 | 26 |
class Animation(object): |
| 27 | 27 |
|
| 28 |
- step = 0.03 # seconds |
|
| 28 |
+ step = 0.03 # seconds |
|
| 29 | 29 |
|
| 30 | 30 |
def __init__(self, dot_widget): |
| 31 | 31 |
self.dot_widget = dot_widget |
| ... | ... |
@@ -45,7 +45,7 @@ class Animation(object): |
| 45 | 45 |
if not self.tick(): |
| 46 | 46 |
self.stop() |
| 47 | 47 |
return False |
| 48 |
- except e: |
|
| 48 |
+ except AttributeError as e: |
|
| 49 | 49 |
self.stop() |
| 50 | 50 |
raise e |
| 51 | 51 |
return True |
| ... | ... |
@@ -92,8 +92,8 @@ class MoveToAnimation(LinearAnimation): |
| 92 | 92 |
def animate(self, t): |
| 93 | 93 |
sx, sy = self.source_x, self.source_y |
| 94 | 94 |
tx, ty = self.target_x, self.target_y |
| 95 |
- self.dot_widget.x = tx * t + sx * (1-t) |
|
| 96 |
- self.dot_widget.y = ty * t + sy * (1-t) |
|
| 95 |
+ self.dot_widget.x = tx * t + sx * (1 - t) |
|
| 96 |
+ self.dot_widget.y = ty * t + sy * (1 - t) |
|
| 97 | 97 |
self.dot_widget.queue_draw() |
| 98 | 98 |
|
| 99 | 99 |
|
| ... | ... |
@@ -118,6 +118,6 @@ class ZoomToAnimation(MoveToAnimation): |
| 118 | 118 |
|
| 119 | 119 |
def animate(self, t): |
| 120 | 120 |
a, b, c = self.source_zoom, self.extra_zoom, self.target_zoom |
| 121 |
- self.dot_widget.zoom_ratio = c*t + b*t*(1-t) + a*(1-t) |
|
| 121 |
+ self.dot_widget.zoom_ratio = c*t + b*t*(1 - t) + a*(1 - t) |
|
| 122 | 122 |
self.dot_widget.zoom_to_fit_on_resize = False |
| 123 | 123 |
MoveToAnimation.animate(self, t) |
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,123 @@ |
| 1 |
+# Copyright 2008-2015 Jose Fonseca |
|
| 2 |
+# |
|
| 3 |
+# This program is free software: you can redistribute it and/or modify it |
|
| 4 |
+# under the terms of the GNU Lesser General Public License as published |
|
| 5 |
+# by the Free Software Foundation, either version 3 of the License, or |
|
| 6 |
+# (at your option) any later version. |
|
| 7 |
+# |
|
| 8 |
+# This program is distributed in the hope that it will be useful, |
|
| 9 |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 10 |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 11 |
+# GNU Lesser General Public License for more details. |
|
| 12 |
+# |
|
| 13 |
+# You should have received a copy of the GNU Lesser General Public License |
|
| 14 |
+# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 15 |
+# |
|
| 16 |
+import math |
|
| 17 |
+import time |
|
| 18 |
+ |
|
| 19 |
+import gi |
|
| 20 |
+gi.require_version('Gtk', '3.0')
|
|
| 21 |
+gi.require_version('PangoCairo', '1.0')
|
|
| 22 |
+ |
|
| 23 |
+from gi.repository import GLib |
|
| 24 |
+ |
|
| 25 |
+ |
|
| 26 |
+class Animation(object): |
|
| 27 |
+ |
|
| 28 |
+ step = 0.03 # seconds |
|
| 29 |
+ |
|
| 30 |
+ def __init__(self, dot_widget): |
|
| 31 |
+ self.dot_widget = dot_widget |
|
| 32 |
+ self.timeout_id = None |
|
| 33 |
+ |
|
| 34 |
+ def start(self): |
|
| 35 |
+ self.timeout_id = GLib.timeout_add(int(self.step * 1000), self.__real_tick) |
|
| 36 |
+ |
|
| 37 |
+ def stop(self): |
|
| 38 |
+ self.dot_widget.animation = NoAnimation(self.dot_widget) |
|
| 39 |
+ if self.timeout_id is not None: |
|
| 40 |
+ GLib.source_remove(self.timeout_id) |
|
| 41 |
+ self.timeout_id = None |
|
| 42 |
+ |
|
| 43 |
+ def __real_tick(self): |
|
| 44 |
+ try: |
|
| 45 |
+ if not self.tick(): |
|
| 46 |
+ self.stop() |
|
| 47 |
+ return False |
|
| 48 |
+ except e: |
|
| 49 |
+ self.stop() |
|
| 50 |
+ raise e |
|
| 51 |
+ return True |
|
| 52 |
+ |
|
| 53 |
+ def tick(self): |
|
| 54 |
+ return False |
|
| 55 |
+ |
|
| 56 |
+ |
|
| 57 |
+class NoAnimation(Animation): |
|
| 58 |
+ |
|
| 59 |
+ def start(self): |
|
| 60 |
+ pass |
|
| 61 |
+ |
|
| 62 |
+ def stop(self): |
|
| 63 |
+ pass |
|
| 64 |
+ |
|
| 65 |
+ |
|
| 66 |
+class LinearAnimation(Animation): |
|
| 67 |
+ |
|
| 68 |
+ duration = 0.6 |
|
| 69 |
+ |
|
| 70 |
+ def start(self): |
|
| 71 |
+ self.started = time.time() |
|
| 72 |
+ Animation.start(self) |
|
| 73 |
+ |
|
| 74 |
+ def tick(self): |
|
| 75 |
+ t = (time.time() - self.started) / self.duration |
|
| 76 |
+ self.animate(max(0, min(t, 1))) |
|
| 77 |
+ return (t < 1) |
|
| 78 |
+ |
|
| 79 |
+ def animate(self, t): |
|
| 80 |
+ pass |
|
| 81 |
+ |
|
| 82 |
+ |
|
| 83 |
+class MoveToAnimation(LinearAnimation): |
|
| 84 |
+ |
|
| 85 |
+ def __init__(self, dot_widget, target_x, target_y): |
|
| 86 |
+ Animation.__init__(self, dot_widget) |
|
| 87 |
+ self.source_x = dot_widget.x |
|
| 88 |
+ self.source_y = dot_widget.y |
|
| 89 |
+ self.target_x = target_x |
|
| 90 |
+ self.target_y = target_y |
|
| 91 |
+ |
|
| 92 |
+ def animate(self, t): |
|
| 93 |
+ sx, sy = self.source_x, self.source_y |
|
| 94 |
+ tx, ty = self.target_x, self.target_y |
|
| 95 |
+ self.dot_widget.x = tx * t + sx * (1-t) |
|
| 96 |
+ self.dot_widget.y = ty * t + sy * (1-t) |
|
| 97 |
+ self.dot_widget.queue_draw() |
|
| 98 |
+ |
|
| 99 |
+ |
|
| 100 |
+class ZoomToAnimation(MoveToAnimation): |
|
| 101 |
+ |
|
| 102 |
+ def __init__(self, dot_widget, target_x, target_y): |
|
| 103 |
+ MoveToAnimation.__init__(self, dot_widget, target_x, target_y) |
|
| 104 |
+ self.source_zoom = dot_widget.zoom_ratio |
|
| 105 |
+ self.target_zoom = self.source_zoom |
|
| 106 |
+ self.extra_zoom = 0 |
|
| 107 |
+ |
|
| 108 |
+ middle_zoom = 0.5 * (self.source_zoom + self.target_zoom) |
|
| 109 |
+ |
|
| 110 |
+ distance = math.hypot(self.source_x - self.target_x, |
|
| 111 |
+ self.source_y - self.target_y) |
|
| 112 |
+ rect = self.dot_widget.get_allocation() |
|
| 113 |
+ visible = min(rect.width, rect.height) / self.dot_widget.zoom_ratio |
|
| 114 |
+ visible *= 0.9 |
|
| 115 |
+ if distance > 0: |
|
| 116 |
+ desired_middle_zoom = visible / distance |
|
| 117 |
+ self.extra_zoom = min(0, 4 * (desired_middle_zoom - middle_zoom)) |
|
| 118 |
+ |
|
| 119 |
+ def animate(self, t): |
|
| 120 |
+ a, b, c = self.source_zoom, self.extra_zoom, self.target_zoom |
|
| 121 |
+ self.dot_widget.zoom_ratio = c*t + b*t*(1-t) + a*(1-t) |
|
| 122 |
+ self.dot_widget.zoom_to_fit_on_resize = False |
|
| 123 |
+ MoveToAnimation.animate(self, t) |