mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 17:40:40 -05:00
391f1d8dd4
Constraints can only update an existing allocation, which means they live only halfway through the layout management system used by Clutter; this limitation makes it impossible, for instance, to query the preferred size of an actor, if the actor is only using constraints to manage its own size.
244 lines
9.7 KiB
C
244 lines
9.7 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Author:
|
|
* Emmanuele Bassi <ebassi@linux.intel.com>
|
|
*/
|
|
|
|
/**
|
|
* SECTION:clutter-constraint
|
|
* @Title: ClutterConstraint
|
|
* @Short_Description: Abstract class for constraints on position or size
|
|
* @See_Also: #ClutterAction
|
|
*
|
|
* #ClutterConstraint is a base abstract class for modifiers of a #ClutterActor
|
|
* position or size.
|
|
*
|
|
* A #ClutterConstraint sub-class should contain the logic for modifying
|
|
* the position or size of the #ClutterActor to which it is applied, by
|
|
* updating the actor's allocation. Each #ClutterConstraint can change the
|
|
* allocation of the actor to which they are applied by overriding the
|
|
* #ClutterConstraintClass.update_allocation() virtual function.
|
|
*
|
|
* #ClutterConstraint is available since Clutter 1.4
|
|
*
|
|
* ## Using Constraints
|
|
*
|
|
* Constraints can be used with fixed layout managers, like
|
|
* #ClutterFixedLayout, or with actors implicitly using a fixed layout
|
|
* manager, like #ClutterGroup and #ClutterStage.
|
|
*
|
|
* Constraints provide a way to build user interfaces by using
|
|
* relations between #ClutterActors, without explicit fixed
|
|
* positioning and sizing, similarly to how fluid layout managers like
|
|
* #ClutterBoxLayout and #ClutterTableLayout lay out their children.
|
|
*
|
|
* Constraints are attached to a #ClutterActor, and are available
|
|
* for inspection using clutter_actor_get_constraints().
|
|
*
|
|
* Clutter provides different implementation of the #ClutterConstraint
|
|
* abstract class, for instance:
|
|
*
|
|
* - #ClutterAlignConstraint, a constraint that can be used to align
|
|
* an actor to another one on either the horizontal or the vertical
|
|
* axis, using a normalized value between 0 and 1.
|
|
* - #ClutterBindConstraint, a constraint binds the X, Y, width or height
|
|
* of an actor to the corresponding position or size of a source actor,
|
|
* with or without an offset.
|
|
* - #ClutterSnapConstraint, a constraint that "snaps" together the edges
|
|
* of two #ClutterActors; if an actor uses two constraints on both its
|
|
* horizontal or vertical edges then it can also expand to fit the empty
|
|
* space.
|
|
*
|
|
* The [constraints example](https://git.gnome.org/browse/clutter/tree/examples/constraints.c?h=clutter-1.18)
|
|
* uses various types of #ClutterConstraints to lay out three actors on a
|
|
* resizable stage. Only the central actor has an explicit size, and no
|
|
* actor has an explicit position.
|
|
*
|
|
* - The #ClutterActor with #ClutterActor:name `layerA` is explicitly
|
|
* sized to 100 pixels by 25 pixels, and it's added to the #ClutterStage
|
|
* - two #ClutterAlignConstraints are used to anchor `layerA` to the
|
|
* center of the stage, by using 0.5 as the alignment #ClutterAlignConstraint:factor on
|
|
* both the X and Y axis
|
|
* - the #ClutterActor with #ClutterActor:name `layerB` is added to the
|
|
* #ClutterStage with no explicit size
|
|
* - the #ClutterActor:x and #ClutterActor:width of `layerB` are bound
|
|
* to the same properties of `layerA` using two #ClutterBindConstraint
|
|
* objects, thus keeping `layerB` aligned to `layerA`
|
|
* - the top edge of `layerB` is snapped together with the bottom edge
|
|
* of `layerA`; the bottom edge of `layerB` is also snapped together with
|
|
* the bottom edge of the #ClutterStage; an offset is given to the two
|
|
* #ClutterSnapConstraintss to allow for some padding; since `layerB` is
|
|
* snapped between two different #ClutterActors, its height is stretched
|
|
* to match the gap
|
|
* - the #ClutterActor with #ClutterActor:name `layerC` mirrors `layerB`,
|
|
* snapping the top edge of the #ClutterStage to the top edge of `layerC`
|
|
* and the top edge of `layerA` to the bottom edge of `layerC`
|
|
*
|
|
* You can try resizing interactively the #ClutterStage and verify
|
|
* that the three #ClutterActors maintain the same position and
|
|
* size relative to each other, and to the #ClutterStage.
|
|
*
|
|
* It is important to note that Clutter does not avoid loops or
|
|
* competing constraints; if two or more #ClutterConstraints
|
|
* are operating on the same positional or dimensional attributes of an
|
|
* actor, or if the constraints on two different actors depend on each
|
|
* other, then the behavior is undefined.
|
|
*
|
|
* ## Implementing a ClutterConstraint
|
|
*
|
|
* Creating a sub-class of #ClutterConstraint requires the
|
|
* implementation of the #ClutterConstraintClass.update_allocation()
|
|
* virtual function.
|
|
*
|
|
* The `update_allocation()` virtual function is called during the
|
|
* allocation sequence of a #ClutterActor, and allows any #ClutterConstraint
|
|
* attached to that actor to modify the allocation before it is passed to
|
|
* the actor's #ClutterActorClass.allocate() implementation.
|
|
*
|
|
* The #ClutterActorBox passed to the `update_allocation()` implementation
|
|
* contains the original allocation of the #ClutterActor, plus the eventual
|
|
* modifications applied by the other #ClutterConstraints, in the same order
|
|
* the constraints have been applied to the actor.
|
|
*
|
|
* It is not necessary for a #ClutterConstraint sub-class to chain
|
|
* up to the parent's implementation.
|
|
*
|
|
* If a #ClutterConstraint is parametrized - i.e. if it contains
|
|
* properties that affect the way the constraint is implemented - it should
|
|
* call clutter_actor_queue_relayout() on the actor to which it is attached
|
|
* to whenever any parameter is changed. The actor to which it is attached
|
|
* can be recovered at any point using clutter_actor_meta_get_actor().
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
#include "clutter-constraint-private.h"
|
|
|
|
#include "clutter-actor.h"
|
|
#include "clutter-actor-meta-private.h"
|
|
#include "clutter-private.h"
|
|
|
|
G_DEFINE_ABSTRACT_TYPE (ClutterConstraint,
|
|
clutter_constraint,
|
|
CLUTTER_TYPE_ACTOR_META);
|
|
|
|
static void
|
|
constraint_update_allocation (ClutterConstraint *constraint,
|
|
ClutterActor *actor,
|
|
ClutterActorBox *allocation)
|
|
{
|
|
}
|
|
|
|
static void
|
|
constraint_update_preferred_size (ClutterConstraint *constraint,
|
|
ClutterActor *actor,
|
|
ClutterOrientation direction,
|
|
float for_size,
|
|
float *minimum_size,
|
|
float *natural_size)
|
|
{
|
|
}
|
|
|
|
static void
|
|
clutter_constraint_notify (GObject *gobject,
|
|
GParamSpec *pspec)
|
|
{
|
|
if (strcmp (pspec->name, "enabled") == 0)
|
|
{
|
|
ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
|
|
ClutterActor *actor = clutter_actor_meta_get_actor (meta);
|
|
|
|
if (actor != NULL)
|
|
clutter_actor_queue_relayout (actor);
|
|
}
|
|
|
|
if (G_OBJECT_CLASS (clutter_constraint_parent_class)->notify != NULL)
|
|
G_OBJECT_CLASS (clutter_constraint_parent_class)->notify (gobject, pspec);
|
|
}
|
|
|
|
static void
|
|
clutter_constraint_class_init (ClutterConstraintClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->notify = clutter_constraint_notify;
|
|
|
|
klass->update_allocation = constraint_update_allocation;
|
|
klass->update_preferred_size = constraint_update_preferred_size;
|
|
}
|
|
|
|
static void
|
|
clutter_constraint_init (ClutterConstraint *self)
|
|
{
|
|
}
|
|
|
|
/*< private >
|
|
* clutter_constraint_update_allocation:
|
|
* @constraint: a #ClutterConstraint
|
|
* @actor: a #ClutterActor
|
|
* @allocation: (inout): the allocation to modify
|
|
*
|
|
* Asks the @constraint to update the @allocation of a #ClutterActor.
|
|
*
|
|
* Returns: %TRUE if the allocation was updated
|
|
*/
|
|
gboolean
|
|
clutter_constraint_update_allocation (ClutterConstraint *constraint,
|
|
ClutterActor *actor,
|
|
ClutterActorBox *allocation)
|
|
{
|
|
ClutterActorBox old_alloc;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_CONSTRAINT (constraint), FALSE);
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
|
|
g_return_val_if_fail (allocation != NULL, FALSE);
|
|
|
|
old_alloc = *allocation;
|
|
|
|
CLUTTER_CONSTRAINT_GET_CLASS (constraint)->update_allocation (constraint,
|
|
actor,
|
|
allocation);
|
|
|
|
return clutter_actor_box_equal (allocation, &old_alloc);
|
|
}
|
|
|
|
void
|
|
clutter_constraint_update_preferred_size (ClutterConstraint *constraint,
|
|
ClutterActor *actor,
|
|
ClutterOrientation direction,
|
|
float for_size,
|
|
float *minimum_size,
|
|
float *natural_size)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
|
|
|
CLUTTER_CONSTRAINT_GET_CLASS (constraint)->update_preferred_size (constraint, actor,
|
|
direction,
|
|
for_size,
|
|
minimum_size,
|
|
natural_size);
|
|
}
|