[animation] Allow registering custom progress function
authorEmmanuele Bassi <ebassi@linux.intel.com>
Thu, 8 Jan 2009 11:15:09 +0000 (11:15 +0000)
committerEmmanuele Bassi <ebassi@linux.intel.com>
Thu, 8 Jan 2009 11:15:09 +0000 (11:15 +0000)
A ClutterInterval can change the way the progress is computed
by subclassing and overriding the ::compute_value() virtual function.

It should also be possible to register a custom progress function
in the same way it is possible to register a custom transformation
function between two GValues.

This commit adds an internal, global hash table that maintains a
GType <-> progress function association; each ClutterInterval
will check if there is a progress function registered for the
GType of the initial and final values of the interval and, if
it has been found, it will call it to compute the value of the
interval depending on the progress factor.

clutter/clutter-interval.c
clutter/clutter-interval.h

index 0b74e3d..efdf58d 100644 (file)
 #include "clutter-interval.h"
 #include "clutter-units.h"
 
+typedef struct
+{
+  GType value_type;
+  ClutterProgressFunc func;
+} ProgressData;
+
+static GHashTable *progress_funcs = NULL;
+
 enum
 {
   PROP_0,
@@ -186,6 +194,25 @@ clutter_interval_real_compute_value (ClutterInterval *interval,
 
   value_type = clutter_interval_get_value_type (interval);
 
+  if (G_UNLIKELY (progress_funcs != NULL))
+    {
+      ProgressData *p_data;
+
+      p_data =
+        g_hash_table_lookup (progress_funcs, GUINT_TO_POINTER (value_type));
+
+      /* if we have a progress function, and that function was
+       * successful in computing the progress, then we bail out
+       * as fast as we can
+       */
+      if (p_data != NULL)
+        {
+          retval = p_data->func (initial, final, factor, value);
+          if (retval)
+            return retval;
+        }
+    }
+
   switch (G_TYPE_FUNDAMENTAL (value_type))
     {
     case G_TYPE_INT:
@@ -870,3 +897,81 @@ clutter_interval_compute_value (ClutterInterval *interval,
                                                                factor,
                                                                value);
 }
+
+/**
+ * clutter_interval_register_progress_func:
+ * @value_type: a #GType
+ * @func: a #ClutterProgressFunc, or %NULL to unset a previously
+ *   set progress function
+ *
+ * Sets the progress function for a given @value_type, like:
+ *
+ * |[
+ *   clutter_interval_register_progress_func (MY_TYPE_FOO,
+ *                                            my_foo_progress);
+ * ]|
+ *
+ * Whenever a #ClutterInterval instance using the default
+ * #ClutterInterval::compute_value implementation is set as an
+ * interval between two #GValue of type @value_type, it will call
+ * @func to establish the value depending on the given progress,
+ * for instance:
+ *
+ * |[
+ *   static gboolean
+ *   my_int_progress (const GValue *a,
+ *                    const GValue *b,
+ *                    gdouble       progress,
+ *                    GValue       *retval)
+ *   {
+ *     gint ia = g_value_get_int (a);
+ *     gint ib = g_value_get_int (b);
+ *     gint res = factor * (ib - ia) + ia;
+ *
+ *     g_value_set_int (retval, res);
+ *
+ *     return TRUE;
+ *   }
+ *
+ *   clutter_interval_register_progress_func (G_TYPE_INT, my_int_progress);
+ * ]|
+ *
+ * To unset a previously set progress function of a #GType, pass %NULL
+ * for @func.
+ *
+ * Since: 1.0
+ */
+void
+clutter_interval_register_progress_func (GType               value_type,
+                                         ClutterProgressFunc func)
+{
+  ProgressData *progress_func;
+
+  g_return_if_fail (value_type != G_TYPE_INVALID);
+
+  if (G_UNLIKELY (progress_funcs == NULL))
+    progress_funcs = g_hash_table_new (NULL, NULL);
+
+  progress_func =
+    g_hash_table_lookup (progress_funcs, GUINT_TO_POINTER (value_type));
+  if (G_UNLIKELY (progress_func))
+    {
+      if (func == NULL)
+        {
+          g_hash_table_remove (progress_funcs, GUINT_TO_POINTER (value_type));
+          g_slice_free (ProgressData, progress_func);
+        }
+      else
+        progress_func->func = func;
+    }
+  else
+    {
+      progress_func = g_slice_new (ProgressData);
+      progress_func->value_type = value_type;
+      progress_func->func = func;
+
+      g_hash_table_replace (progress_funcs,
+                            GUINT_TO_POINTER (value_type),
+                            progress_func);
+    }
+}
index 919369b..72ae530 100644 (file)
@@ -45,6 +45,34 @@ typedef struct _ClutterIntervalPrivate          ClutterIntervalPrivate;
 typedef struct _ClutterIntervalClass            ClutterIntervalClass;
 
 /**
+ * ClutterProgressFunc:
+ * @a: the initial value of an interval
+ * @b: the final value of an interval
+ * @progress: the progress factor, between 0 and 1
+ * @retval: the value used to store the progress
+ *
+ * Prototype of the progress function used to compute the value
+ * between the two ends @a and @b of an interval depending on
+ * the value of @progress.
+ *
+ * The #GValue in @retval is already initialized with the same
+ * type as @a and @b.
+ *
+ * This function will be called by #ClutterInterval if the
+ * type of the values of the interval was registered using
+ * clutter_interval_register_progress_func().
+ *
+ * Return value: %TRUE if the function successfully computed
+ *   the value and stored it inside @retval
+ *
+ * Since: 1.0
+ */
+typedef gboolean (* ClutterProgressFunc) (const GValue *a,
+                                          const GValue *b,
+                                          gdouble       progress,
+                                          GValue       *retval);
+
+/**
  * ClutterInterval:
  *
  * The #ClutterInterval structure contains only private data and should
@@ -126,6 +154,9 @@ gboolean         clutter_interval_compute_value      (ClutterInterval *interval,
                                                       gdouble          factor,
                                                       GValue          *value);
 
+void clutter_interval_register_progress_func (GType               value_type,
+                                              ClutterProgressFunc func);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_INTERVAL_H__ */