~ubuntu-branches/ubuntu/vivid/clutter-1.0/vivid-proposed

« back to all changes in this revision

Viewing changes to clutter/clutter-transition.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl
  • Date: 2012-05-01 23:50:39 UTC
  • mfrom: (4.1.22 experimental)
  • Revision ID: package-import@ubuntu.com-20120501235039-7wehcmtr33nqhv67
Tags: 1.10.4-2
Upload to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Clutter.
 
3
 *
 
4
 * An OpenGL based 'interactive canvas' library.
 
5
 *
 
6
 * Copyright (C) 2012 Intel Corporation
 
7
 *
 
8
 * This library is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU Lesser General Public
 
10
 * License as published by the Free Software Foundation; either
 
11
 * version 2 of the License, or (at your option) any later version.
 
12
 *
 
13
 * This library is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * Lesser General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Lesser General Public
 
19
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 
20
 *
 
21
 * Author: Emmanuele Bassi <ebassi@linux.intel.com>
 
22
 */
 
23
 
 
24
/**
 
25
 * SECTION:clutter-transition
 
26
 * @Title: ClutterTransition
 
27
 * @Short_Description: Transition between two values
 
28
 *
 
29
 * #ClutterTransition is a subclass of #ClutterTimeline that computes
 
30
 * the interpolation between two values, stored by a #ClutterInterval.
 
31
 */
 
32
 
 
33
#ifdef HAVE_CONFIG_H
 
34
#include "config.h"
 
35
#endif
 
36
 
 
37
#include "clutter-transition.h"
 
38
 
 
39
#include "clutter-animatable.h"
 
40
#include "clutter-debug.h"
 
41
#include "clutter-interval.h"
 
42
#include "clutter-private.h"
 
43
#include "clutter-timeline.h"
 
44
 
 
45
struct _ClutterTransitionPrivate
 
46
{
 
47
  ClutterInterval *interval;
 
48
  ClutterAnimatable *animatable;
 
49
 
 
50
  guint remove_on_complete : 1;
 
51
};
 
52
 
 
53
enum
 
54
{
 
55
  PROP_0,
 
56
 
 
57
  PROP_INTERVAL,
 
58
  PROP_ANIMATABLE,
 
59
  PROP_REMOVE_ON_COMPLETE,
 
60
 
 
61
  PROP_LAST
 
62
};
 
63
 
 
64
static GParamSpec *obj_props[PROP_LAST] = { NULL, };
 
65
 
 
66
static GQuark quark_animatable_set = 0;
 
67
 
 
68
G_DEFINE_ABSTRACT_TYPE (ClutterTransition, clutter_transition, CLUTTER_TYPE_TIMELINE)
 
69
 
 
70
static void
 
71
clutter_transition_attach (ClutterTransition *transition,
 
72
                           ClutterAnimatable *animatable)
 
73
{
 
74
  CLUTTER_TRANSITION_GET_CLASS (transition)->attached (transition, animatable);
 
75
}
 
76
 
 
77
static void
 
78
clutter_transition_detach (ClutterTransition *transition,
 
79
                           ClutterAnimatable *animatable)
 
80
{
 
81
  CLUTTER_TRANSITION_GET_CLASS (transition)->detached (transition, animatable);
 
82
}
 
83
 
 
84
static void
 
85
clutter_transition_real_compute_value (ClutterTransition *transition,
 
86
                                       ClutterAnimatable *animatable,
 
87
                                       ClutterInterval   *interval,
 
88
                                       gdouble            progress)
 
89
{
 
90
}
 
91
 
 
92
static void
 
93
clutter_transition_real_attached (ClutterTransition *transition,
 
94
                                  ClutterAnimatable *animatable)
 
95
{
 
96
}
 
97
 
 
98
static void
 
99
clutter_transition_real_detached (ClutterTransition *transition,
 
100
                                  ClutterAnimatable *animatable)
 
101
{
 
102
}
 
103
 
 
104
static void
 
105
clutter_transition_new_frame (ClutterTimeline *timeline,
 
106
                              gint             elapsed G_GNUC_UNUSED)
 
107
{
 
108
  ClutterTransition *transition = CLUTTER_TRANSITION (timeline);
 
109
  ClutterTransitionPrivate *priv = transition->priv;
 
110
  gdouble progress;
 
111
 
 
112
  if (priv->interval == NULL ||
 
113
      priv->animatable == NULL)
 
114
    return;
 
115
 
 
116
  progress = clutter_timeline_get_progress (timeline);
 
117
 
 
118
  CLUTTER_TRANSITION_GET_CLASS (timeline)->compute_value (transition,
 
119
                                                          priv->animatable,
 
120
                                                          priv->interval,
 
121
                                                          progress);
 
122
}
 
