]> www.fi.muni.cz Git - evince.git/blob - shell/ev-transition-animation.c
Added, EvTransitionAnimation will contain the implementations for page
[evince.git] / shell / ev-transition-animation.c
1 /* ev-transition-animation.c
2  *  this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2007 Carlos Garnacho <carlos@imendio.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <cairo.h>
23 #include <gdk/gdk.h>
24 #include "ev-transition-animation.h"
25 #include "ev-timeline.h"
26
27 #define EV_TRANSITION_ANIMATION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EV_TYPE_TRANSITION_ANIMATION, EvTransitionAnimationPriv))
28 #define N_BLINDS 6
29
30 typedef struct EvTransitionAnimationPriv EvTransitionAnimationPriv;
31
32 struct EvTransitionAnimationPriv {
33         EvTransitionEffect *effect;
34         cairo_surface_t *origin_surface;
35         cairo_surface_t *dest_surface;
36 };
37
38 enum {
39         PROP_0,
40         PROP_EFFECT,
41         PROP_ORIGIN_SURFACE,
42         PROP_DEST_SURFACE
43 };
44
45
46 G_DEFINE_TYPE (EvTransitionAnimation, ev_transition_animation, EV_TYPE_TIMELINE)
47
48
49 static void
50 ev_transition_animation_init (EvTransitionAnimation *animation)
51 {
52 }
53
54 static void
55 ev_transition_animation_set_property (GObject      *object,
56                                       guint         prop_id,
57                                       const GValue *value,
58                                       GParamSpec   *pspec)
59 {
60         EvTransitionAnimationPriv *priv;
61
62         priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (object);
63
64         switch (prop_id) {
65         case PROP_EFFECT:
66                 if (priv->effect)
67                         g_object_unref (priv->effect);
68
69                 priv->effect = g_value_dup_object (value);
70                 break;
71         case PROP_ORIGIN_SURFACE:
72                 ev_transition_animation_set_origin_surface (EV_TRANSITION_ANIMATION (object),
73                                                             g_value_get_pointer (value));
74                 break;
75         case PROP_DEST_SURFACE:
76                 ev_transition_animation_set_dest_surface (EV_TRANSITION_ANIMATION (object),
77                                                           g_value_get_pointer (value));
78                 break;
79         default:
80                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
81         }
82 }
83
84 static void
85 ev_transition_animation_get_property (GObject      *object,
86                                       guint         prop_id,
87                                       GValue       *value,
88                                       GParamSpec   *pspec)
89 {
90         EvTransitionAnimationPriv *priv;
91
92         priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (object);
93
94         switch (prop_id) {
95         case PROP_EFFECT:
96                 g_value_set_object (value, priv->effect);
97                 break;
98         case PROP_ORIGIN_SURFACE:
99                 g_value_set_pointer (value, priv->origin_surface);
100                 break;
101         case PROP_DEST_SURFACE:
102                 g_value_set_pointer (value, priv->dest_surface);
103                 break;
104         default:
105                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
106         }
107 }
108
109 static void
110 ev_transition_animation_finalize (GObject *object)
111 {
112         EvTransitionAnimationPriv *priv;
113
114         priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (object);
115
116         if (priv->effect)
117                 g_object_unref (priv->effect);
118
119         if (priv->origin_surface)
120                 cairo_surface_destroy (priv->origin_surface);
121
122         if (priv->dest_surface)
123                 cairo_surface_destroy (priv->dest_surface);
124
125         G_OBJECT_CLASS (ev_transition_animation_parent_class)->finalize (object);
126 }
127
128 static GObject *
129 ev_transition_animation_constructor (GType                  type,
130                                      guint                  n_construct_properties,
131                                      GObjectConstructParam *construct_params)
132 {
133         GObject *object;
134         EvTransitionAnimationPriv *priv;
135         EvTransitionEffect *effect;
136         gint duration;
137
138         object = G_OBJECT_CLASS (ev_transition_animation_parent_class)->constructor (type,
139                                                                                      n_construct_properties,
140                                                                                      construct_params);
141
142         priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (object);
143         effect = priv->effect;
144
145         g_object_get (effect, "duration", &duration, NULL);
146         ev_timeline_set_duration (EV_TIMELINE (object), duration * 1000);
147
148         return object;
149 }
150
151 static void
152 ev_transition_animation_class_init (EvTransitionAnimationClass *klass)
153 {
154         GObjectClass *object_class = G_OBJECT_CLASS (klass);
155
156         object_class->set_property = ev_transition_animation_set_property;
157         object_class->get_property = ev_transition_animation_get_property;
158         object_class->finalize = ev_transition_animation_finalize;
159         object_class->constructor = ev_transition_animation_constructor;
160
161         g_object_class_install_property (object_class,
162                                          PROP_EFFECT,
163                                          g_param_spec_object ("effect",
164                                                               "Effect",
165                                                               "Transition effect description",
166                                                               EV_TYPE_TRANSITION_EFFECT,
167                                                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
168         g_object_class_install_property (object_class,
169                                          PROP_ORIGIN_SURFACE,
170                                          g_param_spec_pointer ("origin-surface",
171                                                                "Origin surface",
172                                                                "Cairo surface from which the animation will happen",
173                                                                G_PARAM_READWRITE));
174         g_object_class_install_property (object_class,
175                                          PROP_DEST_SURFACE,
176                                          g_param_spec_pointer ("dest-surface",
177                                                                "Destination surface",
178                                                                "Cairo surface to which the animation will happen",
179                                                                G_PARAM_READWRITE));
180
181         g_type_class_add_private (klass, sizeof (EvTransitionAnimationPriv));
182 }
183
184 static void
185 paint_surface (cairo_t         *cr,
186                cairo_surface_t *surface,
187                gdouble          x_offset,
188                gdouble          y_offset,
189                gdouble          alpha,
190                GdkRectangle     page_area)
191 {
192         gint width, height;
193
194         gdk_cairo_rectangle (cr, &page_area);
195         cairo_clip (cr);
196
197         width = cairo_image_surface_get_width (surface);
198         height = cairo_image_surface_get_height (surface);
199
200         cairo_save (cr);
201
202         if (width != page_area.width || height != page_area.height) {
203                 cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST);
204                 cairo_scale (cr,
205                              (gdouble) page_area.width / width,
206                              (gdouble) page_area.height / height);
207         }
208
209         cairo_surface_set_device_offset (surface, x_offset, y_offset);
210         cairo_set_source_surface (cr, surface, 0, 0);
211
212         if (alpha == 0.)
213                 cairo_paint (cr);
214         else
215                 cairo_paint_with_alpha (cr, alpha);
216
217         cairo_restore (cr);
218 }
219
220 void
221 ev_transition_animation_paint (EvTransitionAnimation *animation,
222                                cairo_t               *cr,
223                                GdkRectangle           page_area)
224 {
225         EvTransitionAnimationPriv *priv;
226         EvTransitionEffectType type;
227         gdouble progress;
228
229         g_return_if_fail (EV_IS_TRANSITION_ANIMATION (animation));
230
231         priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
232         g_object_get (priv->effect, "type", &type, NULL);
233         progress = ev_timeline_get_progress (EV_TIMELINE (animation));
234
235         if (!priv->dest_surface) {
236                 /* animation is still not ready, paint the origin surface */
237                 paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
238                 return;
239         }
240
241         switch (type) {
242         case EV_TRANSITION_EFFECT_REPLACE:
243                 /* just paint the destination slide */
244                 paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
245                 break;
246         default: {
247                 GEnumValue *enum_value;
248
249                 enum_value = g_enum_get_value (g_type_class_peek (EV_TYPE_TRANSITION_EFFECT_TYPE), type);
250
251                 g_warning ("Unimplemented transition animation: '%s', "
252                            "please post a bug report in Evince bugzilla "
253                            "(http://bugzilla.gnome.org) with a testcase.",
254                            enum_value->value_nick);
255
256                 /* just paint the destination slide */
257                 paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
258                 }
259         }
260 }
261
262 EvTransitionAnimation *
263 ev_transition_animation_new (EvTransitionEffect *effect)
264 {
265         g_return_val_if_fail (EV_IS_TRANSITION_EFFECT (effect), NULL);
266
267         return g_object_new (EV_TYPE_TRANSITION_ANIMATION,
268                              "effect", effect,
269                              NULL);
270 }
271
272 void
273 ev_transition_animation_set_origin_surface (EvTransitionAnimation *animation,
274                                             cairo_surface_t       *origin_surface)
275 {
276         EvTransitionAnimationPriv *priv;
277         cairo_surface_t *surface;
278
279         g_return_if_fail (EV_IS_TRANSITION_ANIMATION (animation));
280
281         priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
282
283         surface = cairo_surface_reference (origin_surface);
284
285         if (priv->origin_surface)
286                 cairo_surface_destroy (priv->origin_surface);
287
288         priv->origin_surface = surface;
289         g_object_notify (G_OBJECT (animation), "origin-surface");
290
291         if (priv->origin_surface && priv->dest_surface)
292                 ev_timeline_start (EV_TIMELINE (animation));
293 }
294
295 void
296 ev_transition_animation_set_dest_surface (EvTransitionAnimation *animation,
297                                           cairo_surface_t       *dest_surface)
298 {
299         EvTransitionAnimationPriv *priv;
300         cairo_surface_t *surface;
301
302         g_return_if_fail (EV_IS_TRANSITION_ANIMATION (animation));
303
304         priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
305
306         surface = cairo_surface_reference (dest_surface);
307
308         if (priv->dest_surface)
309                 cairo_surface_destroy (priv->dest_surface);
310
311         priv->dest_surface = surface;
312         g_object_notify (G_OBJECT (animation), "dest-surface");
313
314         if (priv->origin_surface && priv->dest_surface)
315                 ev_timeline_start (EV_TIMELINE (animation));
316 }