Blame clutter/clutter-property-transition.c

Packit 31ecd5
/*
Packit 31ecd5
 * Clutter.
Packit 31ecd5
 *
Packit 31ecd5
 * An OpenGL based 'interactive canvas' library.
Packit 31ecd5
 *
Packit 31ecd5
 * Copyright (C) 2012  Intel Corporation
Packit 31ecd5
 *
Packit 31ecd5
 * This library is free software; you can redistribute it and/or
Packit 31ecd5
 * modify it under the terms of the GNU Lesser General Public
Packit 31ecd5
 * License as published by the Free Software Foundation; either
Packit 31ecd5
 * version 2 of the License, or (at your option) any later version.
Packit 31ecd5
 *
Packit 31ecd5
 * This library is distributed in the hope that it will be useful,
Packit 31ecd5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 31ecd5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 31ecd5
 * Lesser General Public License for more details.
Packit 31ecd5
 *
Packit 31ecd5
 * You should have received a copy of the GNU Lesser General Public
Packit 31ecd5
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Packit 31ecd5
 */
Packit 31ecd5
Packit 31ecd5
/**
Packit 31ecd5
 * SECTION:clutter-property-transition
Packit 31ecd5
 * @Title: ClutterPropertyTransition
Packit 31ecd5
 * @Short_Description: Property transitions
Packit 31ecd5
 *
Packit 31ecd5
 * #ClutterPropertyTransition is a specialized #ClutterTransition that
Packit 31ecd5
 * can be used to tween a property of a #ClutterAnimatable instance.
Packit 31ecd5
 *
Packit 31ecd5
 * #ClutterPropertyTransition is available since Clutter 1.10
Packit 31ecd5
 */
Packit 31ecd5
Packit 31ecd5
#ifdef HAVE_CONFIG_H
Packit 31ecd5
#include "config.h"
Packit 31ecd5
#endif
Packit 31ecd5
Packit 31ecd5
#include "clutter-property-transition.h"
Packit 31ecd5
Packit 31ecd5
#include "clutter-animatable.h"
Packit 31ecd5
#include "clutter-debug.h"
Packit 31ecd5
#include "clutter-interval.h"
Packit 31ecd5
#include "clutter-private.h"
Packit 31ecd5
#include "clutter-transition.h"
Packit 31ecd5
Packit 31ecd5
struct _ClutterPropertyTransitionPrivate
Packit 31ecd5
{
Packit 31ecd5
  char *property_name;
Packit 31ecd5
Packit 31ecd5
  GParamSpec *pspec;
Packit 31ecd5
};
Packit 31ecd5
Packit 31ecd5
enum
Packit 31ecd5
{
Packit 31ecd5
  PROP_0,
Packit 31ecd5
Packit 31ecd5
  PROP_PROPERTY_NAME,
Packit 31ecd5
Packit 31ecd5
  PROP_LAST
Packit 31ecd5
};
Packit 31ecd5
Packit 31ecd5
static GParamSpec *obj_props[PROP_LAST] = { NULL, };
Packit 31ecd5
Packit 31ecd5
G_DEFINE_TYPE_WITH_PRIVATE (ClutterPropertyTransition, clutter_property_transition, CLUTTER_TYPE_TRANSITION)
Packit 31ecd5
Packit 31ecd5
static inline void
Packit 31ecd5
clutter_property_transition_ensure_interval (ClutterPropertyTransition *transition,
Packit 31ecd5
                                             ClutterAnimatable         *animatable,
Packit 31ecd5
                                             ClutterInterval           *interval)