123
 
 
124
static void
 
125
clutter_transition_completed (ClutterTimeline *timeline)
 
126
{
 
127
  ClutterTransitionPrivate *priv = CLUTTER_TRANSITION (timeline)->priv;
 
128
 
 
129
  if (priv->animatable != NULL && priv->remove_on_complete)
 
130
    {
 
131
      int n_repeats, cur_repeat;
 
132
 
 
133
      n_repeats = clutter_timeline_get_repeat_count (timeline);
 
134
      cur_repeat = clutter_timeline_get_current_repeat (timeline);
 
135
 
 
136
      if (n_repeats == 0 || cur_repeat == n_repeats)
 
137
        {
 
138
          clutter_transition_detach (CLUTTER_TRANSITION (timeline),
 
139
                                     priv->animatable);
 
140
          g_clear_object (&priv->animatable);
 
141
          g_object_unref (timeline);
 
142
        }
 
143
    }
 
144
}
 
145
 
 
146
static void
 
147
clutter_transition_set_property (GObject      *gobject,
 
148
                                 guint         prop_id,
 
149
                                 const GValue *value,
 
150
                                 GParamSpec   *pspec)
 
151
{
 
152
  ClutterTransition *transition = CLUTTER_TRANSITION (gobject);
 
153
 
 
154
  switch (prop_id)
 
155
    {
 
156
    case PROP_INTERVAL:
 
157
      clutter_transition_set_interval (transition, g_value_get_object (value));
 
158
      break;
 
159
 
 
160
    case PROP_ANIMATABLE:
 
161
      clutter_transition_set_animatable (transition, g_value_get_object (value));
 
162
      break;
 
163
 
 
164
    case PROP_REMOVE_ON_COMPLETE:
 
165
      clutter_transition_set_remove_on_complete (transition, g_value_get_boolean (value));
 
166
      break;
 
167
 
 
168
    default:
 
169
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 
170
      break;
 
171
    }
 
172
}
 
173
 
 
174
static void
 
175
clutter_transition_get_property (GObject    *gobject,
 
176
                                 guint       prop_id,
 
177
                                 GValue     *value,
 
178
                                 GParamSpec *pspec)
 
179
{
 
180
  ClutterTransitionPrivate *priv = CLUTTER_TRANSITION (gobject)->priv;
 
181
 
 
182
  switch (prop_id)
 
183
    {
 
184
    case PROP_INTERVAL:
 
185
      g_value_set_object (value, priv->interval);
 
186
      break;
 
187
 
 
188
    case PROP_ANIMATABLE:
 
189
      g_value_set_object (value, priv->animatable);
 
190
      break;
 
191
 
 
192
    case PROP_REMOVE_ON_COMPLETE:
 
193
      g_value_set_boolean (value, priv->remove_on_complete);
 
194
      break;
 
195
 
 
196
    default:
 
197
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 
198
      break;
 
199
    }
 
200
}
 
201
 
 
202
static void
 
203
clutter_transition_dispose (GObject *gobject)
 
204
{
 
205
  ClutterTransitionPrivate *priv = CLUTTER_TRANSITION (gobject)->priv;
 
206
 
 
207
  if (priv->animatable != NULL)
 
208
    clutter_transition_detach (CLUTTER_TRANSITION (gobject),
 
209
                               priv->animatable);
 
210
 
 
211
  g_clear_object (&priv->interval);
 
212
  g_clear_object (&priv->animatable);
 
213
 
 
214
  G_OBJECT_CLASS (clutter_transition_parent_class)->dispose (gobject);
 
215
}
 
216
 
 
217
static void
 
218
clutter_transition_class_init (ClutterTransitionClass *klass)
 
