#!/usr/bin/env python # -*- coding: utf-8 -*- # # animation.py # # Copyright 2012 S. Daniel Francis , # Agustin Zubiaga # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. import gtk import gobject import logging _logger = logging.getLogger('animate-animation') _logger.setLevel(logging.DEBUG) logging.basicConfig() MODE_NORMAL = 0 MODE_RETURN = 1 MODE_PING_PONG = 2 class Animation(gtk.Image): __gproperties__ = {'mode': (gobject.TYPE_INT, 'animation mode', 'mode for iter the frames', 0, 2, 1, gobject.PARAM_READWRITE), 'fps': (gobject.TYPE_INT, 'framerate', 'frames per second', 1, 24, 2, gobject.PARAM_READWRITE)} __gsignals__ = {"current-frame-updated": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_INT, (gobject.TYPE_INT,)), "running": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_BOOLEAN,)), } def __init__(self, width, height, fps=2): super(Animation, self).__init__() self._current_frame = 0 self._timeout = None self._mode = MODE_RETURN self._running = False self.frames = [] self.frames_reverse = False self._size = width, height self._sleep_time = int(1000 / fps) def do_set_property(self, pspec, value): if pspec.name == 'mode': self.set_mode(value) elif pspec.name == 'fps': self.set_fps(value) def do_get_property(self, pspec): if pspec.name == 'mode': return self._mode elif pspec.name == 'fps': return self.get_fps() def move(self, old_pos, new_pos): _object = self.frames[old_pos] self.frames.remove(_object) self.frames.insert(new_pos, _object) def remove_current_frame(self): del(self.frames[self._current_frame]) if len(self.frames): self.set_current_frame(self._current_frame if len(self.frames) >= self._current_frame else len(self.frames) - 1) else: self.set_from_pixbuf(None) self._current_frame = 0 def set_fps(self, fps): self._sleep_time = int(1000 / fps) if self._running: self.pause() self.run() def get_fps(self): return int(self._sleep_time * 1000.0) def set_mode(self, mode): """Defines animation mode""" if self.frames_reverse: self.frames.reverse() self.frames_reverse = False self._mode = mode def get_mode(self): return self._mode def set_size(self, width, height): """Defines animation size""" self._size = width, height # Redraw frame: self.set_current_frame(self._current_frame) def add_frame(self, pixbuf): """Appends an frame to the list""" self.frames.append(pixbuf) def run(self): """Runs the animation""" if not self._running: try: pixbuf = self.frames[self._current_frame] width = pixbuf.get_width() height = pixbuf.get_height() max_size = max(width, height) if max_size is width: scaled_pixbuf = pixbuf.scale_simple(self._size[0], self._size[0] * height / width, gtk.gdk.INTERP_TILES) else: scaled_pixbuf = pixbuf.scale_simple(self._size[1] *\ width / height, self._size[1], gtk.gdk.INTERP_TILES) self.set_from_pixbuf(scaled_pixbuf) self._running = True self.emit('running', True) self._timeout = gobject.timeout_add(self._sleep_time, self.next) _logger.info(" Running!") except IndexError: _logger.error(" There aren't frames") else: _logger.error(" The animation is running already") def get_current_frame(self): return self._current_frame def set_current_frame(self, pos): self._current_frame = pos pixbuf = self.frames[self._current_frame] width = pixbuf.get_width() height = pixbuf.get_height() max_size = max(width, height) if max_size is width: scaled_pixbuf = pixbuf.scale_simple(self._size[0], self._size[0] * height / width, gtk.gdk.INTERP_TILES) else: scaled_pixbuf = pixbuf.scale_simple(self._size[1] * width / height, self._size[1], gtk.gdk.INTERP_TILES) self.set_from_pixbuf(scaled_pixbuf) self.set_from_pixbuf(scaled_pixbuf) def pause(self): """Pause the animation""" gobject.source_remove(self._timeout) self._running = False self.emit('running', False) def next(self): """Shows the next frame""" if self._current_frame != len(self.frames) - 1: self._current_frame += 1 elif not self._current_frame != len(self.frames) - 1 and \ not self._mode == MODE_NORMAL: if self._mode == MODE_PING_PONG: self.frames.reverse() self.frames_reverse = not self.frames_reverse self._current_frame = 1 else: self._current_frame = 0 pos = self.emit("current-frame-updated", self._current_frame) self.set_current_frame(pos) return True def back(self): """Shows the previous frame""" if self._current_frame != 0: self._current_frame -= 1 elif self._current_frame == 0 and not self._mode == MODE_NORMAL: if self._mode == MODE_PING_PONG: self.frames.reverse() self.frames_reverse = not self.frames_reverse self._current_frame = -2 else: self._current_frame = -1 self.emit("current-frame-updated", self._current_frame)