diff --git a/.gitignore b/.gitignore index 65a694870..9381cacfe 100644 --- a/.gitignore +++ b/.gitignore @@ -149,6 +149,8 @@ TAGS /tests/interactive/stamp-test-interactive /tests/interactive/test-animator /tests/interactive/test-stage-sizing +/tests/interactive/test-drag +/tests/interactive/test-constraints /tests/conform/stamp-test-conformance /tests/conform/test-anchors /tests/conform/test-cogl-backface-culling diff --git a/clutter/Makefile.am b/clutter/Makefile.am index 71ab39271..6b112e4d0 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -65,7 +65,10 @@ AM_CFLAGS = $(CLUTTER_CFLAGS) $(MAINTAINER_CFLAGS) $(GCOV_CFLAGS) # please, keep this sorted alphabetically source_h = \ + $(srcdir)/clutter-action.h \ + $(srcdir)/clutter-actor-meta.h \ $(srcdir)/clutter-actor.h \ + $(srcdir)/clutter-align-constraint.h \ $(srcdir)/clutter-alpha.h \ $(srcdir)/clutter-animatable.h \ $(srcdir)/clutter-animation.h \ @@ -78,6 +81,7 @@ source_h = \ $(srcdir)/clutter-behaviour-path.h \ $(srcdir)/clutter-behaviour-rotate.h \ $(srcdir)/clutter-behaviour-scale.h \ + $(srcdir)/clutter-bind-constraint.h \ $(srcdir)/clutter-binding-pool.h \ $(srcdir)/clutter-bin-layout.h \ $(srcdir)/clutter-box.h \ @@ -86,9 +90,11 @@ source_h = \ $(srcdir)/clutter-child-meta.h \ $(srcdir)/clutter-clone.h \ $(srcdir)/clutter-color.h \ + $(srcdir)/clutter-constraint.h \ $(srcdir)/clutter-container.h \ $(srcdir)/clutter-deprecated.h \ $(srcdir)/clutter-device-manager.h \ + $(srcdir)/clutter-drag-action.h \ $(srcdir)/clutter-event.h \ $(srcdir)/clutter-feature.h \ $(srcdir)/clutter-fixed.h \ @@ -138,7 +144,10 @@ include $(top_srcdir)/build/autotools/Makefile.am.enums # please, keep this sorted alphabetically source_c = \ + $(srcdir)/clutter-action.c \ + $(srcdir)/clutter-actor-meta.c \ $(srcdir)/clutter-actor.c \ + $(srcdir)/clutter-align-constraint.c \ $(srcdir)/clutter-alpha.c \ $(srcdir)/clutter-animatable.c \ $(srcdir)/clutter-animation.c \ @@ -152,6 +161,7 @@ source_c = \ $(srcdir)/clutter-behaviour-rotate.c \ $(srcdir)/clutter-behaviour-scale.c \ $(srcdir)/clutter-bezier.c \ + $(srcdir)/clutter-bind-constraint.c \ $(srcdir)/clutter-binding-pool.c \ $(srcdir)/clutter-bin-layout.c \ $(srcdir)/clutter-box.c \ @@ -160,8 +170,10 @@ source_c = \ $(srcdir)/clutter-child-meta.c \ $(srcdir)/clutter-clone.c \ $(srcdir)/clutter-color.c \ + $(srcdir)/clutter-constraint.c \ $(srcdir)/clutter-container.c \ $(srcdir)/clutter-device-manager.c \ + $(srcdir)/clutter-drag-action.c \ clutter-enum-types.c \ $(srcdir)/clutter-event.c \ $(srcdir)/clutter-feature.c \ @@ -206,6 +218,7 @@ source_c_priv = \ $(NULL) source_h_priv = \ + $(srcdir)/clutter-actor-meta-private.h \ $(srcdir)/clutter-bezier.h \ $(srcdir)/clutter-debug.h \ $(srcdir)/clutter-keysyms-table.h \ diff --git a/clutter/clutter-action.c b/clutter/clutter-action.c new file mode 100644 index 000000000..636ab67ed --- /dev/null +++ b/clutter/clutter-action.c @@ -0,0 +1,61 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +/** + * SECTION:clutter-action + * @Title: ClutterAction + * @Short_Description: Abstract class for actor actions + * @See_Also: #ClutterEffect + * + * #ClutterAction is an abstract base class for action that modify the + * user interaction of a #ClutterActor, just like #ClutterEffect is an + * abstract class for modifiers of the appearance of a #ClutterActor. + * + * Implementations of #ClutterAction are associated to an actor and can + * provide behavioral changes when dealing with user input - for instance + * drag and drop capabilities, or scrolling, or panning. + * + * #ClutterAction is available since Clutter 1.4 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-action.h" + +#include "clutter-debug.h" +#include "clutter-private.h" + +G_DEFINE_ABSTRACT_TYPE (ClutterAction, clutter_action, CLUTTER_TYPE_ACTOR_META); + +static void +clutter_action_class_init (ClutterActionClass *klass) +{ +} + +static void +clutter_action_init (ClutterAction *self) +{ +} diff --git a/clutter/clutter-action.h b/clutter/clutter-action.h new file mode 100644 index 000000000..afeafd91c --- /dev/null +++ b/clutter/clutter-action.h @@ -0,0 +1,101 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_ACTION_H__ +#define __CLUTTER_ACTION_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_ACTION (clutter_action_get_type ()) +#define CLUTTER_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ACTION, ClutterAction)) +#define CLUTTER_IS_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ACTION)) +#define CLUTTER_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ACTION, ClutterActionClass)) +#define CLUTTER_IS_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ACTION)) +#define CLUTTER_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ACTION, ClutterActionClass)) + +typedef struct _ClutterActionClass ClutterActionClass; + +/** + * ClutterAction: + * + * The ClutterAction structure contains only + * private data and should be accessed using the provided API + * + * Since: 1.4 + */ +struct _ClutterAction +{ + /*< private >*/ + ClutterActorMeta parent_instance; +}; + +/** + * ClutterActionClass: + * + * The ClutterActionClass structure contains + * only private data + * + * Since: 1.4 + */ +struct _ClutterActionClass +{ + /*< private >*/ + ClutterActorMetaClass parent_class; + + void (* _clutter_action1) (void); + void (* _clutter_action2) (void); + void (* _clutter_action3) (void); + void (* _clutter_action4) (void); + void (* _clutter_action5) (void); + void (* _clutter_action6) (void); + void (* _clutter_action7) (void); + void (* _clutter_action8) (void); +}; + +GType clutter_action_get_type (void) G_GNUC_CONST; + +/* ClutterActor API */ +void clutter_actor_add_action (ClutterActor *self, + ClutterAction *action); +void clutter_actor_add_action_with_name (ClutterActor *self, + const gchar *name, + ClutterAction *action); +void clutter_actor_remove_action (ClutterActor *self, + ClutterAction *action); +void clutter_actor_remove_action_by_name (ClutterActor *self, + const gchar *name); +ClutterAction *clutter_actor_get_action (ClutterActor *self, + const gchar *name); +GList * clutter_actor_get_actions (ClutterActor *self); +void clutter_actor_clear_actions (ClutterActor *self); + +G_END_DECLS + +#endif /* __CLUTTER_ACTION_H__ */ diff --git a/clutter/clutter-actor-meta-private.h b/clutter/clutter-actor-meta-private.h new file mode 100644 index 000000000..e880d025f --- /dev/null +++ b/clutter/clutter-actor-meta-private.h @@ -0,0 +1,42 @@ +#ifndef __CLUTTER_ACTOR_META_PRIVATE_H__ +#define __CLUTTER_ACTOR_META_PRIVATE_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_META_GROUP (_clutter_meta_group_get_type ()) +#define CLUTTER_META_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_META_GROUP, ClutterMetaGroup)) +#define CLUTTER_IS_META_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_META_GROUP)) + +typedef struct _ClutterMetaGroup ClutterMetaGroup; +typedef struct _ClutterMetaGroupClass ClutterMetaGroupClass; + +struct _ClutterMetaGroup +{ + GObject parent_instance; + + ClutterActor *actor; + + GList *meta; +}; + +struct _ClutterMetaGroupClass +{ + GObjectClass parent_class; +}; + +GType _clutter_meta_group_get_type (void) G_GNUC_CONST; + +void _clutter_meta_group_add_meta (ClutterMetaGroup *group, + ClutterActorMeta *meta); +void _clutter_meta_group_remove_meta (ClutterMetaGroup *group, + ClutterActorMeta *meta); +G_CONST_RETURN GList *_clutter_meta_group_peek_metas (ClutterMetaGroup *group); +void _clutter_meta_group_clear_metas (ClutterMetaGroup *group); +ClutterActorMeta * _clutter_meta_group_get_meta (ClutterMetaGroup *group, + const gchar *name); + +G_END_DECLS + +#endif /* __CLUTTER_ACTOR_META_PRIVATE_H__ */ diff --git a/clutter/clutter-actor-meta.c b/clutter/clutter-actor-meta.c new file mode 100644 index 000000000..e318b8f86 --- /dev/null +++ b/clutter/clutter-actor-meta.c @@ -0,0 +1,457 @@ +/** + * SECTION:clutter-actor-meta + * @Title: ClutterActorMeta + * @Short_Description: Base class of actor modifiers + * + * #ClutterActorMeta is an abstract class providing a common API for + * modifiers of #ClutterActor + * + * A #ClutterActorMeta can only be owned by a single #ClutterActor at + * any time + * + * #ClutterActorMeta is available since Clutter 1.4 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-actor-meta-private.h" + +#include "clutter-debug.h" +#include "clutter-private.h" + +struct _ClutterActorMetaPrivate +{ + ClutterActor *actor; + + gchar *name; + + guint is_enabled : 1; +}; + +enum +{ + PROP_0, + + PROP_ACTOR, + PROP_NAME, + PROP_ENABLED +}; + +G_DEFINE_ABSTRACT_TYPE (ClutterActorMeta, + clutter_actor_meta, + G_TYPE_INITIALLY_UNOWNED); + +static void +clutter_actor_meta_real_set_actor (ClutterActorMeta *meta, + ClutterActor *actor) +{ + meta->priv->actor = actor; +} + +static void +clutter_actor_meta_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject); + + switch (prop_id) + { + case PROP_NAME: + clutter_actor_meta_set_name (meta, g_value_get_string (value)); + break; + + case PROP_ENABLED: + clutter_actor_meta_set_enabled (meta, g_value_get_boolean (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +clutter_actor_meta_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject); + + switch (prop_id) + { + case PROP_ACTOR: + g_value_set_object (value, meta->priv->actor); + break; + + case PROP_NAME: + g_value_set_string (value, meta->priv->name); + break; + + case PROP_ENABLED: + g_value_set_boolean (value, meta->priv->is_enabled); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +clutter_actor_meta_finalize (GObject *gobject) +{ + ClutterActorMetaPrivate *priv = CLUTTER_ACTOR_META (gobject)->priv; + + g_free (priv->name); + + G_OBJECT_CLASS (clutter_actor_meta_parent_class)->finalize (gobject); +} + +void +clutter_actor_meta_class_init (ClutterActorMetaClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + g_type_class_add_private (klass, sizeof (ClutterActorMetaPrivate)); + + klass->set_actor = clutter_actor_meta_real_set_actor; + + gobject_class->set_property = clutter_actor_meta_set_property; + gobject_class->get_property = clutter_actor_meta_get_property; + gobject_class->finalize = clutter_actor_meta_finalize; + + /** + * ClutterActorMeta:actor: + * + * The #ClutterActor attached to the #ClutterActorMeta instance + * + * Since: 1.4 + */ + pspec = g_param_spec_object ("actor", + "Actor", + "The actor attached to the meta", + CLUTTER_TYPE_ACTOR, + CLUTTER_PARAM_READABLE); + g_object_class_install_property (gobject_class, PROP_ACTOR, pspec); + + /** + * ClutterActorMeta:name: + * + * The unique name to access the #ClutterActorMeta + * + * Since: 1.4 + */ + pspec = g_param_spec_string ("name", + "Name", + "The name of the meta", + NULL, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_NAME, pspec); + + /** + * ClutterActorMeta:enabled: + * + * Whether or not the #ClutterActorMeta is enabled + * + * Since: 1.4 + */ + pspec = g_param_spec_boolean ("enabled", + "Enabled", + "Whether the meta is enabled", + TRUE, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_ENABLED, pspec); +} + +void +clutter_actor_meta_init (ClutterActorMeta *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + CLUTTER_TYPE_ACTOR_META, + ClutterActorMetaPrivate); + + self->priv->is_enabled = TRUE; +} + +/** + * clutter_actor_meta_set_name: + * @meta: a #ClutterActorMeta + * @name: the name of @meta + * + * Sets the name of @meta + * + * The name can be used to identify the #ClutterActorMeta instance + * + * Since: 1.4 + */ +void +clutter_actor_meta_set_name (ClutterActorMeta *meta, + const gchar *name) +{ + g_return_if_fail (CLUTTER_IS_ACTOR_META (meta)); + + if (g_strcmp0 (meta->priv->name, name) == 0) + return; + + g_free (meta->priv->name); + meta->priv->name = g_strdup (name); + + g_object_notify (G_OBJECT (meta), "name"); +} + +/** + * clutter_actor_meta_get_name: + * @meta: a #ClutterActorMeta + * + * Retrieves the name set using clutter_actor_meta_set_name() + * + * Return value: (transfer none): the name of the #ClutterActorMeta + * instance, or %NULL if none was set. The returned string is owned + * by the #ClutterActorMeta instance and it should not be modified + * or freed + * + * Since: 1.4 + */ +G_CONST_RETURN gchar * +clutter_actor_meta_get_name (ClutterActorMeta *meta) +{ + g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), NULL); + + return meta->priv->name; +} + +/** + * clutter_actor_meta_set_enabled: + * @meta: a #ClutterActorMeta + * @is_enabled: whether @meta is enabled + * + * Sets whether @meta should be enabled or not + * + * Since: 1.4 + */ +void +clutter_actor_meta_set_enabled (ClutterActorMeta *meta, + gboolean is_enabled) +{ + g_return_if_fail (CLUTTER_IS_ACTOR_META (meta)); + + is_enabled = !!is_enabled; + + if (meta->priv->is_enabled == is_enabled) + return; + + meta->priv->is_enabled = is_enabled; + + g_object_notify (G_OBJECT (meta), "enabled"); +} + +/** + * clutter_actor_meta_get_enabled: + * @meta: a #ClutterActorMeta + * + * Retrieves whether @meta is enabled + * + * Return value: %TRUE if the #ClutterActorMeta instance is enabled + * + * Since: 1.4 + */ +gboolean +clutter_actor_meta_get_enabled (ClutterActorMeta *meta) +{ + g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), FALSE); + + return meta->priv->is_enabled; +} + +/* + * _clutter_actor_meta_set_actor + * @meta: a #ClutterActorMeta + * @actor: a #ClutterActor or %NULL + * + * Sets or unsets a back pointer to the #ClutterActor that owns + * the @meta + * + * Since: 1.4 + */ +void +_clutter_actor_meta_set_actor (ClutterActorMeta *meta, + ClutterActor *actor) +{ + g_return_if_fail (CLUTTER_IS_ACTOR_META (meta)); + g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor)); + + CLUTTER_ACTOR_META_GET_CLASS (meta)->set_actor (meta, actor); +} + +/** + * clutter_actor_meta_get_actor: + * @meta: a #ClutterActorMeta + * + * Retrieves a pointer to the #ClutterActor that owns @meta + * + * Return value: (transfer none): a pointer to a #ClutterActor or %NULL + * + * Since: 1.4 + */ +ClutterActor * +clutter_actor_meta_get_actor (ClutterActorMeta *meta) +{ + g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), NULL); + + return meta->priv->actor; +} + +/* + * ClutterMetaGroup: a collection of ClutterActorMeta instances + */ + +G_DEFINE_TYPE (ClutterMetaGroup, _clutter_meta_group, G_TYPE_OBJECT); + +static void +_clutter_meta_group_dispose (GObject *gobject) +{ + _clutter_meta_group_clear_metas (CLUTTER_META_GROUP (gobject)); + + G_OBJECT_CLASS (_clutter_meta_group_parent_class)->dispose (gobject); +} + +static void +_clutter_meta_group_class_init (ClutterMetaGroupClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = _clutter_meta_group_dispose; +} + +static void +_clutter_meta_group_init (ClutterMetaGroup *self) +{ +} + +/* + * _clutter_meta_group_add_meta: + * @group: a #ClutterMetaGroup + * @meta: a #ClutterActorMeta to add + * + * Adds @meta to @group + * + * This function will remove the floating reference of @meta or, if the + * floating reference has already been sunk, add a reference to it + */ +void +_clutter_meta_group_add_meta (ClutterMetaGroup *group, + ClutterActorMeta *meta) +{ + if (meta->priv->actor != NULL) + { + g_warning ("The meta of type '%s' with name '%s' is " + "already attached to actor '%s'", + G_OBJECT_TYPE_NAME (meta), + meta->priv->name != NULL + ? meta->priv->name + : "", + clutter_actor_get_name (meta->priv->actor) != NULL + ? clutter_actor_get_name (meta->priv->actor) + : G_OBJECT_TYPE_NAME (meta->priv->actor)); + return; + } + + group->meta = g_list_append (group->meta, meta); + g_object_ref_sink (meta); + + _clutter_actor_meta_set_actor (meta, group->actor); +} + +/* + * _clutter_meta_group_remove_meta: + * @group: a #ClutterMetaGroup + * @meta: a #ClutterActorMeta to remove + * + * Removes @meta from @group and releases the reference being held on it + */ +void +_clutter_meta_group_remove_meta (ClutterMetaGroup *group, + ClutterActorMeta *meta) +{ + if (meta->priv->actor != group->actor) + { + g_warning ("The meta of type '%s' with name '%s' is not " + "attached to the actor '%s'", + G_OBJECT_TYPE_NAME (meta), + meta->priv->name != NULL + ? meta->priv->name + : "", + clutter_actor_get_name (group->actor) != NULL + ? clutter_actor_get_name (group->actor) + : G_OBJECT_TYPE_NAME (group->actor)); + return; + } + + _clutter_actor_meta_set_actor (meta, NULL); + + group->meta = g_list_remove (group->meta, meta); + g_object_unref (meta); +} + +/* + * _clutter_meta_group_peek_metas: + * @group: a #ClutterMetaGroup + * + * Returns a pointer to the #ClutterActorMeta list + * + * Return value: a const pointer to the #GList of #ClutterActorMeta + */ +G_CONST_RETURN GList * +_clutter_meta_group_peek_metas (ClutterMetaGroup *group) +{ + return group->meta; +} + +/* + * _clutter_meta_group_clear_metas: + * @group: a #ClutterMetaGroup + * + * Clears @group of all #ClutterActorMeta instances and releases + * the reference on them + */ +void +_clutter_meta_group_clear_metas (ClutterMetaGroup *group) +{ + g_list_foreach (group->meta, (GFunc) _clutter_actor_meta_set_actor, NULL); + + g_list_foreach (group->meta, (GFunc) g_object_unref, NULL); + g_list_free (group->meta); + group->meta = NULL; +} + +/* + * _clutter_meta_group_get_meta: + * @group: a #ClutterMetaGroup + * @name: the name of the #ClutterActorMeta to retrieve + * + * Retrieves a named #ClutterActorMeta from @group + * + * Return value: a #ClutterActorMeta for the given name, or %NULL + */ +ClutterActorMeta * +_clutter_meta_group_get_meta (ClutterMetaGroup *group, + const gchar *name) +{ + GList *l; + + for (l = group->meta; l != NULL; l = l->next) + { + ClutterActorMeta *meta = l->data; + + if (g_strcmp0 (meta->priv->name, name) == 0) + return meta; + } + + return NULL; +} diff --git a/clutter/clutter-actor-meta.h b/clutter/clutter-actor-meta.h new file mode 100644 index 000000000..4c8ed5e01 --- /dev/null +++ b/clutter/clutter-actor-meta.h @@ -0,0 +1,84 @@ +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_ACTOR_META_H__ +#define __CLUTTER_ACTOR_META_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_ACTOR_META (clutter_actor_meta_get_type ()) +#define CLUTTER_ACTOR_META(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ACTOR_META, ClutterActorMeta)) +#define CLUTTER_IS_ACTOR_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ACTOR_META)) +#define CLUTTER_ACTOR_META_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ACTOR_META, ClutterActorMetaClass)) +#define CLUTTER_IS_ACTOR_META_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ACTOR_META)) +#define CLUTTER_ACTOR_META_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ACTOR_META, ClutterActorMetaClass)) + +typedef struct _ClutterActorMetaPrivate ClutterActorMetaPrivate; +typedef struct _ClutterActorMetaClass ClutterActorMetaClass; + +/** + * ClutterActorMeta: + * + * The ClutterActorMeta structure contains only + * private data and should be accessed using the provided API + * + * Since: 1.4 + */ +struct _ClutterActorMeta +{ + /*< private >*/ + GInitiallyUnowned parent_instance; + + ClutterActorMetaPrivate *priv; +}; + +/** + * ClutterActorMetaClass: + * @set_actor: virtual function, invoked when attaching and detaching + * a #ClutterActorMeta instance to a #ClutterActor + * + * The ClutterActorMetaClass structure contains + * only private data + * + * Since: 1.4 + */ +struct _ClutterActorMetaClass +{ + /*< private >*/ + GInitiallyUnownedClass parent_class; + + /*< public >*/ + void (* set_actor) (ClutterActorMeta *meta, + ClutterActor *actor); + + /*< private >*/ + void (* _clutter_meta1) (void); + void (* _clutter_meta2) (void); + void (* _clutter_meta3) (void); + void (* _clutter_meta4) (void); + void (* _clutter_meta5) (void); + void (* _clutter_meta6) (void); + void (* _clutter_meta7) (void); +}; + +GType clutter_actor_meta_get_type (void) G_GNUC_CONST; + +void clutter_actor_meta_set_name (ClutterActorMeta *meta, + const gchar *name); +G_CONST_RETURN gchar *clutter_actor_meta_get_name (ClutterActorMeta *meta); +void clutter_actor_meta_set_enabled (ClutterActorMeta *meta, + gboolean is_enabled); +gboolean clutter_actor_meta_get_enabled (ClutterActorMeta *meta); + +ClutterActor * clutter_actor_meta_get_actor (ClutterActorMeta *meta); + +/* private */ +void _clutter_actor_meta_set_actor (ClutterActorMeta *meta, + ClutterActor *actor); + +G_END_DECLS + +#endif /* __CLUTTER_ACTOR_META_H__ */ diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 4e2f46b76..93ad88f00 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -155,6 +155,65 @@ * should read the documentation for the #ClutterUnits parser format for * the valid units and syntax. * + * + * + * Custom animatable properties + * #ClutterActor allows accessing properties of #ClutterAction + * and #ClutterConstraint instances associated to an actor instance + * for animation purposes. + * In order to access a specific #ClutterAction or a #ClutterConstraint + * property it is necessary to set the #ClutterActorMeta:name property on the + * given action or constraint. + * The property can be accessed using the the following syntax: + * + * + * @<section>.<meta-name>.<property-name> + * + * + * The initial @ is mandatory. + * The section fragment can be one between + * "actions" or "constraints". + * The meta-name fragment is the name of the + * action or constraint, as specified by the #ClutterActorMeta:name + * property. + * The property-name fragment is the name of the + * action or constraint property to be animated. + * + * Animating a constraint property + * The example below animates a #ClutterBindConstraint applied to an + * actor using clutter_actor_animate(). The rect has + * a binding constraint for the origin actor, and in + * its initial state is fully transparent and overlapping the actor to + * which is bound to. + * + * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0); + * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x"); + * clutter_actor_add_constraint (rect, constraint); + * + * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0); + * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y"); + * clutter_actor_add_constraint (rect, constraint); + * + * clutter_actor_set_reactive (rect, TRUE); + * clutter_actor_set_opacity (rect, 0); + * + * g_signal_connect (rect, "button-press-event", + * G_CALLBACK (on_button_press), + * NULL); + * + * On button press, the rectangle "slides" from behind the actor to + * which is bound to, using the #ClutterBindConstraint:offset property and + * the #ClutterActor:opacity property. + * + * float new_offset = clutter_actor_get_width (origin) + h_padding; + * + * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500, + * "opacity", 255, + * "@constraints.bind-x.offset", new_offset, + * NULL); + * + * + * */ /** @@ -226,17 +285,23 @@ #endif #include "clutter-actor.h" + +#include "clutter-action.h" +#include "clutter-actor-meta-private.h" +#include "clutter-animatable.h" +#include "clutter-constraint.h" #include "clutter-container.h" -#include "clutter-main.h" +#include "clutter-debug.h" #include "clutter-enum-types.h" -#include "clutter-scriptable.h" -#include "clutter-script.h" +#include "clutter-main.h" #include "clutter-marshal.h" #include "clutter-private.h" -#include "clutter-debug.h" -#include "clutter-units.h" #include "clutter-profile.h" +#include "clutter-scriptable.h" +#include "clutter-script.h" #include "clutter-stage.h" +#include "clutter-units.h" + #include "cogl/cogl.h" typedef struct _ShaderData ShaderData; @@ -391,6 +456,9 @@ struct _ClutterActorPrivate * See clutter_actor_queue_clipped_redraw() for details. */ const ClutterActorBox *oob_queue_redraw_clip; + + ClutterMetaGroup *actions; + ClutterMetaGroup *constraints; }; enum @@ -471,7 +539,10 @@ enum PROP_SHOW_ON_SET_PARENT, PROP_TEXT_DIRECTION, - PROP_HAS_POINTER + PROP_HAS_POINTER, + + PROP_ACTIONS, + PROP_CONSTRAINTS }; enum @@ -506,6 +577,7 @@ enum static guint actor_signals[LAST_SIGNAL] = { 0, }; static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); +static void clutter_animatable_iface_init (ClutterAnimatableIface *iface); static void _clutter_actor_apply_modelview_transform (ClutterActor *self); @@ -571,7 +643,9 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterActor, clutter_actor, G_TYPE_INITIALLY_UNOWNED, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, - clutter_scriptable_iface_init)); + clutter_scriptable_iface_init) + G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE, + clutter_animatable_iface_init)); static const gchar * get_actor_debug_name (ClutterActor *actor) @@ -2892,6 +2966,14 @@ clutter_actor_set_property (GObject *object, clutter_actor_set_text_direction (actor, g_value_get_enum (value)); break; + case PROP_ACTIONS: + clutter_actor_add_action (actor, g_value_get_object (value)); + break; + + case PROP_CONSTRAINTS: + clutter_actor_add_constraint (actor, g_value_get_object (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3199,12 +3281,18 @@ clutter_actor_dispose (GObject *object) destroy_shader_data (self); - if (priv->pango_context) + if (priv->pango_context != NULL) { g_object_unref (priv->pango_context); priv->pango_context = NULL; } + if (priv->actions != NULL) + { + g_object_unref (priv->actions); + priv->actions = NULL; + } + g_signal_emit (self, actor_signals[DESTROY], 0); G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object); @@ -3999,6 +4087,34 @@ clutter_actor_class_init (ClutterActorClass *klass) PROP_HAS_POINTER, pspec); + /** + * ClutterActor:actions: + * + * Adds a #ClutterAction to the actor + * + * Since: 1.4 + */ + pspec = g_param_spec_object ("actions", + "Actions", + "Adds an action to the actor", + CLUTTER_TYPE_ACTION, + CLUTTER_PARAM_WRITABLE); + g_object_class_install_property (object_class, PROP_ACTIONS, pspec); + + /** + * ClutterActor:constraints: + * + * Adds a #ClutterConstaint to the actor + * + * Since: 1.4 + */ + pspec = g_param_spec_object ("constraints", + "Constraints", + "Adds a constraint to the actor", + CLUTTER_TYPE_CONSTRAINT, + CLUTTER_PARAM_WRITABLE); + g_object_class_install_property (object_class, PROP_CONSTRAINTS, pspec); + /** * ClutterActor::destroy: * @actor: the object which received the signal @@ -8104,6 +8220,158 @@ clutter_scriptable_iface_init (ClutterScriptableIface *iface) iface->set_custom_property = clutter_actor_set_custom_property; } +static ClutterActorMeta * +get_meta_from_animation_property (ClutterActor *actor, + const gchar *name, + gchar **name_p) +{ + ClutterActorPrivate *priv = actor->priv; + ClutterActorMeta *meta = NULL; + gchar **tokens; + + /* if this is not a special property, fall through */ + if (name[0] != '@') + return NULL; + + /* detect the properties named using the following spec: + * + * @
.. + * + * where
can be one of the following: + * + * - actions + * - constraints + * + * and is the name set on a specific ActorMeta + */ + + tokens = g_strsplit (name + 1, ".", -1); + if (tokens == NULL || g_strv_length (tokens) != 3) + { + CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'", + name + 1); + g_strfreev (tokens); + return NULL; + } + + if (strcmp (tokens[0], "actions") == 0) + meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]); + + if (strcmp (tokens[0], "constraints") == 0) + meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]); + + if (name_p != NULL) + *name_p = g_strdup (tokens[2]); + + CLUTTER_NOTE (ANIMATION, + "Looking for property '%s' of object '%s' in section '%s'", + tokens[2], + tokens[1], + tokens[0]); + + g_strfreev (tokens); + + return meta; +} + +static GParamSpec * +clutter_actor_find_property (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name) +{ + ClutterActorMeta *meta = NULL; + GObjectClass *klass = NULL; + GParamSpec *pspec = NULL; + gchar *p_name = NULL; + + meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable), + property_name, + &p_name); + + if (meta != NULL) + { + klass = G_OBJECT_GET_CLASS (meta); + + pspec = g_object_class_find_property (klass, p_name); + + g_free (p_name); + } + else + { + klass = G_OBJECT_GET_CLASS (animatable); + + pspec = g_object_class_find_property (klass, property_name); + } + + return pspec; +} + +static void +clutter_actor_get_initial_state (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name, + GValue *initial) +{ + ClutterActorMeta *meta = NULL; + gchar *p_name = NULL; + + meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable), + property_name, + &p_name); + + if (meta != NULL) + g_object_get_property (G_OBJECT (meta), p_name, initial); + else + g_object_get_property (G_OBJECT (animatable), property_name, initial); + + g_free (p_name); +} + +static void +clutter_actor_set_final_state (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name, + const GValue *final) +{ + ClutterActorMeta *meta = NULL; + gchar *p_name = NULL; + + meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable), + property_name, + &p_name); + if (meta != NULL) + g_object_set_property (G_OBJECT (meta), p_name, final); + else + g_object_set_property (G_OBJECT (animatable), property_name, final); + + g_free (p_name); +} + +static gboolean +clutter_actor_animate_property (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name, + const GValue *initial, + const GValue *final, + gdouble progress, + GValue *new_value) +{ + ClutterInterval *interval; + + interval = clutter_animation_get_interval (animation, property_name); + + return clutter_interval_compute_value (interval, progress, new_value); +} + +static void +clutter_animatable_iface_init (ClutterAnimatableIface *iface) +{ + iface->animate_property = clutter_actor_animate_property; + iface->find_property = clutter_actor_find_property; + iface->get_initial_state = clutter_actor_get_initial_state; + iface->set_final_state = clutter_actor_set_final_state; +} + /** * clutter_actor_transform_stage_point * @self: A #ClutterActor @@ -10172,3 +10440,414 @@ clutter_actor_has_allocation (ClutterActor *self) CLUTTER_ACTOR_IS_VISIBLE (self) && !priv->needs_allocation; } + +/** + * clutter_actor_add_action: + * @self: a #ClutterActor + * @action: a #ClutterAction + * + * Adds @action to the list of actions applied to @self + * + * A #ClutterAction can only belong to one actor at a time + * + * The #ClutterActor will hold a reference on @action until either + * clutter_actor_remove_action() or clutter_actor_clear_actions() + * is called + * + * Since: 1.4 + */ +void +clutter_actor_add_action (ClutterActor *self, + ClutterAction *action) +{ + ClutterActorPrivate *priv; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + g_return_if_fail (CLUTTER_IS_ACTION (action)); + + priv = self->priv; + + if (priv->actions == NULL) + { + priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL); + priv->actions->actor = self; + } + + _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action)); + + g_object_notify (G_OBJECT (self), "actions"); +} + +/** + * clutter_actor_add_action_with_name: + * @self: a #ClutterActor + * @name: the name to set on the action + * @action: a #ClutterAction + * + * A convenience function for setting the name of a #ClutterAction + * while adding it to the list of actions applied to @self + * + * This function is the logical equivalent of: + * + * |[ + * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name); + * clutter_actor_add_action (self, action); + * ]| + * + * Since: 1.4 + */ +void +clutter_actor_add_action_with_name (ClutterActor *self, + const gchar *name, + ClutterAction *action) +{ + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + g_return_if_fail (name != NULL); + g_return_if_fail (CLUTTER_IS_ACTION (self)); + + clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name); + clutter_actor_add_action (self, action); +} + +/** + * clutter_actor_remove_action: + * @self: a #ClutterActor + * @action: a #ClutterAction + * + * Removes @action from the list of actions applied to @self + * + * The reference held by @self on the #ClutterAction will be released + * + * Since: 1.4 + */ +void +clutter_actor_remove_action (ClutterActor *self, + ClutterAction *action) +{ + ClutterActorPrivate *priv; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + g_return_if_fail (CLUTTER_IS_ACTION (action)); + + priv = self->priv; + + if (priv->actions == NULL) + return; + + _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action)); + + g_object_notify (G_OBJECT (self), "actions"); +} + +/** + * clutter_actor_remove_action_by_name: + * @self: a #ClutterActor + * @name: the name of the action to remove + * + * Removes the #ClutterAction with the given name from the list + * of actions applied to @self + * + * Since: 1.4 + */ +void +clutter_actor_remove_action_by_name (ClutterActor *self, + const gchar *name) +{ + ClutterActorPrivate *priv; + ClutterActorMeta *meta; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + g_return_if_fail (name != NULL); + + priv = self->priv; + + if (priv->actions == NULL) + return; + + meta = _clutter_meta_group_get_meta (priv->actions, name); + if (meta == NULL) + return; + + _clutter_meta_group_remove_meta (priv->actions, meta); + + g_object_notify (G_OBJECT (self), "actions"); +} + +/** + * clutter_actor_get_actions: + * @self: a #ClutterActor + * + * Retrieves the list of actions applied to @self + * + * Return value: (transfer container) (element-type ClutterAction): a copy + * of the list of #ClutterActions. The contents of the list are + * owned by the #ClutterActor. Use g_list_free() to free the resources + * allocated by the returned #GList + * + * Since: 1.4 + */ +GList * +clutter_actor_get_actions (ClutterActor *self) +{ + const GList *actions; + + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); + + if (self->priv->actions == NULL) + return NULL; + + actions = _clutter_meta_group_peek_metas (self->priv->actions); + + return g_list_copy ((GList *) actions); +} + +/** + * clutter_actor_get_action: + * @self: a #ClutterActor + * @name: the name of the action to retrieve + * + * Retrieves the #ClutterAction with the given name in the list + * of actions applied to @self + * + * Return value: (transfer none): a #ClutterAction for the given + * name, or %NULL. The returned #ClutterAction is owned by the + * actor and it should not be unreferenced directly + * + * Since: 1.4 + */ +ClutterAction * +clutter_actor_get_action (ClutterActor *self, + const gchar *name) +{ + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); + g_return_val_if_fail (name != NULL, NULL); + + if (self->priv->actions == NULL) + return NULL; + + return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name)); +} + +/** + * clutter_actor_clear_actions: + * @self: a #ClutterActor + * + * Clears the list of actions applied to @self + * + * Since: 1.4 + */ +void +clutter_actor_clear_actions (ClutterActor *self) +{ + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + if (self->priv->actions == NULL) + return; + + _clutter_meta_group_clear_metas (self->priv->actions); +} + +/** + * clutter_actor_add_constraint: + * @self: a #ClutterActor + * @constraint: a #ClutterConstraint + * + * Adds @constraint to the list of #ClutterConstraints applied + * to @self + * + * The #ClutterActor will hold a reference on the @constraint until + * either clutter_actor_remove_constraint() or + * clutter_actor_clear_constraints() is called. + * + * Since: 1.4 + */ +void +clutter_actor_add_constraint (ClutterActor *self, + ClutterConstraint *constraint) +{ + ClutterActorPrivate *priv; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint)); + + priv = self->priv; + + if (priv->constraints == NULL) + { + priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL); + priv->constraints->actor = self; + } + + _clutter_meta_group_add_meta (priv->constraints, + CLUTTER_ACTOR_META (constraint)); + + g_object_notify (G_OBJECT (self), "constraints"); +} + +/** + * clutter_actor_add_constraint_with_name: + * @self: a #ClutterActor + * @name: the name to set on the constraint + * @constraint: a #ClutterConstraint + * + * A convenience function for setting the name of a #ClutterConstraint + * while adding it to the list of constraints applied to @self + * + * This function is the logical equivalent of: + * + * |[ + * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name); + * clutter_actor_add_constraint (self, constraint); + * ]| + * + * Since: 1.4 + */ +void +clutter_actor_add_constraint_with_name (ClutterActor *self, + const gchar *name, + ClutterConstraint *constraint) +{ + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + g_return_if_fail (name != NULL); + g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint)); + + clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name); + clutter_actor_add_constraint (self, constraint); +} + +/** + * clutter_actor_remove_constraint: + * @self: a #ClutterActor + * @constraint: a #ClutterConstraint + * + * Removes @constraint from the list of constraints applied to @self + * + * The reference held by @self on the #ClutterConstraint will be released + * + * Since: 1.4 + */ +void +clutter_actor_remove_constraint (ClutterActor *self, + ClutterConstraint *constraint) +{ + ClutterActorPrivate *priv; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint)); + + priv = self->priv; + + if (priv->constraints == NULL) + return; + + _clutter_meta_group_remove_meta (priv->constraints, + CLUTTER_ACTOR_META (constraint)); + + g_object_notify (G_OBJECT (self), "constraints"); +} + +/** + * clutter_actor_remove_constraint_by_name: + * @self: a #ClutterActor + * @name: the name of the constraint to remove + * + * Removes the #ClutterConstraint with the given name from the list + * of constraints applied to @self + * + * Since: 1.4 + */ +void +clutter_actor_remove_constraint_by_name (ClutterActor *self, + const gchar *name) +{ + ClutterActorPrivate *priv; + ClutterActorMeta *meta; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + g_return_if_fail (name != NULL); + + priv = self->priv; + + if (priv->constraints == NULL) + return; + + meta = _clutter_meta_group_get_meta (priv->constraints, name); + if (meta == NULL) + return; + + _clutter_meta_group_remove_meta (priv->constraints, meta); +} + +/** + * clutter_actor_get_constraints: + * @self: a #ClutterActor + * + * Retrieves the list of constraints applied to @self + * + * Return value: (transfer container) (element-type ClutterConstraint): a copy + * of the list of #ClutterConstraints. The contents of the list are + * owned by the #ClutterActor. Use g_list_free() to free the resources + * allocated by the returned #GList + * + * Since: 1.4 + */ +GList * +clutter_actor_get_constraints (ClutterActor *self) +{ + const GList *constraints; + + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); + + if (self->priv->constraints == NULL) + return NULL; + + constraints = _clutter_meta_group_peek_metas (self->priv->constraints); + + return g_list_copy ((GList *) constraints); +} + +/** + * clutter_actor_get_constraint: + * @self: a #ClutterActor + * @name: the name of the constraint to retrieve + * + * Retrieves the #ClutterConstraint with the given name in the list + * of constraints applied to @self + * + * Return value: (transfer none): a #ClutterConstraint for the given + * name, or %NULL. The returned #ClutterConstraint is owned by the + * actor and it should not be unreferenced directly + * + * Since: 1.4 + */ +ClutterConstraint * +clutter_actor_get_constraint (ClutterActor *self, + const gchar *name) +{ + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); + g_return_val_if_fail (name != NULL, NULL); + + if (self->priv->constraints == NULL) + return NULL; + + return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name)); +} + +/** + * clutter_actor_clear_constraints: + * @self: a #ClutterActor + * + * Clears the list of constraints applied to @self + * + * Since: 1.4 + */ +void +clutter_actor_clear_constraints (ClutterActor *self) +{ + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + if (self->priv->constraints == NULL) + return; + + _clutter_meta_group_clear_metas (self->priv->constraints); +} diff --git a/clutter/clutter-align-constraint.c b/clutter/clutter-align-constraint.c new file mode 100644 index 000000000..0ed459c8e --- /dev/null +++ b/clutter/clutter-align-constraint.c @@ -0,0 +1,335 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +/** + * SECTION:clutter-align-constraint + * @Title: ClutterAlignConstraint + * @Short_Description: A constraint aligning the position of an actor + * + * #ClutterAlignConstraint is a #ClutterConstraint that aligns the position + * of the #ClutterActor to which it is applied to the size of another + * #ClutterActor using an alignment factor + * + * #ClutterAlignConstraint is available since Clutter 1.4 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-align-constraint.h" + +#include "clutter-constraint.h" +#include "clutter-debug.h" +#include "clutter-enum-types.h" +#include "clutter-private.h" + +#define CLUTTER_ALIGN_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ALIGN_CONSTRAINT, ClutterAlignConstraintClass)) +#define CLUTTER_IS_ALIGN_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ALIGN_CONSTRAINT)) +#define CLUTTER_ALIGN_CONSTRAINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ALIGN_CONSTRAINT, ClutterAlignConstraintClass)) + +typedef struct _ClutterAlignConstraintClass ClutterAlignConstraintClass; + +struct _ClutterAlignConstraint +{ + ClutterConstraint parent_instance; + + ClutterActor *source; + ClutterAlignAxis align_axis; + gfloat factor; +}; + +struct _ClutterAlignConstraintClass +{ + ClutterConstraintClass parent_class; +}; + +enum +{ + PROP_0, + + PROP_SOURCE, + PROP_ALIGN_AXIS, + PROP_FACTOR +}; + +G_DEFINE_TYPE (ClutterAlignConstraint, + clutter_align_constraint, + CLUTTER_TYPE_CONSTRAINT); + +static void +update_actor_position (ClutterAlignConstraint *align) +{ + gfloat source_width, source_height; + gfloat actor_width, actor_height; + ClutterActor *actor; + + if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (align))) + return; + + actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (align)); + if (actor == NULL) + return; + + clutter_actor_get_size (align->source, &source_width, &source_height); + clutter_actor_get_size (actor, &actor_width, &actor_height); + + switch (align->align_axis) + { + case CLUTTER_ALIGN_X_AXIS: + clutter_actor_set_x (actor, (source_width - actor_width) * align->factor); + break; + + case CLUTTER_ALIGN_Y_AXIS: + clutter_actor_set_y (actor, (source_height - actor_height) * align->factor); + break; + } +} + +static void +source_position_changed (GObject *gobject, + GParamSpec *pspec, + ClutterAlignConstraint *align) +{ + if (strcmp (pspec->name, "width") == 0 || + strcmp (pspec->name, "height") == 0) + { + update_actor_position (align); + } +} + +static void +source_destroyed (ClutterActor *actor, + ClutterAlignConstraint *align) +{ + align->source = NULL; +} + +static void +_clutter_align_constraint_set_source (ClutterAlignConstraint *align, + ClutterActor *source) +{ + ClutterActor *old_source = align->source; + + if (old_source != NULL) + { + g_signal_handlers_disconnect_by_func (old_source, + G_CALLBACK (source_destroyed), + align); + g_signal_handlers_disconnect_by_func (old_source, + G_CALLBACK (source_position_changed), + align); + } + + align->source = source; + g_signal_connect (align->source, "notify", + G_CALLBACK (source_position_changed), + align); + g_signal_connect (align->source, "destroy", + G_CALLBACK (source_destroyed), + align); + + update_actor_position (align); + + g_object_notify (G_OBJECT (align), "source"); +} + +static void +_clutter_align_constraint_set_align_axis (ClutterAlignConstraint *align, + ClutterAlignAxis axis) +{ + if (align->align_axis == axis) + return; + + align->align_axis = axis; + + update_actor_position (align); + + g_object_notify (G_OBJECT (align), "align-axis"); +} + +static void +_clutter_align_constraint_set_factor (ClutterAlignConstraint *align, + gfloat factor) +{ + align->factor = CLAMP (factor, 0.0, 1.0); + + update_actor_position (align); + + g_object_notify (G_OBJECT (align), "factor"); +} + +static void +clutter_align_constraint_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (gobject); + + switch (prop_id) + { + case PROP_SOURCE: + _clutter_align_constraint_set_source (align, g_value_get_object (value)); + break; + + case PROP_ALIGN_AXIS: + _clutter_align_constraint_set_align_axis (align, g_value_get_enum (value)); + break; + + case PROP_FACTOR: + _clutter_align_constraint_set_factor (align, g_value_get_float (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +clutter_align_constraint_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (gobject); + + switch (prop_id) + { + case PROP_SOURCE: + g_value_set_object (value, align->source); + break; + + case PROP_ALIGN_AXIS: + g_value_set_enum (value, align->align_axis); + break; + + case PROP_FACTOR: + g_value_set_float (value, align->factor); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +clutter_align_constraint_class_init (ClutterAlignConstraintClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + gobject_class->set_property = clutter_align_constraint_set_property; + gobject_class->get_property = clutter_align_constraint_get_property; + + /** + * ClutterAlignConstraint:source: + * + * The #ClutterActor used as the source for the alignment + * + * Since: 1.4 + */ + pspec = g_param_spec_object ("source", + "Source", + "The source of the alignment", + CLUTTER_TYPE_ACTOR, + CLUTTER_PARAM_READWRITE | + G_PARAM_CONSTRUCT); + g_object_class_install_property (gobject_class, PROP_SOURCE, pspec); + + /** + * ClutterAlignConstraint:align-axis: + * + * The axis to be used to compute the alignment + * + * Since: 1.4 + */ + pspec = g_param_spec_enum ("align-axis", + "Align Axis", + "The axis to align the position to", + CLUTTER_TYPE_ALIGN_AXIS, + CLUTTER_ALIGN_X_AXIS, + CLUTTER_PARAM_READWRITE | + G_PARAM_CONSTRUCT); + g_object_class_install_property (gobject_class, PROP_ALIGN_AXIS, pspec); + + /** + * ClutterAlignConstraint:factor: + * + * The alignment factor, as a normalized value between 0.0 and 1.0 + * + * The #ClutterAlignConstraint:factor depends on the + * #ClutterAlignConstraint:align-axis value: with %CLUTTER_ALIGN_X_AXIS, + * 0.0 means left and 1.0 means right; with %CLUTTER_ALIGN_Y_AXIS, 0.0 + * means top and 1.0 means bottom + * + * Since: 1.4 + */ + pspec = g_param_spec_float ("factor", + "Factor", + "The alignment factor, between 0.0 and 1.0", + 0.0, 1.0, + 0.0, + CLUTTER_PARAM_READWRITE | + G_PARAM_CONSTRUCT); + g_object_class_install_property (gobject_class, PROP_FACTOR, pspec); +} + +static void +clutter_align_constraint_init (ClutterAlignConstraint *self) +{ + self->source = NULL; + self->align_axis = CLUTTER_ALIGN_X_AXIS; + self->factor = 0.0f; +} + +/** + * clutter_align_constraint_new: + * @source: the #ClutterActor to use as the source of the alignment + * @axis: the axis to be used to compute the alignment + * @factor: the alignment factor, between 0.0 and 1.0 + * + * Creates a new constraint, aligning a #ClutterActor's position with + * regards of the size of the actor to @source, with the given alignment + * @factor + * + * Return value: the newly created #ClutterAlignConstraint + * + * Since: 1.4 + */ +ClutterConstraint * +clutter_align_constraint_new (ClutterActor *source, + ClutterAlignAxis axis, + gfloat factor) +{ + g_return_val_if_fail (CLUTTER_IS_ACTOR (source), NULL); + + return g_object_new (CLUTTER_TYPE_ALIGN_CONSTRAINT, + "source", source, + "align-axis", axis, + "factor", factor, + NULL); +} diff --git a/clutter/clutter-align-constraint.h b/clutter/clutter-align-constraint.h new file mode 100644 index 000000000..c2289c9ee --- /dev/null +++ b/clutter/clutter-align-constraint.h @@ -0,0 +1,73 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_ALIGN_CONSTRAINT_H__ +#define __CLUTTER_ALIGN_CONSTRAINT_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_ALIGN_CONSTRAINT (clutter_align_constraint_get_type ()) +#define CLUTTER_ALIGN_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ALIGN_CONSTRAINT, ClutterAlignConstraint)) +#define CLUTTER_IS_ALIGN_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ALIGN_CONSTRAINT)) + +/** + * ClutterAlignConstraint: + * + * ClutterAlignConstraint is an opaque structure + * whose members cannot be directly accesses + * + * Since: 1.4 + */ +typedef struct _ClutterAlignConstraint ClutterAlignConstraint; + +/** + * ClutterAlignAxis: + * @CLUTTER_ALIGN_X_AXIS: Maintain the alignment on the X axis + * @CLUTTER_ALIGN_Y_AXIS: Maintain the alignment on the Y axis + * + * Specifies the axis on which #ClutterAlignConstraint should maintain + * the alignment + * + * Since: 1.4 + */ +typedef enum { /*< prefix=CLUTTER_ALIGN >*/ + CLUTTER_ALIGN_X_AXIS, + CLUTTER_ALIGN_Y_AXIS, +} ClutterAlignAxis; + +GType clutter_align_constraint_get_type (void) G_GNUC_CONST; + +ClutterConstraint *clutter_align_constraint_new (ClutterActor *source, + ClutterAlignAxis axis, + gfloat factor); + +G_END_DECLS + +#endif /* __CLUTTER_ALIGN_CONSTRAINT_H__ */ diff --git a/clutter/clutter-animatable.c b/clutter/clutter-animatable.c index e448a694f..0674abf7c 100644 --- a/clutter/clutter-animatable.c +++ b/clutter/clutter-animatable.c @@ -124,3 +124,101 @@ clutter_animatable_animate_property (ClutterAnimatable *animatable, return res; } + +/** + * clutter_animatable_find_property: + * @animatable: a #ClutterAnimatable + * @animation: a #ClutterAnimation + * @property_name: the name of the animatable property to find + * + * Finds the #GParamSpec for @property_name + * + * Return value: (transfer none): The #GParamSpec for the given property + * or %NULL + * + * Since: 1.4 + */ +GParamSpec * +clutter_animatable_find_property (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name) +{ + ClutterAnimatableIface *iface; + + g_return_val_if_fail (CLUTTER_IS_ANIMATABLE (animatable), NULL); + g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL); + g_return_val_if_fail (property_name != NULL, NULL); + + CLUTTER_NOTE (ANIMATION, "Looking for property '%s'", property_name); + + iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable); + if (iface->find_property != NULL) + return iface->find_property (animatable, animation, property_name); + + return g_object_class_find_property (G_OBJECT_GET_CLASS (animatable), + property_name); +} + +/** + * clutter_animatable_get_initial_state: + * @animatable: a #ClutterAnimatable + * @animation: a #ClutterAnimation + * @property_name: the name of the animatable property to retrieve + * @value: a #GValue initialized to the type of the property to retrieve + * + * Retrieves the current state of @property_name and sets @value with it + * + * Since: 1.4 + */ +void +clutter_animatable_get_initial_state (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name, + GValue *value) +{ + ClutterAnimatableIface *iface; + + g_return_if_fail (CLUTTER_IS_ANIMATABLE (animatable)); + g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); + g_return_if_fail (property_name != NULL); + + CLUTTER_NOTE (ANIMATION, "Getting initial state of '%s'", property_name); + + iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable); + if (iface->get_initial_state != NULL) + iface->get_initial_state (animatable, animation, property_name, value); + else + g_object_get_property (G_OBJECT (animatable), property_name, value); +} + +/** + * clutter_animatable_set_final_state: + * @animatable: a #ClutterAnimatable + * @animation: a #ClutterAnimation + * @property_name: the name of the animatable property to set + * @value: the value of the animatable property to set + * + * Sets the current state of @property_name to @value + * + * Since: 1.4 + */ +void +clutter_animatable_set_final_state (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name, + const GValue *value) +{ + ClutterAnimatableIface *iface; + + g_return_if_fail (CLUTTER_IS_ANIMATABLE (animatable)); + g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); + g_return_if_fail (property_name != NULL); + + CLUTTER_NOTE (ANIMATION, "Setting state of property '%s'", property_name); + + iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable); + if (iface->set_final_state != NULL) + iface->set_final_state (animatable, animation, property_name, value); + else + g_object_set_property (G_OBJECT (animatable), property_name, value); +} diff --git a/clutter/clutter-animatable.h b/clutter/clutter-animatable.h index a82d13a4b..bddcc5ed0 100644 --- a/clutter/clutter-animatable.h +++ b/clutter/clutter-animatable.h @@ -52,7 +52,14 @@ typedef struct _ClutterAnimatableIface ClutterAnimatableIface; /** * ClutterAnimatableIface: - * @animate_property: virtual function for animating a property + * @animate_property: virtual function for custom interpolation of a + * property + * @find_property: virtual function for retrieving the #GParamSpec of + * an animatable property + * @get_initial_state: virtual function for retrieving the initial + * state of an animatable property + * @set_final_state: virtual function for setting the state of an + * animatable property * * Base interface for #GObjects that can be animated by a * a #ClutterAnimation. @@ -65,24 +72,47 @@ struct _ClutterAnimatableIface GTypeInterface parent_iface; /*< public >*/ - gboolean (* animate_property) (ClutterAnimatable *animatable, - ClutterAnimation *animation, - const gchar *property_name, - const GValue *initial_value, - const GValue *final_value, - gdouble progress, - GValue *value); + gboolean (* animate_property) (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name, + const GValue *initial_value, + const GValue *final_value, + gdouble progress, + GValue *value); + GParamSpec *(* find_property) (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name); + void (* get_initial_state) (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name, + GValue *value); + void (* set_final_state) (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name, + const GValue *value); }; GType clutter_animatable_get_type (void) G_GNUC_CONST; -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); +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); + +GParamSpec *clutter_animatable_find_property (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name); +void clutter_animatable_get_initial_state (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name, + GValue *value); +void clutter_animatable_set_final_state (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name, + const GValue *value); G_END_DECLS diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c index f7d8711b3..dd9599af3 100644 --- a/clutter/clutter-animation.c +++ b/clutter/clutter-animation.c @@ -212,6 +212,7 @@ static void clutter_animation_real_completed (ClutterAnimation *self) { ClutterAnimationPrivate *priv = self->priv; + ClutterAnimatable *animatable = NULL; ClutterAnimation *animation; ClutterTimeline *timeline; ClutterTimelineDirection direction; @@ -221,6 +222,9 @@ clutter_animation_real_completed (ClutterAnimation *self) timeline = clutter_animation_get_timeline (self); direction = clutter_timeline_get_direction (timeline); + if (CLUTTER_IS_ANIMATABLE (priv->object)) + animatable = CLUTTER_ANIMATABLE (priv->object); + /* explicitly set the final state of the animation */ CLUTTER_NOTE (ANIMATION, "Set final state on object [%p]", priv->object); g_hash_table_iter_init (&iter, priv->properties); @@ -235,7 +239,12 @@ clutter_animation_real_completed (ClutterAnimation *self) else p_value = clutter_interval_peek_initial_value (interval); - g_object_set_property (priv->object, p_name, p_value); + if (animatable != NULL) + clutter_animatable_set_final_state (animatable, self, + p_name, + p_value); + else + g_object_set_property (priv->object, p_name, p_value); } /* at this point, if this animation was created by clutter_actor_animate() @@ -580,6 +589,7 @@ clutter_animation_init (ClutterAnimation *self) static inline void clutter_animation_bind_property_internal (ClutterAnimation *animation, + const gchar *property_name, GParamSpec *pspec, ClutterInterval *interval) { @@ -589,17 +599,18 @@ clutter_animation_bind_property_internal (ClutterAnimation *animation, { g_warning ("Cannot bind property '%s': the interval is out " "of bounds", - pspec->name); + property_name); return; } g_hash_table_insert (priv->properties, - g_strdup (pspec->name), + g_strdup (property_name), g_object_ref_sink (interval)); } static inline void clutter_animation_update_property_internal (ClutterAnimation *animation, + const gchar *property_name, GParamSpec *pspec, ClutterInterval *interval) { @@ -609,12 +620,12 @@ clutter_animation_update_property_internal (ClutterAnimation *animation, { g_warning ("Cannot bind property '%s': the interval is out " "of bounds", - pspec->name); + property_name); return; } g_hash_table_replace (priv->properties, - g_strdup (pspec->name), + g_strdup (property_name), g_object_ref_sink (interval)); } @@ -624,7 +635,6 @@ clutter_animation_validate_bind (ClutterAnimation *animation, GType argtype) { ClutterAnimationPrivate *priv; - GObjectClass *klass; GParamSpec *pspec; GType pspec_type; @@ -647,9 +657,22 @@ clutter_animation_validate_bind (ClutterAnimation *animation, return NULL; } - klass = G_OBJECT_GET_CLASS (priv->object); - pspec = g_object_class_find_property (klass, property_name); - if (!pspec) + if (CLUTTER_IS_ANIMATABLE (priv->object)) + { + ClutterAnimatable *animatable = CLUTTER_ANIMATABLE (priv->object); + + pspec = clutter_animatable_find_property (animatable, + animation, + property_name); + } + else + { + GObjectClass *klass = G_OBJECT_GET_CLASS (priv->object); + + pspec = g_object_class_find_property (klass, property_name); + } + + if (pspec == NULL) { g_warning ("Cannot bind property '%s': objects of type '%s' have " "no such property", @@ -715,7 +738,9 @@ clutter_animation_bind_interval (ClutterAnimation *animation, if (pspec == NULL) return NULL; - clutter_animation_bind_property_internal (animation, pspec, interval); + clutter_animation_bind_property_internal (animation, property_name, + pspec, + interval); return animation; } @@ -760,12 +785,21 @@ clutter_animation_bind (ClutterAnimation *animation, return NULL; g_value_init (&initial, G_PARAM_SPEC_VALUE_TYPE (pspec)); - g_object_get_property (priv->object, property_name, &initial); + + if (CLUTTER_IS_ANIMATABLE (priv->object)) + clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (priv->object), + animation, + property_name, + &initial); + else + g_object_get_property (priv->object, property_name, &initial); interval = clutter_interval_new_with_values (type, &initial, final); g_value_unset (&initial); - clutter_animation_bind_property_internal (animation, pspec, interval); + clutter_animation_bind_property_internal (animation, property_name, + pspec, + interval); return animation; } @@ -845,7 +879,6 @@ clutter_animation_update_interval (ClutterAnimation *animation, ClutterInterval *interval) { ClutterAnimationPrivate *priv; - GObjectClass *klass; GParamSpec *pspec; GType pspec_type, int_type; @@ -863,9 +896,22 @@ clutter_animation_update_interval (ClutterAnimation *animation, return; } - klass = G_OBJECT_GET_CLASS (priv->object); - pspec = g_object_class_find_property (klass, property_name); - if (!pspec) + if (CLUTTER_IS_ANIMATABLE (priv->object)) + { + ClutterAnimatable *animatable = CLUTTER_ANIMATABLE (priv->object); + + pspec = clutter_animatable_find_property (animatable, + animation, + property_name); + } + else + { + GObjectClass *klass = G_OBJECT_GET_CLASS (priv->object); + + pspec = g_object_class_find_property (klass, property_name); + } + + if (pspec == NULL) { g_warning ("Cannot update property '%s': objects of type '%s' have " "no such property", @@ -889,7 +935,9 @@ clutter_animation_update_interval (ClutterAnimation *animation, return; } - clutter_animation_update_property_internal (animation, pspec, interval); + clutter_animation_update_property_internal (animation, property_name, + pspec, + interval); } /** @@ -1050,7 +1098,14 @@ on_alpha_notify (GObject *gobject, } if (apply) - g_object_set_property (priv->object, p_name, &value); + { + if (is_animatable) + clutter_animatable_set_final_state (animatable, animation, + p_name, + &value); + else + g_object_set_property (priv->object, p_name, &value); + } g_value_unset (&value); } @@ -1688,26 +1743,41 @@ done: GValue cur_value = { 0, }; g_value_init (&cur_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); - g_object_get_property (priv->object, property_name, &cur_value); + + if (CLUTTER_IS_ANIMATABLE (priv->object)) + clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (priv->object), + animation, + property_name, + &cur_value); + else + g_object_get_property (priv->object, property_name, &cur_value); interval = clutter_interval_new_with_values (G_PARAM_SPEC_VALUE_TYPE (pspec), &cur_value, &real_value); - if (!clutter_animation_has_property (animation, pspec->name)) - clutter_animation_bind_property_internal (animation, + if (!clutter_animation_has_property (animation, property_name)) + clutter_animation_bind_property_internal (animation, property_name, pspec, interval); else - clutter_animation_update_property_internal (animation, + clutter_animation_update_property_internal (animation, property_name, pspec, interval); g_value_unset (&cur_value); } else - g_object_set_property (priv->object, property_name, &real_value); + { + if (CLUTTER_IS_ANIMATABLE (priv->object)) + clutter_animatable_set_final_state (CLUTTER_ANIMATABLE (priv->object), + animation, + property_name, + &real_value); + else + g_object_set_property (priv->object, property_name, &real_value); + } g_value_unset (&real_value); } @@ -1719,11 +1789,15 @@ clutter_animation_setupv (ClutterAnimation *animation, const GValue *values) { ClutterAnimationPrivate *priv = animation->priv; - GObjectClass *klass; - gint i; + ClutterAnimatable *animatable = NULL; + GObjectClass *klass = NULL; gboolean is_fixed = FALSE; + gint i; - klass = G_OBJECT_GET_CLASS (priv->object); + if (CLUTTER_IS_ANIMATABLE (priv->object)) + animatable = CLUTTER_ANIMATABLE (priv->object); + else + klass = G_OBJECT_GET_CLASS (priv->object); for (i = 0; i < n_properties; i++) { @@ -1736,8 +1810,14 @@ clutter_animation_setupv (ClutterAnimation *animation, is_fixed = TRUE; } - pspec = g_object_class_find_property (klass, property_name); - if (!pspec) + if (animatable != NULL) + pspec = clutter_animatable_find_property (animatable, + animation, + property_name); + else + pspec = g_object_class_find_property (klass, property_name); + + if (pspec == NULL) { g_warning ("Cannot bind property '%s': objects of type '%s' do " "not have this property", @@ -1792,10 +1872,14 @@ clutter_animation_setup_valist (ClutterAnimation *animation, va_list var_args) { ClutterAnimationPrivate *priv = animation->priv; - GObjectClass *klass; + ClutterAnimatable *animatable = NULL; + GObjectClass *klass = NULL; const gchar *property_name; - klass = G_OBJECT_GET_CLASS (priv->object); + if (CLUTTER_IS_ANIMATABLE (priv->object)) + animatable = CLUTTER_ANIMATABLE (priv->object); + else + klass = G_OBJECT_GET_CLASS (priv->object); property_name = first_property_name; while (property_name != NULL) @@ -1827,8 +1911,14 @@ clutter_animation_setup_valist (ClutterAnimation *animation, is_fixed = TRUE; } - pspec = g_object_class_find_property (klass, property_name); - if (!pspec) + if (animatable != NULL) + pspec = clutter_animatable_find_property (animatable, + animation, + property_name); + else + pspec = g_object_class_find_property (klass, property_name); + + if (pspec == NULL) { g_warning ("Cannot bind property '%s': objects of type '%s' do " "not have this property", @@ -1899,7 +1989,7 @@ animation_create_for_actor (ClutterActor *actor) * @actor: a #ClutterActor * @alpha: a #ClutterAlpha * @first_property_name: the name of a property - * @VarArgs: a %NULL terminated list of property names and + * @Varargs: a %NULL terminated list of property names and * property values * * Animates the given list of properties of @actor between the current @@ -1956,7 +2046,7 @@ clutter_actor_animate_with_alpha (ClutterActor *actor, * @mode: an animation mode logical id * @timeline: a #ClutterTimeline * @first_property_name: the name of a property - * @VarArgs: a %NULL terminated list of property names and + * @Varargs: a %NULL terminated list of property names and * property values * * Animates the given list of properties of @actor between the current @@ -2007,7 +2097,7 @@ clutter_actor_animate_with_timeline (ClutterActor *actor, * @mode: an animation mode logical id * @duration: duration of the animation, in milliseconds * @first_property_name: the name of a property - * @VarArgs: a %NULL terminated list of property names and + * @Varargs: a %NULL terminated list of property names and * property values * * Animates the given list of properties of @actor between the current diff --git a/clutter/clutter-animator.c b/clutter/clutter-animator.c index 324570802..0c3287ac5 100644 --- a/clutter/clutter-animator.c +++ b/clutter/clutter-animator.c @@ -1150,7 +1150,7 @@ clutter_animator_get_duration (ClutterAnimator *animator) * @first_mode: the id of the alpha function to use * @first_progress: at which stage of the animation this value applies; the * range is a normalized floating point value between 0 and 1 - * @VarArgs: the value first_property_name should have for first_object + * @Varargs: the value first_property_name should have for first_object * at first_progress, followed by more (object, property_name, mode, * progress, value) tuples, followed by %NULL * diff --git a/clutter/clutter-bind-constraint.c b/clutter/clutter-bind-constraint.c new file mode 100644 index 000000000..583ffd18b --- /dev/null +++ b/clutter/clutter-bind-constraint.c @@ -0,0 +1,337 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +/** + * SECTION:clutter-bind-constraint + * @Title: ClutterBindConstraint + * @Short_Description: A constraint binding the position of an actor + * + * #ClutterBindConstraint is a #ClutterConstraint that binds the position of + * the #ClutterActor to which it is applied to the the position of another + * #ClutterActor. + * + * #ClutterBindConstraint is available since Clutter 1.4 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-bind-constraint.h" + +#include "clutter-constraint.h" +#include "clutter-debug.h" +#include "clutter-enum-types.h" +#include "clutter-private.h" + +#define CLUTTER_BIND_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BIND_CONSTRAINT, ClutterBindConstraintClass)) +#define CLUTTER_IS_BIND_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BIND_CONSTRAINT)) +#define CLUTTER_BIND_CONSTRAINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BIND_CONSTRAINT, ClutterBindConstraintClass)) + +typedef struct _ClutterBindConstraintClass ClutterBindConstraintClass; + +struct _ClutterBindConstraint +{ + ClutterConstraint parent_instance; + + ClutterActor *source; + ClutterBindCoordinate coordinate; + gfloat offset; +}; + +struct _ClutterBindConstraintClass +{ + ClutterConstraintClass parent_class; +}; + +enum +{ + PROP_0, + + PROP_SOURCE, + PROP_COORDINATE, + PROP_OFFSET +}; + +G_DEFINE_TYPE (ClutterBindConstraint, + clutter_bind_constraint, + CLUTTER_TYPE_CONSTRAINT); + +static void +update_actor_position (ClutterBindConstraint *bind) +{ + ClutterVertex source_position; + ClutterActor *actor; + + if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (bind))) + return; + + actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (bind)); + if (actor == NULL) + return; + + source_position.x = clutter_actor_get_x (bind->source); + source_position.y = clutter_actor_get_y (bind->source); + source_position.z = clutter_actor_get_depth (bind->source); + + switch (bind->coordinate) + { + case CLUTTER_BIND_X: + clutter_actor_set_x (actor, source_position.x + bind->offset); + break; + + case CLUTTER_BIND_Y: + clutter_actor_set_y (actor, source_position.y + bind->offset); + break; + + case CLUTTER_BIND_Z: + clutter_actor_set_depth (actor, source_position.z + bind->offset); + break; + } +} + +static void +source_position_changed (GObject *gobject, + GParamSpec *pspec, + ClutterBindConstraint *bind) +{ + if (strcmp (pspec->name, "x") == 0 || + strcmp (pspec->name, "y") == 0 || + strcmp (pspec->name, "depth") == 0) + { + update_actor_position (bind); + } +} + +static void +source_destroyed (ClutterActor *actor, + ClutterBindConstraint *bind) +{ + bind->source = NULL; +} + +static void +_clutter_bind_constraint_set_source (ClutterBindConstraint *bind, + ClutterActor *source) +{ + ClutterActor *old_source = bind->source; + + if (old_source != NULL) + { + g_signal_handlers_disconnect_by_func (old_source, + G_CALLBACK (source_destroyed), + bind); + g_signal_handlers_disconnect_by_func (old_source, + G_CALLBACK (source_position_changed), + bind); + } + + bind->source = source; + g_signal_connect (bind->source, "notify", + G_CALLBACK (source_position_changed), + bind); + g_signal_connect (bind->source, "destroy", + G_CALLBACK (source_destroyed), + bind); + + update_actor_position (bind); + + g_object_notify (G_OBJECT (bind), "source"); +} + +static void +_clutter_bind_constraint_set_coordinate (ClutterBindConstraint *bind, + ClutterBindCoordinate coord) +{ + if (bind->coordinate == coord) + return; + + bind->coordinate = coord; + + update_actor_position (bind); + + g_object_notify (G_OBJECT (bind), "coordinate"); +} + +static void +_clutter_bind_constraint_set_offset (ClutterBindConstraint *bind, + gfloat offset) +{ + if (fabs (bind->offset - offset) < 0.00001f) + return; + + bind->offset = offset; + + update_actor_position (bind); + + g_object_notify (G_OBJECT (bind), "offset"); +} + +static void +clutter_bind_constraint_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ClutterBindConstraint *bind = CLUTTER_BIND_CONSTRAINT (gobject); + + switch (prop_id) + { + case PROP_SOURCE: + _clutter_bind_constraint_set_source (bind, g_value_get_object (value)); + break; + + case PROP_COORDINATE: + _clutter_bind_constraint_set_coordinate (bind, g_value_get_enum (value)); + break; + + case PROP_OFFSET: + _clutter_bind_constraint_set_offset (bind, g_value_get_float (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +clutter_bind_constraint_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ClutterBindConstraint *bind = CLUTTER_BIND_CONSTRAINT (gobject); + + switch (prop_id) + { + case PROP_SOURCE: + g_value_set_object (value, bind->source); + break; + + case PROP_COORDINATE: + g_value_set_enum (value, bind->coordinate); + break; + + case PROP_OFFSET: + g_value_set_float (value, bind->offset); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +clutter_bind_constraint_class_init (ClutterBindConstraintClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + gobject_class->set_property = clutter_bind_constraint_set_property; + gobject_class->get_property = clutter_bind_constraint_get_property; + + /** + * ClutterBindConstraint:source: + * + * The #ClutterActor used as the source for the binding + * + * Since: 1.4 + */ + pspec = g_param_spec_object ("source", + "Source", + "The source of the binding", + CLUTTER_TYPE_ACTOR, + CLUTTER_PARAM_READWRITE | + G_PARAM_CONSTRUCT); + g_object_class_install_property (gobject_class, PROP_SOURCE, pspec); + + /** + * ClutterBindConstraint:coordinate: + * + * The coordinate to be bound + * + * Since: 1.4 + */ + pspec = g_param_spec_enum ("coordinate", + "Coordinate", + "The coordinate to bind", + CLUTTER_TYPE_BIND_COORDINATE, + CLUTTER_BIND_X, + CLUTTER_PARAM_READWRITE | + G_PARAM_CONSTRUCT); + g_object_class_install_property (gobject_class, PROP_COORDINATE, pspec); + + /** + * ClutterBindConstraint:offset: + * + * The offset, in pixels, to be applied to the binding + * + * Since: 1.4 + */ + pspec = g_param_spec_float ("offset", + "Offset", + "The offset in pixels to apply to the binding", + -G_MAXFLOAT, G_MAXFLOAT, + 0.0f, + CLUTTER_PARAM_READWRITE | + G_PARAM_CONSTRUCT); + g_object_class_install_property (gobject_class, PROP_OFFSET, pspec); +} + +static void +clutter_bind_constraint_init (ClutterBindConstraint *self) +{ + self->source = NULL; + self->coordinate = CLUTTER_BIND_X; + self->offset = 0.0f; +} + +/** + * clutter_bind_constraint_new: + * @source: the #ClutterActor to use as the source of the binding + * @coordinate: the coordinate to bind + * @offset: the offset to apply to the binding, in pixels + * + * Creates a new constraint, binding a #ClutterActor's position to + * the given @coordinate of the position of @source + * + * Return value: the newly created #ClutterBindConstraint + * + * Since: 1.4 + */ +ClutterConstraint * +clutter_bind_constraint_new (ClutterActor *source, + ClutterBindCoordinate coordinate, + gfloat offset) +{ + g_return_val_if_fail (CLUTTER_IS_ACTOR (source), NULL); + + return g_object_new (CLUTTER_TYPE_BIND_CONSTRAINT, + "source", source, + "coordinate", coordinate, + "offset", offset, + NULL); +} diff --git a/clutter/clutter-bind-constraint.h b/clutter/clutter-bind-constraint.h new file mode 100644 index 000000000..8c713604f --- /dev/null +++ b/clutter/clutter-bind-constraint.h @@ -0,0 +1,74 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_BIND_CONSTRAINT_H__ +#define __CLUTTER_BIND_CONSTRAINT_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_BIND_CONSTRAINT (clutter_bind_constraint_get_type ()) +#define CLUTTER_BIND_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BIND_CONSTRAINT, ClutterBindConstraint)) +#define CLUTTER_IS_BIND_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BIND_CONSTRAINT)) + +/** + * ClutterBindConstraint: + * + * ClutterBindConstraint is an opaque structure + * whose members cannot be directly accessed + * + * Since: 1.4 + */ +typedef struct _ClutterBindConstraint ClutterBindConstraint; + +/** + * ClutterBindCoordinate: + * @CLUTTER_BIND_X: Bind the X coordinate + * @CLUTTER_BIND_Y: Bind the Y coordinate + * @CLUTTER_BIND_Z: Bind the Z coordinate + * + * Specifies which coordinate should be used in a binding + * + * Since: 1.4 + */ +typedef enum { /*< prefix=CLUTTER_BIND >*/ + CLUTTER_BIND_X, + CLUTTER_BIND_Y, + CLUTTER_BIND_Z +} ClutterBindCoordinate; + +GType clutter_bind_constraint_get_type (void) G_GNUC_CONST; + +ClutterConstraint *clutter_bind_constraint_new (ClutterActor *source, + ClutterBindCoordinate coordinate, + gfloat offset); + +G_END_DECLS + +#endif /* __CLUTTER_BIND_CONSTRAINT_H__ */ diff --git a/clutter/clutter-box-layout.c b/clutter/clutter-box-layout.c index b4902317b..28730bb5b 100644 --- a/clutter/clutter-box-layout.c +++ b/clutter/clutter-box-layout.c @@ -1419,7 +1419,7 @@ clutter_box_layout_get_vertical (ClutterBoxLayout *layout) /** * clutter_box_layout_set_homogeneous: * @layout: a #ClutterBoxLayout - * @vertical: %TRUE if the layout should be homogeneous + * @homogeneous: %TRUE if the layout should be homogeneous * * Sets whether the size of @layout children should be * homogeneous diff --git a/clutter/clutter-constraint.c b/clutter/clutter-constraint.c new file mode 100644 index 000000000..49d30c968 --- /dev/null +++ b/clutter/clutter-constraint.c @@ -0,0 +1,33 @@ +/** + * SECTION:clutter-constraint + * @Title: ClutterConstraint + * @Short_Description: A constraint on an actor's position or size + * @See_Also: #ClutterAction + * + * #ClutterConstraint is a base abstract class for modifiers of a #ClutterActor + * position or size. + * + * #ClutterConstraint is available since Clutter 1.4 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-constraint.h" + +#include "clutter-actor-meta-private.h" + +G_DEFINE_ABSTRACT_TYPE (ClutterConstraint, + clutter_constraint, + CLUTTER_TYPE_ACTOR_META); + +static void +clutter_constraint_class_init (ClutterConstraintClass *klass) +{ +} + +static void +clutter_constraint_init (ClutterConstraint *self) +{ +} diff --git a/clutter/clutter-constraint.h b/clutter/clutter-constraint.h new file mode 100644 index 000000000..948670585 --- /dev/null +++ b/clutter/clutter-constraint.h @@ -0,0 +1,102 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_CONSTRAINT_H__ +#define __CLUTTER_CONSTRAINT_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_CONSTRAINT (clutter_constraint_get_type ()) +#define CLUTTER_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CONSTRAINT, ClutterConstraint)) +#define CLUTTER_IS_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CONSTRAINT)) +#define CLUTTER_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_CONSTRAINT, ClutterConstraintClass)) +#define CLUTTER_IS_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_CONSTRAINT)) +#define CLUTTER_CONSTRAINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_CONSTRAINT, ClutterConstraintClass)) + +typedef struct _ClutterConstraintClass ClutterConstraintClass; + +/** + * ClutterConstraint: + * + * The ClutterConstraint structure contains only + * private data and should be accessed using the provided API + * + * Since: 1.4 + */ +struct _ClutterConstraint +{ + /*< private >*/ + ClutterActorMeta parent_instance; +}; + +/** + * ClutterConstraintClass: + * + * The ClutterConstraintClass structure contains + * only private data + * + * Since: 1.4 + */ +struct _ClutterConstraintClass +{ + /*< private >*/ + ClutterActorMetaClass parent_class; + + /*< private >*/ + void (* _clutter_constraint1) (void); + void (* _clutter_constraint2) (void); + void (* _clutter_constraint3) (void); + void (* _clutter_constraint4) (void); + void (* _clutter_constraint5) (void); + void (* _clutter_constraint6) (void); + void (* _clutter_constraint7) (void); + void (* _clutter_constraint8) (void); +}; + +GType clutter_constraint_get_type (void) G_GNUC_CONST; + +/* ClutterActor API */ +void clutter_actor_add_constraint (ClutterActor *self, + ClutterConstraint *constraint); +void clutter_actor_add_constraint_with_name (ClutterActor *self, + const gchar *name, + ClutterConstraint *constraint); +void clutter_actor_remove_constraint (ClutterActor *self, + ClutterConstraint *constraint); +void clutter_actor_remove_constraint_by_name (ClutterActor *self, + const gchar *name); +GList * clutter_actor_get_constraints (ClutterActor *self); +ClutterConstraint *clutter_actor_get_constraint (ClutterActor *self, + const gchar *name); +void clutter_actor_clear_constraints (ClutterActor *self); + +G_END_DECLS + +#endif /* __CLUTTER_CONSTRAINT_H__ */ diff --git a/clutter/clutter-drag-action.c b/clutter/clutter-drag-action.c new file mode 100644 index 000000000..ae51e8104 --- /dev/null +++ b/clutter/clutter-drag-action.c @@ -0,0 +1,813 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +/** + * SECTION:clutter-drag-action + * @Title: ClutterDragAction + * @Short_Description: Action enabling dragging on actors + * + * #ClutterDragAction is a sub-class of #ClutterAction that implements + * all the necessary logic for dragging actors. + * + * The simplest usage of #ClutterDragAction consists in adding it to + * a #ClutterActor and connecting to the #ClutterDragAction::drag-motion + * signal handler to move the actor; for instance: + * + * |[ + * ClutterAction *action = clutter_drag_action_new (); + * + * g_signal_connect (action, "drag-motion", + * G_CALLBACK (on_drag_motion), + * NULL); + * + * clutter_actor_add_action (actor, action); + * ]| + * + * Where the on_drag_motion() signal handler calls clutter_actor_move_by() + * using the delta between motion events passed to the handler: + * + * |[ + * static void + * on_drag_motion (ClutterDragAction *action, + * ClutterActor *actor, + * gfloat delta_x, + * gfloat delta_y, + * ClutterModifierType modifiers) + * { + * clutter_actor_move_by (actor, delta_x, delta_y); + * } + * ]| + * + * It is also possible to set another #ClutterActor as the dragged actor + * by calling clutter_drag_action_set_drag_handle() from within a handle + * of the #ClutterDragAction::drag-begin signal. The drag handle must be + * parented and exist between the emission of #ClutterDragAction::drag-begin + * and #ClutterDragAction::drag-end. + * + * #ClutterDragAction is available since Clutter 1.4 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-drag-action.h" + +#include "clutter-debug.h" +#include "clutter-enum-types.h" +#include "clutter-marshal.h" +#include "clutter-private.h" + +struct _ClutterDragActionPrivate +{ + ClutterActor *stage; + + gfloat drag_threshold; + ClutterActor *drag_handle; + ClutterDragAxis drag_axis; + + gulong button_press_id; + gulong capture_id; + + gfloat press_x; + gfloat press_y; + ClutterModifierType press_state; + gint press_button; + + gfloat last_motion_x; + gfloat last_motion_y; + + gfloat transformed_press_x; + gfloat transformed_press_y; + + guint emit_delayed_press : 1; + guint in_drag : 1; +}; + +enum +{ + PROP_0, + + PROP_DRAG_THRESHOLD, + PROP_DRAG_HANDLE, + PROP_DRAG_AXIS +}; + +enum +{ + DRAG_BEGIN, + DRAG_MOTION, + DRAG_END, + + LAST_SIGNAL +}; + +static guint drag_signals[LAST_SIGNAL] = { 0, }; + +/* forward declaration */ +static gboolean on_captured_event (ClutterActor *stage, + ClutterEvent *event, + ClutterDragAction *action); + +G_DEFINE_TYPE (ClutterDragAction, clutter_drag_action, CLUTTER_TYPE_ACTION); + +static void +emit_drag_begin (ClutterDragAction *action, + ClutterActor *actor, + ClutterEvent *event) +{ + ClutterDragActionPrivate *priv = action->priv; + + g_signal_emit (action, drag_signals[DRAG_BEGIN], 0, + actor, + priv->press_x, priv->press_y, + priv->press_button, + priv->press_state); +} + +static void +emit_drag_motion (ClutterDragAction *action, + ClutterActor *actor, + ClutterEvent *event) +{ + ClutterDragActionPrivate *priv = action->priv; + ClutterActor *drag_handle = NULL; + gfloat delta_x, delta_y; + gfloat motion_x, motion_y; + + clutter_event_get_coords (event, &priv->last_motion_x, &priv->last_motion_y); + + if (priv->drag_handle != NULL && !priv->emit_delayed_press) + drag_handle = priv->drag_handle; + else + drag_handle = actor; + + motion_x = motion_y = 0.0f; + clutter_actor_transform_stage_point (drag_handle, + priv->last_motion_x, + priv->last_motion_y, + &motion_x, &motion_y); + + delta_x = delta_y = 0.0f; + + switch (priv->drag_axis) + { + case CLUTTER_DRAG_AXIS_NONE: + delta_x = motion_x - priv->transformed_press_x; + delta_y = motion_y - priv->transformed_press_y; + break; + + case CLUTTER_DRAG_X_AXIS: + delta_x = motion_x - priv->transformed_press_x; + break; + + case CLUTTER_DRAG_Y_AXIS: + delta_y = motion_y - priv->transformed_press_y; + break; + + default: + g_assert_not_reached (); + return; + } + + if (priv->emit_delayed_press) + { + if (ABS (delta_x) >= priv->drag_threshold || + ABS (delta_y) >= priv->drag_threshold) + { + priv->emit_delayed_press = FALSE; + + emit_drag_begin (action, actor, NULL); + } + else + return; + } + + g_signal_emit (action, drag_signals[DRAG_MOTION], 0, + actor, + delta_x, delta_y); +} + +static void +emit_drag_end (ClutterDragAction *action, + ClutterActor *actor, + ClutterEvent *event) +{ + ClutterDragActionPrivate *priv = action->priv; + + clutter_event_get_coords (event, &priv->last_motion_x, &priv->last_motion_y); + + /* we might not have emitted ::drag-begin yet */ + if (!priv->emit_delayed_press) + g_signal_emit (action, drag_signals[DRAG_END], 0, + actor, + priv->last_motion_x, priv->last_motion_y, + clutter_event_get_button (event), + clutter_event_get_state (event)); + + /* disconnect the capture */ + if (priv->capture_id != 0) + { + g_signal_handler_disconnect (priv->stage, priv->capture_id); + priv->capture_id = 0; + } + + priv->in_drag = FALSE; +} + +static gboolean +on_captured_event (ClutterActor *stage, + ClutterEvent *event, + ClutterDragAction *action) +{ + ClutterDragActionPrivate *priv = action->priv; + ClutterActor *actor; + + actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); + + if (!priv->in_drag) + return FALSE; + + switch (clutter_event_type (event)) + { + case CLUTTER_MOTION: + { + ClutterModifierType mods = clutter_event_get_state (event); + + /* we might miss a button-release event in case of grabs, + * so we need to check whether the button is still down + * during a motion event + */ + if (mods & CLUTTER_BUTTON1_MASK) + emit_drag_motion (action, actor, event); + else + emit_drag_end (action, actor, event); + } + break; + + case CLUTTER_BUTTON_RELEASE: + if (priv->in_drag) + emit_drag_end (action, actor, event); + break; + + default: + break; + } + + return FALSE; +} + +static gboolean +on_button_press (ClutterActor *actor, + ClutterEvent *event, + ClutterDragAction *action) +{ + ClutterDragActionPrivate *priv = action->priv; + + if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action))) + return FALSE; + + if (priv->stage == NULL) + priv->stage = clutter_actor_get_stage (actor); + + clutter_event_get_coords (event, &priv->press_x, &priv->press_y); + priv->press_button = clutter_event_get_button (event); + priv->press_state = clutter_event_get_state (event); + + priv->last_motion_x = priv->press_x; + priv->last_motion_y = priv->press_y; + + priv->transformed_press_x = priv->press_x; + priv->transformed_press_y = priv->press_y; + clutter_actor_transform_stage_point (actor, priv->press_x, priv->press_y, + &priv->transformed_press_x, + &priv->transformed_press_y); + + if (priv->drag_threshold == 0) + emit_drag_begin (action, actor, event); + else + priv->emit_delayed_press = TRUE; + + priv->in_drag = TRUE; + priv->capture_id = g_signal_connect_after (priv->stage, "captured-event", + G_CALLBACK (on_captured_event), + action); + + return FALSE; +} + +static void +clutter_drag_action_set_actor (ClutterActorMeta *meta, + ClutterActor *actor) +{ + ClutterDragActionPrivate *priv = CLUTTER_DRAG_ACTION (meta)->priv; + + if (priv->button_press_id != 0) + { + ClutterActor *old_actor; + + old_actor = clutter_actor_meta_get_actor (meta); + + g_signal_handler_disconnect (old_actor, priv->button_press_id); + + if (priv->capture_id != 0) + g_signal_handler_disconnect (old_actor, priv->capture_id); + + priv->button_press_id = 0; + priv->capture_id = 0; + + priv->stage = NULL; + } + + if (actor != NULL) + priv->button_press_id = g_signal_connect (actor, "button-press-event", + G_CALLBACK (on_button_press), + meta); + + CLUTTER_ACTOR_META_CLASS (clutter_drag_action_parent_class)->set_actor (meta, actor); +} + +static void +clutter_drag_action_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ClutterDragAction *action = CLUTTER_DRAG_ACTION (gobject); + + switch (prop_id) + { + case PROP_DRAG_THRESHOLD: + clutter_drag_action_set_drag_threshold (action, g_value_get_uint (value)); + break; + + case PROP_DRAG_HANDLE: + clutter_drag_action_set_drag_handle (action, g_value_get_object (value)); + break; + + case PROP_DRAG_AXIS: + clutter_drag_action_set_drag_axis (action, g_value_get_enum (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + } +} + +static void +clutter_drag_action_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ClutterDragActionPrivate *priv = CLUTTER_DRAG_ACTION (gobject)->priv; + + switch (prop_id) + { + case PROP_DRAG_THRESHOLD: + g_value_set_uint (value, priv->drag_threshold); + break; + + case PROP_DRAG_HANDLE: + g_value_set_object (value, priv->drag_handle); + break; + + case PROP_DRAG_AXIS: + g_value_set_enum (value, priv->drag_axis); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + } +} + +static void +clutter_drag_action_dispose (GObject *gobject) +{ + ClutterDragActionPrivate *priv = CLUTTER_DRAG_ACTION (gobject)->priv; + + if (priv->capture_id != 0) + { + if (priv->stage != NULL) + g_signal_handler_disconnect (priv->stage, priv->capture_id); + + priv->capture_id = 0; + priv->stage = NULL; + } + + if (priv->button_press_id != 0) + { + ClutterActor *actor; + + actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (gobject)); + g_signal_handler_disconnect (actor, priv->button_press_id); + priv->button_press_id = 0; + } + + G_OBJECT_CLASS (clutter_drag_action_parent_class)->dispose (gobject); +} + +static void +clutter_drag_action_class_init (ClutterDragActionClass *klass) +{ + ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + g_type_class_add_private (klass, sizeof (ClutterDragActionPrivate)); + + gobject_class->set_property = clutter_drag_action_set_property; + gobject_class->get_property = clutter_drag_action_get_property; + gobject_class->dispose = clutter_drag_action_dispose; + + meta_class->set_actor = clutter_drag_action_set_actor; + + /** + * ClutterDragAction:drag-threshold: + * + * The threshold, in pixels, that begins a drag action + * + * When set to a non-zero value, #ClutterDragAction will only emit + * #ClutterDragAction::drag-begin if the pointer has moved at least + * of the given amount of pixels since the button press event + * + * Since: 1.4 + */ + pspec = g_param_spec_uint ("drag-threshold", + "Drag Threshold", + "The amount of pixels required to start " + "dragging", + 0, G_MAXUINT, + 0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_DRAG_THRESHOLD, pspec); + + /** + * ClutterDragAction:drag-handle: + * + * The #ClutterActor that is effectively being dragged + * + * A #ClutterDragActor will, be default, use the #ClutterActor that + * has been attached to the action; it is possible to create a + * separate #ClutterActor and use it instead. + * + * Setting this property has no effect on the #ClutterActor argument + * passed to the #ClutterDragAction signals + * + * Since: 1.4 + */ + pspec = g_param_spec_object ("drag-handle", + "Drag Handle", + "The actor that is being dragged", + CLUTTER_TYPE_ACTOR, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_DRAG_HANDLE, pspec); + + /** + * ClutterDragAction:drag-axis: + * + * Constraints the dragging action to the specified axis + * + * Since: 1.4 + */ + pspec = g_param_spec_enum ("drag-axis", + "Drag Axis", + "Constraints the dragging to an axis", + CLUTTER_TYPE_DRAG_AXIS, + CLUTTER_DRAG_AXIS_NONE, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_DRAG_AXIS, pspec); + + /** + * ClutterDragAction::drag-begin: + * @action: the #ClutterDragAction that emitted the signal + * @actor: the #ClutterActor attached to the action + * @event_x: the X coordinate (in stage space) of the press event + * @event_y: the Y coordinate (in stage space) of the press event + * @button: the button of the press event + * @modifiers: the modifiers of the press event + * + * The ::drag-begin signal is emitted when the #ClutterDragAction + * starts the dragging + * + * The emission of this signal can be delayed by using the + * #ClutterDragAction:drag-threshold property + * + * Since: 1.4 + */ + drag_signals[DRAG_BEGIN] = + g_signal_new (I_("drag-begin"), + CLUTTER_TYPE_DRAG_ACTION, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ClutterDragActionClass, drag_begin), + NULL, NULL, + clutter_marshal_VOID__OBJECT_FLOAT_FLOAT_INT_FLAGS, + G_TYPE_NONE, 5, + CLUTTER_TYPE_ACTOR, + G_TYPE_FLOAT, + G_TYPE_FLOAT, + G_TYPE_INT, + CLUTTER_TYPE_MODIFIER_TYPE); + + /** + * ClutterDragAction::drag-motion + * @action: the #ClutterDragAction that emitted the signal + * @actor: the #ClutterActor attached to the action + * @delta_x: the X component of the distance between the press event + * that began the dragging and the current position of the pointer, + * as of the latest motion event + * @delta_y: the Y component of the distance between the press event + * that began the dragging and the current position of the pointer, + * as of the latest motion event + * @modifiers: the modifiers of the latest motion event + * + * The ::drag-motion signal is emitted for each motion event after + * the #ClutterDragAction::drag-begin signal has been emitted. + * + * The components of the distance between the press event and the + * latest motion event are computed in the actor's coordinate space, + * to take into account eventual transformations. If you want the + * stage coordinates of the latest motion event you can use + * clutter_drag_action_get_motion_coords(). + * + * Since: 1.4 + */ + drag_signals[DRAG_MOTION] = + g_signal_new (I_("drag-motion"), + CLUTTER_TYPE_DRAG_ACTION, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ClutterDragActionClass, drag_motion), + NULL, NULL, + clutter_marshal_VOID__OBJECT_FLOAT_FLOAT, + G_TYPE_NONE, 3, + CLUTTER_TYPE_ACTOR, + G_TYPE_FLOAT, + G_TYPE_FLOAT); + + /** + * ClutterDragAction::drag-end: + * @action: the #ClutterDragAction that emitted the signal + * @actor: the #ClutterActor attached to the action + * @event_x: the X coordinate (in stage space) of the release event + * @event_y: the Y coordinate (in stage space) of the release event + * @button: the button of the release event + * @modifiers: the modifiers of the release event + * + * The ::drag-end signal is emitted at the end of the dragging, + * when the pointer button's is released + * + * This signal is emitted if and only if the #ClutterDragAction::drag-begin + * signal has been emitted first + * + * Since: 1.4 + */ + drag_signals[DRAG_END] = + g_signal_new (I_("drag-end"), + CLUTTER_TYPE_DRAG_ACTION, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ClutterDragActionClass, drag_end), + NULL, NULL, + clutter_marshal_VOID__OBJECT_FLOAT_FLOAT_INT_FLAGS, + G_TYPE_NONE, 5, + CLUTTER_TYPE_ACTOR, + G_TYPE_FLOAT, + G_TYPE_FLOAT, + G_TYPE_INT, + CLUTTER_TYPE_MODIFIER_TYPE); +} + +static void +clutter_drag_action_init (ClutterDragAction *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_DRAG_ACTION, + ClutterDragActionPrivate); +} + +/** + * clutter_drag_action_new: + * + * Creates a new #ClutterDragAction instance + * + * Return value: the newly created #ClutterDragAction + * + * Since: 1.4 + */ +ClutterAction * +clutter_drag_action_new (void) +{ + return g_object_new (CLUTTER_TYPE_DRAG_ACTION, NULL); +} + +/** + * clutter_drag_action_set_drag_threshold: + * @action: a #ClutterDragAction + * @threshold: a distance, in pixels + * + * Sets the drag threshold that must be cleared by the pointer + * before @action can begin the dragging + * + * Since: 1.4 + */ +void +clutter_drag_action_set_drag_threshold (ClutterDragAction *action, + guint threshold) +{ + ClutterDragActionPrivate *priv; + + g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action)); + + priv = action->priv; + + if (priv->drag_threshold == threshold) + return; + + priv->drag_threshold = threshold; + + g_object_notify (G_OBJECT (action), "drag-threshold"); +} + +/** + * clutter_drag_action_get_drag_threshold: + * @action: a #ClutterDragAction + * + * Retrieves the value set by clutter_drag_action_set_drag_threshold() + * + * Return value: the drag threshold value, in pixels + * + * Since: 1.4 + */ +guint +clutter_drag_action_get_drag_threshold (ClutterDragAction *action) +{ + g_return_val_if_fail (CLUTTER_IS_DRAG_ACTION (action), 0); + + return action->priv->drag_threshold; +} + +/** + * clutter_drag_action_set_drag_handle: + * @action: a #ClutterDragHandle + * @handle: a #ClutterActor + * + * Sets the actor to be used as the drag handle + * + * Since: 1.4 + */ +void +clutter_drag_action_set_drag_handle (ClutterDragAction *action, + ClutterActor *handle) +{ + ClutterDragActionPrivate *priv; + + g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action)); + g_return_if_fail (CLUTTER_IS_ACTOR (handle)); + + priv = action->priv; + + if (priv->drag_handle == handle) + return; + + priv->drag_handle = handle; + + g_object_notify (G_OBJECT (action), "drag-handle"); +} + +/** + * clutter_drag_action_get_drag_handle: + * @action: a #ClutterDragAction + * + * Retrieves the drag handle set by clutter_drag_action_set_drag_handle() + * + * Return value: (transfer none): a #ClutterActor, used as the drag + * handle, or %NULL if none was set + * + * Since: 1.4 + */ +ClutterActor * +clutter_drag_action_get_drag_handle (ClutterDragAction *action) +{ + g_return_val_if_fail (CLUTTER_IS_DRAG_ACTION (action), NULL); + + return action->priv->drag_handle; +} + +/** + * clutter_drag_action_set_drag_axis: + * @action: a #ClutterDragAction + * @axis: the axis to constraint the dragging to + * + * Restricts the dragging action to a specific axis + * + * Since: 1.4 + */ +void +clutter_drag_action_set_drag_axis (ClutterDragAction *action, + ClutterDragAxis axis) +{ + ClutterDragActionPrivate *priv; + + g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action)); + g_return_if_fail (axis >= CLUTTER_DRAG_AXIS_NONE && + axis <= CLUTTER_DRAG_Y_AXIS); + + priv = action->priv; + + if (priv->drag_axis == axis) + return; + + priv->drag_axis = axis; + + g_object_notify (G_OBJECT (action), "drag-axis"); +} + +/** + * clutter_drag_action_get_drag_axis: + * @action: a #ClutterDragAction + * + * Retrieves the axis constraint set by clutter_drag_action_set_drag_axis() + * + * Return value: the axis constraint + * + * Since: 1.4 + */ +ClutterDragAxis +clutter_drag_action_get_drag_axis (ClutterDragAction *action) +{ + g_return_val_if_fail (CLUTTER_IS_DRAG_ACTION (action), + CLUTTER_DRAG_AXIS_NONE); + + return action->priv->drag_axis; +} + +/** + * clutter_drag_action_get_press_coords: + * @action: a #ClutterDragAction + * @press_x: (out): return location for the press event's X coordinate + * @press_y: (out): return location for the press event's Y coordinate + * + * Retrieves the coordinates, in stage space, of the press event + * that started the dragging + * + * Since: 1.4 + */ +void +clutter_drag_action_get_press_coords (ClutterDragAction *action, + gfloat *press_x, + gfloat *press_y) +{ + g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action)); + + if (press_x) + *press_x = action->priv->press_x; + + if (press_y) + *press_y = action->priv->press_y; +} + +/** + * clutter_drag_action_get_motion_coords: + * @action: a #ClutterDragAction + * @motion_x: (out): return location for the latest motion + * event's X coordinate + * @motion_y: (out): return location for the latest motion + * event's Y coordinate + * + * Retrieves the coordinates, in stage space, of the latest motion + * event during the dragging + * + * Since: 1.4 + */ +void +clutter_drag_action_get_motion_coords (ClutterDragAction *action, + gfloat *motion_x, + gfloat *motion_y) +{ + g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action)); + + if (motion_x) + *motion_x = action->priv->last_motion_x; + + if (motion_y) + *motion_y = action->priv->last_motion_y; +} diff --git a/clutter/clutter-drag-action.h b/clutter/clutter-drag-action.h new file mode 100644 index 000000000..78290dcf5 --- /dev/null +++ b/clutter/clutter-drag-action.h @@ -0,0 +1,148 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_DRAG_ACTION_H__ +#define __CLUTTER_DRAG_ACTION_H__ + +#include +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_DRAG_ACTION (clutter_drag_action_get_type ()) +#define CLUTTER_DRAG_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DRAG_ACTION, ClutterDragAction)) +#define CLUTTER_IS_DRAG_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DRAG_ACTION)) +#define CLUTTER_DRAG_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DRAG_ACTION, ClutterDragActionClass)) +#define CLUTTER_IS_DRAG_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DRAG_ACTION)) +#define CLUTTER_DRAG_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DRAG_ACTION, ClutterDragActionClass)) + +typedef struct _ClutterDragAction ClutterDragAction; +typedef struct _ClutterDragActionPrivate ClutterDragActionPrivate; +typedef struct _ClutterDragActionClass ClutterDragActionClass; + +/** + * ClutterDragAxis: + * @CLUTTER_DRAG_AXIS_NONE: No constraint + * @CLUTTER_DRAG_X_AXIS: Set a constraint on the X axis + * @CLUTTER_DRAG_Y_AXIS: Set a constraint on the Y axis + * + * The axis of the constraint that should be applied on the + * dragging action + * + * Since: 1.4 + */ +typedef enum { /*< prefix=CLUTTER_DRAG >*/ + CLUTTER_DRAG_AXIS_NONE = 0, + + CLUTTER_DRAG_X_AXIS, + CLUTTER_DRAG_Y_AXIS +} ClutterDragAxis; + +/** + * ClutterDragAction: + * + * The ClutterDragAction structure contains only + * private data and should be accessed using the provided API + * + * Since: 1.4 + */ +struct _ClutterDragAction +{ + /*< private >*/ + ClutterAction parent_instance; + + ClutterDragActionPrivate *priv; +}; + +/** + * ClutterDragActionClass: + * @drag_begin: class handler of the #ClutterDragAction::drag-begin signal + * @drag_motion: class handler of the #ClutterDragAction::drag-motion signal + * @drag_end: class handler of the #ClutterDragAction::drag-end signal + * + * The ClutterDragActionClass structure contains + * only private data + * + * Since: 1.4 + */ +struct _ClutterDragActionClass +{ + /*< private >*/ + ClutterActionClass parent_class; + + /*< public >*/ + void (* drag_begin) (ClutterDragAction *action, + ClutterActor *actor, + gfloat event_x, + gfloat event_y, + gint button, + ClutterModifierType modifiers); + void (* drag_motion) (ClutterDragAction *action, + ClutterActor *actor, + gfloat delta_x, + gfloat delta_y, + ClutterModifierType modifiers); + void (* drag_end) (ClutterDragAction *action, + ClutterActor *actor, + gfloat event_x, + gfloat event_y, + gint button, + ClutterModifierType modifiers); + + /*< private >*/ + void (* _clutter_drag_action1) (void); + void (* _clutter_drag_action2) (void); + void (* _clutter_drag_action3) (void); + void (* _clutter_drag_action4) (void); + void (* _clutter_drag_action5) (void); +}; + +GType clutter_drag_action_get_type (void) G_GNUC_CONST; + +ClutterAction * clutter_drag_action_new (void); + +void clutter_drag_action_set_drag_threshold (ClutterDragAction *action, + guint threshold); +guint clutter_drag_action_get_drag_threshold (ClutterDragAction *action); +void clutter_drag_action_set_drag_handle (ClutterDragAction *action, + ClutterActor *handle); +ClutterActor * clutter_drag_action_get_drag_handle (ClutterDragAction *action); +void clutter_drag_action_set_drag_axis (ClutterDragAction *action, + ClutterDragAxis axis); +ClutterDragAxis clutter_drag_action_get_drag_axis (ClutterDragAction *action); + +void clutter_drag_action_get_press_coords (ClutterDragAction *action, + gfloat *press_x, + gfloat *press_y); +void clutter_drag_action_get_motion_coords (ClutterDragAction *action, + gfloat *motion_x, + gfloat *motion_y); + +G_END_DECLS + +#endif /* __CLUTTER_DRAG_ACTION_H__ */ diff --git a/clutter/clutter-event.h b/clutter/clutter-event.h index f0dc8a357..d5e641b6b 100644 --- a/clutter/clutter-event.h +++ b/clutter/clutter-event.h @@ -417,7 +417,6 @@ struct _ClutterStageStateEvent /** * ClutterEvent: - * @type: event type * * Generic event wrapper. * @@ -425,6 +424,7 @@ struct _ClutterStageStateEvent */ union _ClutterEvent { + /*< private >*/ ClutterEventType type; ClutterAnyEvent any; diff --git a/clutter/clutter-marshal.list b/clutter/clutter-marshal.list index 8296f9add..0ad57424f 100644 --- a/clutter/clutter-marshal.list +++ b/clutter/clutter-marshal.list @@ -10,6 +10,8 @@ VOID:INT,INT VOID:FLOAT,FLOAT VOID:INT,INT,INT,INT VOID:OBJECT +VOID:OBJECT,FLOAT,FLOAT +VOID:OBJECT,FLOAT,FLOAT,INT,FLAGS VOID:OBJECT,OBJECT,PARAM VOID:OBJECT,POINTER VOID:POINTER diff --git a/clutter/clutter-media.h b/clutter/clutter-media.h index a1a768818..7471940d4 100644 --- a/clutter/clutter-media.h +++ b/clutter/clutter-media.h @@ -65,6 +65,7 @@ struct _ClutterMediaIface /*< private >*/ GTypeInterface base_iface; + /*< public >*/ /* signals */ void (* eos) (ClutterMedia *media); void (* error) (ClutterMedia *media, diff --git a/clutter/clutter-stage-manager.h b/clutter/clutter-stage-manager.h index 09a334c14..6cb9c5171 100644 --- a/clutter/clutter-stage-manager.h +++ b/clutter/clutter-stage-manager.h @@ -53,10 +53,6 @@ typedef struct _ClutterStageManagerClass ClutterStageManagerClass; /** * ClutterStageManagerClass: - * @stage_added: class handler for the #ClutterStageManager::stage-added - * signal - * @stage_removed: class handler for the #ClutterStageManager::stage-removed - * signal * * The #ClutterStageManagerClass structure contains only private data * and should be accessed using the provided API diff --git a/clutter/clutter-types.h b/clutter/clutter-types.h index 72090fa2a..9d53ea9a0 100644 --- a/clutter/clutter-types.h +++ b/clutter/clutter-types.h @@ -40,12 +40,18 @@ G_BEGIN_DECLS /* Forward delarations to avoid header catch 22's */ typedef struct _ClutterActor ClutterActor; + typedef struct _ClutterStage ClutterStage; typedef struct _ClutterContainer ClutterContainer; /* dummy */ typedef struct _ClutterChildMeta ClutterChildMeta; typedef struct _ClutterLayoutMeta ClutterLayoutMeta; +typedef struct _ClutterActorMeta ClutterActorMeta; + typedef struct _ClutterAnimator ClutterAnimator; +typedef struct _ClutterAction ClutterAction; +typedef struct _ClutterConstraint ClutterConstraint; + typedef union _ClutterEvent ClutterEvent; /** diff --git a/clutter/clutter.h b/clutter/clutter.h index f56876173..49c3dabe3 100644 --- a/clutter/clutter.h +++ b/clutter/clutter.h @@ -30,7 +30,10 @@ #include "clutter-deprecated.h" +#include "clutter-action.h" #include "clutter-actor.h" +#include "clutter-actor-meta.h" +#include "clutter-align-constraint.h" #include "clutter-alpha.h" #include "clutter-animatable.h" #include "clutter-animation.h" @@ -43,6 +46,7 @@ #include "clutter-behaviour-path.h" #include "clutter-behaviour-rotate.h" #include "clutter-behaviour-scale.h" +#include "clutter-bind-constraint.h" #include "clutter-binding-pool.h" #include "clutter-bin-layout.h" #include "clutter-box.h" @@ -51,8 +55,10 @@ #include "clutter-child-meta.h" #include "clutter-clone.h" #include "clutter-color.h" +#include "clutter-constraint.h" #include "clutter-container.h" #include "clutter-device-manager.h" +#include "clutter-drag-action.h" #include "clutter-event.h" #include "clutter-feature.h" #include "clutter-fixed-layout.h" diff --git a/clutter/json/json-array.c b/clutter/json/json-array.c index 16f36a4b0..83e2e0245 100644 --- a/clutter/json/json-array.c +++ b/clutter/json/json-array.c @@ -27,7 +27,7 @@ #include "json-types-private.h" -/** +/* * SECTION:json-array * @short_description: a JSON array representation * @@ -57,7 +57,7 @@ json_array_get_type (void) return array_type; } -/** +/* * json_array_new: * * Creates a new #JsonArray. @@ -77,7 +77,7 @@ json_array_new (void) return array; } -/** +/* * json_array_sized_new: * @n_elements: number of slots to pre-allocate * @@ -98,7 +98,7 @@ json_array_sized_new (guint n_elements) return array; } -/** +/* * json_array_ref: * @array: a #JsonArray * @@ -118,7 +118,7 @@ json_array_ref (JsonArray *array) return array; } -/** +/* * json_array_unref: * @array: a #JsonArray * @@ -151,7 +151,7 @@ json_array_unref (JsonArray *array) } } -/** +/* * json_array_get_elements: * @array: a #JsonArray * @@ -178,7 +178,7 @@ json_array_get_elements (JsonArray *array) return g_list_reverse (retval); } -/** +/* * json_array_dup_element: * @array: a #JsonArray * @index_: the index of the element to retrieve @@ -207,7 +207,7 @@ json_array_dup_element (JsonArray *array, return json_node_copy (retval); } -/** +/* * json_array_get_element: * @array: a #JsonArray * @index_: the index of the element to retrieve @@ -227,7 +227,7 @@ json_array_get_element (JsonArray *array, return g_ptr_array_index (array->elements, index_); } -/** +/* * json_array_get_int_element: * @array: a #JsonArray * @index_: the index of the element to retrieve @@ -257,7 +257,7 @@ json_array_get_int_element (JsonArray *array, return json_node_get_int (node); } -/** +/* * json_array_get_double_element: * @array: a #JsonArray * @index_: the index of the element to retrieve @@ -287,7 +287,7 @@ json_array_get_double_element (JsonArray *array, return json_node_get_double (node); } -/** +/* * json_array_get_boolean_element: * @array: a #JsonArray * @index_: the index of the element to retrieve @@ -317,7 +317,7 @@ json_array_get_boolean_element (JsonArray *array, return json_node_get_boolean (node); } -/** +/* * json_array_get_string_element: * @array: a #JsonArray * @index_: the index of the element to retrieve @@ -348,7 +348,7 @@ json_array_get_string_element (JsonArray *array, return json_node_get_string (node); } -/** +/* * json_array_get_null_element: * @array: a #JsonArray * @index_: the index of the element to retrieve @@ -376,7 +376,7 @@ json_array_get_null_element (JsonArray *array, return JSON_NODE_TYPE (node) == JSON_NODE_NULL; } -/** +/* * json_array_get_array_element: * @array: a #JsonArray * @index_: the index of the element to retrieve @@ -406,7 +406,7 @@ json_array_get_array_element (JsonArray *array, return json_node_get_array (node); } -/** +/* * json_array_get_object_element: * @array: a #JsonArray * @index_: the index of the element to retrieve @@ -436,7 +436,7 @@ json_array_get_object_element (JsonArray *array, return json_node_get_object (node); } -/** +/* * json_array_get_length: * @array: a #JsonArray * @@ -452,7 +452,7 @@ json_array_get_length (JsonArray *array) return array->elements->len; } -/** +/* * json_array_add_element: * @array: a #JsonArray * @node: a #JsonNode @@ -470,7 +470,7 @@ json_array_add_element (JsonArray *array, g_ptr_array_add (array->elements, node); } -/** +/* * json_array_add_int_element: * @array: a #JsonArray * @value: an integer value @@ -495,7 +495,7 @@ json_array_add_int_element (JsonArray *array, g_ptr_array_add (array->elements, node); } -/** +/* * json_array_add_double_element: * @array: a #JsonArray * @value: a floating point value @@ -520,7 +520,7 @@ json_array_add_double_element (JsonArray *array, g_ptr_array_add (array->elements, node); } -/** +/* * json_array_add_boolean_element: * @array: a #JsonArray * @value: a boolean value @@ -545,7 +545,7 @@ json_array_add_boolean_element (JsonArray *array, g_ptr_array_add (array->elements, node); } -/** +/* * json_array_add_string_element: * @array: a #JsonArray * @value: a string value @@ -571,7 +571,7 @@ json_array_add_string_element (JsonArray *array, g_ptr_array_add (array->elements, node); } -/** +/* * json_array_add_null_element: * @array: a #JsonArray * @@ -593,7 +593,7 @@ json_array_add_null_element (JsonArray *array) g_ptr_array_add (array->elements, node); } -/** +/* * json_array_add_array_element: * @array: a #JsonArray * @value: a #JsonArray @@ -620,7 +620,7 @@ json_array_add_array_element (JsonArray *array, g_ptr_array_add (array->elements, node); } -/** +/* * json_array_add_object_element: * @array: a #JsonArray * @value: a #JsonObject @@ -647,7 +647,7 @@ json_array_add_object_element (JsonArray *array, g_ptr_array_add (array->elements, node); } -/** +/* * json_array_remove_element: * @array: a #JsonArray * @index_: the position of the element to be removed @@ -665,7 +665,7 @@ json_array_remove_element (JsonArray *array, json_node_free (g_ptr_array_remove_index (array->elements, index_)); } -/** +/* * json_array_foreach_element: * @array: a #JsonArray * @func: the function to be called on each element diff --git a/clutter/json/json-generator.c b/clutter/json/json-generator.c index c77830e61..0766df34b 100644 --- a/clutter/json/json-generator.c +++ b/clutter/json/json-generator.c @@ -21,7 +21,7 @@ * Emmanuele Bassi */ -/** +/* * SECTION:json-generator * @short_description: Generates JSON data streams * @@ -191,7 +191,7 @@ json_generator_class_init (JsonGeneratorClass *klass) gobject_class->get_property = json_generator_get_property; gobject_class->finalize = json_generator_finalize; - /** + /* * JsonGenerator:pretty: * * Whether the output should be "pretty-printed", with indentation and @@ -205,7 +205,7 @@ json_generator_class_init (JsonGeneratorClass *klass) "Pretty-print the output", FALSE, G_PARAM_READWRITE)); - /** + /* * JsonGenerator:indent: * * Number of spaces to be used to indent when pretty printing. @@ -218,7 +218,7 @@ json_generator_class_init (JsonGeneratorClass *klass) 0, G_MAXUINT, 2, G_PARAM_READWRITE)); - /** + /* * JsonGenerator:root: * * The root #JsonNode to be used when constructing a JSON data @@ -233,7 +233,7 @@ json_generator_class_init (JsonGeneratorClass *klass) "Root of the JSON data tree", JSON_TYPE_NODE, G_PARAM_READWRITE)); - /** + /* * JsonGenerator:indent-char: * * The character that should be used when indenting in pretty print. @@ -519,7 +519,7 @@ dump_object (JsonGenerator *generator, return g_string_free (buffer, FALSE); } -/** +/* * json_generator_new: * * Creates a new #JsonGenerator. You can use this object to generate a @@ -534,7 +534,7 @@ json_generator_new (void) return g_object_new (JSON_TYPE_GENERATOR, NULL); } -/** +/* * json_generator_to_data: * @generator: a #JsonGenerator * @length: (out): return location for the length of the returned @@ -588,7 +588,7 @@ json_generator_to_data (JsonGenerator *generator, return retval; } -/** +/* * json_generator_to_file: * @generator: a #JsonGenerator * @filename: path to the target file @@ -618,7 +618,7 @@ json_generator_to_file (JsonGenerator *generator, return retval; } -/** +/* * json_generator_set_root: * @generator: a #JsonGenerator * @node: a #JsonNode diff --git a/clutter/json/json-node.c b/clutter/json/json-node.c index e1e457a7d..a56fc7493 100644 --- a/clutter/json/json-node.c +++ b/clutter/json/json-node.c @@ -29,7 +29,7 @@ #include "json-types-private.h" -/** +/* * SECTION:json-node * @short_description: Node in a JSON object model * @@ -61,7 +61,7 @@ json_node_get_type (void) return node_type; } -/** +/* * json_node_get_value_type: * @node: a #JsonNode * @@ -96,7 +96,7 @@ json_node_get_value_type (JsonNode *node) } } -/** +/* * json_node_new: * @type: a #JsonNodeType * @@ -118,7 +118,7 @@ json_node_new (JsonNodeType type) return data; } -/** +/* * json_node_copy: * @node: a #JsonNode * @@ -167,7 +167,7 @@ json_node_copy (JsonNode *node) return copy; } -/** +/* * json_node_set_object: * @node: a #JsonNode * @object: a #JsonObject @@ -190,7 +190,7 @@ json_node_set_object (JsonNode *node, node->data.object = NULL; } -/** +/* * json_node_take_object: * @node: a #JsonNode * @object: a #JsonObject @@ -214,7 +214,7 @@ json_node_take_object (JsonNode *node, node->data.object = object; } -/** +/* * json_node_get_object: * @node: a #JsonNode * @@ -231,7 +231,7 @@ json_node_get_object (JsonNode *node) return node->data.object; } -/** +/* * json_node_dup_object: * @node: a #JsonNode * @@ -252,7 +252,7 @@ json_node_dup_object (JsonNode *node) return NULL; } -/** +/* * json_node_set_array: * @node: a #JsonNode * @array: a #JsonArray @@ -275,7 +275,7 @@ json_node_set_array (JsonNode *node, node->data.array = NULL; } -/** +/* * json_node_take_array: * @node: a #JsonNode * @array: a #JsonArray @@ -299,7 +299,7 @@ json_node_take_array (JsonNode *node, node->data.array = array; } -/** +/* * json_node_get_array: * @node: a #JsonNode * @@ -316,7 +316,7 @@ json_node_get_array (JsonNode *node) return node->data.array; } -/** +/* * json_node_dup_array * @node: a #JsonNode * @@ -337,7 +337,7 @@ json_node_dup_array (JsonNode *node) return NULL; } -/** +/* * json_node_get_value: * @node: a #JsonNode * @value: return location for an uninitialized value @@ -366,7 +366,7 @@ node_value_unset (JsonNode *node) g_value_unset (&(node->data.value)); } -/** +/* * json_node_set_value: * @node: a #JsonNode * @value: the #GValue to set @@ -417,7 +417,7 @@ json_node_set_value (JsonNode *node, } -/** +/* * json_node_free: * @node: a #JsonNode * @@ -452,7 +452,7 @@ json_node_free (JsonNode *node) } } -/** +/* * json_node_type_name: * @node: a #JsonNode * @@ -484,7 +484,7 @@ json_node_type_name (JsonNode *node) return "unknown"; } -/** +/* * json_node_get_parent: * @node: a #JsonNode * @@ -500,7 +500,7 @@ json_node_get_parent (JsonNode *node) return node->parent; } -/** +/* * json_node_set_string: * @node: a #JsonNode of type %JSON_NODE_VALUE * @value: a string value @@ -530,7 +530,7 @@ json_node_set_string (JsonNode *node, } } -/** +/* * json_node_get_string: * @node: a #JsonNode of type %JSON_NODE_VALUE * @@ -552,7 +552,7 @@ json_node_get_string (JsonNode *node) return NULL; } -/** +/* * json_node_dup_string: * @node: a #JsonNode of type %JSON_NODE_VALUE * @@ -575,7 +575,7 @@ json_node_dup_string (JsonNode *node) return NULL; } -/** +/* * json_node_set_int: * @node: a #JsonNode of type %JSON_NODE_VALUE * @value: an integer value @@ -605,7 +605,7 @@ json_node_set_int (JsonNode *node, } } -/** +/* * json_node_get_int: * @node: a #JsonNode of type %JSON_NODE_VALUE * @@ -627,7 +627,7 @@ json_node_get_int (JsonNode *node) return 0; } -/** +/* * json_node_set_double: * @node: a #JsonNode of type %JSON_NODE_VALUE * @value: a double value @@ -657,7 +657,7 @@ json_node_set_double (JsonNode *node, } } -/** +/* * json_node_get_double: * @node: a #JsonNode of type %JSON_NODE_VALUE * @@ -679,7 +679,7 @@ json_node_get_double (JsonNode *node) return 0.0; } -/** +/* * json_node_set_boolean: * @node: a #JsonNode of type %JSON_NODE_VALUE * @value: a boolean value @@ -709,7 +709,7 @@ json_node_set_boolean (JsonNode *node, } } -/** +/* * json_node_get_boolean: * @node: a #JsonNode of type %JSON_NODE_VALUE * @@ -731,7 +731,7 @@ json_node_get_boolean (JsonNode *node) return FALSE; } -/** +/* * json_node_get_node_type: * @node: a #JsonNode * @@ -749,7 +749,7 @@ json_node_get_node_type (JsonNode *node) return node->type; } -/** +/* * json_node_is_null: * @node: a #JsonNode * diff --git a/clutter/json/json-object.c b/clutter/json/json-object.c index d1bbe98cd..f3324976b 100644 --- a/clutter/json/json-object.c +++ b/clutter/json/json-object.c @@ -29,7 +29,7 @@ #include "json-types-private.h" -/** +/* * SECTION:json-object * @short_description: a JSON object representation * @@ -64,7 +64,7 @@ json_object_get_type (void) return object_type; } -/** +/* * json_object_new: * * Creates a new #JsonObject, an JSON object type representation. @@ -86,7 +86,7 @@ json_object_new (void) return object; } -/** +/* * json_object_ref: * @object: a #JsonObject * @@ -106,7 +106,7 @@ json_object_ref (JsonObject *object) return object; } -/** +/* * json_object_unref: * @object: a #JsonObject * @@ -144,7 +144,7 @@ object_set_member_internal (JsonObject *object, node); } -/** +/* * json_object_add_member: * @object: a #JsonObject * @member_name: the name of the member @@ -178,7 +178,7 @@ json_object_add_member (JsonObject *object, object_set_member_internal (object, member_name, node); } -/** +/* * json_object_set_member: * @object: a #JsonObject * @member_name: the name of the member @@ -204,7 +204,7 @@ json_object_set_member (JsonObject *object, object_set_member_internal (object, member_name, node); } -/** +/* * json_object_set_int_member: * @object: a #JsonObject * @member_name: the name of the member @@ -232,7 +232,7 @@ json_object_set_int_member (JsonObject *object, object_set_member_internal (object, member_name, node); } -/** +/* * json_object_set_double_member: * @object: a #JsonObject * @member_name: the name of the member @@ -260,7 +260,7 @@ json_object_set_double_member (JsonObject *object, object_set_member_internal (object, member_name, node); } -/** +/* * json_object_set_boolean_member: * @object: a #JsonObject * @member_name: the name of the member @@ -288,7 +288,7 @@ json_object_set_boolean_member (JsonObject *object, object_set_member_internal (object, member_name, node); } -/** +/* * json_object_set_string_member: * @object: a #JsonObject * @member_name: the name of the member @@ -316,7 +316,7 @@ json_object_set_string_member (JsonObject *object, object_set_member_internal (object, member_name, node); } -/** +/* * json_object_set_null_member: * @object: a #JsonObject * @member_name: the name of the member @@ -341,7 +341,7 @@ json_object_set_null_member (JsonObject *object, object_set_member_internal (object, member_name, node); } -/** +/* * json_object_set_array_member: * @object: a #JsonObject * @member_name: the name of the member @@ -371,7 +371,7 @@ json_object_set_array_member (JsonObject *object, object_set_member_internal (object, member_name, node); } -/** +/* * json_object_set_object_member: * @object: a #JsonObject * @member_name: the name of the member @@ -448,7 +448,7 @@ g_hash_table_get_values (GHashTable *hash_table) } #endif /* GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 14 */ -/** +/* * json_object_get_members: * @object: a #JsonObject * @@ -468,7 +468,7 @@ json_object_get_members (JsonObject *object) return g_hash_table_get_keys (object->members); } -/** +/* * json_object_get_values: * @object: a #JsonObject * @@ -487,7 +487,7 @@ json_object_get_values (JsonObject *object) return g_hash_table_get_values (object->members); } -/** +/* * json_object_dup_member: * @object: a #JsonObject * @member_name: the name of the JSON object member to access @@ -523,7 +523,7 @@ object_get_member_internal (JsonObject *object, return g_hash_table_lookup (object->members, member_name); } -/** +/* * json_object_get_member: * @object: a #JsonObject * @member_name: the name of the JSON object member to access @@ -544,7 +544,7 @@ json_object_get_member (JsonObject *object, return object_get_member_internal (object, member_name); } -/** +/* * json_object_get_int_member: * @object: a #JsonObject * @member_name: the name of the member @@ -574,7 +574,7 @@ json_object_get_int_member (JsonObject *object, return json_node_get_int (node); } -/** +/* * json_object_get_double_member: * @object: a #JsonObject * @member_name: the name of the member @@ -604,7 +604,7 @@ json_object_get_double_member (JsonObject *object, return json_node_get_double (node); } -/** +/* * json_object_get_boolean_member: * @object: a #JsonObject * @member_name: the name of the member @@ -634,7 +634,7 @@ json_object_get_boolean_member (JsonObject *object, return json_node_get_boolean (node); } -/** +/* * json_object_get_null_member: * @object: a #JsonObject * @member_name: the name of the member @@ -663,7 +663,7 @@ json_object_get_null_member (JsonObject *object, return JSON_NODE_TYPE (node) == JSON_NODE_NULL; } -/** +/* * json_object_get_string_member: * @object: a #JsonObject * @member_name: the name of the member @@ -693,7 +693,7 @@ json_object_get_string_member (JsonObject *object, return json_node_get_string (node); } -/** +/* * json_object_get_array_member: * @object: a #JsonObject * @member_name: the name of the member @@ -723,7 +723,7 @@ json_object_get_array_member (JsonObject *object, return json_node_get_array (node); } -/** +/* * json_object_get_object_member: * @object: a #JsonObject * @member_name: the name of the member @@ -753,7 +753,7 @@ json_object_get_object_member (JsonObject *object, return json_node_get_object (node); } -/** +/* * json_object_has_member: * @object: a #JsonObject * @member_name: the name of a JSON object member @@ -772,7 +772,7 @@ json_object_has_member (JsonObject *object, return (g_hash_table_lookup (object->members, member_name) != NULL); } -/** +/* * json_object_get_size: * @object: a #JsonObject * @@ -788,7 +788,7 @@ json_object_get_size (JsonObject *object) return g_hash_table_size (object->members); } -/** +/* * json_object_remove_member: * @object: a #JsonObject * @member_name: the name of the member to remove @@ -827,7 +827,7 @@ json_object_foreach_internal (gpointer key, clos->func (clos->object, member_name, member_node, clos->data); } -/** +/* * json_object_foreach_member: * @object: a #JsonObject * @func: the function to be called on each member diff --git a/clutter/json/json-parser.c b/clutter/json/json-parser.c index 3ef5afb93..0cd2f64e4 100644 --- a/clutter/json/json-parser.c +++ b/clutter/json/json-parser.c @@ -17,7 +17,7 @@ * Emmanuele Bassi */ -/** +/* * SECTION:json-parser * @short_description: Parse JSON data streams * @@ -167,7 +167,7 @@ json_parser_class_init (JsonParserClass *klass) gobject_class->dispose = json_parser_dispose; - /** + /* * JsonParser::parse-start: * @parser: the #JsonParser that received the signal * @@ -182,7 +182,7 @@ json_parser_class_init (JsonParserClass *klass) NULL, NULL, _json_marshal_VOID__VOID, G_TYPE_NONE, 0); - /** + /* * JsonParser::parse-end: * @parser: the #JsonParser that received the signal * @@ -197,7 +197,7 @@ json_parser_class_init (JsonParserClass *klass) NULL, NULL, _json_marshal_VOID__VOID, G_TYPE_NONE, 0); - /** + /* * JsonParser::object-start: * @parser: the #JsonParser that received the signal * @@ -212,7 +212,7 @@ json_parser_class_init (JsonParserClass *klass) NULL, NULL, _json_marshal_VOID__VOID, G_TYPE_NONE, 0); - /** + /* * JsonParser::object-member: * @parser: the #JsonParser that received the signal * @object: a #JsonObject @@ -232,7 +232,7 @@ json_parser_class_init (JsonParserClass *klass) G_TYPE_NONE, 2, JSON_TYPE_OBJECT, G_TYPE_STRING); - /** + /* * JsonParser::object-end: * @parser: the #JsonParser that received the signal * @object: the parsed #JsonObject @@ -249,7 +249,7 @@ json_parser_class_init (JsonParserClass *klass) _json_marshal_VOID__BOXED, G_TYPE_NONE, 1, JSON_TYPE_OBJECT); - /** + /* * JsonParser::array-start: * @parser: the #JsonParser that received the signal * @@ -264,7 +264,7 @@ json_parser_class_init (JsonParserClass *klass) NULL, NULL, _json_marshal_VOID__VOID, G_TYPE_NONE, 0); - /** + /* * JsonParser::array-element: * @parser: the #JsonParser that received the signal * @array: a #JsonArray @@ -284,7 +284,7 @@ json_parser_class_init (JsonParserClass *klass) G_TYPE_NONE, 2, JSON_TYPE_ARRAY, G_TYPE_INT); - /** + /* * JsonParser::array-end: * @parser: the #JsonParser that received the signal * @array: the parsed #JsonArrary @@ -301,7 +301,7 @@ json_parser_class_init (JsonParserClass *klass) _json_marshal_VOID__BOXED, G_TYPE_NONE, 1, JSON_TYPE_ARRAY); - /** + /* * JsonParser::error: * @parser: the parser instance that received the signal * @error: a pointer to the #GError @@ -885,7 +885,7 @@ json_scanner_new (JsonParser *parser) return scanner; } -/** +/* * json_parser_new: * * Creates a new #JsonParser instance. You can use the #JsonParser to @@ -901,7 +901,7 @@ json_parser_new (void) return g_object_new (JSON_TYPE_PARSER, NULL); } -/** +/* * json_parser_load_from_file: * @parser: a #JsonParser * @filename: the path for the file to parse @@ -944,7 +944,7 @@ json_parser_load_from_file (JsonParser *parser, return retval; } -/** +/* * json_parser_load_from_data: * @parser: a #JsonParser * @data: the buffer to parse @@ -1067,7 +1067,7 @@ json_parser_load_from_data (JsonParser *parser, return retval; } -/** +/* * json_parser_get_root: * @parser: a #JsonParser * @@ -1084,7 +1084,7 @@ json_parser_get_root (JsonParser *parser) return parser->priv->root; } -/** +/* * json_parser_get_current_line: * @parser: a #JsonParser * @@ -1103,7 +1103,7 @@ json_parser_get_current_line (JsonParser *parser) return 0; } -/** +/* * json_parser_get_current_pos: * @parser: a #JsonParser * diff --git a/configure.ac b/configure.ac index 6b4507315..5b107d8e7 100644 --- a/configure.ac +++ b/configure.ac @@ -799,8 +799,8 @@ PKG_CHECK_MODULES(CLUTTER_DEPS, [$CLUTTER_REQUIRES]) AC_SUBST(CLUTTER_REQUIRES) -CLUTTER_CFLAGS="$SDL_CFLAGS $EGL_CFLAGS $GLX_CFLAGS $OSX_CFLAGS $WIN32_CFLAGS $CLUTTER_DEPS_CFLAGS $CLUTTER_PROFILE_CFLAGS $GLIB_CFLAGS" -CLUTTER_LIBS="$SDL_LIBS $EGL_LIBS $X11_LIBS $GLX_LIBS $OSX_LIBS $WIN32_LIBS $CLUTTER_DEPS_LIBS $CLUTTER_PROFILE_LDFLAGS $GLIB_LIBS" +CLUTTER_CFLAGS="$EGL_CFLAGS $GLX_CFLAGS $OSX_CFLAGS $WIN32_CFLAGS $CLUTTER_DEPS_CFLAGS $CLUTTER_PROFILE_CFLAGS $GLIB_CFLAGS" +CLUTTER_LIBS="$EGL_LIBS $X11_LIBS $GLX_LIBS $OSX_LIBS $WIN32_LIBS $CLUTTER_DEPS_LIBS $CLUTTER_PROFILE_LDFLAGS $GLIB_LIBS" AC_SUBST(CLUTTER_CFLAGS) AC_SUBST(CLUTTER_LIBS) @@ -811,7 +811,7 @@ GOBJECT_INTROSPECTION_CHECK([0.6.7]) dnl === GTK Doc check ========================================================= -GTK_DOC_CHECK([1.13]) +GTK_DOC_CHECK([1.13], [--flavour no-tmpl]) # we don't want to build the documentation from a Git clone unless we # explicitly tell configure to do so; this allows avoiding to recurse into diff --git a/doc/reference/clutter/Makefile.am b/doc/reference/clutter/Makefile.am index bcedb36ec..f0486c28c 100644 --- a/doc/reference/clutter/Makefile.am +++ b/doc/reference/clutter/Makefile.am @@ -38,6 +38,7 @@ MKTMPL_OPTIONS= # Extra options to supply to gtkdoc-fixref. Not normally needed. # e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html FIXXREF_OPTIONS=\ + --extra-dir=../cogl/html \ --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/glib \ --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/gobject \ --extra-dir=$(CAIRO_PREFIX)/share/gtk-doc/html/cairo \ @@ -64,6 +65,7 @@ CFILE_GLOB=$(top_srcdir)/clutter/*.c \ # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h IGNORE_HFILES=\ clutter.h \ + clutter-actor-meta-private.h \ clutter-bezier.h \ clutter-debug.h \ clutter-deprecated.h \ @@ -83,7 +85,7 @@ IGNORE_HFILES=\ cogl \ eglnative \ eglx \ - fruity \ + fruity \ glx \ osx \ x11 \ diff --git a/doc/reference/clutter/clutter-docs.xml.in b/doc/reference/clutter/clutter-docs.xml.in index 2fa61f3ca..080d3297b 100644 --- a/doc/reference/clutter/clutter-docs.xml.in +++ b/doc/reference/clutter/clutter-docs.xml.in @@ -60,6 +60,7 @@ + @@ -88,6 +89,16 @@ + + Actor Modifiers + + + + + + + + diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index 7c65d53d4..ae870b997 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -274,7 +274,6 @@ CLUTTER_ACTOR_IS_REACTIVE ClutterActorFlags ClutterRequestMode -ClutterGeometry CLUTTER_CALLBACK ClutterCallback ClutterActor @@ -409,6 +408,22 @@ clutter_actor_set_text_direction clutter_actor_get_text_direction clutter_actor_has_pointer + +clutter_actor_add_action +clutter_actor_add_action_with_name +clutter_actor_remove_action +clutter_actor_remove_action_by_name +clutter_actor_get_actions +clutter_actor_get_action +clutter_actor_clear_actions +clutter_actor_add_constraint +clutter_actor_add_constraint_with_name +clutter_actor_remove_constraint +clutter_actor_remove_constraint_by_name +clutter_actor_get_constraints +clutter_actor_get_constraint +clutter_actor_clear_constraints + ClutterActorBox clutter_actor_box_new @@ -434,6 +449,10 @@ clutter_vertex_copy clutter_vertex_free clutter_vertex_equal + +ClutterGeometry +clutter_geometry_union + CLUTTER_TYPE_GEOMETRY CLUTTER_TYPE_ACTOR_BOX @@ -444,7 +463,9 @@ CLUTTER_TYPE_ACTOR CLUTTER_ACTOR_CLASS CLUTTER_IS_ACTOR_CLASS CLUTTER_ACTOR_GET_CLASS + +ClutterRedrawFlags ClutterActorPrivate clutter_actor_get_type clutter_actor_box_get_type @@ -1712,6 +1733,9 @@ clutter_text_get_type ClutterAnimatable ClutterAnimatableIface clutter_animatable_animate_property +clutter_animatable_find_property +clutter_animatable_get_initial_state +clutter_animatable_set_final_state CLUTTER_TYPE_ANIMATABLE @@ -1993,6 +2017,8 @@ clutter_box_layout_set_spacing clutter_box_layout_get_spacing clutter_box_layout_set_vertical clutter_box_layout_get_vertical +clutter_box_layout_set_homogeneous +clutter_box_layout_get_homogeneous clutter_box_layout_pack @@ -2075,3 +2101,120 @@ clutter_animator_get_type clutter_animator_key_get_type ClutterAnimatorPrivate
+ +
+clutter-actor-meta +ClutterActorMeta +ClutterActorMeta +ClutterActorMetaClass +clutter_actor_meta_set_name +clutter_actor_meta_get_name +clutter_actor_meta_set_enabled +clutter_actor_meta_get_enabled + + +clutter_actor_meta_get_actor + + +CLUTTER_TYPE_ACTOR_META +CLUTTER_ACTOR_META +CLUTTER_ACTOR_META_CLASS +CLUTTER_IS_ACTOR_META +CLUTTER_IS_ACTOR_META_CLASS +CLUTTER_ACTOR_META_GET_CLASS +clutter_actor_meta_get_type + + +ClutterActorMetaPrivate +
+ +
+clutter-action +ClutterAction +ClutterAction +ClutterActionClass + + +CLUTTER_TYPE_ACTION +CLUTTER_ACTION +CLUTTER_ACTION_CLASS +CLUTTER_IS_ACTION +CLUTTER_IS_ACTION_CLASS +CLUTTER_ACTION_GET_CLASS +clutter_action_get_type +
+ +
+clutter-constraint +ClutterConstraint +ClutterConstraint +ClutterConstraintClass + + +CLUTTER_TYPE_CONSTRAINT +CLUTTER_CONSTRAINT +CLUTTER_CONSTRAINT_CLASS +CLUTTER_IS_CONSTRAINT +CLUTTER_IS_CONSTRAINT_CLASS +CLUTTER_CONSTRAINT_GET_CLASS +clutter_constraint_get_type +
+ +
+clutter-drag-action +ClutterDragAction +ClutterDragAction +ClutterDragActionClass +clutter_drag_action_new +clutter_drag_action_set_drag_threshold +clutter_drag_action_get_drag_threshold +clutter_drag_action_set_drag_handle +clutter_drag_action_get_drag_handle +ClutterDragAxis +clutter_drag_action_set_drag_axis +clutter_drag_action_get_drag_axis + + +clutter_drag_action_get_press_coords +clutter_drag_action_get_motion_coords + + +CLUTTER_TYPE_DRAG_ACTION +CLUTTER_DRAG_ACTION +CLUTTER_DRAG_ACTION_CLASS +CLUTTER_IS_DRAG_ACTION +CLUTTER_IS_DRAG_ACTION_CLASS +CLUTTER_DRAG_ACTION_GET_CLASS +clutter_drag_action_get_type + + +ClutterDragActionPrivate +
+ +
+clutter-bind-constraint +ClutterBindConstraint +ClutterBindConstraint +ClutterBindCoordinate +clutter_bind_constraint_new + + +CLUTTER_TYPE_BIND_CONSTRAINT +CLUTTER_BIND_CONSTRAINT +CLUTTER_IS_BIND_CONSTRAINT +clutter_bind_constraint_get_type +
+ +
+clutter-align-constraint +ClutterAlignConstraint +ClutterAlignConstraint +ClutterAlignAxis +clutter_align_constraint_new + + +CLUTTER_TYPE_ALIGN_CONSTRAINT +CLUTTER_ALIGN_CONSTRAINT +CLUTTER_IS_ALIGN_CONSTRAINT +clutter_align_constraint_get_type +
diff --git a/doc/reference/clutter/clutter.types b/doc/reference/clutter/clutter.types index 21b6a809d..ce8d6ab13 100644 --- a/doc/reference/clutter/clutter.types +++ b/doc/reference/clutter/clutter.types @@ -43,3 +43,9 @@ clutter_box_layout_get_type clutter_input_device_get_type clutter_device_manager_get_type clutter_animator_get_type +clutter_actor_meta_get_type +clutter_action_get_type +clutter_drag_action_get_type +clutter_constraint_get_type +clutter_bind_constraint_get_type +clutter_align_constraint_get_type diff --git a/tests/interactive/Makefile.am b/tests/interactive/Makefile.am index b7e6295d3..19f829177 100644 --- a/tests/interactive/Makefile.am +++ b/tests/interactive/Makefile.am @@ -48,7 +48,9 @@ UNIT_TESTS = \ test-bin-layout.c \ test-flow-layout.c \ test-box-layout.c \ - test-stage-sizing.c + test-stage-sizing.c \ + test-drag.c \ + test-constraints.c if X11_TESTS UNIT_TESTS += test-pixmap.c diff --git a/tests/interactive/test-constraints.c b/tests/interactive/test-constraints.c new file mode 100644 index 000000000..9efb55dab --- /dev/null +++ b/tests/interactive/test-constraints.c @@ -0,0 +1,173 @@ +#include +#include +#include + +#define H_PADDING 32 +#define V_PADDING 32 + +enum +{ + NorthWest, North, NorthEast, + West, Center, East, + SouthWest, South, SouthEast, + + N_RECTS +}; + +static ClutterActor *rects[N_RECTS] = { NULL, }; +static const gchar *colors[N_RECTS] = { + "#8ae234", "#73d216", "#4e9a06", + "#729fcf", "#3465a4", "#204a87", + "#ef2929", "#cc0000", "#a40000" +}; + +static gboolean is_expanded = FALSE; + +static gboolean +on_button_release (ClutterActor *actor, + ClutterEvent *event, + gpointer data G_GNUC_UNUSED) +{ + if (!is_expanded) + { + gfloat north_offset, south_offset; + gfloat west_offset, east_offset; + + north_offset = (clutter_actor_get_height (rects[Center]) + V_PADDING) + * -1.0f; + south_offset = (clutter_actor_get_height (rects[Center]) + V_PADDING); + + west_offset = (clutter_actor_get_width (rects[Center]) + H_PADDING) + * -1.0f; + east_offset = (clutter_actor_get_width (rects[Center]) + H_PADDING); + + clutter_actor_animate (rects[NorthWest], CLUTTER_EASE_OUT_CUBIC, 500, + "opacity", 255, + "@constraints.x-bind.offset", west_offset, + "@constraints.y-bind.offset", north_offset, + NULL); + clutter_actor_animate (rects[North], CLUTTER_EASE_OUT_CUBIC, 500, + "opacity", 255, + "@constraints.y-bind.offset", north_offset, + NULL); + clutter_actor_animate (rects[NorthEast], CLUTTER_EASE_OUT_CUBIC, 500, + "opacity", 255, + "@constraints.x-bind.offset", east_offset, + "@constraints.y-bind.offset", north_offset, + NULL); + + clutter_actor_animate (rects[West], CLUTTER_EASE_OUT_CUBIC, 500, + "opacity", 255, + "@constraints.x-bind.offset", west_offset, + NULL); + clutter_actor_animate (rects[Center], CLUTTER_LINEAR, 500, + "opacity", 128, + NULL); + clutter_actor_animate (rects[East], CLUTTER_EASE_OUT_CUBIC, 500, + "opacity", 255, + "@constraints.x-bind.offset", east_offset, + NULL); + + clutter_actor_animate (rects[SouthWest], CLUTTER_EASE_OUT_CUBIC, 500, + "opacity", 255, + "@constraints.x-bind.offset", west_offset, + "@constraints.y-bind.offset", south_offset, + NULL); + clutter_actor_animate (rects[South], CLUTTER_EASE_OUT_CUBIC, 500, + "opacity", 255, + "@constraints.y-bind.offset", south_offset, + NULL); + clutter_actor_animate (rects[SouthEast], CLUTTER_EASE_OUT_CUBIC, 500, + "opacity", 255, + "@constraints.x-bind.offset", east_offset, + "@constraints.y-bind.offset", south_offset, + NULL); + } + else + { + gint i; + + clutter_actor_animate (rects[Center], CLUTTER_LINEAR, 500, + "opacity", 255, + NULL); + + for (i = NorthWest; i < N_RECTS; i++) + { + if (i == Center) + continue; + + clutter_actor_animate (rects[i], CLUTTER_EASE_OUT_CUBIC, 500, + "opacity", 0, + "@constraints.x-bind.offset", 0.0f, + "@constraints.y-bind.offset", 0.0f, + NULL); + } + } + + is_expanded = !is_expanded; + + return TRUE; +} + +G_MODULE_EXPORT int +test_constraints_main (int argc, char *argv[]) +{ + ClutterActor *stage, *rect; + ClutterConstraint *constraint; + ClutterColor rect_color; + gint i; + + clutter_init (&argc, &argv); + + stage = clutter_stage_new (); + g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); + clutter_stage_set_title (CLUTTER_STAGE (stage), "Constraints"); + clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); + clutter_actor_set_size (stage, 800, 600); + + /* main rect */ + clutter_color_from_string (&rect_color, "#3465a4"); + rect = clutter_rectangle_new (); + g_signal_connect (rect, "button-release-event", + G_CALLBACK (on_button_release), + NULL); + clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &rect_color); + clutter_actor_set_size (rect, 128, 128); + clutter_actor_set_reactive (rect, TRUE); + clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); + + constraint = clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5); + clutter_actor_add_constraint_with_name (rect, "x-align", constraint); + + constraint = clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5); + clutter_actor_add_constraint_with_name (rect, "y-align", constraint); + + rects[Center] = rect; + + for (i = 0; i < N_RECTS; i++) + { + if (i == Center) + continue; + + clutter_color_from_string (&rect_color, colors[i]); + rect = clutter_rectangle_new (); + clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &rect_color); + clutter_actor_set_size (rect, 128, 128); + clutter_actor_set_opacity (rect, 0); + clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); + + constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_X, 0.0); + clutter_actor_add_constraint_with_name (rect, "x-bind", constraint); + + constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_Y, 0.0); + clutter_actor_add_constraint_with_name (rect, "y-bind", constraint); + + rects[i] = rect; + } + + clutter_actor_show (stage); + + clutter_main (); + + return EXIT_SUCCESS; +} diff --git a/tests/interactive/test-drag.c b/tests/interactive/test-drag.c new file mode 100644 index 000000000..e8c479cfd --- /dev/null +++ b/tests/interactive/test-drag.c @@ -0,0 +1,189 @@ +#include +#include +#include + +static void +on_drag_begin (ClutterDragAction *action, + ClutterActor *actor, + gfloat event_x, + gfloat event_y, + gint button, + ClutterModifierType modifiers) +{ + gboolean is_copy = (modifiers & CLUTTER_SHIFT_MASK) ? TRUE : FALSE; + ClutterActor *drag_handle = NULL; + + if (is_copy) + { + ClutterActor *stage = clutter_actor_get_stage (actor); + ClutterColor handle_color; + + drag_handle = clutter_rectangle_new (); + clutter_actor_set_size (drag_handle, 48, 48); + + clutter_color_from_string (&handle_color, "#204a87aa"); + clutter_rectangle_set_color (CLUTTER_RECTANGLE (drag_handle), &handle_color); + + clutter_container_add_actor (CLUTTER_CONTAINER (stage), drag_handle); + clutter_actor_set_position (drag_handle, event_x, event_y); + } + else + drag_handle = actor; + + clutter_drag_action_set_drag_handle (action, drag_handle); + + clutter_actor_set_opacity (actor, 128); +} + +static void +on_drag_motion (ClutterDragAction *action, + ClutterActor *actor, + gfloat delta_x, + gfloat delta_y, + ClutterModifierType modifiers) +{ + ClutterActor *drag_handle; + + drag_handle = clutter_drag_action_get_drag_handle (action); + g_assert (drag_handle != NULL); + + clutter_actor_move_by (drag_handle, delta_x, delta_y); +} + +static void +on_drag_end (ClutterDragAction *action, + ClutterActor *actor, + gfloat event_x, + gfloat event_y, + gint button, + ClutterModifierType modifiers) +{ + ClutterActor *drag_handle; + + drag_handle = clutter_drag_action_get_drag_handle (action); + if (actor != drag_handle) + { + gfloat real_x, real_y; + ClutterActor *parent; + + /* if we are dragging a copy we can destroy the copy now + * and animate the real actor to the drop coordinates, + * transformed in the parent's coordinate space + */ + clutter_actor_animate (drag_handle, CLUTTER_LINEAR, 150, + "opacity", 0, + "signal-swapped-after::completed", + G_CALLBACK (clutter_actor_destroy), + drag_handle, + NULL); + + parent = clutter_actor_get_parent (actor); + clutter_actor_transform_stage_point (parent, event_x, event_y, + &real_x, + &real_y); + + clutter_actor_animate (actor, CLUTTER_EASE_OUT_CUBIC, 150, + "opacity", 255, + "x", real_x, + "y", real_y, + NULL); + } + else + clutter_actor_animate (actor, CLUTTER_LINEAR, 150, + "opacity", 255, + NULL); +} + +static ClutterDragAxis +get_drag_axis (const gchar *str) +{ + if (str == NULL || *str == '\0') + return CLUTTER_DRAG_AXIS_NONE; + + if (*str == 'x' || *str == 'X') + return CLUTTER_DRAG_X_AXIS; + + if (*str == 'y' || *str == 'Y') + return CLUTTER_DRAG_Y_AXIS; + + g_warn_if_reached (); + + return CLUTTER_DRAG_AXIS_NONE; +} + +static gchar *drag_axis = NULL; +static gint drag_threshold = 0; + +static GOptionEntry entries[] = { + { + "threshold", 't', + 0, + G_OPTION_ARG_INT, + &drag_threshold, + "Set the drag threshold", "PIXELS" + }, + { + "axis", 'a', + 0, + G_OPTION_ARG_STRING, + &drag_axis, + "Set the drag axis", "AXIS" + }, + + { NULL } +}; + +G_MODULE_EXPORT int +test_drag_main (int argc, char *argv[]) +{ + ClutterActor *stage, *handle; + ClutterAction *action; + ClutterColor handle_color; + GError *error; + + error = NULL; + clutter_init_with_args (&argc, &argv, + "test-drag", + entries, + NULL, + &error); + if (error != NULL) + { + g_print ("Unable to run test-drag: %s\n", error->message); + g_error_free (error); + + return EXIT_FAILURE; + } + + stage = clutter_stage_new (); + clutter_stage_set_title (CLUTTER_STAGE (stage), "Drag Test"); + clutter_actor_set_size (stage, 800, 600); + g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); + + clutter_color_from_string (&handle_color, "#729fcfff"); + + handle = clutter_rectangle_new (); + clutter_rectangle_set_color (CLUTTER_RECTANGLE (handle), &handle_color); + clutter_actor_set_size (handle, 128, 128); + clutter_actor_set_position (handle, (800 - 128) / 2, (600 - 128) / 2); + clutter_actor_set_reactive (handle, TRUE); + clutter_container_add_actor (CLUTTER_CONTAINER (stage), handle); + + action = clutter_drag_action_new (); + clutter_drag_action_set_drag_threshold (CLUTTER_DRAG_ACTION (action), + drag_threshold); + clutter_drag_action_set_drag_axis (CLUTTER_DRAG_ACTION (action), + get_drag_axis (drag_axis)); + + g_signal_connect (action, "drag-begin", G_CALLBACK (on_drag_begin), NULL); + g_signal_connect (action, "drag-motion", G_CALLBACK (on_drag_motion), NULL); + g_signal_connect (action, "drag-end", G_CALLBACK (on_drag_end), NULL); + + clutter_actor_add_action (handle, action); + + clutter_actor_show (stage); + + clutter_main (); + + return EXIT_SUCCESS; +}