219
{
 
220
  ClutterTimelineClass *timeline_class = CLUTTER_TIMELINE_CLASS (klass);
 
221
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
222
 
 
223
  quark_animatable_set =
 
224
    g_quark_from_static_string ("-clutter-transition-animatable-set");
 
225
 
 
226
  g_type_class_add_private (klass, sizeof (ClutterTransitionPrivate));
 
227
 
 
228
  klass->compute_value = clutter_transition_real_compute_value;
 
229
  klass->attached = clutter_transition_real_attached;
 
230
  klass->detached = clutter_transition_real_detached;
 
231
 
 
232
  timeline_class->new_frame = clutter_transition_new_frame;
 
233
  timeline_class->completed = clutter_transition_completed;
 
234
 
 
235
  gobject_class->set_property = clutter_transition_set_property;
 
236
  gobject_class->get_property = clutter_transition_get_property;
 
237
  gobject_class->dispose = clutter_transition_dispose;
 
238
 
 
239
  /**
 
240
   * ClutterTransition:interval:
 
241
   *
 
242
   * The #ClutterInterval used to describe the initial and final states
 
243
   * of the transition.
 
244
   *
 
245
   * Since: 1.10
 
246
   */
 
247
  obj_props[PROP_INTERVAL] =
 
248
    g_param_spec_object ("interval",
 
249
                         P_("Interval"),
 
250
                         P_("The interval of values to transition"),
 
251
                         CLUTTER_TYPE_INTERVAL,
 
252
                         G_PARAM_READWRITE |
 
253
                         G_PARAM_STATIC_STRINGS);
 
254
 
 
255
  /**
 
256
   * ClutterTransition:animatable:
 
257
   *
 
258
   * The #ClutterAnimatable instance currently being animated.
 
259
   *
 
260
   * Since: 1.10
 
261
   */
 
262
  obj_props[PROP_ANIMATABLE] =
 
263
    g_param_spec_object ("animatable",
 
264
                         P_("Animatable"),
 
265
                         P_("The animatable object"),
 
266
                         CLUTTER_TYPE_ANIMATABLE,
 
267
                         G_PARAM_READWRITE |
 
268
                         G_PARAM_STATIC_STRINGS);
 
269
 
 
270
  /**
 
271
   * ClutterTransition:remove-on-complete:
 
272
   *
 
273
   * Whether the #ClutterTransition should be automatically detached
 
274
   * from the #ClutterTransition:animatable instance whenever the
 
275
   * #ClutterTimeline::completed signal is emitted.
 
276
   *
 
277
   * The #ClutterTransition:remove-on-complete property takes into
 
278
   * account the value of the #ClutterTimeline:repeat-count property,
 
279
   * and it only detaches the transition if the transition is not
 
280
   * repeating.
 
281
   *
 
282
   * Since: 1.10
 
283
   */
 
284
  obj_props[PROP_REMOVE_ON_COMPLETE] =
 
285
    g_param_spec_boolean ("remove-on-complete",
 
286
                          P_("Remove on Complete"),
 
287
                          P_("Detach the transition when completed"),
 
288
                          FALSE,
 
289
                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
290
 
 
291
  g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
 
292
}
 
293
 
 
294
static void
 
295
clutter_transition_init (ClutterTransition *self)
 
296
{
 
297
  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_TRANSITION,
 
298
                                            ClutterTransitionPrivate);
 
299
}
 
300
 
 
301
/**
 
302
 * clutter_transition_set_interval:
 
303
 * @transition: a #ClutterTransition
 
304
 * @interval: (allow-none): a #ClutterInterval, or %NULL
 
305
 *
 
306
 * Sets the #ClutterTransition:interval property using @interval.
 
307
 *
 
308
 * The @transition will acquire a reference on the @interval, sinking
 
309
 * the floating flag on it if necessary.
 
310
 *
 
311
 * Since: 1.10
 
312
 */
 
313
void
 
314
clutter_transition_set_interval (ClutterTransition *transition,
 
315
                                 ClutterInterval   *interval)
 
316
{
 
317
  ClutterTransitionPrivate *priv;
 
318
 
 
319
  g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
 
320
  g_return_if_fail (interval == NULL || CLUTTER_IS_INTERVAL (interval));
 
321
 
 
322
  priv = transition->priv;
 
323
 
 
324
  g_clear_object (&priv->interval);
 
325
 
 
326
  if (interval != NULL)
 
327
    priv->interval = g_object_ref_sink (interval);
 
328
 
 
329
  g_object_notify_by_pspec (G_OBJECT (transition), obj_props[PROP_INTERVAL]);
 
330
}
 
331
 
 
332
/**
 
333
 * clutter_transition_get_interval:
 
334
 * @transition: a #ClutterTransition
 
335
 *
 
336
 * Retrieves the interval set using clutter_transition_set_interval()
 
337
 *
 
338
 * Return value: (transfer none): a #ClutterInterval, or %NULL; the returned
 
339
 *   interval is owned by the #ClutterTransition and it should not be freed
 
340
 *   directly
 
341
 *
 
342
 * Since: 1.10
 
343
 */
 
344
ClutterInterval *
 
345
clutter_transition_get_interval (ClutterTransition *transition)
 
