interval: Compute progress for signed char
[profile/ivi/clutter.git] / clutter / clutter-interval.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Copyright (C) 2008  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-interval
27  * @short_description: An object holding an interval of two values
28  *
29  * #ClutterInterval is a simple object that can hold two values
30  * defining an interval. #ClutterInterval can hold any value that
31  * can be enclosed inside a #GValue.
32  *
33  * Once a #ClutterInterval for a specific #GType has been instantiated
34  * the #ClutterInterval:value-type property cannot be changed anymore.
35  *
36  * #ClutterInterval starts with a floating reference; this means that
37  * any object taking a reference on a #ClutterInterval instance should
38  * also take ownership of the interval by using g_object_ref_sink().
39  *
40  * #ClutterInterval is used by #ClutterAnimation to define the
41  * interval of values that an implicit animation should tween over.
42  *
43  * #ClutterInterval can be subclassed to override the validation
44  * and value computation.
45  *
46  * #ClutterInterval is available since Clutter 1.0
47  */
48
49 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif
52
53 #include <stdlib.h>
54 #include <string.h>
55
56 #include <glib.h>
57 #include <glib-object.h>
58 #include <gobject/gvaluecollector.h>
59
60 #include "clutter-color.h"
61 #include "clutter-fixed.h"
62 #include "clutter-interval.h"
63 #include "clutter-private.h"
64 #include "clutter-units.h"
65
66 enum
67 {
68   PROP_0,
69
70   PROP_VALUE_TYPE,
71   PROP_INITIAL,
72   PROP_FINAL,
73
74   PROP_LAST
75 };
76
77 static GParamSpec *obj_props[PROP_LAST];
78
79 enum
80 {
81   INITIAL = 0,
82   FINAL,
83   RESULT,
84
85   N_VALUES
86 };
87
88 #define CLUTTER_INTERVAL_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_INTERVAL, ClutterIntervalPrivate))
89
90 struct _ClutterIntervalPrivate
91 {
92   GType value_type;
93
94   GValue *values;
95 };
96
97 G_DEFINE_TYPE (ClutterInterval, clutter_interval, G_TYPE_INITIALLY_UNOWNED);
98
99 static gboolean
100 clutter_interval_real_validate (ClutterInterval *interval,
101                                 GParamSpec      *pspec)
102 {
103   GType pspec_gtype = G_PARAM_SPEC_VALUE_TYPE (pspec);
104
105   /* check the GTypes we provide first */
106   if (pspec_gtype == COGL_TYPE_FIXED)
107     {
108       ClutterParamSpecFixed *pspec_fixed = CLUTTER_PARAM_SPEC_FIXED (pspec);
109       CoglFixed a, b;
110
111       a = b = 0;
112       clutter_interval_get_interval (interval, &a, &b);
113       if ((a >= pspec_fixed->minimum && a <= pspec_fixed->maximum) &&
114           (b >= pspec_fixed->minimum && b <= pspec_fixed->maximum))
115         return TRUE;
116       else
117         return FALSE;
118     }
119
120   /* then check the fundamental types */
121   switch (G_TYPE_FUNDAMENTAL (pspec_gtype))
122     {
123     case G_TYPE_INT:
124       {
125         GParamSpecInt *pspec_int = G_PARAM_SPEC_INT (pspec);
126         gint a, b;
127
128         a = b = 0;
129         clutter_interval_get_interval (interval, &a, &b);
130         if ((a >= pspec_int->minimum && a <= pspec_int->maximum) &&
131             (b >= pspec_int->minimum && b <= pspec_int->maximum))
132           return TRUE;
133         else
134           return FALSE;
135       }
136       break;
137
138     case G_TYPE_INT64:
139       {
140         GParamSpecInt64 *pspec_int = G_PARAM_SPEC_INT64 (pspec);
141         gint64 a, b;
142
143         a = b = 0;
144         clutter_interval_get_interval (interval, &a, &b);
145         if ((a >= pspec_int->minimum && a <= pspec_int->maximum) &&
146             (b >= pspec_int->minimum && b <= pspec_int->maximum))
147           return TRUE;
148         else
149           return FALSE;
150       }
151       break;
152
153     case G_TYPE_UINT:
154       {
155         GParamSpecUInt *pspec_uint = G_PARAM_SPEC_UINT (pspec);
156         guint a, b;
157
158         a = b = 0;
159         clutter_interval_get_interval (interval, &a, &b);
160         if ((a >= pspec_uint->minimum && a <= pspec_uint->maximum) &&
161             (b >= pspec_uint->minimum && b <= pspec_uint->maximum))
162           return TRUE;
163         else
164           return FALSE;
165       }
166       break;
167
168     case G_TYPE_UINT64:
169       {
170         GParamSpecUInt64 *pspec_int = G_PARAM_SPEC_UINT64 (pspec);
171         guint64 a, b;
172
173         a = b = 0;
174         clutter_interval_get_interval (interval, &a, &b);
175         if ((a >= pspec_int->minimum && a <= pspec_int->maximum) &&
176             (b >= pspec_int->minimum && b <= pspec_int->maximum))
177           return TRUE;
178         else
179           return FALSE;
180       }
181       break;
182
183     case G_TYPE_CHAR:
184       {
185         GParamSpecChar *pspec_char = G_PARAM_SPEC_CHAR (pspec);
186         guchar a, b;
187
188         a = b = 0;
189         clutter_interval_get_interval (interval, &a, &b);
190         if ((a >= pspec_char->minimum && a <= pspec_char->maximum) &&
191             (b >= pspec_char->minimum && b <= pspec_char->maximum))
192           return TRUE;
193         else
194           return FALSE;
195       }
196       break;
197
198     case G_TYPE_UCHAR:
199       {
200         GParamSpecUChar *pspec_uchar = G_PARAM_SPEC_UCHAR (pspec);
201         guchar a, b;
202
203         a = b = 0;
204         clutter_interval_get_interval (interval, &a, &b);
205         if ((a >= pspec_uchar->minimum && a <= pspec_uchar->maximum) &&
206             (b >= pspec_uchar->minimum && b <= pspec_uchar->maximum))
207           return TRUE;
208         else
209           return FALSE;
210       }
211       break;
212
213     case G_TYPE_FLOAT:
214       {
215         GParamSpecFloat *pspec_flt = G_PARAM_SPEC_FLOAT (pspec);
216         float a, b;
217
218         a = b = 0.f;
219         clutter_interval_get_interval (interval, &a, &b);
220         if ((a >= pspec_flt->minimum && a <= pspec_flt->maximum) &&
221             (b >= pspec_flt->minimum && b <= pspec_flt->maximum))
222           return TRUE;
223         else
224           return FALSE;
225       }
226       break;
227
228     case G_TYPE_DOUBLE:
229       {
230         GParamSpecDouble *pspec_flt = G_PARAM_SPEC_DOUBLE (pspec);
231         double a, b;
232
233         a = b = 0;
234         clutter_interval_get_interval (interval, &a, &b);
235         if ((a >= pspec_flt->minimum && a <= pspec_flt->maximum) &&
236             (b >= pspec_flt->minimum && b <= pspec_flt->maximum))
237           return TRUE;
238         else
239           return FALSE;
240       }
241       break;
242
243     case G_TYPE_BOOLEAN:
244       return TRUE;
245
246     default:
247       break;
248     }
249
250   return TRUE;
251 }
252
253 static gboolean
254 clutter_interval_real_compute_value (ClutterInterval *interval,
255                                      gdouble          factor,
256                                      GValue          *value)
257 {
258   GValue *initial, *final;
259   GType value_type;
260   gboolean retval = FALSE;
261
262   initial = clutter_interval_peek_initial_value (interval);
263   final = clutter_interval_peek_final_value (interval);
264
265   value_type = clutter_interval_get_value_type (interval);
266
267   if (_clutter_has_progress_function (value_type))
268     {
269       retval = _clutter_run_progress_function (value_type,
270                                                initial,
271                                                final,
272                                                factor,
273                                                value);
274       if (retval)
275         return TRUE;
276     }
277
278   switch (G_TYPE_FUNDAMENTAL (value_type))
279     {
280     case G_TYPE_INT:
281       {
282         gint ia, ib, res;
283
284         ia = g_value_get_int (initial);
285         ib = g_value_get_int (final);
286
287         res = (factor * (ib - ia)) + ia;
288
289         g_value_set_int (value, res);
290
291         retval = TRUE;
292       }
293       break;
294
295     case G_TYPE_CHAR:
296       {
297         gchar ia, ib, res;
298
299         ia = g_value_get_schar (initial);
300         ib = g_value_get_schar (final);
301
302         res = (factor * (ib - (gdouble) ia)) + ia;
303
304         g_value_set_schar (value, res);
305
306         retval = TRUE;
307       }
308       break;
309
310     case G_TYPE_UINT:
311       {
312         guint ia, ib, res;
313
314         ia = g_value_get_uint (initial);
315         ib = g_value_get_uint (final);
316
317         res = (factor * (ib - (gdouble) ia)) + ia;
318
319         g_value_set_uint (value, res);
320
321         retval = TRUE;
322       }
323       break;
324
325     case G_TYPE_UCHAR:
326       {
327         guchar ia, ib, res;
328
329         ia = g_value_get_uchar (initial);
330         ib = g_value_get_uchar (final);
331
332         res = (factor * (ib - (gdouble) ia)) + ia;
333
334         g_value_set_uchar (value, res);
335
336         retval = TRUE;
337       }
338       break;
339
340     case G_TYPE_FLOAT:
341     case G_TYPE_DOUBLE:
342       {
343         gdouble ia, ib, res;
344
345         if (value_type == G_TYPE_DOUBLE)
346           {
347             ia = g_value_get_double (initial);
348             ib = g_value_get_double (final);
349           }
350         else
351           {
352             ia = g_value_get_float (initial);
353             ib = g_value_get_float (final);
354           }
355
356         res = (factor * (ib - ia)) + ia;
357
358         if (value_type == G_TYPE_DOUBLE)
359           g_value_set_double (value, res);
360         else
361           g_value_set_float (value, res);
362
363         retval = TRUE;
364       }
365       break;
366
367     case G_TYPE_BOOLEAN:
368       if (factor > 0.5)
369         g_value_set_boolean (value, TRUE);
370       else
371         g_value_set_boolean (value, FALSE);
372
373       retval = TRUE;
374       break;
375
376     case G_TYPE_BOXED:
377       break;
378
379     default:
380       break;
381     }
382
383   /* We're trying to animate a property without knowing how to do that. Issue
384    * a warning with a hint to what could be done to fix that */
385   if (G_UNLIKELY (retval == FALSE))
386     {
387       g_warning ("%s: Could not compute progress between two %s. You can "
388                  "register a progress function to instruct ClutterInterval "
389                  "how to deal with this GType",
390                  G_STRLOC,
391                  g_type_name (value_type));
392     }
393
394   return retval;
395 }
396
397 static void
398 clutter_interval_finalize (GObject *gobject)
399 {
400   ClutterIntervalPrivate *priv = CLUTTER_INTERVAL (gobject)->priv;
401
402   g_value_unset (&priv->values[0]);
403   g_value_unset (&priv->values[1]);
404
405   g_free (priv->values);
406
407   G_OBJECT_CLASS (clutter_interval_parent_class)->finalize (gobject);
408 }
409
410 static void
411 clutter_interval_set_property (GObject      *gobject,
412                                guint         prop_id,
413                                const GValue *value,
414                                GParamSpec   *pspec)
415 {
416   ClutterIntervalPrivate *priv = CLUTTER_INTERVAL_GET_PRIVATE (gobject);
417
418   switch (prop_id)
419     {
420     case PROP_VALUE_TYPE:
421       priv->value_type = g_value_get_gtype (value);
422       break;
423
424     case PROP_INITIAL:
425       if (g_value_get_boxed (value) != NULL)
426         clutter_interval_set_initial_value (CLUTTER_INTERVAL (gobject),
427                                             g_value_get_boxed (value));
428       else if (G_IS_VALUE (&priv->values[INITIAL]))
429         g_value_unset (&priv->values[INITIAL]);
430       break;
431
432     case PROP_FINAL:
433       if (g_value_get_boxed (value) != NULL)
434         clutter_interval_set_final_value (CLUTTER_INTERVAL (gobject),
435                                           g_value_get_boxed (value));
436       else if (G_IS_VALUE (&priv->values[FINAL]))
437         g_value_unset (&priv->values[FINAL]);
438       break;
439
440     default:
441       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
442       break;
443     }
444 }
445
446 static void
447 clutter_interval_get_property (GObject    *gobject,
448                                guint       prop_id,
449                                GValue     *value,
450                                GParamSpec *pspec)
451 {
452   ClutterIntervalPrivate *priv = CLUTTER_INTERVAL_GET_PRIVATE (gobject);
453
454   switch (prop_id)
455     {
456     case PROP_VALUE_TYPE:
457       g_value_set_gtype (value, priv->value_type);
458       break;
459
460     case PROP_INITIAL:
461       if (G_IS_VALUE (&priv->values[INITIAL]))
462         g_value_set_boxed (value, &priv->values[INITIAL]);
463       break;
464
465     case PROP_FINAL:
466       if (G_IS_VALUE (&priv->values[FINAL]))
467         g_value_set_boxed (value, &priv->values[FINAL]);
468       break;
469
470     default:
471       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
472       break;
473     }
474 }
475
476 static void
477 clutter_interval_class_init (ClutterIntervalClass *klass)
478 {
479   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
480
481   g_type_class_add_private (klass, sizeof (ClutterIntervalPrivate));
482
483   klass->validate = clutter_interval_real_validate;
484   klass->compute_value = clutter_interval_real_compute_value;
485
486   gobject_class->set_property = clutter_interval_set_property,
487   gobject_class->get_property = clutter_interval_get_property;
488   gobject_class->finalize = clutter_interval_finalize;
489
490   /**
491    * ClutterInterval:value-type:
492    *
493    * The type of the values in the interval.
494    *
495    * Since: 1.0
496    */
497   obj_props[PROP_VALUE_TYPE] =
498     g_param_spec_gtype ("value-type",
499                         P_("Value Type"),
500                         P_("The type of the values in the interval"),
501                         G_TYPE_NONE,
502                         G_PARAM_READWRITE |
503                         G_PARAM_CONSTRUCT_ONLY |
504                         G_PARAM_STATIC_STRINGS);
505
506   /**
507    * ClutterInterval:initial:
508    *
509    * The initial value of the interval.
510    *
511    * Since: 1.12
512    */
513   obj_props[PROP_INITIAL] =
514     g_param_spec_boxed ("initial",
515                         P_("Initial Value"),
516                         P_("Initial value of the interval"),
517                         G_TYPE_VALUE,
518                         G_PARAM_READWRITE |
519                         G_PARAM_STATIC_STRINGS);
520
521   /**
522    * ClutterInterval:final:
523    *
524    * The final value of the interval.
525    *
526    * Since: 1.12
527    */
528   obj_props[PROP_FINAL] =
529     g_param_spec_boxed ("final",
530                         P_("Final Value"),
531                         P_("Final value of the interval"),
532                         G_TYPE_VALUE,
533                         G_PARAM_READWRITE |
534                         G_PARAM_STATIC_STRINGS);
535
536   g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
537 }
538
539 static void
540 clutter_interval_init (ClutterInterval *self)
541 {
542   ClutterIntervalPrivate *priv;
543
544   self->priv = priv = CLUTTER_INTERVAL_GET_PRIVATE (self);
545
546   priv->value_type = G_TYPE_INVALID;
547   priv->values = g_malloc0 (sizeof (GValue) * N_VALUES);
548 }
549
550 static inline void
551 clutter_interval_set_value_internal (ClutterInterval *interval,
552                                      gint             index_,
553                                      const GValue    *value)
554 {
555   ClutterIntervalPrivate *priv = interval->priv;
556   GType value_type;
557
558   g_assert (index_ >= INITIAL && index_ <= RESULT);
559
560   if (G_IS_VALUE (&priv->values[index_]))
561     g_value_unset (&priv->values[index_]);
562
563   g_value_init (&priv->values[index_], priv->value_type);
564
565   value_type = G_VALUE_TYPE (value);
566   if (value_type != priv->value_type ||
567       !g_type_is_a (value_type, priv->value_type))
568     {
569       if (g_value_type_compatible (value_type, priv->value_type))
570         {
571           g_value_copy (value, &priv->values[index_]);
572           return;
573         }
574
575       if (g_value_type_transformable (value_type, priv->value_type))
576         {
577           GValue transform = G_VALUE_INIT;
578
579           g_value_init (&transform, priv->value_type);
580
581           if (g_value_transform (value, &transform))
582             g_value_copy (&transform, &priv->values[index_]);
583           else
584             {
585               g_warning ("%s: Unable to convert a value of type '%s' into "
586                          "the value type '%s' of the interval.",
587                          G_STRLOC,
588                          g_type_name (value_type),
589                          g_type_name (priv->value_type));
590             }
591
592           g_value_unset (&transform);
593         }
594     }
595   else
596     g_value_copy (value, &priv->values[index_]);
597 }
598
599 static inline void
600 clutter_interval_get_value_internal (ClutterInterval *interval,
601                                      gint             index_,
602                                      GValue          *value)
603 {
604   ClutterIntervalPrivate *priv = interval->priv;
605
606   g_assert (index_ >= INITIAL && index_ <= RESULT);
607
608   g_value_copy (&priv->values[index_], value);
609 }
610
611 static gboolean
612 clutter_interval_set_initial_internal (ClutterInterval *interval,
613                                        va_list         *args)
614 {
615   GType gtype = interval->priv->value_type;
616   GValue value = G_VALUE_INIT;
617   gchar *error;
618
619   /* initial value */
620   G_VALUE_COLLECT_INIT (&value, gtype, *args, 0, &error);
621
622   if (error)
623     {
624       g_warning ("%s: %s", G_STRLOC, error);
625
626       /* we leak the value here as it might not be in a valid state
627        * given the error and calling g_value_unset() might lead to
628        * undefined behaviour
629        */
630       g_free (error);
631       return FALSE;
632     }
633
634   clutter_interval_set_value_internal (interval, INITIAL, &value);
635   g_value_unset (&value);
636
637   return TRUE;
638 }
639
640 static gboolean
641 clutter_interval_set_final_internal (ClutterInterval *interval,
642                                      va_list         *args)
643 {
644   GType gtype = interval->priv->value_type;
645   GValue value = G_VALUE_INIT;
646   gchar *error;
647
648   /* initial value */
649   G_VALUE_COLLECT_INIT (&value, gtype, *args, 0, &error);
650
651   if (error)
652     {
653       g_warning ("%s: %s", G_STRLOC, error);
654
655       /* we leak the value here as it might not be in a valid state
656        * given the error and calling g_value_unset() might lead to
657        * undefined behaviour
658        */
659       g_free (error);
660       return FALSE;
661     }
662
663   clutter_interval_set_value_internal (interval, FINAL, &value);
664   g_value_unset (&value);
665
666   return TRUE;
667 }
668
669 static void
670 clutter_interval_get_interval_valist (ClutterInterval *interval,
671                                       va_list          var_args)
672 {
673   GType gtype = interval->priv->value_type;
674   GValue value = G_VALUE_INIT;
675   gchar *error;
676
677   /* initial value */
678   g_value_init (&value, gtype);
679   clutter_interval_get_initial_value (interval, &value);
680   G_VALUE_LCOPY (&value, var_args, 0, &error);
681   if (error)
682     {
683       g_warning ("%s: %s", G_STRLOC, error);
684       g_free (error);
685       g_value_unset (&value);
686       return;
687     }
688
689   g_value_unset (&value);
690
691   /* final value */
692   g_value_init (&value, gtype);
693   clutter_interval_get_final_value (interval, &value);
694   G_VALUE_LCOPY (&value, var_args, 0, &error);
695   if (error)
696     {
697       g_warning ("%s: %s", G_STRLOC, error);
698       g_free (error);
699       g_value_unset (&value);
700       return;
701     }
702
703   g_value_unset (&value);
704 }
705
706 /**
707  * clutter_interval_new:
708  * @gtype: the type of the values in the interval
709  * @...: the initial value and the final value of the interval
710  *
711  * Creates a new #ClutterInterval holding values of type @gtype.
712  *
713  * This function avoids using a #GValue for the initial and final values
714  * of the interval:
715  *
716  * |[
717  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0.0, 1.0);
718  *   interval = clutter_interval_new (G_TYPE_BOOLEAN, FALSE, TRUE);
719  *   interval = clutter_interval_new (G_TYPE_INT, 0, 360);
720  * ]|
721  *
722  * Return value: the newly created #ClutterInterval
723  *
724  * Since: 1.0
725  */
726 ClutterInterval *
727 clutter_interval_new (GType gtype,
728                       ...)
729 {
730   ClutterInterval *retval;
731   va_list args;
732
733   g_return_val_if_fail (gtype != G_TYPE_INVALID, NULL);
734
735   retval = g_object_new (CLUTTER_TYPE_INTERVAL, "value-type", gtype, NULL);
736
737   va_start (args, gtype);
738
739   if (!clutter_interval_set_initial_internal (retval, &args))
740     goto out;
741
742   clutter_interval_set_final_internal (retval, &args);
743
744 out:
745   va_end (args);
746
747   return retval;
748 }
749
750 /**
751  * clutter_interval_new_with_values:
752  * @gtype: the type of the values in the interval
753  * @initial: (allow-none): a #GValue holding the initial value of the interval
754  * @final: (allow-none): a #GValue holding the final value of the interval
755  *
756  * Creates a new #ClutterInterval of type @gtype, between @initial
757  * and @final.
758  *
759  * This function is useful for language bindings.
760  *
761  * Return value: the newly created #ClutterInterval
762  *
763  * Since: 1.0
764  */
765 ClutterInterval *
766 clutter_interval_new_with_values (GType         gtype,
767                                   const GValue *initial,
768                                   const GValue *final)
769 {
770   g_return_val_if_fail (gtype != G_TYPE_INVALID, NULL);
771   g_return_val_if_fail (initial == NULL || G_VALUE_TYPE (initial) == gtype, NULL);
772   g_return_val_if_fail (final == NULL || G_VALUE_TYPE (final) == gtype, NULL);
773
774   return g_object_new (CLUTTER_TYPE_INTERVAL,
775                        "value-type", gtype,
776                        "initial", initial,
777                        "final", final,
778                        NULL);
779 }
780
781 /**
782  * clutter_interval_clone:
783  * @interval: a #ClutterInterval
784  *
785  * Creates a copy of @interval.
786  *
787  * Return value: (transfer full): the newly created #ClutterInterval
788  *
789  * Since: 1.0
790  */
791 ClutterInterval *
792 clutter_interval_clone (ClutterInterval *interval)
793 {
794   ClutterInterval *retval;
795   GType gtype;
796   GValue *tmp;
797
798   g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), NULL);
799   g_return_val_if_fail (interval->priv->value_type != G_TYPE_INVALID, NULL);
800
801   gtype = interval->priv->value_type;
802   retval = g_object_new (CLUTTER_TYPE_INTERVAL, "value-type", gtype, NULL);
803
804   tmp = clutter_interval_peek_initial_value (interval);
805   clutter_interval_set_initial_value (retval, tmp);
806
807   tmp = clutter_interval_peek_final_value (interval);
808   clutter_interval_set_final_value (retval, tmp);
809
810   return retval;
811 }
812
813 /**
814  * clutter_interval_get_value_type:
815  * @interval: a #ClutterInterval
816  *
817  * Retrieves the #GType of the values inside @interval.
818  *
819  * Return value: the type of the value, or G_TYPE_INVALID
820  *
821  * Since: 1.0
822  */
823 GType
824 clutter_interval_get_value_type (ClutterInterval *interval)
825 {
826   g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), G_TYPE_INVALID);
827
828   return interval->priv->value_type;
829 }
830
831 /**
832  * clutter_interval_set_initial_value:
833  * @interval: a #ClutterInterval
834  * @value: a #GValue
835  *
836  * Sets the initial value of @interval to @value. The value is copied
837  * inside the #ClutterInterval.
838  *
839  * Rename to: clutter_interval_set_initial
840  *
841  * Since: 1.0
842  */
843 void
844 clutter_interval_set_initial_value (ClutterInterval *interval,
845                                     const GValue    *value)
846 {
847   g_return_if_fail (CLUTTER_IS_INTERVAL (interval));
848   g_return_if_fail (value != NULL);
849
850   clutter_interval_set_value_internal (interval, INITIAL, value);
851 }
852
853 /**
854  * clutter_interval_set_initial: (skip)
855  * @interval: a #ClutterInterval
856  * @...: the initial value of the interval.
857  *
858  * Variadic arguments version of clutter_interval_set_initial_value().
859  *
860  * This function is meant as a convenience for the C API.
861  *
862  * Language bindings should use clutter_interval_set_initial_value()
863  * instead.
864  *
865  * Since: 1.10
866  */
867 void
868 clutter_interval_set_initial (ClutterInterval *interval,
869                               ...)
870 {
871   va_list args;
872
873   g_return_if_fail (CLUTTER_IS_INTERVAL (interval));
874
875   va_start (args, interval);
876   clutter_interval_set_initial_internal (interval, &args);
877   va_end (args);
878 }
879
880 /**
881  * clutter_interval_get_initial_value:
882  * @interval: a #ClutterInterval
883  * @value: (out caller-allocates): a #GValue
884  *
885  * Retrieves the initial value of @interval and copies
886  * it into @value.
887  *
888  * The passed #GValue must be initialized to the value held by
889  * the #ClutterInterval.
890  *
891  * Since: 1.0
892  */
893 void
894 clutter_interval_get_initial_value (ClutterInterval *interval,
895                                     GValue          *value)
896 {
897   g_return_if_fail (CLUTTER_IS_INTERVAL (interval));
898   g_return_if_fail (value != NULL);
899
900   clutter_interval_get_value_internal (interval, INITIAL, value);
901 }
902
903 /**
904  * clutter_interval_peek_initial_value:
905  * @interval: a #ClutterInterval
906  *
907  * Gets the pointer to the initial value of @interval
908  *
909  * Return value: (transfer none): the initial value of the interval.
910  *   The value is owned by the #ClutterInterval and it should not be
911  *   modified or freed
912  *
913  * Since: 1.0
914  */
915 GValue *
916 clutter_interval_peek_initial_value (ClutterInterval *interval)
917 {
918   g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), NULL);
919
920   return interval->priv->values + INITIAL;
921 }
922
923 /**
924  * clutter_interval_set_final_value:
925  * @interval: a #ClutterInterval
926  * @value: a #GValue
927  *
928  * Sets the final value of @interval to @value. The value is
929  * copied inside the #ClutterInterval.
930  *
931  * Rename to: clutter_interval_set_final
932  *
933  * Since: 1.0
934  */
935 void
936 clutter_interval_set_final_value (ClutterInterval *interval,
937                                   const GValue    *value)
938 {
939   g_return_if_fail (CLUTTER_IS_INTERVAL (interval));
940   g_return_if_fail (value != NULL);
941
942   clutter_interval_set_value_internal (interval, FINAL, value);
943 }
944
945 /**
946  * clutter_interval_get_final_value:
947  * @interval: a #ClutterInterval
948  * @value: (out caller-allocates): a #GValue
949  *
950  * Retrieves the final value of @interval and copies
951  * it into @value.
952  *
953  * The passed #GValue must be initialized to the value held by
954  * the #ClutterInterval.
955  *
956  * Since: 1.0
957  */
958 void
959 clutter_interval_get_final_value (ClutterInterval *interval,
960                                   GValue          *value)
961 {
962   g_return_if_fail (CLUTTER_IS_INTERVAL (interval));
963   g_return_if_fail (value != NULL);
964
965   clutter_interval_get_value_internal (interval, FINAL, value);
966 }
967
968 /**
969  * clutter_interval_set_final: (skip)
970  * @interval: a #ClutterInterval
971  * @...: the final value of the interval
972  *
973  * Variadic arguments version of clutter_interval_set_final_value().
974  *
975  * This function is meant as a convenience for the C API.
976  *
977  * Language bindings should use clutter_interval_set_final_value() instead.
978  *
979  * Since: 1.10
980  */
981 void
982 clutter_interval_set_final (ClutterInterval *interval,
983                             ...)
984 {
985   va_list args;
986
987   g_return_if_fail (CLUTTER_IS_INTERVAL (interval));
988
989   va_start (args, interval);
990   clutter_interval_set_final_internal (interval, &args);
991   va_end (args);
992 }
993
994 /**
995  * clutter_interval_peek_final_value:
996  * @interval: a #ClutterInterval
997  *
998  * Gets the pointer to the final value of @interval
999  *
1000  * Return value: (transfer none): the final value of the interval.
1001  *   The value is owned by the #ClutterInterval and it should not be
1002  *   modified or freed
1003  *
1004  * Since: 1.0
1005  */
1006 GValue *
1007 clutter_interval_peek_final_value (ClutterInterval *interval)
1008 {
1009   g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), NULL);
1010
1011   return interval->priv->values + FINAL;
1012 }
1013
1014 /**
1015  * clutter_interval_set_interval:
1016  * @interval: a #ClutterInterval
1017  * @...: the initial and final values of the interval
1018  *
1019  * Variable arguments wrapper for clutter_interval_set_initial_value()
1020  * and clutter_interval_set_final_value() that avoids using the
1021  * #GValue arguments:
1022  *
1023  * |[
1024  *   clutter_interval_set_interval (interval, 0, 50);
1025  *   clutter_interval_set_interval (interval, 1.0, 0.0);
1026  *   clutter_interval_set_interval (interval, FALSE, TRUE);
1027  * ]|
1028  *
1029  * This function is meant for the convenience of the C API; bindings
1030  * should reimplement this function using the #GValue-based API.
1031  *
1032  * Since: 1.0
1033  */
1034 void
1035 clutter_interval_set_interval (ClutterInterval *interval,
1036                                ...)
1037 {
1038   va_list args;
1039
1040   g_return_if_fail (CLUTTER_IS_INTERVAL (interval));
1041   g_return_if_fail (interval->priv->value_type != G_TYPE_INVALID);
1042
1043   va_start (args, interval);
1044
1045   if (!clutter_interval_set_initial_internal (interval, &args))
1046     goto out;
1047
1048   clutter_interval_set_final_internal (interval, &args);
1049
1050 out:
1051   va_end (args);
1052 }
1053
1054 /**
1055  * clutter_interval_get_interval:
1056  * @interval: a #ClutterInterval
1057  * @...: return locations for the initial and final values of
1058  *   the interval
1059  *
1060  * Variable arguments wrapper for clutter_interval_get_initial_value()
1061  * and clutter_interval_get_final_value() that avoids using the
1062  * #GValue arguments:
1063  *
1064  * |[
1065  *   gint a = 0, b = 0;
1066  *   clutter_interval_get_interval (interval, &a, &b);
1067  * ]|
1068  *
1069  * This function is meant for the convenience of the C API; bindings
1070  * should reimplement this function using the #GValue-based API.
1071  *
1072  * Since: 1.0
1073  */
1074 void
1075 clutter_interval_get_interval (ClutterInterval *interval,
1076                                ...)
1077 {
1078   va_list args;
1079
1080   g_return_if_fail (CLUTTER_IS_INTERVAL (interval));
1081   g_return_if_fail (interval->priv->value_type != G_TYPE_INVALID);
1082
1083   va_start (args, interval);
1084   clutter_interval_get_interval_valist (interval, args);
1085   va_end (args);
1086 }
1087
1088 /**
1089  * clutter_interval_validate:
1090  * @interval: a #ClutterInterval
1091  * @pspec: a #GParamSpec
1092  *
1093  * Validates the initial and final values of @interval against
1094  * a #GParamSpec.
1095  *
1096  * Return value: %TRUE if the #ClutterInterval is valid, %FALSE otherwise
1097  *
1098  * Since: 1.0
1099  */
1100 gboolean
1101 clutter_interval_validate (ClutterInterval *interval,
1102                            GParamSpec      *pspec)
1103 {
1104   g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), FALSE);
1105   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1106
1107   return CLUTTER_INTERVAL_GET_CLASS (interval)->validate (interval, pspec);
1108 }
1109
1110 /**
1111  * clutter_interval_compute_value:
1112  * @interval: a #ClutterInterval
1113  * @factor: the progress factor, between 0 and 1
1114  * @value: (out caller-allocates): return location for an initialized #GValue
1115  *
1116  * Computes the value between the @interval boundaries given the
1117  * progress @factor and copies it into @value.
1118  *
1119  * Return value: %TRUE if the operation was successful
1120  *
1121  * Since: 1.0
1122  */
1123 gboolean
1124 clutter_interval_compute_value (ClutterInterval *interval,
1125                                 gdouble          factor,
1126                                 GValue          *value)
1127 {
1128   g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), FALSE);
1129   g_return_val_if_fail (value != NULL, FALSE);
1130
1131   return CLUTTER_INTERVAL_GET_CLASS (interval)->compute_value (interval,
1132                                                                factor,
1133                                                                value);
1134 }
1135
1136 /**
1137  * clutter_interval_compute:
1138  * @interval: a #ClutterInterval
1139  * @factor: the progress factor, between 0 and 1
1140  *
1141  * Computes the value between the @interval boundaries given the
1142  * progress @factor
1143  *
1144  * Unlike clutter_interval_compute_value(), this function will
1145  * return a const pointer to the computed value
1146  *
1147  * You should use this function if you immediately pass the computed
1148  * value to another function that makes a copy of it, like
1149  * g_object_set_property()
1150  *
1151  * Return value: (transfer none): a pointer to the computed value,
1152  *   or %NULL if the computation was not successfull
1153  *
1154  * Since: 1.4
1155  */
1156 const GValue *
1157 clutter_interval_compute (ClutterInterval *interval,
1158                           gdouble          factor)
1159 {
1160   GValue *value;
1161   gboolean res;
1162
1163   g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), NULL);
1164
1165   value = &(interval->priv->values[RESULT]);
1166
1167   if (G_VALUE_TYPE (value) == G_TYPE_INVALID)
1168     g_value_init (value, interval->priv->value_type);
1169
1170   res = CLUTTER_INTERVAL_GET_CLASS (interval)->compute_value (interval,
1171                                                               factor,
1172                                                               value);
1173
1174   if (res)
1175     return interval->priv->values + RESULT;
1176
1177   return NULL;
1178 }
1179
1180 /**
1181  * clutter_interval_is_valid:
1182  * @interval: a #ClutterInterval
1183  *
1184  * Checks if the @interval has a valid initial and final values.
1185  *
1186  * Return value: %TRUE if the #ClutterInterval has an initial and
1187  *   final values, and %FALSE otherwise
1188  *
1189  * Since: 1.12
1190  */
1191 gboolean
1192 clutter_interval_is_valid (ClutterInterval *interval)
1193 {
1194   ClutterIntervalPrivate *priv;
1195
1196   g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), FALSE);
1197
1198   priv = interval->priv;
1199
1200   return G_IS_VALUE (&priv->values[INITIAL]) &&
1201          G_IS_VALUE (&priv->values[FINAL]);
1202 }