diff --git a/doc/cookbook/Makefile.am b/doc/cookbook/Makefile.am
index e2956317d..d77f4cdc5 100644
--- a/doc/cookbook/Makefile.am
+++ b/doc/cookbook/Makefile.am
@@ -12,6 +12,7 @@ XML_FILES = \
introduction.xml \
text.xml \
textures.xml \
+ layouts.xml \
$(NULL)
XSLTOPTS = \
@@ -36,6 +37,7 @@ IMAGE_FILES = \
images/actors-opacity-container-affects-opacity.png \
images/text-shadow.png \
images/textures-sub-texture.png \
+ images/layouts-stacking-diff-actor-sizes.png \
$(NULL)
VIDEO_FILES = \
videos/animations-fading-out.ogv \
diff --git a/doc/cookbook/clutter-cookbook.xml.in b/doc/cookbook/clutter-cookbook.xml.in
index ade193535..3bd710821 100644
--- a/doc/cookbook/clutter-cookbook.xml.in
+++ b/doc/cookbook/clutter-cookbook.xml.in
@@ -44,6 +44,7 @@
+ Contributing to this document
diff --git a/doc/cookbook/examples/.gitignore b/doc/cookbook/examples/.gitignore
index af4ba9caf..29c14b0f1 100644
--- a/doc/cookbook/examples/.gitignore
+++ b/doc/cookbook/examples/.gitignore
@@ -3,3 +3,5 @@
/textures-reflection
/textures-split-go
/textures-sub-texture
+/layouts-stacking
+/layouts-stacking-diff-sized-actors
diff --git a/doc/cookbook/examples/Makefile.am b/doc/cookbook/examples/Makefile.am
index 662786ead..2369e7a0f 100644
--- a/doc/cookbook/examples/Makefile.am
+++ b/doc/cookbook/examples/Makefile.am
@@ -8,6 +8,8 @@ noinst_PROGRAMS = \
textures-reflection \
textures-split-go \
textures-sub-texture \
+ layouts-stacking \
+ layouts-stacking-diff-sized-actors \
$(NULL)
INCLUDES = \
@@ -29,8 +31,10 @@ AM_CFLAGS = \
AM_LDFLAGS = $(CLUTTER_LIBS)
-animations_rotating_SOURCES = animations-rotating.c
-text_shadow_SOURCES = text-shadow.c
-textures_reflection_SOURCES = textures-reflection.c
-textures_split_go_SOURCES = textures-split-go.c
-textures_sub_texture_SOURCES = textures-sub-texture.c
+animations_rotating_SOURCES = animations-rotating.c
+text_shadow_SOURCES = text-shadow.c
+textures_reflection_SOURCES = textures-reflection.c
+textures_split_go_SOURCES = textures-split-go.c
+textures_sub_texture_SOURCES = textures-sub-texture.c
+layouts_stacking_SOURCES = layouts-stacking.c
+layouts_stacking_diff_sized_actors_SOURCES = layouts-stacking-diff-sized-actors.c
diff --git a/doc/cookbook/examples/layouts-stacking-diff-sized-actors.c b/doc/cookbook/examples/layouts-stacking-diff-sized-actors.c
new file mode 100644
index 000000000..6030eeeda
--- /dev/null
+++ b/doc/cookbook/examples/layouts-stacking-diff-sized-actors.c
@@ -0,0 +1,78 @@
+#include
+
+static const ClutterColor dark_grey = { 0x66, 0x66, 0x66, 0xff };
+static const ClutterColor light_grey = { 0xcc, 0xcc, 0xcc, 0xff };
+
+int
+main (int argc, char *argv[])
+{
+ ClutterActor *stage;
+ ClutterLayoutManager *layout;
+ ClutterActor *box;
+ ClutterActor *rect1, *rect2;
+ guint align_x, align_y, diff_x, diff_y;
+
+ clutter_init (&argc, &argv);
+
+ stage = clutter_stage_get_default ();
+ clutter_actor_set_size (stage, 400, 400);
+
+ layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_START,
+ CLUTTER_BIN_ALIGNMENT_START);
+
+ box = clutter_box_new (layout);
+
+ rect1 = clutter_rectangle_new_with_color (&dark_grey);
+ clutter_actor_set_size (rect1, 400, 200);
+
+ rect2 = clutter_rectangle_new_with_color (&light_grey);
+ clutter_actor_set_size (rect2, 200, 400);
+
+ clutter_container_add (CLUTTER_CONTAINER (box),
+ rect1,
+ rect2,
+ NULL);
+
+ /*
+ * 2 = CLUTTER_BIN_ALIGNMENT_START
+ * 3 = CLUTTER_BIN_ALIGNMENT_END
+ * 4 = CLUTTER_BIN_ALIGNMENT_CENTER
+ */
+ for (align_x = 2; align_x < 5; align_x++)
+ {
+ for (align_y = 2; align_y < 5; align_y++)
+ {
+ diff_x = align_x - 1;
+ if (align_x == 3)
+ diff_x = 3;
+ else if (align_x == 4)
+ diff_x = 2;
+
+ diff_y = align_y - 1;
+ if (align_y == 3)
+ diff_y = 3;
+ else if (align_y == 4)
+ diff_y = 2;
+
+ ClutterColor *color = clutter_color_new (255 - diff_x * 50,
+ 100 + diff_y * 50,
+ 0,
+ 255);
+ ClutterActor *rect = clutter_rectangle_new_with_color (color);
+ clutter_actor_set_size (rect, 100, 100);
+ clutter_bin_layout_set_alignment (CLUTTER_BIN_LAYOUT (layout),
+ rect,
+ align_x,
+ align_y);
+ clutter_container_add_actor (CLUTTER_CONTAINER (box), rect);
+ }
+ }
+
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
+
+ clutter_actor_show (stage);
+
+ clutter_main ();
+
+ return 0;
+}
diff --git a/doc/cookbook/examples/layouts-stacking.c b/doc/cookbook/examples/layouts-stacking.c
new file mode 100644
index 000000000..8e9f05381
--- /dev/null
+++ b/doc/cookbook/examples/layouts-stacking.c
@@ -0,0 +1,80 @@
+/*
+ * Display multiple rotated copies of an image on top of each other
+ *
+ * Invoke with the path to a file to load a custom image
+ */
+#include
+
+#define STAGE_SIDE 512
+
+static const ClutterColor box_color = { 0x33, 0x33, 0x55, 0xff };
+
+int
+main (int argc, char *argv[])
+{
+ gchar *filename = TESTS_DATA_DIR "/redhand.png";
+
+ if (argc > 1)
+ filename = argv[1];
+
+ ClutterLayoutManager *layout;
+ ClutterActor *box;
+ ClutterActor *stage;
+ ClutterActor *texture;
+ CoglHandle *cogl_texture;
+ GError *error = NULL;
+ gfloat width;
+
+ clutter_init (&argc, &argv);
+
+ stage = clutter_stage_get_default ();
+ clutter_actor_set_size (stage, STAGE_SIDE, STAGE_SIDE);
+
+ layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
+ CLUTTER_BIN_ALIGNMENT_CENTER);
+
+ box = clutter_box_new (layout);
+ clutter_box_set_color (CLUTTER_BOX (box), &box_color);
+
+ texture = clutter_texture_new_from_file (filename, &error);
+
+ if (error != NULL)
+ g_error ("Error loading file %s; message was:\n%s",
+ filename,
+ error->message);
+
+ /*
+ * get a reference to the underlying Cogl texture
+ * for copying onto each Clutter texture placed into the layout
+ */
+ cogl_texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (texture));
+
+ /*
+ * add gradually turning and shrinking textures,
+ * smallest one last; each actor ends up on top
+ * of the one added just before it
+ */
+ for (width = STAGE_SIDE * 0.75; width >= STAGE_SIDE * 0.0625; width -= STAGE_SIDE * 0.0625)
+ {
+ ClutterActor *texture_copy = clutter_texture_new ();
+ clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (texture_copy),
+ cogl_texture);
+ clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (texture_copy),
+ TRUE);
+ clutter_actor_set_z_rotation_from_gravity (texture_copy,
+ (gfloat)(width * 0.5) - (STAGE_SIDE * 0.03125),
+ CLUTTER_GRAVITY_CENTER);
+ clutter_actor_set_width (texture_copy, width);
+ clutter_container_add_actor (CLUTTER_CONTAINER (box), texture_copy);
+ }
+
+ clutter_actor_add_constraint (box, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5));
+ clutter_actor_add_constraint (box, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5));
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
+
+ clutter_actor_show (stage);
+
+ clutter_main ();
+
+ return 0;
+}
diff --git a/doc/cookbook/images/layouts-stacking-diff-actor-sizes.png b/doc/cookbook/images/layouts-stacking-diff-actor-sizes.png
new file mode 100644
index 000000000..54c59f1c7
Binary files /dev/null and b/doc/cookbook/images/layouts-stacking-diff-actor-sizes.png differ
diff --git a/doc/cookbook/layouts.xml b/doc/cookbook/layouts.xml
new file mode 100644
index 000000000..618f9dcf9
--- /dev/null
+++ b/doc/cookbook/layouts.xml
@@ -0,0 +1,590 @@
+
+
+
+
+ Layout management
+
+
+ Abigail Adams, wife of John Adams, in a letter to John
+ Thaxter (1778-09-29)
+ If we do not lay out ourselves in the service of mankind,
+ whom should we serve?
+
+
+
+ Introduction
+
+ Layout management in Clutter controls how an actor and
+ children "inside" that actor are sized and positioned. More
+ specifically, layouts are managed by associating a parent with a
+ ClutterLayoutManager; the parent is usually either a
+ composite ClutterActor (composed of several
+ ClutterActors) or a ClutterContainer
+ (containing child ClutterActors). The
+ ClutterLayoutManager then manages:
+
+
+
+ The size requisition
+ (determination of the desired height and width) of the
+ parent.
+
+
+ The allocation (size and position)
+ assigned to each composed or child ClutterActor.
+
+
+
+
+ To make this more concrete, imagine you have a sheet of
+ paper and some coloured squares to place on it. Someone stands
+ next to you telling you how big the piece of paper should be,
+ how big the squares should be, and where to put each square on the
+ piece of paper.
+ The sheet of paper is analogous to the container or
+ composite actor; the squares are analogous to the child
+ ClutterActors; and the person giving you instructions
+ is analogous to the layout manager.
+
+
+ The following sections give an overview of how layout
+ management works in Clutter.
+
+
+ Using layouts
+
+ Although Clutter provides plenty of flexibility in how you
+ can use layout management, the simplest way to get started is to
+ use the built-in ClutterBox class with one of the
+ provided ClutterLayoutManager implementations.
+
+ The pattern for doing this is:
+
+
+
+ Create an instance of one of the
+ ClutterLayoutManager implementations (see
+ the
+ following section).
+
+
+ Configure the layout manager's default policies
+ (e.g. how actors are aligned by default, whether to pack
+ actors horizontally or vertically, spacing between actors
+ in the layout).
+
+
+ Create a ClutterBox, setting its layout
+ manager to the one you just created.
+
+
+ Pack actors into the ClutterBox,
+ setting layout properties (if required) as each is added.
+
+
+ Modify layout properties of child actors using
+ clutter_layout_manager_child_set()
+ (if required).
+
+
+
+ Individual recipes in this section give more examples of
+ how to make use of the different layout manager
+ implementations.
+
+
+ It is not possible to use a layout manager with an arbitrary
+ ClutterContainer: you must use a ClutterActor
+ subclass which can delegate its layout to a layout manager (either
+ use ClutterBox or write your own).
+
+
+
+
+
+ Types of layout manager
+
+ Clutter provides a range of layout managers suitable
+ for different use cases:
+
+
+
+ ClutterFixedLayout arranges actors
+ at fixed positions on the stage. No alignment options are
+ available, so you have to manually compute and manage the
+ coordinates (or use ClutterConstraints) which
+ will align actors how you want them.
+
+
+ ClutterBinLayout arranges actors in a
+ depth-ordered stack on top of each other, aligned to the container.
+ This is useful for arranging actors inside composites (e.g.
+ creating a button widget from a ClutterTexture
+ with a ClutterText on top of it).
+
+
+ ClutterBoxLayout arranges actors in a
+ single horizontal row or vertical column. This type of layout is
+ common in UI elements like toolbars and menus.
+
+
+ ClutterFlowLayout arranges actors
+ in reflowing columns and rows. If the container's allocation
+ changes, the child actors are rearranged to fit inside its
+ new allocation. This can be useful for arranging actors
+ where you're not sure how many there might be; or where
+ new ones are going to be added into the UI, perhaps displacing
+ others. An example might be a photo viewer or an
+ RSS feed display.
+
+
+
+
+
+
+ Layout properties
+
+ How actors are sized and positioned inside a container
+ associated with a layout manager depends on two things:
+
+
+
+
+ Properties which apply to all actors added to the layout
+ There will be one setting at the layout level which can't
+ be overridden per actor. This includes properties like spacing
+ between rows and columns, whether the layout is homogenous
+ (each actor gets the same allocation), etc.
+
+
+
+
+ Properties for each actor added to the layout
+ These are properties of the relationship between the
+ layout, the container associated with the layout, and the
+ children of the container. Each layout/container/actor
+ combination can have different settings for each of these
+ properties.
+
+
+
+
+ Each layout manager implementation supports a subset of the
+ following layout properties; different managers may have different
+ names or functions for setting them, but the functionality remains
+ the same. Individual recipes give more details about which
+ properties can be set for each layout manager implementation.
+
+
+
+
+ Alignment
+ How an actor aligns to the container's axes, e.g.
+ aligned to the container's left, right, or center. For some
+ layouts (like ClutterBinLayout) alignment
+ is also used to set expand and fill properties.
+
+
+
+
+ Horizontal/vertical orientation
+ Whether actors are arranged in a horizontal row or
+ vertical column.
+
+
+
+
+ Homogenous rows and columns
+ Grid-like layouts (e.g. ClutterFlowLayout)
+ can be configured to have uniform rows and/or columns,
+ expanding to fit the largest actor they contain.
+
+
+
+
+ Row height and column width
+ Grid-like layouts arranged in rows and columns
+ can be configured with maximum and minimum row height and
+ column width.
+
+
+
+
+ Row and column spacing
+ Grid-like layouts enable you to define a space (in pixels)
+ between rows and columns.
+
+
+
+
+ Expand
+ Some layouts can be configured to minimize their size request
+ to fit the actors they contain (expand is FALSE);
+ or to increase the allocation of actors they contain so
+ that all available space in the layout is used
+ (expand is TRUE). In the latter case, you'd
+ also need to set a size for the container associated with
+ the layout, otherwise the container will just fit itself to the
+ actors inside it.
+
+
+
+
+ Fill
+ This property only has an effect when
+ expand is on. The fill
+ setting controls whether actors are resized to fill their
+ allocation (fill is TRUE); or if the
+ space around the actor is increased (fill is
+ FALSE).
+
+
+
+
+ Pack at start/end
+ This controls whether actors at prepended or appended
+ to the layout.
+
+
+ If the orientation is vertical, prepended
+ actors are added to the top of the layout and appended
+ actors to the bottom.
+
+
+ If the orientation is horizontal, prepended
+ actors are added at the left of the layout and appended actors
+ on the right.
+
+
+
+
+
+
+
+ Setting layout properties
+
+ Layout properties can be set in one or more of the following ways
+ (depending on the type of property and the layout manager):
+
+
+
+ By setting a default value for the property on the
+ layout manager (e.g. using
+ clutter_bin_layout_set_alignment(),
+ clutter_box_layout_set_expand()). Any
+ actor added to the layout gets this value for the property,
+ unless it is overridden for that actor.
+
+
+ When adding an actor to a ClutterBox container
+ using clutter_box_pack(), you can set
+ properties on the actor which you're adding.
+
+
+ When adding an actor to a layout you can use a function
+ which enables setting properties simultaneously (e.g.
+ clutter_box_layout_pack(),
+ clutter_bin_layout_add()).
+
+
+ By using
+ clutter_layout_manager_child_set() on
+ the child of a layout.
+
+
+
+
+
+
+
+
+ Not using layout managers
+
+ It is perfectly possible to arrange ClutterActors
+ without using layout managers; however, you may have to do
+ more of your own calculations about actor sizes and positions.
+
+ There are two (not mutually-exclusive) approaches you can
+ take to do this, described below.
+
+
+ Manual positioning and alignment
+
+ This basically means using the ClutterActor
+ bounding box mechanism (see the ClutterActor
+ documentation for details) to set actor sizes and positions.
+ This is the approach you will see in a lot of older Clutter
+ code (written before layout managers were available).
+
+ This approach is simplest where the UI is relatively static
+ and is composed of a few known actors. It will work in larger,
+ more complex scenarios, but in those sorts of cases it is better
+ to make use of layout managers and constraints (see below) instead.
+
+
+
+ Using ClutterConstraint
+
+ Constraints provide mechanisms for:
+
+
+
+ Aligning actors with each other
+ (ClutterAlignConstraint). For example, you
+ can align the top, bottom or center of one actor with the
+ top, bottom or center of another (on the y
+ axis). Similarly, you can align one actor to another
+ on the x axis.
+
+
+ Binding properties of one actor to those of
+ another. For example, you could ensure that two actors
+ always remain the same width; or you could specify
+ that two actors always have the same x
+ coordinate. In both these cases and others, you can
+ specify that the properties should be the same, or the same
+ +/- some offset.
+
+
+
+
+ ClutterConstraints can be used in combination
+ with some layout managers, but you need to be careful that
+ constraints don't fight with the layout manager policies.
+ Unpredictable results could ensue.
+
+
+
+
+
+
+
+
+
+ Stacking actors on top of each other
+
+
+ Problem
+
+ You want to lay out several actors so that they are in
+ layers on top of each other (e.g. to create a button widget
+ composed from a rectangle with text on top of it).
+
+
+
+ Solution
+
+ The most flexible approach is to use a ClutterBinLayout
+ associated with a ClutterBox:
+
+
+
+
+
+
+
+
+
+ Discussion
+
+ This section covers some other aspects of using a
+ ClutterBinLayout.
+
+
+ Setting and changing alignment
+
+ Alignment is the only
+ layout
+ property available for ClutterBinLayout. Each
+ actor can have a different setting for its alignment in one or both
+ of the x or y axes. However, as shown in the
+ solution above, alignment can also be used to expand an actor to
+ fill the container (CLUTTER_BIN_ALIGNMENT_FILL)
+ in one or both axes.
+
+ Setting alignment does not have any effect if the container
+ is the same size as all of the actors inside it: in this case,
+ every alignment produces the same layout. But if the container
+ associated with the layout is larger than the actor being aligned,
+ alignment will have an effect; see
+ this
+ section for more details.
+
+ Changing an actor's alignment after it has been added
+ to a ClutterBinLayout may make the actor "jump"
+ (without animation) to a new position and/or change its size.
+ The exception is changing from some other alignment to
+ CLUTTER_BIN_ALIGNMENT_FIXED:
+ in this case, the actor will retain the position and size it
+ had before its alignment was fixed.
+
+
+
+ Size requisitioning
+
+ A container with a ClutterBinLayout will by
+ default request the width of the widest actor in it, and the
+ height of the tallest. If you add actors smaller than those
+ dimensions, they will be aligned inside the container according
+ to the layout's policies. Here's an example where a
+ ClutterBinLayout requests a size to encompass the
+ tallest (light grey rectangle) and widest (dark grey rectangle)
+ actors inside it, with other actors aligned within
+ those bounds:
+
+
+
+
+
+
+
+ Size requisition in a ClutterBinLayout
+
+
+
+
+
+ The screenshot also shows the 9 possible combinations
+ of start, center and end alignments on the x and
+ y axes. See
+ the sample
+ code for more details.
+
+
+ The white space is the stage visible behind the
+ ClutterBox holding the coloured rectangles.
+ Notice that the layout is the width of the widest actor
+ within it and the height of the tallest.
+
+ You can also manually set a size on the container associated
+ with a layout to override the automatically-computed size
+ requisition.
+
+
+
+
+ Depth ordering
+
+ Another important consideration is the
+ depth ordering of actors inside a
+ ClutterBinLayout. By default, the depth ordering
+ mirrors the order in which actors are added to the layout: the
+ earlier an actor is added, the lower down in the depth order it
+ is. If this isn't what you want, you can fix the depth ordering using
+ clutter_actor_raise(),
+ clutter_actor_lower() and their relatives.
+
+
+
+ Other ways to stack actors
+
+ ClutterBinLayout makes it simple to lay out
+ large numbers of actors in a stack and align them to the
+ container; see the
+ example below which shows layering of many actors on
+ top of each other.
+
+ However, if you have a small number of actors and you
+ need some simple alignment, an alternative is to use
+ manual positioning inside a ClutterFixedLayout
+ (or even a ClutterGroup), possibly combined with
+ ClutterConstraints to align actors with each other
+ and bind their widths and heights together. See
+ this
+ section for more details.
+
+
+
+
+
+ Full examples
+
+
+ ClutterBinLayout, with actors in 9
+ combinations of start, center and end alignment combinations
+
+
+ a code sample should be here... but isn't
+
+
+
+
+
+ Layering multiple textures on top of each other
+ inside a ClutterBinLayout
+
+
+ a code sample should be here... but isn't
+
+
+
+
+
+
+
+
+