346
{
 
347
  g_return_val_if_fail (CLUTTER_IS_TRANSITION (transition), NULL);
 
348
 
 
349
  return transition->priv->interval;
 
350
}
 
351
 
 
352
/**
 
353
 * clutter_transition_set_animatable:
 
354
 * @transition: a #ClutterTransition
 
355
 * @animatable: (allow-none): a #ClutterAnimatable, or %NULL
 
356
 *
 
357
 * Sets the #ClutterTransition:animatable property.
 
358
 *
 
359
 * The @transition will acquire a reference to the @animatable instance,
 
360
 * and will call the #ClutterTransitionClass.attached() virtual function.
 
361
 *
 
362
 * If an existing #ClutterAnimatable is attached to @transition, the
 
363
 * reference will be released, and the #ClutterTransitionClass.detached()
 
364
 * virtual function will be called.
 
365
 *
 
366
 * Since: 1.10
 
367
 */
 
368
void
 
369
clutter_transition_set_animatable (ClutterTransition *transition,
 
370
                                   ClutterAnimatable *animatable)
 
371
{
 
372
  ClutterTransitionPrivate *priv;
 
373
 
 
374
  g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
 
375
  g_return_if_fail (animatable == NULL || CLUTTER_IS_ANIMATABLE (animatable));
 
376
 
 
377
  priv = transition->priv;
 
378
 
 
379
  if (priv->animatable == animatable)
 
380
    return;
 
381
 
 
382
  if (priv->animatable != NULL)
 
383
    clutter_transition_detach (transition, priv->animatable);
 
384
 
 
385
  g_clear_object (&priv->animatable);
 
386
 
 
387
  if (animatable != NULL)
 
388
    {
 
389
      priv->animatable = g_object_ref (animatable);
 
390
      clutter_transition_attach (transition, priv->animatable);
 
391
    }
 
392
}
 
393
 
 
394
/**
 
395
 * clutter_transition_get_animatable:
 
396
 * @transition: a #ClutterTransition
 
397
 *
 
398
 * Retrieves the #ClutterAnimatable set using clutter_transition_set_animatable().
 
399
 *
 
400
 * Return value: (transfer none): a #ClutterAnimatable, or %NULL; the returned
 
401
 *   animatable is owned by the #ClutterTransition, and it should not be freed
 
402
 *   directly.
 
403
 *
 
404
 * Since: 1.10
 
405
 */
 
406
ClutterAnimatable *
 
407
clutter_transition_get_animatable (ClutterTransition *transition)
 
408
{
 
409
  g_return_val_if_fail (CLUTTER_IS_TRANSITION (transition), NULL);
 
410
 
 
411
  return transition->priv->animatable;
 
412
}
 
413
 
 
414
/**
 
415
 * clutter_transition_set_remove_on_complete:
 
416
 * @transition: a #ClutterTransition
 
417
 * @remove_complete: whether to detach @transition when complete
 
418
 *
 
419
 * Sets whether @transition should be detached from the #ClutterAnimatable
 
420
 * set using clutter_transition_set_animatable() when the
 
421
 * #ClutterTimeline::completed signal is emitted.
 
422
 *
 
423
 * Since: 1.10
 
424
 */
 
425
void
 
426
clutter_transition_set_remove_on_complete (ClutterTransition *transition,
 
427
                                           gboolean           remove_complete)
 
428
{
 
429
  g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
 
430
 
 
431
  remove_complete = !!remove_complete;
 
432
 
 
433
  if (transition->priv->remove_on_complete == remove_complete)
 
434
    return;
 
435
 
 
436
  transition->priv->remove_on_complete = remove_complete;
 
437
 
 
438
  g_object_notify_by_pspec (G_OBJECT (transition),
 
439
                            obj_props[PROP_REMOVE_ON_COMPLETE]);
 
440
}
 
441
 
 
442
/**
 
443
 * clutter_transition_get_remove_on_complete:
 
444
 * @transition: a #ClutterTransition
 
445
 *
 
446
 * Retrieves the value of the #ClutterTransition:remove-on-complete property.
 
447
 *
 
448
 * Return value: %TRUE if the @transition should be detached when complete,
 
449
 *   and %FALSE otherwise
 
450
 *
 
451
 * Since: 1.10
 
452
 */
 
453
gboolean
 
454
clutter_transition_get_remove_on_complete (ClutterTransition *transition)
 
455
{
 
456
  g_return_val_if_fail (CLUTTER_IS_TRANSITION (transition), FALSE);
 
457
 
 
458
  return transition->priv->remove_on_complete;
 
459
}