From: Marius Gedminas <marius@gedmin.as>
... | ... |
@@ -27,6 +27,7 @@ import sys |
27 | 27 |
import subprocess |
28 | 28 |
import math |
29 | 29 |
import colorsys |
30 |
+import time |
|
30 | 31 |
|
31 | 32 |
import gobject |
32 | 33 |
import gtk |
... | ... |
@@ -598,6 +599,70 @@ class XDotParser: |
598 | 599 |
return x, y |
599 | 600 |
|
600 | 601 |
|
602 |
+class Animation(object): |
|
603 |
+ |
|
604 |
+ step = 0.03 # seconds |
|
605 |
+ |
|
606 |
+ def __init__(self, dot_widget): |
|
607 |
+ self.dot_widget = dot_widget |
|
608 |
+ self.timeout_id = None |
|
609 |
+ |
|
610 |
+ def start(self): |
|
611 |
+ self.timeout_id = gobject.timeout_add(int(self.step * 1000), self.tick) |
|
612 |
+ |
|
613 |
+ def stop(self): |
|
614 |
+ self.dot_widget.animation = NoAnimation(self.dot_widget) |
|
615 |
+ if self.timeout_id is not None: |
|
616 |
+ gobject.source_remove(self.timeout_id) |
|
617 |
+ self.timeout_id = None |
|
618 |
+ |
|
619 |
+ def tick(self): |
|
620 |
+ self.stop() |
|
621 |
+ |
|
622 |
+ |
|
623 |
+class NoAnimation(Animation): |
|
624 |
+ |
|
625 |
+ def start(self): |
|
626 |
+ pass |
|
627 |
+ |
|
628 |
+ def stop(self): |
|
629 |
+ pass |
|
630 |
+ |
|
631 |
+ |
|
632 |
+class LinearAnimation(Animation): |
|
633 |
+ |
|
634 |
+ duration = 0.6 |
|
635 |
+ |
|
636 |
+ def start(self): |
|
637 |
+ self.started = time.time() |
|
638 |
+ Animation.start(self) |
|
639 |
+ |
|
640 |
+ def tick(self): |
|
641 |
+ t = (time.time() - self.started) / self.duration |
|
642 |
+ self.animate(max(0, min(t, 1))) |
|
643 |
+ return (t < 1) |
|
644 |
+ |
|
645 |
+ def animate(self, t): |
|
646 |
+ pass |
|
647 |
+ |
|
648 |
+ |
|
649 |
+class MoveToAnimation(LinearAnimation): |
|
650 |
+ |
|
651 |
+ def __init__(self, dot_widget, target_x, target_y): |
|
652 |
+ Animation.__init__(self, dot_widget) |
|
653 |
+ self.source_x = dot_widget.x |
|
654 |
+ self.source_y = dot_widget.y |
|
655 |
+ self.target_x = target_x |
|
656 |
+ self.target_y = target_y |
|
657 |
+ |
|
658 |
+ def animate(self, t): |
|
659 |
+ sx, sy = self.source_x, self.source_y |
|
660 |
+ tx, ty = self.target_x, self.target_y |
|
661 |
+ self.dot_widget.x = tx * t + sx * (1-t) |
|
662 |
+ self.dot_widget.y = ty * t + sy * (1-t) |
|
663 |
+ self.dot_widget.queue_draw() |
|
664 |
+ |
|
665 |
+ |
|
601 | 666 |
class DotWidget(gtk.DrawingArea): |
602 | 667 |
"""PyGTK widget that draws dot graphs.""" |
603 | 668 |
|
... | ... |
@@ -742,12 +807,9 @@ class DotWidget(gtk.DrawingArea): |
742 | 807 |
return True |
743 | 808 |
|
744 | 809 |
jump = self.get_jump(x, y) |
745 |
- x, y = self.window2graph(x, y) |
|
746 | 810 |
if jump is not None: |
747 | 811 |
jumpx, jumpy = jump |
748 |
- self.x += jumpx - x |
|
749 |
- self.y += jumpy - y |
|
750 |
- self.queue_draw() |
|
812 |
+ self.animate_to(jumpx, jumpy) |
|
751 | 813 |
return False |
752 | 814 |
|
753 | 815 |
def on_area_button_release(self, area, event): |
... | ... |
@@ -787,6 +849,10 @@ class DotWidget(gtk.DrawingArea): |
787 | 849 |
|
788 | 850 |
return True |
789 | 851 |
|
852 |
+ def animate_to(self, x, y): |
|
853 |
+ self.animation = MoveToAnimation(self, x, y) |
|
854 |
+ self.animation.start() |
|
855 |
+ |
|
790 | 856 |
def window2graph(self, x, y): |
791 | 857 |
rect = self.get_allocation() |
792 | 858 |
x -= 0.5*rect.width |