interval: Add is_valid() method
[profile/ivi/clutter.git] / clutter / clutter-property-transition.c
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
22 /**
23  * SECTION:clutter-property-transition
24  * @Title: ClutterPropertyTransition
25  * @Short_Description: Property transitions
26  *
27  * #ClutterPropertyTransition is a specialized #ClutterTransition that
28  * can be used to tween a property of a #ClutterAnimatable instance.
29  *
30  * #ClutterPropertyTransition is available since Clutter 1.10
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "clutter-property-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-transition.h"
44
45 struct _ClutterPropertyTransitionPrivate
46 {
47   char *property_name;
48
49   GParamSpec *pspec;
50 };
51
52 enum
53 {
54   PROP_0,
55
56   PROP_PROPERTY_NAME,
57
58   PROP_LAST
59 };
60
61 static GParamSpec *obj_props[PROP_LAST] = { NULL, };
62
63 G_DEFINE_TYPE (ClutterPropertyTransition, clutter_property_transition, CLUTTER_TYPE_TRANSITION)
64
65 static void
66 clutter_property_transition_attached (ClutterTransition *transition,
67                                       ClutterAnimatable *animatable)
68 {
69   ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (transition);
70   ClutterPropertyTransitionPrivate *priv = self->priv;
71   ClutterInterval *interval;
72   GValue *value;
73
74   if (priv->property_name == NULL)
75     return;
76
77   priv->pspec =
78     clutter_animatable_find_property (animatable, priv->property_name);
79
80   if (priv->pspec == NULL)
81     return;
82
83   interval = clutter_transition_get_interval (transition);
84   if (interval == NULL)
85     return;
86
87   /* if no initial value has been set, use the current value */
88   value = clutter_interval_peek_initial_value (interval);
89   if (!G_IS_VALUE (value))
90     {
91       g_value_init (value, clutter_interval_get_value_type (interval));
92       clutter_animatable_get_initial_state (animatable,
93                                             priv->property_name,
94                                             value);
95     }
96
97   /* if no final value has been set, use the current value */
98   value = clutter_interval_peek_final_value (interval);
99   if (!G_IS_VALUE (value))
100     {
101       g_value_init (value, clutter_interval_get_value_type (interval));
102       clutter_animatable_get_initial_state (animatable,
103                                             priv->property_name,
104                                             value);
105     }
106 }
107
108 static void
109 clutter_property_transition_detached (ClutterTransition *transition,
110                                       ClutterAnimatable *animatable)
111 {
112   ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (transition);
113   ClutterPropertyTransitionPrivate *priv = self->priv;
114
115   priv->pspec = NULL; 
116 }
117
118 static void
119 clutter_property_transition_compute_value (ClutterTransition *transition,
120                                            ClutterAnimatable *animatable,
121                                            ClutterInterval   *interval,
122                                            gdouble            progress)
123 {
124   ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (transition);
125   ClutterPropertyTransitionPrivate *priv = self->priv;
126   GValue value = G_VALUE_INIT;
127   gboolean res;
128
129   /* if we have a GParamSpec we also have an animatable instance */
130   if (priv->pspec == NULL)
131     return;
132
133   g_value_init (&value, clutter_interval_get_value_type (interval));
134
135   res = clutter_animatable_interpolate_value (animatable,
136                                               priv->property_name,
137                                               interval,
138                                               progress,
139                                               &value);
140
141   if (res)
142     clutter_animatable_set_final_state (animatable,
143                                         priv->property_name,
144                                         &value);
145
146   g_value_unset (&value);
147 }
148
149 static void
150 clutter_property_transition_set_property (GObject      *gobject,
151                                           guint         prop_id,
152                                           const GValue *value,
153                                           GParamSpec   *pspec)
154 {
155   ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (gobject);
156
157   switch (prop_id)
158     {
159     case PROP_PROPERTY_NAME:
160       clutter_property_transition_set_property_name (self,
161                                                      g_value_get_string (value));
162       break;
163
164     default:
165       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
166     }
167 }
168
169 static void
170 clutter_property_transition_get_property (GObject    *gobject,
171                                           guint       prop_id,
172                                           GValue     *value,
173                                           GParamSpec *pspec)
174 {
175   ClutterPropertyTransitionPrivate *priv = CLUTTER_PROPERTY_TRANSITION (gobject)->priv;
176
177   switch (prop_id)
178     {
179     case PROP_PROPERTY_NAME:
180       g_value_set_string (value, priv->property_name);
181       break;
182
183     default:
184       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
185     }
186 }
187
188 static void
189 clutter_property_transition_finalize (GObject *gobject)
190 {
191   ClutterPropertyTransitionPrivate *priv;
192
193   priv = CLUTTER_PROPERTY_TRANSITION (gobject)->priv;
194
195   g_free (priv->property_name);
196
197   G_OBJECT_CLASS (clutter_property_transition_parent_class)->finalize (gobject);
198 }
199
200 static void
201 clutter_property_transition_class_init (ClutterPropertyTransitionClass *klass)
202 {
203   ClutterTransitionClass *transition_class = CLUTTER_TRANSITION_CLASS (klass);
204   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
205
206   g_type_class_add_private (klass, sizeof (ClutterPropertyTransitionPrivate));
207
208   transition_class->attached = clutter_property_transition_attached;
209   transition_class->detached = clutter_property_transition_detached;
210   transition_class->compute_value = clutter_property_transition_compute_value;
211
212   gobject_class->set_property = clutter_property_transition_set_property;
213   gobject_class->get_property = clutter_property_transition_get_property;
214   gobject_class->finalize = clutter_property_transition_finalize;
215
216   /**
217    * ClutterPropertyTransition:property-name:
218    *
219    * The name of the property of a #ClutterAnimatable to animate.
220    *
221    * Since: 1.10
222    */
223   obj_props[PROP_PROPERTY_NAME] =
224     g_param_spec_string ("property-name",
225                          P_("Property Name"),
226                          P_("The name of the property to animate"),
227                          NULL,
228                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
229
230   g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
231 }
232
233 static void
234 clutter_property_transition_init (ClutterPropertyTransition *self)
235 {
236   self->priv =
237     G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_PROPERTY_TRANSITION,
238                                  ClutterPropertyTransitionPrivate);
239 }
240
241 /**
242  * clutter_property_transition_new:
243  * @property_name: (allow-none): a property of @animatable, or %NULL
244  *
245  * Creates a new #ClutterPropertyTransition.
246  *
247  * Return value: (transfer full): the newly created #ClutterPropertyTransition.
248  *   Use g_object_unref() when done
249  *
250  * Since: 1.10
251  */
252 ClutterTransition *
253 clutter_property_transition_new (const char *property_name)
254 {
255   return g_object_new (CLUTTER_TYPE_PROPERTY_TRANSITION,
256                        "property-name", property_name,
257                        NULL);
258 }
259
260 /**
261  * clutter_property_transition_set_property_name:
262  * @transition: a #ClutterPropertyTransition
263  * @property_name: (allow-none): a property name
264  *
265  * Sets the #ClutterPropertyTransition:property-name property of @transition.
266  *
267  * Since: 1.10
268  */
269 void
270 clutter_property_transition_set_property_name (ClutterPropertyTransition *transition,
271                                                const char                *property_name)
272 {
273   ClutterPropertyTransitionPrivate *priv;
274   ClutterAnimatable *animatable;
275
276   g_return_if_fail (CLUTTER_IS_PROPERTY_TRANSITION (transition));
277
278   priv = transition->priv;
279
280   if (g_strcmp0 (priv->property_name, property_name) == 0)
281     return;
282
283   g_free (priv->property_name);
284   priv->property_name = g_strdup (property_name);
285   priv->pspec = NULL;
286
287   animatable =
288     clutter_transition_get_animatable (CLUTTER_TRANSITION (transition));
289   if (animatable != NULL)
290     {
291       priv->pspec = clutter_animatable_find_property (animatable,
292                                                       priv->property_name);
293     }
294
295   g_object_notify_by_pspec (G_OBJECT (transition),
296                             obj_props[PROP_PROPERTY_NAME]);
297 }
298
299 /**
300  * clutter_property_transition_get_property_name:
301  * @transition: a #ClutterPropertyTransition
302  *
303  * Retrieves the value of the #ClutterPropertyTransition:property-name
304  * property.
305  *
306  * Return value: the name of the property being animated, or %NULL if
307  *   none is set. The returned string is owned by the @transition and
308  *   it should not be freed.
309  *
310  * Since: 1.10
311  */
312 const char *
313 clutter_property_transition_get_property_name (ClutterPropertyTransition *transition)
314 {
315   g_return_val_if_fail (CLUTTER_IS_PROPERTY_TRANSITION (transition), NULL);
316
317   return transition->priv->property_name;
318 }