constraint: Re-implement using update_allocation()

Instead of using the fixed position and size API, use the newly added
update_allocation() virtual function in ClutterConstraint to change the
allocation of a ClutterActor. This allows using constraints inside
layout managers, and also allows Constraints to react to changes in the
size of an actor without causing relayout cycles.

http://bugzilla.clutter-project.org/show_bug.cgi?id=2319
This commit is contained in:
Emmanuele Bassi 2010-09-17 12:13:29 +01:00
parent 5da0064de7
commit cdff2a9e7a
3 changed files with 153 additions and 110 deletions

View File

@ -55,6 +55,7 @@ struct _ClutterAlignConstraint
{
ClutterConstraint parent_instance;
ClutterActor *actor;
ClutterActor *source;
ClutterAlignAxis align_axis;
gfloat factor;
@ -82,52 +83,14 @@ 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;
gfloat source_x, source_y;
gfloat new_position;
ClutterActor *actor;
if (align->source == NULL)
return;
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_position (align->source, &source_x, &source_y);
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:
new_position = ((source_width - actor_width) * align->factor)
+ source_x;
clutter_actor_set_x (actor, new_position);
break;
case CLUTTER_ALIGN_Y_AXIS:
new_position = ((source_height - actor_height) * align->factor)
+ source_y;
clutter_actor_set_y (actor, new_position);
break;
}
}
static void
source_position_changed (ClutterActor *actor,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags,
ClutterAlignConstraint *align)
{
update_actor_position (align);
if (align->actor != NULL)
clutter_actor_queue_relayout (align->actor);
}
static void
@ -137,6 +100,62 @@ source_destroyed (ClutterActor *actor,
align->source = NULL;
}
static void
clutter_align_constraint_set_actor (ClutterActorMeta *meta,
ClutterActor *new_actor)
{
ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (meta);
ClutterActorMetaClass *parent;
/* store the pointer to the actor, for later use */
align->actor = new_actor;
parent = CLUTTER_ACTOR_META_CLASS (clutter_align_constraint_parent_class);
parent->set_actor (meta, new_actor);
}
static void
clutter_align_constraint_update_allocation (ClutterConstraint *constraint,
ClutterActor *actor,
ClutterActorBox *allocation)
{
ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (constraint);
ClutterActorMeta *meta = CLUTTER_ACTOR_META (constraint);
gfloat source_width, source_height;
gfloat actor_width, actor_height;
gfloat source_x, source_y;
if (align->source == NULL)
return;
if (!clutter_actor_meta_get_enabled (meta))
return;
clutter_actor_get_position (align->source, &source_x, &source_y);
clutter_actor_get_size (align->source, &source_width, &source_height);
switch (align->align_axis)
{
case CLUTTER_ALIGN_X_AXIS:
actor_width = clutter_actor_box_get_width (allocation);
allocation->x1 = ((source_width - actor_width) * align->factor)
+ source_x;
allocation->x2 = allocation->x1 + actor_width;
break;
case CLUTTER_ALIGN_Y_AXIS:
actor_height = clutter_actor_box_get_height (allocation);
allocation->y1 = ((source_height - actor_height) * align->factor)
+ source_y;
allocation->y2 = allocation->y1 + actor_height;
break;
default:
g_assert_not_reached ();
break;
}
}
static void
clutter_align_constraint_set_property (GObject *gobject,
guint prop_id,
@ -197,11 +216,17 @@ static void
clutter_align_constraint_class_init (ClutterAlignConstraintClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
ClutterConstraintClass *constraint_class = CLUTTER_CONSTRAINT_CLASS (klass);
GParamSpec *pspec;
gobject_class->set_property = clutter_align_constraint_set_property;
gobject_class->get_property = clutter_align_constraint_get_property;
meta_class->set_actor = clutter_align_constraint_set_actor;
constraint_class->update_allocation = clutter_align_constraint_update_allocation;
/**
* ClutterAlignConstraint:source:
*
@ -261,6 +286,7 @@ clutter_align_constraint_class_init (ClutterAlignConstraintClass *klass)
static void
clutter_align_constraint_init (ClutterAlignConstraint *self)
{
self->actor = NULL;
self->source = NULL;
self->align_axis = CLUTTER_ALIGN_X_AXIS;
self->factor = 0.0f;
@ -328,7 +354,6 @@ clutter_align_constraint_set_source (ClutterAlignConstraint *align,
}
align->source = source;
if (align->source != NULL)
{
g_signal_connect (align->source, "allocation-changed",
@ -338,7 +363,8 @@ clutter_align_constraint_set_source (ClutterAlignConstraint *align,
G_CALLBACK (source_destroyed),
align);
update_actor_position (align);
if (align->actor != NULL)
clutter_actor_queue_relayout (align->actor);
}
_clutter_notify_by_pspec (G_OBJECT (align), obj_props[PROP_SOURCE]);
@ -383,7 +409,8 @@ clutter_align_constraint_set_align_axis (ClutterAlignConstraint *align,
align->align_axis = axis;
update_actor_position (align);
if (align->actor != NULL)
clutter_actor_queue_relayout (align->actor);
_clutter_notify_by_pspec (G_OBJECT (align), obj_props[PROP_ALIGN_AXIS]);
}
@ -434,7 +461,8 @@ clutter_align_constraint_set_factor (ClutterAlignConstraint *align,
align->factor = CLAMP (factor, 0.0, 1.0);
update_actor_position (align);
if (align->actor != NULL)
clutter_actor_queue_relayout (align->actor);
_clutter_notify_by_pspec (G_OBJECT (align), obj_props[PROP_FACTOR]);
}

View File

@ -101,6 +101,7 @@ struct _ClutterBindConstraint
{
ClutterConstraint parent_instance;
ClutterActor *actor;
ClutterActor *source;
ClutterBindCoordinate coordinate;
gfloat offset;
@ -128,67 +129,14 @@ G_DEFINE_TYPE (ClutterBindConstraint,
clutter_bind_constraint,
CLUTTER_TYPE_CONSTRAINT);
static void
update_actor_coords (ClutterBindConstraint *bind)
{
gfloat source_width, source_height;
ClutterVertex source_position;
ClutterActor *actor;
if (bind->source == NULL)
return;
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);
clutter_actor_get_size (bind->source, &source_width, &source_height);
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;
case CLUTTER_BIND_WIDTH:
clutter_actor_set_width (actor, source_width + bind->offset);
break;
case CLUTTER_BIND_HEIGHT:
clutter_actor_set_height (actor, source_height + bind->offset);
break;
}
}
static void
source_allocation_changed (ClutterActor *source,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags,
ClutterBindConstraint *bind)
{
update_actor_coords (bind);
}
static void
source_depth_changed (GObject *gobject,
GParamSpec *pspec,
ClutterBindConstraint *bind)
{
update_actor_coords (bind);
if (bind->actor != NULL)
clutter_actor_queue_relayout (bind->actor);
}
static void
@ -198,6 +146,69 @@ source_destroyed (ClutterActor *actor,
bind->source = NULL;
}
static void
clutter_bind_constraint_update_allocation (ClutterConstraint *constraint,
ClutterActor *actor,
ClutterActorBox *allocation)
{
ClutterBindConstraint *bind = CLUTTER_BIND_CONSTRAINT (constraint);
ClutterActorMeta *meta = CLUTTER_ACTOR_META (constraint);
gfloat source_width, source_height;
gfloat actor_width, actor_height;
ClutterVertex source_position = { 0., };
if (bind->source == NULL)
return;
if (!clutter_actor_meta_get_enabled (meta))
return;
source_position.x = clutter_actor_get_x (bind->source);
source_position.y = clutter_actor_get_y (bind->source);
clutter_actor_get_size (bind->source, &source_width, &source_height);
clutter_actor_box_get_size (allocation, &actor_width, &actor_height);
switch (bind->coordinate)
{
case CLUTTER_BIND_X:
allocation->x1 = source_position.x + bind->offset;
allocation->x2 = allocation->x1 + actor_width;
break;
case CLUTTER_BIND_Y:
allocation->y1 = source_position.y + bind->offset;
allocation->y2 = allocation->y1 + actor_height;
break;
case CLUTTER_BIND_WIDTH:
allocation->x2 = allocation->x1 + source_width + bind->offset;
break;
case CLUTTER_BIND_HEIGHT:
allocation->y2 = allocation->y1 + source_height + bind->offset;
break;
default:
g_assert_not_reached ();
break;
}
}
static void
clutter_bind_constraint_set_actor (ClutterActorMeta *meta,
ClutterActor *new_actor)
{
ClutterBindConstraint *bind = CLUTTER_BIND_CONSTRAINT (meta);
ClutterActorMetaClass *parent;
/* store the pointer to the actor, for later use */
bind->actor = new_actor;
parent = CLUTTER_ACTOR_META_CLASS (clutter_bind_constraint_parent_class);
parent->set_actor (meta, new_actor);
}
static void
clutter_bind_constraint_set_property (GObject *gobject,
guint prop_id,
@ -257,12 +268,17 @@ clutter_bind_constraint_get_property (GObject *gobject,
static void
clutter_bind_constraint_class_init (ClutterBindConstraintClass *klass)
{
ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
ClutterConstraintClass *constraint_class = CLUTTER_CONSTRAINT_CLASS (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;
meta_class->set_actor = clutter_bind_constraint_set_actor;
constraint_class->update_allocation = clutter_bind_constraint_update_allocation;
/**
* ClutterBindConstraint:source:
*
@ -317,6 +333,7 @@ clutter_bind_constraint_class_init (ClutterBindConstraintClass *klass)
static void
clutter_bind_constraint_init (ClutterBindConstraint *self)
{
self->actor = NULL;
self->source = NULL;
self->coordinate = CLUTTER_BIND_X;
self->offset = 0.0f;
@ -368,6 +385,9 @@ clutter_bind_constraint_set_source (ClutterBindConstraint *constraint,
g_return_if_fail (CLUTTER_IS_BIND_CONSTRAINT (constraint));
g_return_if_fail (source == NULL || CLUTTER_IS_ACTOR (source));
if (constraint->source == source)
return;
old_source = constraint->source;
if (old_source != NULL)
{
@ -377,9 +397,6 @@ clutter_bind_constraint_set_source (ClutterBindConstraint *constraint,
g_signal_handlers_disconnect_by_func (old_source,
G_CALLBACK (source_allocation_changed),
constraint);
g_signal_handlers_disconnect_by_func (old_source,
G_CALLBACK (source_depth_changed),
constraint);
}
constraint->source = source;
@ -388,14 +405,12 @@ clutter_bind_constraint_set_source (ClutterBindConstraint *constraint,
g_signal_connect (constraint->source, "allocation-changed",
G_CALLBACK (source_allocation_changed),
constraint);
g_signal_connect (constraint->source, "notify::depth",
G_CALLBACK (source_depth_changed),
constraint);
g_signal_connect (constraint->source, "destroy",
G_CALLBACK (source_destroyed),
constraint);
update_actor_coords (constraint);
if (constraint->actor != NULL)
clutter_actor_queue_relayout (constraint->actor);
}
_clutter_notify_by_pspec (G_OBJECT (constraint), obj_props[PROP_SOURCE]);
@ -439,7 +454,8 @@ clutter_bind_constraint_set_coordinate (ClutterBindConstraint *constraint,
constraint->coordinate = coordinate;
update_actor_coords (constraint);
if (constraint->actor != NULL)
clutter_actor_queue_relayout (constraint->actor);
_clutter_notify_by_pspec (G_OBJECT (constraint), obj_props[PROP_COORDINATE]);
}
@ -483,7 +499,8 @@ clutter_bind_constraint_set_offset (ClutterBindConstraint *constraint,
constraint->offset = offset;
update_actor_coords (constraint);
if (constraint->actor != NULL)
clutter_actor_queue_relayout (constraint->actor);
_clutter_notify_by_pspec (G_OBJECT (constraint), obj_props[PROP_OFFSET]);
}

View File

@ -51,7 +51,6 @@ 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
* @CLUTTER_BIND_WIDTH: Bind the width
* @CLUTTER_BIND_HEIGHT: Bidng the height
*
@ -62,7 +61,6 @@ typedef struct _ClutterBindConstraint ClutterBindConstraint;
typedef enum { /*< prefix=CLUTTER_BIND >*/
CLUTTER_BIND_X,
CLUTTER_BIND_Y,
CLUTTER_BIND_Z,
CLUTTER_BIND_WIDTH,
CLUTTER_BIND_HEIGHT
} ClutterBindCoordinate;