mirror of
https://github.com/brl/mutter.git
synced 2024-12-27 05:12:15 +00:00
894c0527df
General improvements to readability, formatting, fixing typos etc.
1194 lines
47 KiB
XML
1194 lines
47 KiB
XML
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
|
|
|
<chapter id="layouts"
|
|
xmlns:xi="http://www.w3.org/2003/XInclude">
|
|
|
|
<title>Layout management</title>
|
|
|
|
<epigraph>
|
|
<attribution>Abigail Adams, wife of John Adams, in a letter to John
|
|
Thaxter (1778-09-29)</attribution>
|
|
<para>If we do not lay out ourselves in the service of mankind,
|
|
whom should we serve?</para>
|
|
</epigraph>
|
|
|
|
<section id="layouts-introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para>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
|
|
<type>ClutterLayoutManager</type>; the parent is usually either a
|
|
composite <type>ClutterActor</type> (composed of several
|
|
<type>ClutterActors</type>) or a <type>ClutterContainer</type>
|
|
(containing child <type>ClutterActors</type>). The
|
|
<type>ClutterLayoutManager</type> then manages:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>The <emphasis>size requisition</emphasis>
|
|
(determination of the desired height and width) of the
|
|
parent.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>The <emphasis>allocation</emphasis> (size and position)
|
|
assigned to each composed or child ClutterActor.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<note>
|
|
<para>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.</para>
|
|
<para>The sheet of paper is analogous to the container or
|
|
composite actor; the squares are analogous to the child
|
|
<type>ClutterActors</type>; and the person giving you instructions
|
|
is analogous to the layout manager.</para>
|
|
</note>
|
|
|
|
<para>The following sections give an overview of how layout
|
|
management works in Clutter.</para>
|
|
|
|
<section>
|
|
<title>Using layouts</title>
|
|
|
|
<para>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 <type>ClutterBox</type> class with one of the
|
|
provided <type>ClutterLayoutManager</type> implementations.</para>
|
|
|
|
<para>The pattern for doing this is:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Create an instance of one of the
|
|
<type>ClutterLayoutManager</type> implementations (see
|
|
<link linkend="layouts-introduction-manager-types">the
|
|
following section</link>).</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>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).</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Create a <type>ClutterBox</type>, setting its layout
|
|
manager to the one you just created.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Pack actors into the <type>ClutterBox</type>,
|
|
setting layout properties (if required) as each is added.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Modify layout properties of child actors using
|
|
<function>clutter_layout_manager_child_set()</function>
|
|
(if required).</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Individual recipes in this section give more examples of
|
|
how to make use of the different layout manager
|
|
implementations.</para>
|
|
|
|
<note>
|
|
<para>It is not possible to use a layout manager with an arbitrary
|
|
<type>ClutterContainer</type>: you must use a <type>ClutterActor</type>
|
|
subclass which can delegate its layout to a layout manager (either
|
|
use <type>ClutterBox</type> or write your own).</para>
|
|
</note>
|
|
|
|
</section>
|
|
|
|
<section id="layouts-introduction-manager-types">
|
|
<title>Types of layout manager</title>
|
|
|
|
<para>Clutter provides a range of layout managers suitable
|
|
for different use cases:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><type>ClutterFixedLayout</type> 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 <type>ClutterConstraints</type>) which
|
|
will align actors how you want them.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><type>ClutterBinLayout</type> 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 <type>ClutterTexture</type>
|
|
with a <type>ClutterText</type> on top of it).</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><type>ClutterBoxLayout</type> arranges actors in a
|
|
single horizontal row or vertical column. This type of layout is
|
|
common in UI elements like toolbars and menus.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><type>ClutterFlowLayout</type> 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.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</section>
|
|
|
|
<section id="layouts-introduction-layout-properties">
|
|
<title>Layout properties</title>
|
|
|
|
<para>How actors are sized and positioned inside a container
|
|
associated with a layout manager depends on two things:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<formalpara>
|
|
<title>Properties which apply to all actors added to the layout</title>
|
|
<para>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.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
<listitem>
|
|
<formalpara>
|
|
<title>Properties for each actor added to the layout</title>
|
|
<para>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.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>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.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<formalpara>
|
|
<title>Alignment</title>
|
|
<para>How an actor aligns to the container's axes, e.g.
|
|
aligned to the container's left, right, or center. For some
|
|
layouts (like <type>ClutterBinLayout</type>) alignment
|
|
is also used to set expand and fill properties.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
<listitem>
|
|
<formalpara>
|
|
<title>Horizontal/vertical orientation</title>
|
|
<para>Whether actors are arranged in a horizontal row or
|
|
vertical column.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
<listitem>
|
|
<formalpara>
|
|
<title>Homogenous rows and columns</title>
|
|
<para>Grid-like layouts (e.g. <type>ClutterFlowLayout</type>)
|
|
can be configured to have uniform rows and/or columns,
|
|
expanding to fit the largest actor they contain.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
<listitem>
|
|
<formalpara>
|
|
<title>Row height and column width</title>
|
|
<para>Grid-like layouts arranged in rows and columns
|
|
can be configured with maximum and minimum row height and
|
|
column width.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
<listitem>
|
|
<formalpara>
|
|
<title>Row and column spacing</title>
|
|
<para>Grid-like layouts enable you to define a space (in pixels)
|
|
between rows and columns.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
<listitem>
|
|
<formalpara>
|
|
<title>Expand</title>
|
|
<para>Some layouts can be configured to minimize their size request
|
|
to fit the actors they contain (<emphasis>expand is FALSE</emphasis>);
|
|
or to increase the allocation of actors they contain so
|
|
that all available space in the layout is used
|
|
(<emphasis>expand is TRUE</emphasis>). 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.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
<listitem>
|
|
<formalpara>
|
|
<title>Fill</title>
|
|
<para>This property only has an effect when
|
|
<emphasis>expand</emphasis> is on. The <emphasis>fill</emphasis>
|
|
setting controls whether actors are resized to fill their
|
|
allocation (<emphasis>fill is TRUE</emphasis>); or if the
|
|
space around the actor is increased (<emphasis>fill is
|
|
FALSE</emphasis>).</para>
|
|
</formalpara>
|
|
</listitem>
|
|
<listitem>
|
|
<formalpara>
|
|
<title>Pack at start/end</title>
|
|
<para>This controls whether actors at prepended or appended
|
|
to the layout.</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>If the orientation is vertical, prepended
|
|
actors are added to the top of the layout and appended
|
|
actors to the bottom.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>If the orientation is horizontal, prepended
|
|
actors are added at the left of the layout and appended actors
|
|
on the right.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</formalpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<section>
|
|
<title>Setting layout properties</title>
|
|
|
|
<para>Layout properties can be set in one or more of the following ways
|
|
(depending on the type of property and the layout manager):</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>By setting a default value for the property on the
|
|
layout manager (e.g. using
|
|
<function>clutter_bin_layout_set_alignment()</function>,
|
|
<function>clutter_box_layout_set_expand()</function>). Any
|
|
actor added to the layout gets this value for the property,
|
|
unless it is overridden for that actor.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>When adding an actor to a <type>ClutterBox</type> container
|
|
using <function>clutter_box_pack()</function>, you can set
|
|
properties on the actor which you're adding.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>When adding an actor to a layout you can use a function
|
|
which enables setting properties simultaneously (e.g.
|
|
<function>clutter_box_layout_pack()</function>,
|
|
<function>clutter_bin_layout_add()</function>).</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>By using
|
|
<function>clutter_layout_manager_child_set()</function> on
|
|
the child of a layout.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|
|
<section id="layouts-introduction-not-using-layout-managers">
|
|
<title>Not using layout managers</title>
|
|
|
|
<para>It is perfectly possible to arrange <type>ClutterActors</type>
|
|
without using layout managers; however, you may have to do
|
|
more of your own calculations about actor sizes and positions.</para>
|
|
|
|
<para>There are two (not mutually-exclusive) approaches you can
|
|
take to do this, described below.</para>
|
|
|
|
<section>
|
|
<title>Manual positioning and alignment</title>
|
|
|
|
<para>This basically means using the <type>ClutterActor</type>
|
|
bounding box mechanism (see the <type>ClutterActor</type>
|
|
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).</para>
|
|
|
|
<para>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.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Using <type>ClutterConstraint</type></title>
|
|
|
|
<para>Constraints provide mechanisms for:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Aligning actors with each other
|
|
(<type>ClutterAlignConstraint</type>). For example, you
|
|
can align the top, bottom or center of one actor with the
|
|
top, bottom or center of another (on the <code>y</code>
|
|
axis). Similarly, you can align one actor to another
|
|
on the <code>x</code> axis.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>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 <code>x</code>
|
|
coordinate. In both these cases and others, you can
|
|
specify that the properties should be the same, or the same
|
|
+/- some offset.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<note>
|
|
<para><type>ClutterConstraints</type> 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.</para>
|
|
</note>
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|
|
<section id="layouts-stacking">
|
|
<title>Stacking actors on top of each other</title>
|
|
|
|
<section>
|
|
<title>Problem</title>
|
|
|
|
<para>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).</para>
|
|
</section>
|
|
|
|
<section id="layouts-stacking-solution">
|
|
<title>Solution</title>
|
|
|
|
<para>The most flexible approach is to use a <type>ClutterBinLayout</type>
|
|
associated with a <type>ClutterBox</type>:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
<![CDATA[
|
|
/* define some colors */
|
|
const ClutterColor background_color = { 0xaa, 0x99, 0x00, 0xff };
|
|
const ClutterColor text_color = { 0xff, 0xff, 0xff, 0xff };
|
|
|
|
ClutterLayoutManager *layout;
|
|
ClutterActor *box;
|
|
ClutterActor *background;
|
|
ClutterActor *text;
|
|
|
|
/*
|
|
* create a layout, setting the default x and y alignment;
|
|
* actors fill the whole allocation of the layout's container
|
|
* by default
|
|
*/
|
|
layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_FILL,
|
|
CLUTTER_BIN_ALIGNMENT_FILL);
|
|
|
|
/* create the box whose children the layout will manage */
|
|
box = clutter_box_new (layout);
|
|
|
|
/*
|
|
* fill doesn't have much effect here
|
|
* unless the container has height and/or width
|
|
*/
|
|
clutter_actor_set_size (box, 100, 30);
|
|
|
|
/*
|
|
* background for the button; could equally be a texture
|
|
* with an image loaded into it or any other ClutterActor
|
|
*/
|
|
background = clutter_rectangle_new_with_color (&background_color);
|
|
|
|
/*
|
|
* add the background to the container;
|
|
* as it should use the default alignment, it can be added
|
|
* direct to the container, rather than via the layout
|
|
*/
|
|
clutter_container_add_actor (CLUTTER_CONTAINER (box), background);
|
|
|
|
/* text for the button */
|
|
text = clutter_text_new_full ("Sans 15px", "Click me", &text_color);
|
|
|
|
/*
|
|
* the text requires a different alignment from the background
|
|
* (centered on the box)
|
|
* so we add it via the layout so the default
|
|
* alignment can be overridden
|
|
*/
|
|
clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout),
|
|
text,
|
|
CLUTTER_BIN_ALIGNMENT_CENTER,
|
|
CLUTTER_BIN_ALIGNMENT_CENTER);
|
|
|
|
/*
|
|
* ensure the actors are arranged in the correct depth order;
|
|
* in this case, the text is on top
|
|
* (NB this is not strictly necesary here as text is added after
|
|
* background)
|
|
*/
|
|
clutter_actor_raise_top (text);
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Discussion</title>
|
|
|
|
<para>This section covers some other aspects of using a
|
|
<type>ClutterBinLayout</type>.</para>
|
|
|
|
<section>
|
|
<title>Setting and changing alignment</title>
|
|
|
|
<para>Alignment is the only
|
|
<link linkend="layouts-introduction-layout-properties">layout
|
|
property</link> available for <type>ClutterBinLayout</type>. Each
|
|
actor can have a different setting for its alignment in one or both
|
|
of the <code>x</code> or <code>y</code> axes. However, as shown in the
|
|
solution above, alignment can also be used to expand an actor to
|
|
fill the container (<constant>CLUTTER_BIN_ALIGNMENT_FILL</constant>)
|
|
in one or both axes.</para>
|
|
|
|
<para>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
|
|
<link linkend="layouts-stacking-size-requisitioning">this
|
|
section</link> for more details.</para>
|
|
|
|
<para>Changing an actor's alignment after it has been added
|
|
to a <type>ClutterBinLayout</type> 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
|
|
<constant>CLUTTER_BIN_ALIGNMENT_FIXED</constant>:
|
|
in this case, the actor will retain the position and size it
|
|
had before its alignment was fixed.</para>
|
|
</section>
|
|
|
|
<section id="layouts-stacking-size-requisitioning">
|
|
<title>Size requisitioning</title>
|
|
|
|
<para>A container with a <type>ClutterBinLayout</type> 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
|
|
<type>ClutterBinLayout</type> 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:</para>
|
|
|
|
<screenshot>
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata format="PNG"
|
|
fileref="images/layouts-stacking-diff-actor-sizes.png" />
|
|
</imageobject>
|
|
<alt>
|
|
<para>Size requisition in a <type>ClutterBinLayout</type></para>
|
|
</alt>
|
|
</mediaobject>
|
|
</screenshot>
|
|
|
|
<note>
|
|
<para>The screenshot also shows the 9 possible combinations
|
|
of start, center and end alignments on the <code>x</code> and
|
|
<code>y</code> axes. See
|
|
<link linkend="layouts-stacking-example-1">the sample
|
|
code</link> for more details.</para>
|
|
</note>
|
|
|
|
<para>The white space is the stage visible behind the
|
|
<type>ClutterBox</type> holding the coloured rectangles.
|
|
Notice that the layout is the width of the widest actor
|
|
within it and the height of the tallest.</para>
|
|
|
|
<para>You can also manually set a size on the container associated
|
|
with a layout to override the automatically-computed size
|
|
requisition.</para>
|
|
|
|
</section>
|
|
|
|
<section>
|
|
<title>Depth ordering</title>
|
|
|
|
<para>Another important consideration is the
|
|
<emphasis>depth ordering</emphasis> of actors inside a
|
|
<type>ClutterBinLayout</type>. 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
|
|
<function>clutter_actor_raise()</function>,
|
|
<function>clutter_actor_lower()</function> and their relatives.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Other ways to stack actors</title>
|
|
|
|
<para><type>ClutterBinLayout</type> makes it simple to lay out
|
|
large numbers of actors in a stack and align them to the
|
|
container; see <link linkend="layouts-stacking-example-2">the
|
|
example below</link> which shows layering of many actors on
|
|
top of each other.</para>
|
|
|
|
<para>However, if you have a small number of actors and you
|
|
need some simple alignment, an alternative is to use
|
|
manual positioning inside a <type>ClutterFixedLayout</type>
|
|
(or even a <type>ClutterGroup</type>), possibly combined with
|
|
<type>ClutterConstraints</type> to align actors with each other
|
|
and bind their widths and heights together. See
|
|
<link linkend="layouts-introduction-not-using-layout-managers">this
|
|
section</link> for more details.</para>
|
|
</section>
|
|
|
|
</section>
|
|
|
|
<section>
|
|
<title>Full examples</title>
|
|
|
|
<example id="layouts-stacking-example-1">
|
|
<title><type>ClutterBinLayout</type>, with actors in 9
|
|
combinations of start, center and end alignment combinations</title>
|
|
<programlisting>
|
|
<xi:include href="examples/layouts-stacking-diff-sized-actors.c" parse="text">
|
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
|
</xi:include>
|
|
</programlisting>
|
|
</example>
|
|
|
|
<example id="layouts-stacking-example-2">
|
|
<title>Layering multiple textures on top of each other
|
|
inside a <type>ClutterBinLayout</type></title>
|
|
<programlisting>
|
|
<xi:include href="examples/layouts-stacking.c" parse="text">
|
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
|
</xi:include>
|
|
</programlisting>
|
|
</example>
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|
|
<section id="layouts-bind-constraint">
|
|
<title>Binding the size of one actor to the size of another</title>
|
|
|
|
<section>
|
|
<title>Problem</title>
|
|
|
|
<para>You want one actor (the "target") to automatically change
|
|
its width or height (or both) when the size of another
|
|
actor (the "source") changes.</para>
|
|
|
|
<para>Example use cases:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Making an actor adjust itself to the size of the stage
|
|
(particularly when the stage is resizable).</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Putting one actor on top of another and keeping their
|
|
sizes in sync.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</section>
|
|
|
|
<section>
|
|
<title>Solution</title>
|
|
|
|
<para>Create a <type>ClutterBindConstraint</type> bound to the
|
|
width and/or height of one actor (the "source"). Add that constraint
|
|
to an actor (the "target") whose size should follow the
|
|
size of the source.</para>
|
|
|
|
<para>This short example shows how to create and add a constraint;
|
|
<varname>source</varname> and <varname>target</varname> can
|
|
be any two <type>ClutterActors</type>:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
<emphasis>ClutterConstraint *width_constraint;</emphasis>
|
|
|
|
/* create a constraint which binds a target actor's width to 100px less than
|
|
* the width of the source actor (use CLUTTER_BIND_HEIGHT to create a
|
|
* constraint based on an actor's height)
|
|
*
|
|
* the third argument is a positive or negative offset from the actor's
|
|
* dimension, in pixels; this is added to the height or width of the source
|
|
* actor before the constraint is applied to the target actor
|
|
*/
|
|
<emphasis>width_constraint = clutter_bind_constraint_new (source, CLUTTER_BIND_WIDTH, -100);</emphasis>
|
|
|
|
/* add the constraint to an actor */
|
|
<emphasis>clutter_actor_add_constraint (target, width_constraint);</emphasis>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>Below is a full example, showing how to incorporate a
|
|
constraint into a Clutter application.</para>
|
|
|
|
<example id="layouts-bind-constraint-example-1">
|
|
<title>Constraining the size of a texture to
|
|
the size of the stage using <type>ClutterBindConstraint</type></title>
|
|
<programlisting>
|
|
<xi:include href="examples/layouts-bind-constraint-stage.c" parse="text">
|
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
|
</xi:include>
|
|
</programlisting>
|
|
</example>
|
|
|
|
<para>The texture in this example is 100px smaller than the stage,
|
|
leaving a border of visible stage around the texture; and the texture
|
|
has a tiled image on it. The tiling changes as the texture changes
|
|
size. Also note that two <type>ClutterAlignConstraints</type> are
|
|
added to center the actor on the stage.</para>
|
|
|
|
<para>The result looks like this:</para>
|
|
|
|
<screenshot>
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata format="PNG"
|
|
fileref="images/layouts-bind-constraint-stage.png" />
|
|
</imageobject>
|
|
<alt>
|
|
<para>A texture bound to the height and width of the
|
|
stage using <type>ClutterBindConstraint</type></para>
|
|
</alt>
|
|
</mediaobject>
|
|
</screenshot>
|
|
|
|
</section>
|
|
|
|
<section>
|
|
<title>Discussion</title>
|
|
|
|
<para>Sizing constraints are a good solution in these cases:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Where you can't use a layout manager. For
|
|
example, you can't apply a layout manager to the stage
|
|
directly; so if you want to control the size of an actor
|
|
based on the size of the stage (as in
|
|
<link linkend="layouts-bind-constraint-example-1">the example
|
|
above</link>), constraints are a good substitute for a layout
|
|
manager .</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Where the layout of a UI is fairly simple (perhaps
|
|
up to half a dozen actors) and fairly static. An example
|
|
might be something like a text editor, where the arrangement
|
|
of the UI (menu bar, toolbar, editing panel, footer) changes
|
|
infrequently. Of course, it is possible to arrange top-level
|
|
components using constraints, but still use layout
|
|
managers inside individual components (e.g. a flow layout
|
|
manager to manage buttons in the toolbar).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Where you have an actor whose size can change erratically,
|
|
but you still want to be able to track its size to control
|
|
another actor's size. An example might be an application like
|
|
a drawing program, where a user can create their own actors:
|
|
you might want the user to be able to describe loose, custom
|
|
constraints between actors like "keep these actors at the
|
|
same width", then allow those actors to be moved around and
|
|
resized in a free-form way as a group. In this situation, a
|
|
layout manager is too rigid and not appropriate;
|
|
but adding <type>ClutterConstraints</type> to actors
|
|
in response to user actions could work well.</para>
|
|
|
|
<para>The <link linkend="layouts-bind-constraint-example-2">sample
|
|
code in the appendix</link> is the kind of thing you might include
|
|
in a drawing program: you can resize a texture with a key press
|
|
(<code>+</code> to increase size, <code>-</code> to decrease), and
|
|
click on the actor to select/deselect it (a semi-transparent overlay is
|
|
toggled on the texture). The size of the overlay is bound and
|
|
aligned to the texture, so that it covers and slightly overlaps the
|
|
texture regardless of its size.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<note>
|
|
<para>You can bind an actor to a single dimension (just height or
|
|
depth) of another actor: you don't have to bind both height
|
|
and width. Also, you don't have to bind both dimensions of the
|
|
target to the same source: for example, you could bind the target's
|
|
height to one source (actor A) and its width to another source
|
|
(actor B).</para>
|
|
|
|
<para>A <type>ClutterBindConstraint</type> can also be used to
|
|
constrain a target actor's position on the <code>x</code> and
|
|
<code>y</code> axes to the position of a source actor. This is
|
|
covered in another recipe.</para>
|
|
</note>
|
|
|
|
<section>
|
|
<title>Another way to bind actors' sizes together</title>
|
|
|
|
<para>There is another way to control the size of a target
|
|
actor, based on the size of a source: you can create a handler
|
|
for the <code>allocation-changed</code> signal
|
|
of the source, emitted when its size and/or position
|
|
changes. This signal includes all the data
|
|
about the source's new allocation (height, width, x and y
|
|
coordindates), which the handler function can then use to
|
|
resize the target.</para>
|
|
|
|
<para>Alternatively, if you're only interested in
|
|
a change to width or height, you can create a handler
|
|
for the <code>notify::width</code> or
|
|
<code>notify::height</code> signal (respectively), and modify
|
|
the target's width/height in the handler.</para>
|
|
|
|
<para>This approach may be useful if you need a type of
|
|
control over alignment and size which is not possible using
|
|
constraints alone (e.g. one actor's size should be
|
|
a proportion of another's). See
|
|
<link linkend="layouts-bind-constraint-example-3">the code in
|
|
this section</link> for an example where the size
|
|
of one actor is dynamically set to 10% more than the
|
|
size of another.</para>
|
|
|
|
<note>
|
|
<para><link linkend="actors-allocation-notify">This recipe</link>
|
|
explains more about monitoring changes to an actor's size.</para>
|
|
</note>
|
|
</section>
|
|
|
|
</section>
|
|
|
|
<section>
|
|
<title>Full examples</title>
|
|
|
|
<example id="layouts-bind-constraint-example-2">
|
|
<title>Creating an automatically-resizing overlay for a
|
|
texture using <type>ClutterBindConstraint</type></title>
|
|
<programlisting>
|
|
<xi:include href="examples/layouts-bind-constraint-overlay.c" parse="text">
|
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
|
</xi:include>
|
|
</programlisting>
|
|
</example>
|
|
|
|
<example id="layouts-bind-constraint-example-3">
|
|
<title>Using the <code>allocation-changed</code>
|
|
signal of one actor to trigger proportional size changes in
|
|
another</title>
|
|
<programlisting>
|
|
<xi:include href="examples/layouts-bind-constraint-allocation.c" parse="text">
|
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
|
</xi:include>
|
|
</programlisting>
|
|
</example>
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|
|
<section id="layouts-box">
|
|
<title>Arranging actors in a single row or column</title>
|
|
|
|
<section>
|
|
<title>Problem</title>
|
|
|
|
<para>You want to layout several actors in a single row
|
|
or column.</para>
|
|
|
|
<para>Example use cases:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Creating an application menu.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Showing message subject lines as a list in an
|
|
email client.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Solution</title>
|
|
|
|
<para>Create a <type>ClutterBox</type> with a
|
|
<type>ClutterBoxLayout</type> as its layout manager.</para>
|
|
|
|
<para>A <type>ClutterBoxLayout</type> can hold a single row or
|
|
column of <type>ClutterActors</type>, and has configurable spacing,
|
|
actor alignments, and expand and fill options.</para>
|
|
|
|
<para>The code fragment below is excerpted from the
|
|
<link linkend="layouts-box-example-1">full example</link>. It
|
|
demonstrates how to lay out three rectangles in a vertical
|
|
column. A different approach is used to set the <varname>x-fill</varname>
|
|
property on each rectangle, so each fills the horizontal space in
|
|
the layout (each rectangle is 100 pixels wide, while the
|
|
box they are inside is 200 pixels wide).</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
<![CDATA[
|
|
/* create a ClutterBoxLayout */
|
|
box_layout = clutter_box_layout_new ();
|
|
|
|
/* configure it to lay out actors vertically */
|
|
clutter_box_layout_set_vertical (CLUTTER_BOX_LAYOUT (box_layout), TRUE);
|
|
|
|
/* put 5px of spacing between actors */
|
|
clutter_box_layout_set_spacing (CLUTTER_BOX_LAYOUT (box_layout), 5);
|
|
|
|
/* actors are packed into this box; we set its width, but
|
|
* allow its height to be determined by the children it contains
|
|
*/
|
|
box = clutter_box_new (box_layout);
|
|
clutter_box_set_color (CLUTTER_BOX (box), &box_color);
|
|
clutter_actor_set_position (box, 100, 50);
|
|
clutter_actor_set_width (box, 200);
|
|
|
|
/* pack an actor into the layout and set all layout properties on it
|
|
* at the same time
|
|
*/
|
|
yellow = clutter_rectangle_new_with_color (&yellow_color);
|
|
clutter_actor_set_size (yellow, 100, 100);
|
|
|
|
clutter_box_layout_pack (CLUTTER_BOX_LAYOUT (box_layout),
|
|
yellow,
|
|
FALSE, /* expand */
|
|
TRUE, /* x-fill */
|
|
FALSE, /* y-fill */
|
|
CLUTTER_BOX_ALIGNMENT_START, /* x-align */
|
|
CLUTTER_BOX_ALIGNMENT_START); /* y-align */
|
|
|
|
/* pack an actor into the box and set layout properties at the
|
|
* same time; note this is more concise if you mostly want to
|
|
* use the default properties for the layout
|
|
*/
|
|
red = clutter_rectangle_new_with_color (&red_color);
|
|
clutter_actor_set_size (red, 100, 100);
|
|
|
|
clutter_box_pack (CLUTTER_BOX (box),
|
|
red,
|
|
"x-fill", TRUE,
|
|
NULL);
|
|
|
|
/* add an actor to the box as a container and set layout properties
|
|
* afterwards; the latter is useful if you want to change properties on
|
|
* actors already inside a layout, but note that you have to
|
|
* pass the function both the layout AND the container
|
|
*/
|
|
blue = clutter_rectangle_new_with_color (&blue_color);
|
|
clutter_actor_set_size (blue, 100, 100);
|
|
|
|
clutter_container_add_actor (CLUTTER_CONTAINER (box), blue);
|
|
|
|
clutter_layout_manager_child_set (box_layout,
|
|
CLUTTER_CONTAINER (box),
|
|
blue,
|
|
"x-fill", TRUE,
|
|
NULL);
|
|
|
|
/* put the box on the stage */
|
|
clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>The result looks like this:</para>
|
|
|
|
<screenshot>
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata format="PNG"
|
|
fileref="images/layouts-box.png" />
|
|
</imageobject>
|
|
<alt>
|
|
<para>A simple vertical <type>ClutterBoxLayout</type></para>
|
|
</alt>
|
|
</mediaobject>
|
|
</screenshot>
|
|
|
|
</section>
|
|
|
|
<section>
|
|
<title>Discussion</title>
|
|
|
|
<para><type>ClutterBoxLayout</type> is not a reflowing layout:
|
|
that is, if the layout's container changes size, the actors inside
|
|
aren't automatically repositioned to occupy or find new positions
|
|
in its available area. If you want that behaviour, use
|
|
<type>ClutterFlowLayout</type> instead.</para>
|
|
|
|
<para>If you want the container to be resizable, but find that
|
|
resizing the container obscures its child actors, you could put
|
|
the container inside a scrollable area. Then the container's actors
|
|
can be scrolled to if they go out of sight.
|
|
<link linkend="events-mouse-scroll">This recipe</link> explains
|
|
how to make a container scrollable.</para>
|
|
|
|
<section>
|
|
<title>Layout properties</title>
|
|
|
|
<para><type>ClutterBoxLayout</type> is very flexible, with
|
|
several properties which influence the appearance of the
|
|
layout and its children. As with other layouts, these properties
|
|
are either applicable to the layout itself, or to individual
|
|
children of the layout.</para>
|
|
|
|
<para>As most of these properties are documented in the API reference,
|
|
they aren't covered in much detail here. However, below is a brief
|
|
overview of the properties available, as well as details of properties
|
|
particular to <type>ClutterBoxLayout</type>.</para>
|
|
|
|
<para>The main issue you may face when applying these properties
|
|
is understanding how they interact. As this is harder to describe
|
|
than to show, you can run the
|
|
<link linkend="layouts-box-example-3">example</link>
|
|
below to toggle and tweak various properties and see
|
|
how they affect the layout's appearance.</para>
|
|
|
|
<note>
|
|
<para>The "toggle and tweak"
|
|
<link linkend="layouts-box-example-3">example</link> sets
|
|
child properties (fill, alignment, expand) on all children
|
|
of the layout when those properties are changed. If you want
|
|
to see the effect of setting these to different values for
|
|
<emphasis>each</emphasis> child, you will have to experiment
|
|
yourself.</para>
|
|
</note>
|
|
|
|
<section>
|
|
<title><type>ClutterBoxLayout</type> properties</title>
|
|
|
|
<para><type>ClutterBoxLayout</type> has the following properties
|
|
which affect the appearance of all children inside the container.</para>
|
|
|
|
<note>
|
|
<para>Animation properties are covered separately
|
|
<link linkend="layouts-box-animating-layout-changes">later</link>.
|
|
</para>
|
|
</note>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<formalpara>
|
|
<title><varname>vertical</varname>; set with
|
|
<function>clutter_box_layout_set_vertical()</function></title>
|
|
|
|
<para>Set to <constant>TRUE</constant> to lay out
|
|
child actors in a column; if <constant>FALSE</constant>
|
|
(the default), actors are laid out horizontally.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<formalpara>
|
|
<title><varname>homogeneous</varname>; set with
|
|
<function>clutter_box_layout_set_homogeneous()</function></title>
|
|
|
|
<para>Set to <constant>TRUE</constant> to allocate all
|
|
child actors the same amount of space in the row or column
|
|
(depending on the setting for <varname>vertical</varname>).
|
|
This overrides per-actor <varname>expand</varname> settings
|
|
and preferred sizes for child actors. The default value for
|
|
this property is <constant>FALSE</constant>.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<formalpara>
|
|
<title><varname>spacing</varname>; set with
|
|
<function>clutter_box_layout_set_spacing()</function></title>
|
|
|
|
<para>Sets the number of pixels to place between actors
|
|
in the layout.</para>
|
|
</formalpara>
|
|
|
|
<para>Note that if you increase spacing too much, actors
|
|
may go outside the edges of the layout's container (if
|
|
the container has a fixed size).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<formalpara>
|
|
<title><varname>pack-start</varname>; set with
|
|
<function>clutter_box_layout_set_pack_start()</function></title>
|
|
|
|
<para>Set <varname>pack-start</varname> to
|
|
<constant>TRUE</constant> to configure the layout to
|
|
prepend actors to the row or column; the default is
|
|
<constant>FALSE</constant>, meaning that actors are
|
|
appended to the row or column when added.</para>
|
|
</formalpara>
|
|
|
|
<para>Changing this property on a layout which already has
|
|
actors in it will reverse the order of those actors, as
|
|
well as changing how new actors are added to the layout.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</section>
|
|
|
|
<section>
|
|
<title>Child properties</title>
|
|
|
|
<para>These properties apply to individual children within
|
|
the layout's container. Each child can have different values
|
|
for each of these properties.</para>
|
|
|
|
<para>To set properties, you can use
|
|
<function>clutter_box_layout_pack()</function> or
|
|
<function>clutter_box_pack()</function> (if using a
|
|
<type>ClutterBox</type>) while packing actors into the layout.
|
|
You can also set properties later using
|
|
<function>clutter_layout_manager_child_set()</function>
|
|
etc. See the <link linkend="layouts-introduction">layouts
|
|
introduction</link> for more details.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><varname>x-fill</varname> and <varname>y-fill</varname>
|
|
set whether an actor will fill its allocated horizontal
|
|
or vertical space (respectively) within the layout. Setting
|
|
these properties only has an effect where an actor is smaller
|
|
(on the appropriate fill axes) than the layout's container.</para>
|
|
|
|
<para>Note that the actor's actual size is not changed
|
|
if it is set to fill: the reported width and height are
|
|
unaffected.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><varname>expand</varname> sets whether an actor
|
|
will be expanded inside the layout. If
|
|
<varname>expand</varname> is <constant>TRUE</constant>
|
|
and <varname>fill</varname> is <constant>TRUE</constant>
|
|
for the orientation axis, the actor is resized to fill
|
|
its whole allocation on that axis; if <varname>expand</varname>
|
|
is <constant>TRUE</constant> but <varname>fill</varname>
|
|
is <constant>FALSE</constant>, extra padding is added
|
|
around the actor to fill the allocation.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><varname>x-align</varname> and <varname>y-align</varname>
|
|
set how an actor is aligned within its allocation, in
|
|
cases where it doesn't fill that allocation. In practical
|
|
terms, these properties come into effect if a child is set
|
|
to expand but <varname>fill</varname> is set to
|
|
<constant>FALSE</constant> on the align axis.</para>
|
|
|
|
<para>For example, if <varname>expand</varname> is
|
|
<constant>TRUE</constant> but <varname>x-fill</varname>
|
|
is <constant>FALSE</constant>, some padding is added
|
|
around the actor to fill its allocation. In this case,
|
|
the <varname>x-align</varname> property can be set to
|
|
align the actor to the left, center or right of the
|
|
allocation; any whitespace would be redistributed around
|
|
the actor's new position after alignment.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>These properties are only useful where you have
|
|
actors of non-uniform sizes and/or a container which is
|
|
either wider or taller (or both) than one or more of the
|
|
child actors it contains.</para>
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|
|
<section id="layouts-box-animating-layout-changes">
|
|
<title>Animating layout changes</title>
|
|
|
|
<para>If actors are added to a layout, or if the layout's
|
|
properties or its children's properties are changed, the
|
|
appearance of the layout may also change. The
|
|
<varname>use-animations</varname> property (set with
|
|
<function>clutter_box_layout_set_use_animations()</function>)
|
|
determines whether such changes to the layout are animated: if set
|
|
to <constant>TRUE</constant>, any changes to actor
|
|
allocations resulting from the changes (movements, resizings)
|
|
are animated.</para>
|
|
|
|
<para>If this property is <constant>FALSE</constant> (the default)
|
|
changes to other properties or addition of new actors will
|
|
cause actors to be laid out instantaneously. For example, if
|
|
a new actor is prepended with animations on, the new actor is
|
|
added to the layout and the other actors shifted to make room
|
|
for it; if animations are off, child actors jump to their new
|
|
positions at the same instant as the new actor is added.</para>
|
|
|
|
<para>To change the appearance of the animations, you can use
|
|
<function>clutter_box_layout_set_easing_mode()</function> and
|
|
<function>clutter_box_layout_set_duration()</function> (see the
|
|
<link linkend="animations-introduction">animations
|
|
introduction</link> for more about easing and duration
|
|
properties).</para>
|
|
|
|
<para>The <link linkend="layouts-box-example-3">"toggle and tweak"
|
|
example</link> uses animation for layout changes, and can give
|
|
you some idea of what to expect in your own animated layouts.</para>
|
|
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Full examples</title>
|
|
|
|
<example id="layouts-box-example-1">
|
|
<title>Different approaches to setting child layout properties
|
|
in a <type>ClutterBoxLayout</type></title>
|
|
<programlisting>
|
|
<xi:include href="examples/layouts-box.c" parse="text">
|
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
|
</xi:include>
|
|
</programlisting>
|
|
</example>
|
|
|
|
<example id="layouts-box-example-2">
|
|
<title>A simple <type>ClutterBoxLayout</type> menu</title>
|
|
<programlisting>
|
|
<xi:include href="examples/layouts-box-menu.c" parse="text">
|
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
|
</xi:include>
|
|
</programlisting>
|
|
</example>
|
|
|
|
<example id="layouts-box-example-3">
|
|
<title>A demonstrator for "toggling and tweaking" a
|
|
<type>ClutterBoxLayout's</type> properties</title>
|
|
<programlisting>
|
|
<xi:include href="examples/layouts-box-property-effects.c" parse="text">
|
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
|
</xi:include>
|
|
</programlisting>
|
|
</example>
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|
|
</chapter>
|