constraints: Add AlignConstraint
authorEmmanuele Bassi <ebassi@linux.intel.com>
Wed, 19 May 2010 12:02:43 +0000 (13:02 +0100)
committerEmmanuele Bassi <ebassi@linux.intel.com>
Wed, 19 May 2010 12:02:43 +0000 (13:02 +0100)
AlignConstraint is a simple constraint that keeps an actor's position
aligned to the width or height of another actor, multiplied by an
alignment factor.

clutter/Makefile.am
clutter/clutter-align-constraint.c [new file with mode: 0644]
clutter/clutter-align-constraint.h [new file with mode: 0644]
clutter/clutter.h
tests/interactive/test-constraints.c

index e753d91..6b777f0 100644 (file)
@@ -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 (file)
index 0000000..c083340
--- /dev/null
@@ -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 (file)
index 0000000..34e376d
--- /dev/null
@@ -0,0 +1,31 @@
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only <clutter/clutter.h> can be included directly."
+#endif
+
+#ifndef __CLUTTER_ALIGN_CONSTRAINT_H__
+#define __CLUTTER_ALIGN_CONSTRAINT_H__
+
+#include <clutter/clutter-constraint.h>
+
+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__ */
index ccf7298..49c3dab 100644 (file)
@@ -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"
index 6c37335..a2b7b28 100644 (file)
@@ -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;