Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/animation.py
blob: a0818a84ea34aefa68d983d4b521e307ab84207d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# animation.py
#
# Copyright 2012 S. Daniel Francis <francis@sugarlabs.org>,
#                Agustin Zubiaga <aguz@sugarlabs.org>
#
# 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,))}

    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(old_pos)
        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._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

    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)