From d37da7ee882ac037d55550f995383ff62e078023 Mon Sep 17 00:00:00 2001 From: Sam Parkinson Date: Tue, 26 Jul 2016 21:06:44 +1000 Subject: [PATCH] Add do_stop method for animations This adds a explicit method for cleaning up the animation. Previously, animations expected the next_frame to be called where frame=end. That guarantee was never provided by the api. This resulted in animations sometimes being in odd states. For example, Browse activity had an animation that overrode the Gtk "draw" signal. If the signal was not unbound, the animated object was mistakenly rendered after the completion of the animation, obstructing the user's view. This api is explicit and allows cleaner code in the animation implementation. The clean up code goes in do_stop rather than in a conditional of next_frame. --- src/sugar3/graphics/animator.py | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/sugar3/graphics/animator.py b/src/sugar3/graphics/animator.py index 37224890..d7368456 100644 --- a/src/sugar3/graphics/animator.py +++ b/src/sugar3/graphics/animator.py @@ -146,6 +146,9 @@ class Animator(GObject.GObject): ''' Stop the animation and emit the `completed` signal ''' + for animation in self._animations: + animation.do_stop() + if self._timeout_sid and \ not hasattr(self._widget, 'add_tick_callback'): GObject.source_remove(self._timeout_sid) @@ -235,3 +238,43 @@ class Animation(object): the current progress in the animation ''' pass + + def do_stop(self): + ''' + This method is called whenever the animation is stopped, either + due to the animation ending or being stopped by the animation. + `next_frame` will not be called after do_stop, unless the animation + is restarted. + + .. versionadded:: 0.109.0.3 + + This should be used in subclasses if they bind any signals. Eg. + if they bind the draw signal for a widget: + + .. code-block:: python + + class SignalAnimation(Animation): + + def __init__(self, widget): + Animation.__init__(self, 0, 1) + self._draw_hid = None + self._widget = widget + + def next_frame(self, frame): + self._frame = frame + if self._draw_hid is None: + self._draw_hid = self._widget.connect_after( + 'draw', self.__draw_cb) + self._widget.queue_draw() + + def __draw_cb(self, widget, cr): + cr.save() + # Do the draw + cr.restore() + + def do_stop(self): + self._widget.disconnect(self._draw_hid) + self._widget.queue_draw() + + ''' + pass