From 769e964424f4de41b7e875b8a08a2bd17fdd2f70 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 19 May 2010 12:25:28 +0100 Subject: [PATCH] constraint: Add BindConstraint The BindConstraint object is a constraint that binds the current position of an actor on a given axis to the actor that has the constraint applied. --- clutter/Makefile.am | 2 + clutter/clutter-bind-constraint.c | 267 ++++++++++++++++++++++++++++++ clutter/clutter-bind-constraint.h | 32 ++++ clutter/clutter.h | 1 + 4 files changed, 302 insertions(+) create mode 100644 clutter/clutter-bind-constraint.c create mode 100644 clutter/clutter-bind-constraint.h diff --git a/clutter/Makefile.am b/clutter/Makefile.am index 9571cd232..e753d910b 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -80,6 +80,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 \ @@ -158,6 +159,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 \ diff --git a/clutter/clutter-bind-constraint.c b/clutter/clutter-bind-constraint.c new file mode 100644 index 000000000..199b3f526 --- /dev/null +++ b/clutter/clutter-bind-constraint.c @@ -0,0 +1,267 @@ +#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; + ClutterBindAxis bind_axis; + gfloat offset; +}; + +struct _ClutterBindConstraintClass +{ + ClutterConstraintClass parent_class; +}; + +enum +{ + PROP_0, + + PROP_SOURCE, + PROP_BIND_AXIS, + 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->bind_axis) + { + case CLUTTER_BIND_X_AXIS: + clutter_actor_set_x (actor, source_position.x + bind->offset); + break; + + case CLUTTER_BIND_Y_AXIS: + clutter_actor_set_y (actor, source_position.y + bind->offset); + break; + + case CLUTTER_BIND_Z_AXIS: + 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_bind_axis (ClutterBindConstraint *bind, + ClutterBindAxis axis) +{ + if (bind->bind_axis == axis) + return; + + bind->bind_axis = axis; + + update_actor_position (bind); + + g_object_notify (G_OBJECT (bind), "bind-axis"); +} + +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_BIND_AXIS: + _clutter_bind_constraint_set_bind_axis (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_BIND_AXIS: + g_value_set_enum (value, bind->bind_axis); + 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; + + 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); + + pspec = g_param_spec_enum ("bind-axis", + "Bind Axis", + "The axis to bind the position from", + CLUTTER_TYPE_BIND_AXIS, + CLUTTER_BIND_X_AXIS, + CLUTTER_PARAM_READWRITE | + G_PARAM_CONSTRUCT); + g_object_class_install_property (gobject_class, PROP_BIND_AXIS, pspec); + + 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->bind_axis = CLUTTER_BIND_X_AXIS; + self->offset = 0.0f; +} + +ClutterConstraint * +clutter_bind_constraint_new (ClutterActor *source, + ClutterBindAxis axis, + gfloat offset) +{ + g_return_val_if_fail (CLUTTER_IS_ACTOR (source), NULL); + + return g_object_new (CLUTTER_TYPE_BIND_CONSTRAINT, + "source", source, + "bind-axis", axis, + "offset", offset, + NULL); +} diff --git a/clutter/clutter-bind-constraint.h b/clutter/clutter-bind-constraint.h new file mode 100644 index 000000000..8aaed181c --- /dev/null +++ b/clutter/clutter-bind-constraint.h @@ -0,0 +1,32 @@ +#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)) + +typedef struct _ClutterBindConstraint ClutterBindConstraint; + +typedef enum { /*< prefix=CLUTTER_BIND >*/ + CLUTTER_BIND_X_AXIS, + CLUTTER_BIND_Y_AXIS, + CLUTTER_BIND_Z_AXIS +} ClutterBindAxis; + +GType clutter_bind_constraint_get_type (void) G_GNUC_CONST; + +ClutterConstraint *clutter_bind_constraint_new (ClutterActor *source, + ClutterBindAxis axis, + gfloat offset); + +G_END_DECLS + +#endif /* __CLUTTER_BIND_CONSTRAINT_H__ */ diff --git a/clutter/clutter.h b/clutter/clutter.h index 9347e0930..ccf729837 100644 --- a/clutter/clutter.h +++ b/clutter/clutter.h @@ -45,6 +45,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"