Release Clutter 1.11.4 (snapshot)
[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
72   if (priv->property_name == NULL)
73     return;
74
75   priv->pspec = clutter_animatable_find_property (animatable,
76                                                   priv->property_name);
77 }
78
79 static void
80 clutter_property_transition_detached (ClutterTransition *transition,
81                                       ClutterAnimatable *animatable)
82 {
83   ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (transition);
84   ClutterPropertyTransitionPrivate *priv = self->priv;
85
86   priv->pspec = NULL; 
87 }
88
89 static void
90 clutter_property_transition_compute_value (ClutterTransition *transition,
91                                            ClutterAnimatable *animatable,
92                                            ClutterInterval   *interval,
93                                            gdouble            progress)
94 {
95   ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (transition);
96   ClutterPropertyTransitionPrivate *priv = self->priv;
97   GValue value = G_VALUE_INIT;
98   gboolean res;
99
100   /* if we have a GParamSpec we also have an animatable instance */
101   if (priv->pspec == NULL)
102     return;
103
104   g_value_init (&value, clutter_interval_get_value_type (interval));
105
106   res = clutter_animatable_interpolate_value (animatable,
107                                               priv->property_name,
108                                               interval,
109                                               progress,
110                                               &value);
111
112   if (res)
113     clutter_animatable_set_final_state (animatable,
114                                         priv->property_name,
115                                         &value);
116
117   g_value_unset (&value);
118 }
119
120 static void
121 clutter_property_transition_set_property (GObject      *gobject,
122                                           guint         prop_id,
123                                           const GValue *value,
124                                           GParamSpec   *pspec)
125 {
126   ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (gobject);
127
128   switch (prop_id)
129     {
130     case PROP_PROPERTY_NAME:
131       clutter_property_transition_set_property_name (self,
132                                                      g_value_get_string (value));
133       break;
134
135     default:
136       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
137     }
138 }
139
140 static void
141 clutter_property_transition_get_property (GObject    *gobject,
142                                           guint       prop_id,
143                                           GValue     *value,
144                                           GParamSpec *pspec)
145 {
146   ClutterPropertyTransitionPrivate *priv = CLUTTER_PROPERTY_TRANSITION (gobject)->priv;
147
148   switch (prop_id)
149     {
150     case PROP_PROPERTY_NAME:
151       g_value_set_string (value, priv->property_name);
152       break;
153
154     default:
155       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
156     }
157 }
158
159 static void
160 clutter_property_transition_finalize (GObject *gobject)
161 {
162   ClutterPropertyTransitionPrivate *priv;
163
164   priv = CLUTTER_PROPERTY_TRANSITION (gobject)->priv;
165
166   g_free (priv->property_name);
167
168   G_OBJECT_CLASS (clutter_property_transition_parent_class)->finalize (gobject);
169 }
170
171 static void
172 clutter_property_transition_class_init (ClutterPropertyTransitionClass *klass)
173 {
174   ClutterTransitionClass *transition_class = CLUTTER_TRANSITION_CLASS (klass);
175   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
176
177   g_type_class_add_private (klass, sizeof (ClutterPropertyTransitionPrivate));
178
179   transition_class->attached = clutter_property_transition_attached;
180   transition_class->detached = clutter_property_transition_detached;
181   transition_class->compute_value = clutter_property_transition_compute_value;
182
183   gobject_class->set_property = clutter_property_transition_set_property;
184   gobject_class->get_property = clutter_property_transition_get_property;
185   gobject_class->finalize = clutter_property_transition_finalize;
186
187   /**
188    * ClutterPropertyTransition:property-name:
189    *
190    * The name of the property of a #ClutterAnimatable to animate.
191    *
192    * Since: 1.10
193    */
194   obj_props[PROP_PROPERTY_NAME] =
195     g_param_spec_string ("property-name",
196                          P_("Property Name"),
197                          P_("The name of the property to animate"),
198                          NULL,
199                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
200
201   g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
202 }
203
204 static void
205 clutter_property_transition_init (ClutterPropertyTransition *self)
206 {
207   self->priv =
208     G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_PROPERTY_TRANSITION,
209                                  ClutterPropertyTransitionPrivate);
210 }
211
212 /**
213  * clutter_property_transition_new:
214  * @property_name: (allow-none): a property of @animatable, or %NULL
215  *
216  * Creates a new #ClutterPropertyTransition.
217  *
218  * Return value: (transfer full): the newly created #ClutterPropertyTransition.
219  *   Use g_object_unref() when done
220  *
221  * Since: 1.10
222  */
223 ClutterTransition *
224 clutter_property_transition_new (const char *property_name)
225 {
226   return g_object_new (CLUTTER_TYPE_PROPERTY_TRANSITION,
227                        "property-name", property_name,
228                        NULL);
229 }
230
231 /**
232  * clutter_property_transition_set_property_name:
233  * @transition: a #ClutterPropertyTransition
234  * @property_name: (allow-none): a property name
235  *
236  * Sets the #ClutterPropertyTransition:property-name property of @transition.
237  *
238  * Since: 1.10
239  */
240 void
241 clutter_property_transition_set_property_name (ClutterPropertyTransition *transition,
242                                                const char                *property_name)
243 {
244   ClutterPropertyTransitionPrivate *priv;
245   ClutterAnimatable *animatable;
246
247   g_return_if_fail (CLUTTER_IS_PROPERTY_TRANSITION (transition));
248
249   priv = transition->priv;
250
251   if (g_strcmp0 (priv->property_name, property_name) == 0)
252     return;
253
254   g_free (priv->property_name);
255   priv->property_name = g_strdup (property_name);
256   priv->pspec = NULL;
257
258   animatable =
259     clutter_transition_get_animatable (CLUTTER_TRANSITION (transition));
260   if (animatable != NULL)
261     {
262       priv->pspec = clutter_animatable_find_property (animatable,
263                                                       priv->property_name);
264     }
265
266   g_object_notify_by_pspec (G_OBJECT (transition),
267                             obj_props[PROP_PROPERTY_NAME]);
268 }
269
270 /**
271  * clutter_property_transition_get_property_name:
272  * @transition: a #ClutterPropertyTransition
273  *
274  * Retrieves the value of the #ClutterPropertyTransition:property-name
275  * property.
276  *
277  * Return value: the name of the property being animated, or %NULL if
278  *   none is set. The returned string is owned by the @transition and
279  *   it should not be freed.
280  *
281  * Since: 1.10
282  */
283 const char *
284 clutter_property_transition_get_property_name (ClutterPropertyTransition *transition)
285 {
286   g_return_val_if_fail (CLUTTER_IS_PROPERTY_TRANSITION (transition), NULL);
287
288   return transition->priv->property_name;
289 }