diff --git a/clutter/Makefile.am b/clutter/Makefile.am index e753d910b..6b777f0ae 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -68,6 +68,7 @@ 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 \ @@ -146,6 +147,7 @@ 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 \ diff --git a/clutter/clutter-align-constraint.c b/clutter/clutter-align-constraint.c new file mode 100644 index 000000000..c08334029 --- /dev/null +++ b/clutter/clutter-align-constraint.c @@ -0,0 +1,259 @@ +#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; + + 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 ("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); + + 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; +} + +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..34e376d77 --- /dev/null +++ b/clutter/clutter-align-constraint.h @@ -0,0 +1,31 @@ +#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)) + +typedef struct _ClutterAlignConstraint ClutterAlignConstraint; + +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.h b/clutter/clutter.h index ccf729837..49c3dabe3 100644 --- a/clutter/clutter.h +++ b/clutter/clutter.h @@ -33,6 +33,7 @@ #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" diff --git a/tests/interactive/test-constraints.c b/tests/interactive/test-constraints.c index 6c3733584..a2b7b28af 100644 --- a/tests/interactive/test-constraints.c +++ b/tests/interactive/test-constraints.c @@ -72,7 +72,6 @@ test_constraints_main (int argc, char *argv[]) clutter_actor_set_reactive (rect, TRUE); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); -#if 0 constraint = clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5); clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "x-align"); clutter_actor_add_constraint (rect, constraint); @@ -80,9 +79,6 @@ test_constraints_main (int argc, char *argv[]) constraint = clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5); clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "y-align"); clutter_actor_add_constraint (rect, constraint); -#else - clutter_actor_set_position (rect, (800 - 256) / 2.0, (600 - 256) / 2.0); -#endif center_rect = rect; @@ -98,13 +94,9 @@ test_constraints_main (int argc, char *argv[]) clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "x-bind"); clutter_actor_add_constraint (rect, constraint); -#if 0 constraint = clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5); clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "y-align"); clutter_actor_add_constraint (rect, constraint); -#else - clutter_actor_set_y (rect, (600 - 256) / 2.0); -#endif left_rect = rect; @@ -120,13 +112,9 @@ test_constraints_main (int argc, char *argv[]) clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "x-bind"); clutter_actor_add_constraint (rect, constraint); -#if 0 constraint = clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5); clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "y-align"); clutter_actor_add_constraint (rect, constraint); -#else - clutter_actor_set_y (rect, (600 - 256) / 2.0); -#endif right_rect = rect;