1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Copyright (C) 2009  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:
22  *   Emmanuele Bassi <ebassi@linux.intel.com>
23  */
24 
25 /**
26  * SECTION:clutter-animatable
27  * @short_description: Interface for animatable classes
28  *
29  * #ClutterAnimatable is an interface that allows a #GObject class
30  * to control how a #ClutterAnimation will animate a property.
31  *
32  * Each #ClutterAnimatable should implement the
33  * #ClutterAnimatableIface.interpolate_property() virtual function of the
34  * interface to compute the animation state between two values of an interval
35  * depending on a progress factor, expressed as a floating point value.
36  *
37  * If a #ClutterAnimatable is animated by a #ClutterAnimation
38  * instance, the #ClutterAnimation will call
39  * clutter_animatable_interpolate_property() passing the name of the
40  * currently animated property; the values interval; and the progress factor.
41  * The #ClutterAnimatable implementation should return the computed value for
42  * the animated
43  * property.
44  *
45  * #ClutterAnimatable is available since Clutter 1.0
46  */
47 
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51 
52 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
53 
54 #include "clutter-animatable.h"
55 #include "clutter-interval.h"
56 #include "clutter-debug.h"
57 #include "clutter-private.h"
58 
59 #include "deprecated/clutter-animatable.h"
60 #include "deprecated/clutter-animation.h"
61 
62 typedef ClutterAnimatableIface  ClutterAnimatableInterface;
63 G_DEFINE_INTERFACE (ClutterAnimatable, clutter_animatable, G_TYPE_OBJECT);
64 
65 static void
clutter_animatable_default_init(ClutterAnimatableInterface * iface)66 clutter_animatable_default_init (ClutterAnimatableInterface *iface)
67 {
68 }
69 
70 /**
71  * clutter_animatable_animate_property:
72  * @animatable: a #ClutterAnimatable
73  * @animation: a #ClutterAnimation
74  * @property_name: the name of the animated property
75  * @initial_value: the initial value of the animation interval
76  * @final_value: the final value of the animation interval
77  * @progress: the progress factor
78  * @value: return location for the animation value
79  *
80  * Calls the animate_property() virtual function for @animatable.
81  *
82  * The @initial_value and @final_value #GValue<!-- -->s must contain
83  * the same type; @value must have been initialized to the same
84  * type of @initial_value and @final_value.
85  *
86  * All implementation of the #ClutterAnimatable interface must
87  * implement this function.
88  *
89  * Return value: %TRUE if the value has been validated and can
90  *   be applied to the #ClutterAnimatable, and %FALSE otherwise
91  *
92  * Since: 1.0
93  *
94  * Deprecated: 1.8: Use clutter_animatable_interpolate_value()
95  *   instead
96  */
97 gboolean
clutter_animatable_animate_property(ClutterAnimatable * animatable,ClutterAnimation * animation,const gchar * property_name,const GValue * initial_value,const GValue * final_value,gdouble progress,GValue * value)98 clutter_animatable_animate_property (ClutterAnimatable *animatable,
99                                      ClutterAnimation  *animation,
100                                      const gchar       *property_name,
101                                      const GValue      *initial_value,
102                                      const GValue      *final_value,
103                                      gdouble            progress,
104                                      GValue            *value)
105 {
106   ClutterAnimatableIface *iface;
107   gboolean res;
108 
109   g_return_val_if_fail (CLUTTER_IS_ANIMATABLE (animatable), FALSE);
110   g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), FALSE);
111   g_return_val_if_fail (property_name != NULL, FALSE);
112   g_return_val_if_fail (initial_value != NULL && final_value != NULL, FALSE);
113   g_return_val_if_fail (G_VALUE_TYPE (initial_value) != G_TYPE_INVALID, FALSE);
114   g_return_val_if_fail (G_VALUE_TYPE (final_value) != G_TYPE_INVALID, FALSE);
115   g_return_val_if_fail (value != NULL, FALSE);
116   g_return_val_if_fail (G_VALUE_TYPE (value) == G_VALUE_TYPE (initial_value) &&
117                         G_VALUE_TYPE (value) == G_VALUE_TYPE (final_value),
118                         FALSE);
119 
120   iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable);
121   if (iface->animate_property == NULL)
122     {
123       ClutterInterval *interval;
124 
125       interval = clutter_animation_get_interval (animation, property_name);
126       if (interval == NULL)
127         return FALSE;
128 
129       res = clutter_animatable_interpolate_value (animatable, property_name,
130                                                   interval,
131                                                   progress,
132                                                   value);
133     }
134   else
135     res = iface->animate_property (animatable, animation,
136                                    property_name,
137                                    initial_value, final_value,
138                                    progress,
139                                    value);
140 
141   return res;
142 }
143 
144 /**
145  * clutter_animatable_find_property:
146  * @animatable: a #ClutterAnimatable
147  * @property_name: the name of the animatable property to find
148  *
149  * Finds the #GParamSpec for @property_name
150  *
151  * Return value: (transfer none): The #GParamSpec for the given property
152  *   or %NULL
153  *
154  * Since: 1.4
155  */
156 GParamSpec *
clutter_animatable_find_property(ClutterAnimatable * animatable,const gchar * property_name)157 clutter_animatable_find_property (ClutterAnimatable *animatable,
158                                   const gchar       *property_name)
159 {
160   ClutterAnimatableIface *iface;
161 
162   g_return_val_if_fail (CLUTTER_IS_ANIMATABLE (animatable), NULL);
163   g_return_val_if_fail (property_name != NULL, NULL);
164 
165   CLUTTER_NOTE (ANIMATION, "Looking for property '%s'", property_name);
166 
167   iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable);
168   if (iface->find_property != NULL)
169     return iface->find_property (animatable, property_name);
170 
171   return g_object_class_find_property (G_OBJECT_GET_CLASS (animatable),
172                                        property_name);
173 }
174 
175 /**
176  * clutter_animatable_get_initial_state:
177  * @animatable: a #ClutterAnimatable
178  * @property_name: the name of the animatable property to retrieve
179  * @value: a #GValue initialized to the type of the property to retrieve
180  *
181  * Retrieves the current state of @property_name and sets @value with it
182  *
183  * Since: 1.4
184  */
185 void
clutter_animatable_get_initial_state(ClutterAnimatable * animatable,const gchar * property_name,GValue * value)186 clutter_animatable_get_initial_state (ClutterAnimatable *animatable,
187                                       const gchar       *property_name,
188                                       GValue            *value)
189 {
190   ClutterAnimatableIface *iface;
191 
192   g_return_if_fail (CLUTTER_IS_ANIMATABLE (animatable));
193   g_return_if_fail (property_name != NULL);
194 
195   CLUTTER_NOTE (ANIMATION, "Getting initial state of '%s'", property_name);
196 
197   iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable);
198   if (iface->get_initial_state != NULL)
199     iface->get_initial_state (animatable, property_name, value);
200   else
201     g_object_get_property (G_OBJECT (animatable), property_name, value);
202 }
203 
204 /**
205  * clutter_animatable_set_final_state:
206  * @animatable: a #ClutterAnimatable
207  * @property_name: the name of the animatable property to set
208  * @value: the value of the animatable property to set
209  *
210  * Sets the current state of @property_name to @value
211  *
212  * Since: 1.4
213  */
214 void
clutter_animatable_set_final_state(ClutterAnimatable * animatable,const gchar * property_name,const GValue * value)215 clutter_animatable_set_final_state (ClutterAnimatable *animatable,
216                                     const gchar       *property_name,
217                                     const GValue      *value)
218 {
219   ClutterAnimatableIface *iface;
220 
221   g_return_if_fail (CLUTTER_IS_ANIMATABLE (animatable));
222   g_return_if_fail (property_name != NULL);
223 
224   CLUTTER_NOTE (ANIMATION, "Setting state of property '%s'", property_name);
225 
226   iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable);
227   if (iface->set_final_state != NULL)
228     iface->set_final_state (animatable, property_name, value);
229   else
230     g_object_set_property (G_OBJECT (animatable), property_name, value);
231 }
232 
233 /**
234  * clutter_animatable_interpolate_value:
235  * @animatable: a #ClutterAnimatable
236  * @property_name: the name of the property to interpolate
237  * @interval: a #ClutterInterval with the animation range
238  * @progress: the progress to use to interpolate between the
239  *   initial and final values of the @interval
240  * @value: (out): return location for an initialized #GValue
241  *   using the same type of the @interval
242  *
243  * Asks a #ClutterAnimatable implementation to interpolate a
244  * a named property between the initial and final values of
245  * a #ClutterInterval, using @progress as the interpolation
246  * value, and store the result inside @value.
247  *
248  * This function should be used for every property animation
249  * involving #ClutterAnimatable<!-- -->s.
250  *
251  * This function replaces clutter_animatable_animate_property().
252  *
253  * Return value: %TRUE if the interpolation was successful,
254  *   and %FALSE otherwise
255  *
256  * Since: 1.8
257  */
258 gboolean
clutter_animatable_interpolate_value(ClutterAnimatable * animatable,const gchar * property_name,ClutterInterval * interval,gdouble progress,GValue * value)259 clutter_animatable_interpolate_value (ClutterAnimatable *animatable,
260                                       const gchar       *property_name,
261                                       ClutterInterval   *interval,
262                                       gdouble            progress,
263                                       GValue            *value)
264 {
265   ClutterAnimatableIface *iface;
266 
267   g_return_val_if_fail (CLUTTER_IS_ANIMATABLE (animatable), FALSE);
268   g_return_val_if_fail (property_name != NULL, FALSE);
269   g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), FALSE);
270   g_return_val_if_fail (value != NULL, FALSE);
271 
272   CLUTTER_NOTE (ANIMATION, "Interpolating '%s' (progress: %.3f)",
273                 property_name,
274                 progress);
275 
276   iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable);
277   if (iface->interpolate_value != NULL)
278     {
279       return iface->interpolate_value (animatable, property_name,
280                                        interval,
281                                        progress,
282                                        value);
283     }
284   else
285     return clutter_interval_compute_value (interval, progress, value);
286 }
287