Packit 31ecd5
{
Packit 31ecd5
  ClutterPropertyTransitionPrivate *priv = transition->priv;
Packit 31ecd5
  GValue *value_p;
Packit 31ecd5
Packit 31ecd5
  if (clutter_interval_is_valid (interval))
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  /* if no initial value has been set, use the current value */
Packit 31ecd5
  value_p = clutter_interval_peek_initial_value (interval);
Packit 31ecd5
  if (!G_IS_VALUE (value_p))
Packit 31ecd5
    {
Packit 31ecd5
      g_value_init (value_p, clutter_interval_get_value_type (interval));
Packit 31ecd5
      clutter_animatable_get_initial_state (animatable,
Packit 31ecd5
                                            priv->property_name,
Packit 31ecd5
                                            value_p);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  /* if no final value has been set, use the current value */
Packit 31ecd5
  value_p = clutter_interval_peek_final_value (interval);
Packit 31ecd5
  if (!G_IS_VALUE (value_p))
Packit 31ecd5
    {
Packit 31ecd5
      g_value_init (value_p, clutter_interval_get_value_type (interval));
Packit 31ecd5
      clutter_animatable_get_initial_state (animatable,
Packit 31ecd5
                                            priv->property_name,
Packit 31ecd5
                                            value_p);
Packit 31ecd5
    }
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_property_transition_attached (ClutterTransition *transition,
Packit 31ecd5
                                      ClutterAnimatable *animatable)
Packit 31ecd5
{
Packit 31ecd5
  ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (transition);
Packit 31ecd5
  ClutterPropertyTransitionPrivate *priv = self->priv;
Packit 31ecd5
  ClutterInterval *interval;
Packit 31ecd5
Packit 31ecd5
  if (priv->property_name == NULL)
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  priv->pspec =
Packit 31ecd5
    clutter_animatable_find_property (animatable, priv->property_name);
Packit 31ecd5
Packit 31ecd5
  if (priv->pspec == NULL)
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  interval = clutter_transition_get_interval (transition);
Packit 31ecd5
  if (interval == NULL)
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  clutter_property_transition_ensure_interval (self, animatable, interval);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_property_transition_detached (ClutterTransition *transition,
Packit 31ecd5
                                      ClutterAnimatable *animatable)
Packit 31ecd5
{
Packit 31ecd5
  ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (transition);
Packit 31ecd5
  ClutterPropertyTransitionPrivate *priv = self->priv;
Packit 31ecd5
Packit 31ecd5
  priv->pspec = NULL; 
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_property_transition_compute_value (ClutterTransition *transition,
Packit 31ecd5
                                           ClutterAnimatable *animatable,
Packit 31ecd5
                                           ClutterInterval   *interval,
Packit 31ecd5
                                           gdouble            progress)
Packit 31ecd5
{
Packit 31ecd5
  ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (transition);
Packit 31ecd5
  ClutterPropertyTransitionPrivate *priv = self->priv;
Packit 31ecd5
  GValue value = G_VALUE_INIT;
Packit 31ecd5
  GType p_type, i_type;
Packit 31ecd5
  gboolean res;
Packit 31ecd5
Packit 31ecd5
  /* if we have a GParamSpec we also have an animatable instance */
Packit 31ecd5
  if (priv->pspec == NULL)
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  clutter_property_transition_ensure_interval (self, animatable, interval);
Packit 31ecd5
Packit 31ecd5
  p_type = G_PARAM_SPEC_VALUE_TYPE (priv->pspec);
Packit 31ecd5
  i_type = clutter_interval_get_value_type (interval);
Packit 31ecd5
Packit 31ecd5
  g_value_init (&value, i_type);
Packit 31ecd5
Packit 31ecd5
  res = clutter_animatable_interpolate_value (animatable,
Packit 31ecd5
                                              priv->property_name,
Packit 31ecd5
                                              interval,
Packit 31ecd5
                                              progress,
Packit 31ecd5
                                              &value);
Packit 31ecd5
Packit 31ecd5
  if (res)
Packit 31ecd5
    {
Packit 31ecd5
      if (i_type != p_type || g_type_is_a (i_type, p_type))
Packit 31ecd5
        {
Packit 31ecd5
          if (g_value_type_transformable (i_type, p_type))
Packit 31ecd5
            {
Packit 31ecd5
              GValue transform = G_VALUE_INIT;
Packit 31ecd5
Packit 31ecd5
              g_value_init (&transform, p_type);
Packit 31ecd5
Packit 31ecd5
              if (g_value_transform (&value, &transform))
Packit 31ecd5
                {
Packit 31ecd5
                  clutter_animatable_set_final_state (animatable,
Packit 31ecd5
                                                      priv->property_name,
Packit 31ecd5
                                                      &transform);
Packit 31ecd5
                }
Packit 31ecd5
              else
Packit 31ecd5
                g_warning ("%s: Unable to convert a value of type '%s' from "
Packit 31ecd5
                           "the value type '%s' of the interval.",
Packit 31ecd5
                           G_STRLOC,
Packit 31ecd5
                           g_type_name (p_type),
Packit 31ecd5
                           g_type_name (i_type));
Packit 31ecd5
Packit 31ecd5
              g_value_unset (&transform);
Packit 31ecd5
            }
Packit 31ecd5
        }
Packit 31ecd5
      else
Packit 31ecd5
        clutter_animatable_set_final_state (animatable,
Packit 31ecd5
                                            priv->property_name,
Packit 31ecd5
                                            &value);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  g_value_unset (&value);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_property_transition_set_property (GObject      *gobject,
Packit 31ecd5
                                          guint         prop_id,
Packit 31ecd5
                                          const GValue *value,
Packit 31ecd5
                                          GParamSpec   *pspec)
Packit 31ecd5
{
Packit 31ecd5
  ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (gobject);
Packit 31ecd5
Packit 31ecd5
  switch (prop_id)
Packit 31ecd5
    {
Packit 31ecd5
    case PROP_PROPERTY_NAME:
Packit 31ecd5
      clutter_property_transition_set_property_name (self,
Packit 31ecd5
                                                     g_value_get_string (value));
Packit 31ecd5
      break;
Packit 31ecd5
Packit 31ecd5
    default:
Packit 31ecd5
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
Packit 31ecd5
    }
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_property_transition_get_property (GObject    *gobject,
Packit 31ecd5
                                          guint       prop_id,
Packit 31ecd5
                                          GValue     *value,
Packit 31ecd5
                                          GParamSpec *pspec)
Packit 31ecd5
{
Packit 31ecd5
  ClutterPropertyTransitionPrivate *priv = CLUTTER_PROPERTY_TRANSITION (gobject)->priv;
Packit 31ecd5
Packit 31ecd5
  switch (prop_id)
Packit 31ecd5
    {
Packit 31ecd5
    case PROP_PROPERTY_NAME:
Packit 31ecd5
      g_value_set_string (value, priv->property_name);
Packit 31ecd5
      break;
Packit 31ecd5
Packit 31ecd5
    default:
Packit 31ecd5
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
Packit 31ecd5
    }
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_property_transition_finalize (GObject *gobject)
Packit 31ecd5
{
Packit 31ecd5
  ClutterPropertyTransitionPrivate *priv;
Packit 31ecd5
Packit 31ecd5
  priv = CLUTTER_PROPERTY_TRANSITION (gobject)->priv;
Packit 31ecd5
Packit 31ecd5
  g_free (priv->property_name);
Packit 31ecd5
Packit 31ecd5
  G_OBJECT_CLASS (clutter_property_transition_parent_class)->finalize (gobject);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_property_transition_class_init (ClutterPropertyTransitionClass *klass)
Packit 31ecd5
{
Packit 31ecd5
  ClutterTransitionClass *transition_class = CLUTTER_TRANSITION_CLASS (klass);
Packit 31ecd5
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit 31ecd5
Packit 31ecd5
  transition_class->attached = clutter_property_transition_attached;
Packit 31ecd5
  transition_class->detached = clutter_property_transition_detached;
Packit 31ecd5
  transition_class->compute_value = clutter_property_transition_compute_value;
Packit 31ecd5
Packit 31ecd5
  gobject_class->set_property = clutter_property_transition_set_property;
Packit 31ecd5
  gobject_class->get_property = clutter_property_transition_get_property;
Packit 31ecd5
  gobject_class->finalize = clutter_property_transition_finalize;
Packit 31ecd5
Packit 31ecd5
  /**
Packit 31ecd5
   * ClutterPropertyTransition:property-name:
Packit 31ecd5
   *
Packit 31ecd5
   * The name of the property of a #ClutterAnimatable to animate.
Packit 31ecd5
   *
Packit 31ecd5
   * Since: 1.10
Packit 31ecd5
   */
Packit 31ecd5
  obj_props[PROP_PROPERTY_NAME] =
Packit 31ecd5
    g_param_spec_string ("property-name",
Packit 31ecd5
                         P_("Property Name"),
Packit 31ecd5
                         P_("The name of the property to animate"),
Packit 31ecd5
                         NULL,
Packit 31ecd5
                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
Packit 31ecd5
Packit 31ecd5
  g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_property_transition_init (ClutterPropertyTransition *self)
Packit 31ecd5
{
Packit 31ecd5
  self->priv = clutter_property_transition_get_instance_private (self);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
/**
Packit 31ecd5
 * clutter_property_transition_new:
Packit 31ecd5
 * @property_name: (allow-none): a property of @animatable, or %NULL
Packit 31ecd5
 *
Packit 31ecd5
 * Creates a new #ClutterPropertyTransition.
Packit 31ecd5
 *
Packit 31ecd5
 * Return value: (transfer full): the newly created #ClutterPropertyTransition.
Packit 31ecd5
 *   Use g_object_unref() when done
Packit 31ecd5
 *
Packit 31ecd5
 * Since: 1.10
Packit 31ecd5
 */
Packit 31ecd5
ClutterTransition *
Packit 31ecd5
clutter_property_transition_new (const char *property_name)
Packit 31ecd5
{
Packit 31ecd5
  return g_object_new (CLUTTER_TYPE_PROPERTY_TRANSITION,
Packit 31ecd5
                       "property-name", property_name,
Packit 31ecd5
                       NULL);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
/**
Packit 31ecd5
 * clutter_property_transition_set_property_name:
Packit 31ecd5
 * @transition: a #ClutterPropertyTransition
Packit 31ecd5
 * @property_name: (allow-none): a property name
Packit 31ecd5
 *
Packit 31ecd5
 * Sets the #ClutterPropertyTransition:property-name property of @transition.
Packit 31ecd5
 *
Packit 31ecd5
 * Since: 1.10
Packit 31ecd5
 */
Packit 31ecd5
void
Packit 31ecd5
clutter_property_transition_set_property_name (ClutterPropertyTransition *transition,
Packit 31ecd5
                                               const char                *property_name)
Packit 31ecd5
{
Packit 31ecd5
  ClutterPropertyTransitionPrivate *priv;
Packit 31ecd5
  ClutterAnimatable *animatable;
Packit 31ecd5
Packit 31ecd5
  g_return_if_fail (CLUTTER_IS_PROPERTY_TRANSITION (transition));
Packit 31ecd5
Packit 31ecd5
  priv = transition->priv;
Packit 31ecd5
Packit 31ecd5
  if (g_strcmp0 (priv->property_name, property_name) == 0)
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  g_free (priv->property_name);
Packit 31ecd5
  priv->property_name = g_strdup (property_name);
Packit 31ecd5
  priv->pspec = NULL;
Packit 31ecd5
Packit 31ecd5
  animatable =
Packit 31ecd5
    clutter_transition_get_animatable (CLUTTER_TRANSITION (transition));
Packit 31ecd5
  if (animatable != NULL)
Packit 31ecd5
    {
Packit 31ecd5
      priv->pspec = clutter_animatable_find_property (animatable,
Packit 31ecd5
                                                      priv->property_name);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  g_object_notify_by_pspec (G_OBJECT (transition),
Packit 31ecd5
                            obj_props[PROP_PROPERTY_NAME]);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
/**
Packit 31ecd5
 * clutter_property_transition_get_property_name:
Packit 31ecd5
 * @transition: a #ClutterPropertyTransition
Packit 31ecd5
 *
Packit 31ecd5
 * Retrieves the value of the #ClutterPropertyTransition:property-name
Packit 31ecd5
 * property.
Packit 31ecd5
 *
Packit 31ecd5
 * Return value: the name of the property being animated, or %NULL if
Packit 31ecd5
 *   none is set. The returned string is owned by the @transition and
Packit 31ecd5
 *   it should not be freed.
Packit 31ecd5
 *
Packit 31ecd5
 * Since: 1.10
Packit 31ecd5
 */
Packit 31ecd5
const char *
Packit 31ecd5
clutter_property_transition_get_property_name (ClutterPropertyTransition *transition)
Packit 31ecd5
{
Packit 31ecd5
  g_return_val_if_fail (CLUTTER_IS_PROPERTY_TRANSITION (transition), NULL);
Packit 31ecd5
Packit 31ecd5
  return transition->priv->property_name;
Packit 31ecd5
}