Merge branch 'layout-manager'

* layout-manager: (50 commits)
  docs: Reword a link
  layout, docs: Add more documentation to LayoutManager
  layout, docs: Fix description of Bin properties
  layout, bin: Use ceilf() instead of casting to int
  layout, docs: Add long description for FlowLayout
  layout, box: Clean up
  layout, box: Write long description for Box
  layout, docs: Remove unused functions
  layout: Document BoxLayout
  layout: Add BoxLayout, a single line layout manager
  layout: Report the correct size of FlowLayout
  layout: Resizing the stage resizes the FlowLayout box
  layout: Use the get_request_mode() getter in BinLayout
  layout: Change the request-mode along with the orientation
  actor: Add set_request_mode() method
  [layout] Remove FlowLayout:wrap
  [layout] Rename BinLayout and FlowLayout interactive tests
  [layout] Skip invisible children in FlowLayout
  [layout] Clean up and document FlowLayout
  [layout] Snap children of FlowLayout to column/row
  ...
This commit is contained in:
Emmanuele Bassi 2009-10-19 11:45:15 +01:00
commit ba25571c8e
28 changed files with 7412 additions and 119 deletions

3
.gitignore vendored
View File

@ -132,6 +132,9 @@ TAGS
/tests/interactive/redhand_alpha.png
/tests/interactive/test-script.json
/tests/interactive/test-clutter-cairo-flowers
/tests/interactive/test-bin-layout
/tests/interactive/test-flow-layout
/tests/interactive/test-box-layout
/tests/conform/stamp-test-conformance
/tests/conform/test-anchors
/tests/conform/test-conformance

View File

@ -64,6 +64,9 @@ source_h = \
$(srcdir)/clutter-behaviour-rotate.h \
$(srcdir)/clutter-behaviour-scale.h \
$(srcdir)/clutter-binding-pool.h \
$(srcdir)/clutter-bin-layout.h \
$(srcdir)/clutter-box.h \
$(srcdir)/clutter-box-layout.h \
$(srcdir)/clutter-cairo-texture.h \
$(srcdir)/clutter-child-meta.h \
$(srcdir)/clutter-clone.h \
@ -73,10 +76,14 @@ source_h = \
$(srcdir)/clutter-event.h \
$(srcdir)/clutter-feature.h \
$(srcdir)/clutter-fixed.h \
$(srcdir)/clutter-fixed-layout.h \
$(srcdir)/clutter-flow-layout.h \
$(srcdir)/clutter-frame-source.h \
$(srcdir)/clutter-group.h \
$(srcdir)/clutter-interval.h \
$(srcdir)/clutter-keysyms.h \
$(srcdir)/clutter-layout-manager.h \
$(srcdir)/clutter-layout-meta.h \
$(srcdir)/clutter-list-model.h \
$(srcdir)/clutter-main.h \
$(srcdir)/clutter-media.h \
@ -128,6 +135,9 @@ source_c = \
$(srcdir)/clutter-behaviour-scale.c \
$(srcdir)/clutter-bezier.c \
$(srcdir)/clutter-binding-pool.c \
$(srcdir)/clutter-bin-layout.c \
$(srcdir)/clutter-box.c \
$(srcdir)/clutter-box-layout.c \
$(srcdir)/clutter-cairo-texture.c \
$(srcdir)/clutter-child-meta.c \
$(srcdir)/clutter-clone.c \
@ -137,10 +147,14 @@ source_c = \
$(srcdir)/clutter-event.c \
$(srcdir)/clutter-feature.c \
$(srcdir)/clutter-fixed.c \
$(srcdir)/clutter-fixed-layout.c \
$(srcdir)/clutter-flow-layout.c \
$(srcdir)/clutter-frame-source.c \
$(srcdir)/clutter-group.c \
$(srcdir)/clutter-id-pool.c \
$(srcdir)/clutter-interval.c \
$(srcdir)/clutter-layout-manager.c \
$(srcdir)/clutter-layout-meta.c \
$(srcdir)/clutter-list-model.c \
$(srcdir)/clutter-main.c \
clutter-marshal.c \

View File

@ -473,8 +473,6 @@ static void clutter_actor_set_natural_width_set (ClutterActor *self,
gboolean use_natural_width);
static void clutter_actor_set_natural_height_set (ClutterActor *self,
gboolean use_natural_height);
static void clutter_actor_set_request_mode (ClutterActor *self,
ClutterRequestMode mode);
static void clutter_actor_update_map_state (ClutterActor *self,
MapStateChange change);
static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
@ -3297,7 +3295,7 @@ clutter_actor_class_init (ClutterActorClass *klass)
* gfloat natural_width, min_width;
* gfloat natural_height, min_height;
*
* g_object_get (G_OBJECT (child), "request-mode", &mode, NULL);
* mode = clutter_actor_get_request_mode (child);
* if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
* {
* clutter_actor_get_preferred_width (child, -1,
@ -5184,11 +5182,28 @@ clutter_actor_set_natural_height_set (ClutterActor *self,
clutter_actor_queue_relayout (self);
}
static void
/**
* clutter_actor_set_request_mode:
* @self: a #ClutterActor
* @mode: the request mode
*
* Sets the geometry request mode of @self.
*
* The @mode determines the order for invoking
* clutter_actor_get_preferred_width() and
* clutter_actor_get_preferred_height()
*
* Since: 1.2
*/
void
clutter_actor_set_request_mode (ClutterActor *self,
ClutterRequestMode mode)
{
ClutterActorPrivate *priv = self->priv;
ClutterActorPrivate *priv;
g_return_if_fail (CLUTTER_IS_ACTOR (self));
priv = self->priv;
if (priv->request_mode == mode)
return;
@ -5203,6 +5218,25 @@ clutter_actor_set_request_mode (ClutterActor *self,
clutter_actor_queue_relayout (self);
}
/**
* clutter_actor_get_request_mode:
* @self: a #ClutterActor
*
* Retrieves the geometry request mode of @self
*
* Return value: the request mode for the actor
*
* Since: 1.2
*/
ClutterRequestMode
clutter_actor_get_request_mode (ClutterActor *self)
{
g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
return self->priv->request_mode;
}
/* variant of set_width() without checks and without notification
* freeze+thaw, for internal usage only
*/

View File

@ -301,6 +301,9 @@ void clutter_actor_queue_relayout (ClutterActor
void clutter_actor_destroy (ClutterActor *self);
/* size negotiation */
void clutter_actor_set_request_mode (ClutterActor *self,
ClutterRequestMode mode);
ClutterRequestMode clutter_actor_get_request_mode (ClutterActor *self);
void clutter_actor_get_preferred_width (ClutterActor *self,
gfloat for_height,
gfloat *min_width_p,

View File

@ -0,0 +1,865 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009 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-bin-layout
* @short_description: A simple layout manager
*
* #ClutterBinLayout is a layout manager which implements the following
* policy:
*
* <itemizedlist>
* <listitem><simpara>the preferred size is the maximum preferred size
* between all the children of the container using the
* layout;</simpara></listitem>
* <listitem><simpara>each child is allocated in "layers", on on top
* of the other;</simpara></listitem>
* <listitem><simpara>for each layer there are horizontal and vertical
* alignment policies.</simpara></listitem>
* </itemizedlist>
*
* <example id="example-clutter-bin-layout">
* <title>How to pack actors inside a BinLayout</title>
* <para>The following code shows how to build a composite actor with
* a texture and a background, and add controls overlayed on top. The
* background is set to fill the whole allocation, whilst the texture
* is centered; there is a control in the top right corner and a label
* in the bottom, filling out the whole allocated width.</para>
* <programlisting>
* ClutterLayoutManager *manager;
* ClutterActor *box;
*
* /&ast; create the layout first &ast;/
* layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
* CLUTTER_BIN_ALIGNMENT_CENTER);
* box = clutter_box_new (layout); /&ast; then the container &ast;/
*
* /&ast; we can use the layout object to add actors &ast;/
* clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), background,
* CLUTTER_BIN_ALIGNMENT_FILL,
* CLUTTER_BIN_ALIGNMENT_FILL);
* clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), icon,
* CLUTTER_BIN_ALIGNMENT_CENTER,
* CLUTTER_BIN_ALIGNMENT_CENTER);
*
* /&ast; align to the bottom left &ast;/
* clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), label,
* CLUTTER_BIN_ALIGNMENT_START,
* CLUTTER_BIN_ALIGNMENT_END);
* /&ast; align to the top right &ast;/
* clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), button,
* CLUTTER_BIN_ALIGNMENT_END,
* CLUTTER_BIN_ALIGNMENT_START);
* </programlisting>
* </example>
*
* #ClutterBinLayout is available since Clutter 1.2
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include "clutter-actor.h"
#include "clutter-animatable.h"
#include "clutter-bin-layout.h"
#include "clutter-child-meta.h"
#include "clutter-debug.h"
#include "clutter-enum-types.h"
#include "clutter-layout-meta.h"
#include "clutter-private.h"
#define CLUTTER_TYPE_BIN_LAYER (clutter_bin_layer_get_type ())
#define CLUTTER_BIN_LAYER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BIN_LAYER, ClutterBinLayer))
#define CLUTTER_IS_BIN_LAYER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BIN_LAYER))
#define CLUTTER_BIN_LAYOUT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_BIN_LAYOUT, ClutterBinLayoutPrivate))
typedef struct _ClutterBinLayer ClutterBinLayer;
typedef struct _ClutterLayoutMetaClass ClutterBinLayerClass;
struct _ClutterBinLayoutPrivate
{
ClutterBinAlignment x_align;
ClutterBinAlignment y_align;
ClutterContainer *container;
};
struct _ClutterBinLayer
{
ClutterLayoutMeta parent_instance;
ClutterBinAlignment x_align;
ClutterBinAlignment y_align;
};
enum
{
PROP_LAYER_0,
PROP_LAYER_X_ALIGN,
PROP_LAYER_Y_ALIGN
};
enum
{
PROP_0,
PROP_X_ALIGN,
PROP_Y_ALIGN
};
G_DEFINE_TYPE (ClutterBinLayer,
clutter_bin_layer,
CLUTTER_TYPE_LAYOUT_META);
G_DEFINE_TYPE (ClutterBinLayout,
clutter_bin_layout,
CLUTTER_TYPE_LAYOUT_MANAGER);
/*
* ClutterBinLayer
*/
static void
set_layer_x_align (ClutterBinLayer *self,
ClutterBinAlignment alignment)
{
ClutterLayoutManager *manager;
ClutterLayoutMeta *meta;
if (self->x_align == alignment)
return;
self->x_align = alignment;
meta = CLUTTER_LAYOUT_META (self);
manager = clutter_layout_meta_get_manager (meta);
clutter_layout_manager_layout_changed (manager);
g_object_notify (G_OBJECT (self), "x-align");
}
static void
set_layer_y_align (ClutterBinLayer *self,
ClutterBinAlignment alignment)
{
ClutterLayoutManager *manager;
ClutterLayoutMeta *meta;
if (self->y_align == alignment)
return;
self->y_align = alignment;
meta = CLUTTER_LAYOUT_META (self);
manager = clutter_layout_meta_get_manager (meta);
clutter_layout_manager_layout_changed (manager);
g_object_notify (G_OBJECT (self), "y-align");
}
static void
clutter_bin_layer_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterBinLayer *layer = CLUTTER_BIN_LAYER (gobject);
switch (prop_id)
{
case PROP_LAYER_X_ALIGN:
set_layer_x_align (layer, g_value_get_enum (value));
break;
case PROP_LAYER_Y_ALIGN:
set_layer_y_align (layer, g_value_get_enum (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_bin_layer_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterBinLayer *layer = CLUTTER_BIN_LAYER (gobject);
switch (prop_id)
{
case PROP_LAYER_X_ALIGN:
g_value_set_enum (value, layer->x_align);
break;
case PROP_LAYER_Y_ALIGN:
g_value_set_enum (value, layer->y_align);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_bin_layer_class_init (ClutterBinLayerClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
gobject_class->set_property = clutter_bin_layer_set_property;
gobject_class->get_property = clutter_bin_layer_get_property;
pspec = g_param_spec_enum ("x-align",
"Horizontal Alignment",
"Horizontal alignment for the actor "
"inside the layer",
CLUTTER_TYPE_BIN_ALIGNMENT,
CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_LAYER_X_ALIGN,
pspec);
pspec = g_param_spec_enum ("y-align",
"Vertical Alignment",
"Vertical alignment for the actor "
"inside the layer manager",
CLUTTER_TYPE_BIN_ALIGNMENT,
CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_LAYER_Y_ALIGN,
pspec);
}
static void
clutter_bin_layer_init (ClutterBinLayer *layer)
{
layer->x_align = CLUTTER_BIN_ALIGNMENT_CENTER;
layer->y_align = CLUTTER_BIN_ALIGNMENT_CENTER;
}
/*
* ClutterBinLayout
*/
static void
set_x_align (ClutterBinLayout *self,
ClutterBinAlignment alignment)
{
ClutterBinLayoutPrivate *priv = self->priv;
if (priv->x_align != alignment)
{
ClutterLayoutManager *manager;
priv->x_align = alignment;
manager = CLUTTER_LAYOUT_MANAGER (self);
clutter_layout_manager_layout_changed (manager);
g_object_notify (G_OBJECT (self), "x-align");
}
}
static void
set_y_align (ClutterBinLayout *self,
ClutterBinAlignment alignment)
{
ClutterBinLayoutPrivate *priv = self->priv;
if (priv->y_align != alignment)
{
ClutterLayoutManager *manager;
priv->y_align = alignment;
manager = CLUTTER_LAYOUT_MANAGER (self);
clutter_layout_manager_layout_changed (manager);
g_object_notify (G_OBJECT (self), "y-align");
}
}
static void
clutter_bin_layout_get_preferred_width (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_height,
gfloat *min_width_p,
gfloat *nat_width_p)
{
GList *children = clutter_container_get_children (container);
GList *l;
gfloat min_width, nat_width;
min_width = nat_width = 0.0;
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
gfloat minimum, natural;
clutter_actor_get_preferred_width (child, for_height,
&minimum,
&natural);
min_width = MAX (min_width, minimum);
nat_width = MAX (nat_width, natural);
}
if (min_width_p)
*min_width_p = min_width;
if (nat_width_p)
*nat_width_p = nat_width;
}
static void
clutter_bin_layout_get_preferred_height (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_width,
gfloat *min_height_p,
gfloat *nat_height_p)
{
GList *children = clutter_container_get_children (container);
GList *l;
gfloat min_height, nat_height;
min_height = nat_height = 0.0;
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
gfloat minimum, natural;
clutter_actor_get_preferred_height (child, for_width,
&minimum,
&natural);
min_height = MAX (min_height, minimum);
nat_height = MAX (nat_height, natural);
}
if (min_height_p)
*min_height_p = min_height;
if (nat_height_p)
*nat_height_p = nat_height;
}
static gdouble
get_bin_alignment_factor (ClutterBinAlignment alignment)
{
switch (alignment)
{
case CLUTTER_BIN_ALIGNMENT_CENTER:
return 0.5;
case CLUTTER_BIN_ALIGNMENT_START:
return 0.0;
case CLUTTER_BIN_ALIGNMENT_END:
return 1.0;
case CLUTTER_BIN_ALIGNMENT_FIXED:
case CLUTTER_BIN_ALIGNMENT_FILL:
return 0.0;
}
return 0.0;
}
static void
clutter_bin_layout_allocate (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
{
GList *children = clutter_container_get_children (container);
GList *l;
gfloat available_w, available_h;
available_w = clutter_actor_box_get_width (allocation);
available_h = clutter_actor_box_get_height (allocation);
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
ClutterLayoutMeta *meta;
ClutterBinLayer *layer;
ClutterActorBox child_alloc = { 0, };
gfloat child_width, child_height;
ClutterRequestMode request;
meta = clutter_layout_manager_get_child_meta (manager,
container,
child);
layer = CLUTTER_BIN_LAYER (meta);
if (layer->x_align == CLUTTER_BIN_ALIGNMENT_FILL)
{
child_alloc.x1 = 0;
child_alloc.x2 = ceilf (available_w);
}
if (layer->y_align == CLUTTER_BIN_ALIGNMENT_FILL)
{
child_alloc.y1 = 0;
child_alloc.y2 = ceilf (available_h);
}
/* if we are filling horizontally and vertically then we
* can break here because we already have a full allocation
*/
if (layer->x_align == CLUTTER_BIN_ALIGNMENT_FILL &&
layer->y_align == CLUTTER_BIN_ALIGNMENT_FILL)
{
clutter_actor_allocate (child, &child_alloc, flags);
continue;
}
request = clutter_actor_get_request_mode (child);
if (request == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
{
gfloat min_width, nat_width;
gfloat min_height, nat_height;
clutter_actor_get_preferred_width (child, available_h,
&min_width,
&nat_width);
child_width = CLAMP (nat_width, min_width, available_w);
clutter_actor_get_preferred_height (child, child_width,
&min_height,
&nat_height);
child_height = CLAMP (nat_height, min_height, available_h);
}
else if (request == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
{
gfloat min_width, nat_width;
gfloat min_height, nat_height;
clutter_actor_get_preferred_height (child, available_w,
&min_height,
&nat_height);
child_height = CLAMP (nat_height, min_height, available_h);
clutter_actor_get_preferred_width (child, child_height,
&min_width,
&nat_width);
child_width = CLAMP (nat_width, min_width, available_w);
}
if (layer->x_align == CLUTTER_BIN_ALIGNMENT_FIXED)
{
child_alloc.x1 = ceilf (clutter_actor_get_x (child));
child_alloc.x2 = ceilf (child_alloc.x1 + child_width);
}
else
{
gdouble x_align = get_bin_alignment_factor (layer->x_align);
if (layer->x_align != CLUTTER_BIN_ALIGNMENT_FILL)
{
child_alloc.x1 = ceilf ((available_w - child_width) * x_align);
child_alloc.x2 = ceilf (child_alloc.x1 + child_width);
}
}
if (layer->y_align == CLUTTER_BIN_ALIGNMENT_FIXED)
{
child_alloc.y1 = ceilf (clutter_actor_get_y (child));
child_alloc.y2 = ceilf (child_alloc.y1 + child_height);
}
else
{
gdouble y_align = get_bin_alignment_factor (layer->y_align);
if (layer->y_align != CLUTTER_BIN_ALIGNMENT_FILL)
{
child_alloc.y1 = ceilf ((available_h - child_height) * y_align);
child_alloc.y2 = ceilf (child_alloc.y1 + child_height);
}
}
clutter_actor_allocate (child, &child_alloc, flags);
}
g_list_free (children);
}
static ClutterLayoutMeta *
clutter_bin_layout_create_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor)
{
ClutterBinLayoutPrivate *priv;
priv = CLUTTER_BIN_LAYOUT (manager)->priv;
return g_object_new (CLUTTER_TYPE_BIN_LAYER,
"container", container,
"actor", actor,
"manager", manager,
"x-align", priv->x_align,
"y_align", priv->y_align,
NULL);
}
static void
clutter_bin_layout_set_container (ClutterLayoutManager *manager,
ClutterContainer *container)
{
ClutterBinLayoutPrivate *priv;
priv = CLUTTER_BIN_LAYOUT (manager)->priv;
priv->container = container;
}
static void
clutter_bin_layout_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterBinLayout *layout = CLUTTER_BIN_LAYOUT (gobject);
switch (prop_id)
{
case PROP_X_ALIGN:
set_x_align (layout, g_value_get_enum (value));
break;
case PROP_Y_ALIGN:
set_y_align (layout, g_value_get_enum (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_bin_layout_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterBinLayoutPrivate *priv;
priv = CLUTTER_BIN_LAYOUT (gobject)->priv;
switch (prop_id)
{
case PROP_X_ALIGN:
g_value_set_enum (value, priv->x_align);
break;
case PROP_Y_ALIGN:
g_value_set_enum (value, priv->y_align);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_bin_layout_class_init (ClutterBinLayoutClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterLayoutManagerClass *layout_class =
CLUTTER_LAYOUT_MANAGER_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (ClutterBinLayoutPrivate));
gobject_class->set_property = clutter_bin_layout_set_property;
gobject_class->get_property = clutter_bin_layout_get_property;
/**
* ClutterBinLayout:x-align:
*
* The default horizontal alignment policy for actors managed
* by the #ClutterBinLayout
*
* Since: 1.2
*/
pspec = g_param_spec_enum ("x-align",
"Horizontal Alignment",
"Default horizontal alignment for the actors "
"inside the layout manager",
CLUTTER_TYPE_BIN_ALIGNMENT,
CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_X_ALIGN, pspec);
/**
* ClutterBinLayout:y-align:
*
* The default vertical alignment policy for actors managed
* by the #ClutterBinLayout
*
* Since: 1.2
*/
pspec = g_param_spec_enum ("y-align",
"Vertical Alignment",
"Default vertical alignment for the actors "
"inside the layout manager",
CLUTTER_TYPE_BIN_ALIGNMENT,
CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_Y_ALIGN, pspec);
layout_class->get_preferred_width =
clutter_bin_layout_get_preferred_width;
layout_class->get_preferred_height =
clutter_bin_layout_get_preferred_height;
layout_class->allocate =
clutter_bin_layout_allocate;
layout_class->create_child_meta =
clutter_bin_layout_create_child_meta;
layout_class->set_container =
clutter_bin_layout_set_container;
}
static void
clutter_bin_layout_init (ClutterBinLayout *self)
{
self->priv = CLUTTER_BIN_LAYOUT_GET_PRIVATE (self);
self->priv->x_align = CLUTTER_BIN_ALIGNMENT_CENTER;
self->priv->y_align = CLUTTER_BIN_ALIGNMENT_CENTER;
}
/**
* clutter_bin_layout_new:
* @x_align: the default alignment policy to be used on the
* horizontal axis
* @y_align: the default alignment policy to be used on the
* vertical axis
*
* Creates a new #ClutterBinLayout layout manager
*
* Return value: the newly created layout manager
*
* Since: 1.2
*/
ClutterLayoutManager *
clutter_bin_layout_new (ClutterBinAlignment x_align,
ClutterBinAlignment y_align)
{
return g_object_new (CLUTTER_TYPE_BIN_LAYOUT,
"x-align", x_align,
"y-align", y_align,
NULL);
}
/**
* clutter_bin_layout_set_alignment:
* @self: a #ClutterBinLayout
* @child: (allow-none): a child of @container
* @x_align: the horizontal alignment policy to be used for the @child
* inside @container
* @y_align: the vertical aligment policy to be used on the @child
* inside @container
*
* Sets the horizontal and vertical alignment policies to be applied
* to a @child of @self
*
* If @child is %NULL then the @x_align and @y_align values will
* be set as the default alignment policies
*
* Since: 1.2
*/
void
clutter_bin_layout_set_alignment (ClutterBinLayout *self,
ClutterActor *child,
ClutterBinAlignment x_align,
ClutterBinAlignment y_align)
{
ClutterBinLayoutPrivate *priv;
ClutterLayoutManager *manager;
ClutterLayoutMeta *meta;
g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
g_return_if_fail (child == NULL || CLUTTER_IS_ACTOR (child));
priv = self->priv;
if (priv->container == NULL)
{
if (child == NULL)
{
set_x_align (self, x_align);
set_y_align (self, y_align);
}
else
g_warning ("The layout of type '%s' must be associated to "
"a ClutterContainer before setting the alignment "
"on its children",
G_OBJECT_TYPE_NAME (self));
return;
}
manager = CLUTTER_LAYOUT_MANAGER (self);
meta = clutter_layout_manager_get_child_meta (manager,
priv->container,
child);
g_assert (CLUTTER_IS_BIN_LAYER (meta));
set_layer_x_align (CLUTTER_BIN_LAYER (meta), x_align);
set_layer_y_align (CLUTTER_BIN_LAYER (meta), y_align);
}
/**
* clutter_bin_layout_get_alignment:
* @self: a #ClutterBinLayout
* @child: (allow-none): a child of @container
* @x_align: (out) (allow-none): return location for the horizontal
* alignment policy
* @y_align: (out) (allow-none): return location for the vertical
* alignment policy
*
* Retrieves the horizontal and vertical alignment policies for
* a child of @self
*
* If @child is %NULL the default alignment policies will be returned
* instead
*
* Since: 1.2
*/
void
clutter_bin_layout_get_alignment (ClutterBinLayout *self,
ClutterActor *child,
ClutterBinAlignment *x_align,
ClutterBinAlignment *y_align)
{
ClutterBinLayoutPrivate *priv;
ClutterLayoutManager *manager;
ClutterLayoutMeta *meta;
ClutterBinLayer *layer;
g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
priv = self->priv;
if (priv->container == NULL)
{
if (child == NULL)
{
if (x_align)
*x_align = priv->x_align;
if (y_align)
*y_align = priv->y_align;
}
else
g_warning ("The layout of type '%s' must be associated to "
"a ClutterContainer before getting the alignment "
"of its children",
G_OBJECT_TYPE_NAME (self));
return;
}
manager = CLUTTER_LAYOUT_MANAGER (self);
meta = clutter_layout_manager_get_child_meta (manager,
priv->container,
child);
g_assert (CLUTTER_IS_BIN_LAYER (meta));
layer = CLUTTER_BIN_LAYER (meta);
if (x_align)
*x_align = layer->x_align;
if (y_align)
*y_align = layer->y_align;
}
/**
* clutter_bin_layout_add:
* @self: a #ClutterBinLayout
* @child: a #ClutterActor
* @x_align: horizontal alignment policy for @child
* @y_align: vertical alignment policy for @child
*
* Adds a #ClutterActor to the container using @self and
* sets the alignment policies for it
*
* This function is equivalent to clutter_container_add_actor()
* and clutter_layout_manager_child_set_property() but it does not
* require a pointer to the #ClutterContainer associated to the
* #ClutterBinLayout
*
* Since: 1.2
*/
void
clutter_bin_layout_add (ClutterBinLayout *self,
ClutterActor *child,
ClutterBinAlignment x_align,
ClutterBinAlignment y_align)
{
ClutterBinLayoutPrivate *priv;
ClutterLayoutManager *manager;
ClutterLayoutMeta *meta;
g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
g_return_if_fail (CLUTTER_IS_ACTOR (child));
priv = self->priv;
if (priv->container == NULL)
{
g_warning ("The layout of type '%s' must be associated to "
"a ClutterContainer before adding children",
G_OBJECT_TYPE_NAME (self));
return;
}
clutter_container_add_actor (priv->container, child);
manager = CLUTTER_LAYOUT_MANAGER (self);
meta = clutter_layout_manager_get_child_meta (manager,
priv->container,
child);
g_assert (CLUTTER_IS_BIN_LAYER (meta));
set_layer_x_align (CLUTTER_BIN_LAYER (meta), x_align);
set_layer_y_align (CLUTTER_BIN_LAYER (meta), y_align);
}

View File

@ -0,0 +1,123 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009 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>
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_BIN_LAYOUT_H__
#define __CLUTTER_BIN_LAYOUT_H__
#include <clutter/clutter-layout-manager.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_BIN_LAYOUT (clutter_bin_layout_get_type ())
#define CLUTTER_BIN_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BIN_LAYOUT, ClutterBinLayout))
#define CLUTTER_IS_BIN_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BIN_LAYOUT))
#define CLUTTER_BIN_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BIN_LAYOUT, ClutterBinLayoutClass))
#define CLUTTER_IS_BIN_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BIN_LAYOUT))
#define CLUTTER_BIN_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BIN_LAYOUT, ClutterBinLayoutClass))
typedef struct _ClutterBinLayout ClutterBinLayout;
typedef struct _ClutterBinLayoutPrivate ClutterBinLayoutPrivate;
typedef struct _ClutterBinLayoutClass ClutterBinLayoutClass;
/**
* ClutterBinAlignment:
* @CLUTTER_BIN_ALIGNMENT_FIXED: Fixed position alignment; the
* #ClutterBinLayout will honour the fixed position provided
* by the actors themselves when allocating them
* @CLUTTER_BIN_ALIGNMENT_FILL: Fill the allocation size
* @CLUTTER_BIN_ALIGNMENT_START: Position the actors at the top
* or left side of the container, depending on the axis
* @CLUTTER_BIN_ALIGNMENT_END: Position the actors at the bottom
* or right side of the container, depending on the axis
* @CLUTTER_BIN_ALIGNMENT_CENTER: Position the actors at the
* center of the container, depending on the axis
*
* The alignment policies available on each axis for #ClutterBinLayout
*
* Since: 1.2
*/
typedef enum {
CLUTTER_BIN_ALIGNMENT_FIXED,
CLUTTER_BIN_ALIGNMENT_FILL,
CLUTTER_BIN_ALIGNMENT_START,
CLUTTER_BIN_ALIGNMENT_END,
CLUTTER_BIN_ALIGNMENT_CENTER
} ClutterBinAlignment;
/**
* ClutterBinLayout:
*
* The #ClutterBinLayout structure contains only private data
* and should be accessed using the provided API
*
* Since: 1.2
*/
struct _ClutterBinLayout
{
/*< private >*/
ClutterLayoutManager parent_instance;
ClutterBinLayoutPrivate *priv;
};
/**
* ClutterBinLayoutClass:
*
* The #ClutterBinLayoutClass structure contains only private
* data and should be accessed using the provided API
*
* Since: 1.2
*/
struct _ClutterBinLayoutClass
{
/*< private >*/
ClutterLayoutManagerClass parent_class;
};
GType clutter_bin_layout_get_type (void) G_GNUC_CONST;
ClutterLayoutManager *clutter_bin_layout_new (ClutterBinAlignment x_align,
ClutterBinAlignment y_align);
void clutter_bin_layout_set_alignment (ClutterBinLayout *self,
ClutterActor *child,
ClutterBinAlignment x_align,
ClutterBinAlignment y_align);
void clutter_bin_layout_get_alignment (ClutterBinLayout *self,
ClutterActor *child,
ClutterBinAlignment *x_align,
ClutterBinAlignment *y_align);
void clutter_bin_layout_add (ClutterBinLayout *self,
ClutterActor *child,
ClutterBinAlignment x_align,
ClutterBinAlignment y_align);
G_END_DECLS
#endif /* __CLUTTER_BIN_LAYOUT_H__ */

1496
clutter/clutter-box-layout.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,143 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009 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>
*
* Based on the NBTK NbtkBoxLayout actor by:
* Thomas Wood <thomas.wood@intel.com>
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_BOX_LAYOUT_H__
#define __CLUTTER_BOX_LAYOUT_H__
#include <clutter/clutter-layout-manager.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_BOX_LAYOUT (clutter_box_layout_get_type ())
#define CLUTTER_BOX_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BOX_LAYOUT, ClutterBoxLayout))
#define CLUTTER_IS_BOX_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BOX_LAYOUT))
#define CLUTTER_BOX_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BOX_LAYOUT, ClutterBoxLayoutClass))
#define CLUTTER_IS_BOX_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BOX_LAYOUT))
#define CLUTTER_BOX_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BOX_LAYOUT, ClutterBoxLayoutClass))
typedef struct _ClutterBoxLayout ClutterBoxLayout;
typedef struct _ClutterBoxLayoutPrivate ClutterBoxLayoutPrivate;
typedef struct _ClutterBoxLayoutClass ClutterBoxLayoutClass;
/**
* ClutterBoxAlignment:
* @CLUTTER_BOX_ALIGNMENT_START: Align the child to the top or to
* to the left, depending on the used axis
* @CLUTTER_BOX_ALIGNMENT_CENTER: Align the child to the center
* @CLUTTER_BOX_ALIGNMENT_END: Align the child to the bottom or to
* the right, depending on the used axis
*
* The alignment policies available on each axis of the #ClutterBoxLayout
*
* Since: 1.2
*/
typedef enum {
CLUTTER_BOX_ALIGNMENT_START,
CLUTTER_BOX_ALIGNMENT_END,
CLUTTER_BOX_ALIGNMENT_CENTER
} ClutterBoxAlignment;
/**
* ClutterBoxLayout:
*
* The #ClutterBoxLayout structure contains only private data
* and should be accessed using the provided API
*
* Since: 1.2
*/
struct _ClutterBoxLayout
{
/*< private >*/
ClutterLayoutManager parent_instance;
ClutterBoxLayoutPrivate *priv;
};
/**
* ClutterBoxLayoutClass:
*
* The #ClutterBoxLayoutClass structure contains only private
* data and should be accessed using the provided API
*
* Since: 1.2
*/
struct _ClutterBoxLayoutClass
{
/*< private >*/
ClutterLayoutManagerClass parent_class;
};
GType clutter_box_layout_get_type (void) G_GNUC_CONST;
ClutterLayoutManager *clutter_box_layout_new (void);
void clutter_box_layout_set_spacing (ClutterBoxLayout *layout,
guint spacing);
guint clutter_box_layout_get_spacing (ClutterBoxLayout *layout);
void clutter_box_layout_set_vertical (ClutterBoxLayout *layout,
gboolean vertical);
gboolean clutter_box_layout_get_vertical (ClutterBoxLayout *layout);
void clutter_box_layout_set_pack_start (ClutterBoxLayout *layout,
gboolean pack_start);
gboolean clutter_box_layout_get_pack_start (ClutterBoxLayout *layout);
void clutter_box_layout_pack (ClutterBoxLayout *layout,
ClutterActor *actor,
gboolean expand,
gboolean x_fill,
gboolean y_fill,
ClutterBoxAlignment x_align,
ClutterBoxAlignment y_align);
void clutter_box_layout_set_alignment (ClutterBoxLayout *layout,
ClutterActor *actor,
ClutterBoxAlignment x_align,
ClutterBoxAlignment y_align);
void clutter_box_layout_get_alignment (ClutterBoxLayout *layout,
ClutterActor *actor,
ClutterBoxAlignment *x_align,
ClutterBoxAlignment *y_align);
void clutter_box_layout_set_fill (ClutterBoxLayout *layout,
ClutterActor *actor,
gboolean x_fill,
gboolean y_fill);
void clutter_box_layout_get_fill (ClutterBoxLayout *layout,
ClutterActor *actor,
gboolean *x_fill,
gboolean *y_fill);
void clutter_box_layout_set_expand (ClutterBoxLayout *layout,
ClutterActor *actor,
gboolean expand);
gboolean clutter_box_layout_get_expand (ClutterBoxLayout *layout,
ClutterActor *actor);
G_END_DECLS
#endif /* __CLUTTER_BOX_LAYOUT_H__ */

828
clutter/clutter-box.c Normal file
View File

@ -0,0 +1,828 @@
/**
* SECTION:clutter-box
* @short_description: A Generic layout container
*
* #ClutterBox is a #ClutterActor sub-class implementing the #ClutterContainer
* interface. A Box delegates the whole size requisition and size allocation to
* a #ClutterLayoutManager instance.
*
* <example id="example-clutter-box">
* <title>Using ClutterBox</title>
* <para>The following code shows how to create a #ClutterBox with
* a #ClutterLayoutManager sub-class, and how to add children to
* it via clutter_box_pack().</para>
* <programlisting>
* ClutterActor *box;
* ClutterLayoutManager *layout;
*
* /&ast; Create the layout manager first &ast;/
* layout = clutter_box_layout_new ();
* clutter_box_layout_set_homogeneous (CLUTTER_BOX_LAYOUT (layout), TRUE);
* clutter_box_layout_set_spacing (CLUTTER_BOX_LAYOUT (layout), 12);
*
* /&ast; Then create the ClutterBox actor. The Box will take
* &ast; ownership of the ClutterLayoutManager instance by sinking
* &ast; its floating reference
* &ast;/
* box = clutter_box_new (layout);
*
* /&ast; Now add children to the Box using the variadic arguments
* &ast; function clutter_box_pack() to set layout properties
* &ast;/
* clutter_box_pack (CLUTTER_BOX (box), actor,
* "x-align", CLUTTER_BOX_ALIGNMENT_CENTER,
* "y-align", CLUTTER_BOX_ALIGNMENT_END,
* "expand", TRUE,
* NULL);
* </programlisting>
* </example>
*
* #ClutterBox<!-- -->'s clutter_box_pack() wraps the generic
* clutter_container_add_actor() function, but it also allows setting
* layout properties while adding the new child to the box.
*
* #ClutterBox is available since Clutter 1.2
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib-object.h>
#include <gobject/gvaluecollector.h>
#include "clutter-box.h"
#include "clutter-debug.h"
#include "clutter-enum-types.h"
#include "clutter-marshal.h"
#include "clutter-private.h"
#define CLUTTER_BOX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_BOX, ClutterBoxPrivate))
struct _ClutterBoxPrivate
{
ClutterLayoutManager *manager;
GList *children;
guint changed_id;
ClutterColor color;
guint color_set : 1;
};
enum
{
PROP_0,
PROP_LAYOUT_MANAGER,
PROP_COLOR,
PROP_COLOR_SET
};
static const ClutterColor default_box_color = { 255, 255, 255, 255 };
static void clutter_container_iface_init (ClutterContainerIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterBox, clutter_box, CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
clutter_container_iface_init));
static gint
sort_by_depth (gconstpointer a,
gconstpointer b)
{
gfloat depth_a = clutter_actor_get_depth ((ClutterActor *) a);
gfloat depth_b = clutter_actor_get_depth ((ClutterActor *) b);
if (depth_a < depth_b)
return -1;
if (depth_a > depth_b)
return 1;
return 0;
}
static void
clutter_box_real_add (ClutterContainer *container,
ClutterActor *actor)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (container)->priv;
g_object_ref (actor);
priv->children = g_list_insert_sorted (priv->children,
actor,
sort_by_depth);
clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
clutter_layout_manager_add_child_meta (priv->manager,
container,
actor);
clutter_actor_queue_relayout (actor);
g_signal_emit_by_name (container, "actor-added", actor);
g_object_unref (actor);
}
static void
clutter_box_real_remove (ClutterContainer *container,
ClutterActor *actor)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (container)->priv;
g_object_ref (actor);
priv->children = g_list_remove (priv->children, actor);
clutter_actor_unparent (actor);
clutter_layout_manager_remove_child_meta (priv->manager,
container,
actor);
clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
g_signal_emit_by_name (container, "actor-removed", actor);
g_object_unref (actor);
}
static void
clutter_box_real_foreach (ClutterContainer *container,
ClutterCallback callback,
gpointer user_data)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (container)->priv;
GList *l;
for (l = priv->children; l != NULL; l = l->next)
(* callback) (l->data, user_data);
}
static void
clutter_box_real_raise (ClutterContainer *container,
ClutterActor *actor,
ClutterActor *sibling)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (container)->priv;
priv->children = g_list_remove (priv->children, actor);
if (sibling == NULL)
priv->children = g_list_append (priv->children, actor);
else
{
gint index_ = g_list_index (priv->children, sibling) + 1;
priv->children = g_list_insert (priv->children, actor, index_);
}
clutter_actor_queue_redraw (CLUTTER_ACTOR (container));
}
static void
clutter_box_real_lower (ClutterContainer *container,
ClutterActor *actor,
ClutterActor *sibling)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (container)->priv;
priv->children = g_list_remove (priv->children, actor);
if (sibling == NULL)
priv->children = g_list_prepend (priv->children, actor);
else
{
gint index_ = g_list_index (priv->children, sibling);
priv->children = g_list_insert (priv->children, actor, index_);
}
clutter_actor_queue_redraw (CLUTTER_ACTOR (container));
}
static void
clutter_box_real_sort_depth_order (ClutterContainer *container)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (container)->priv;
priv->children = g_list_sort (priv->children, sort_by_depth);
clutter_actor_queue_redraw (CLUTTER_ACTOR (container));
}
static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
iface->add = clutter_box_real_add;
iface->remove = clutter_box_real_remove;
iface->foreach = clutter_box_real_foreach;
iface->raise = clutter_box_real_raise;
iface->lower = clutter_box_real_lower;
iface->sort_depth_order = clutter_box_real_sort_depth_order;
}
static void
clutter_box_real_paint (ClutterActor *actor)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (actor)->priv;
if (priv->color_set)
{
ClutterActorBox box = { 0, };
gfloat width, height;
guint8 tmp_alpha;
clutter_actor_get_allocation_box (actor, &box);
clutter_actor_box_get_size (&box, &width, &height);
tmp_alpha = clutter_actor_get_paint_opacity (actor)
* priv->color.alpha
/ 255;
cogl_set_source_color4ub (priv->color.red,
priv->color.green,
priv->color.blue,
tmp_alpha);
cogl_rectangle (0, 0, width, height);
}
g_list_foreach (priv->children, (GFunc) clutter_actor_paint, NULL);
}
static void
clutter_box_real_pick (ClutterActor *actor,
const ClutterColor *pick)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (actor)->priv;
CLUTTER_ACTOR_CLASS (clutter_box_parent_class)->pick (actor, pick);
g_list_foreach (priv->children, (GFunc) clutter_actor_paint, NULL);
}
static void
clutter_box_real_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width,
gfloat *natural_width)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (actor)->priv;
/* if we don't have any children don't bother proxying the
* call to the layout manager instance
*/
if (priv->children == NULL)
{
if (min_width)
*min_width = 0.0;
if (natural_width)
*natural_width = 0.0;
return;
}
clutter_layout_manager_get_preferred_width (priv->manager,
CLUTTER_CONTAINER (actor),
for_height,
min_width, natural_width);
}
static void
clutter_box_real_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height,
gfloat *natural_height)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (actor)->priv;
/* if we don't have any children don't bother proxying the
* call to the layout manager instance
*/
if (priv->children == NULL)
{
if (min_height)
*min_height = 0.0;
if (natural_height)
*natural_height = 0.0;
return;
}
clutter_layout_manager_get_preferred_height (priv->manager,
CLUTTER_CONTAINER (actor),
for_width,
min_height, natural_height);
}
static void
clutter_box_real_allocate (ClutterActor *actor,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (actor)->priv;
ClutterActorClass *klass;
klass = CLUTTER_ACTOR_CLASS (clutter_box_parent_class);
klass->allocate (actor, allocation, flags);
if (priv->children == NULL)
return;
clutter_layout_manager_allocate (priv->manager,
CLUTTER_CONTAINER (actor),
allocation, flags);
}
static void
clutter_box_destroy (ClutterActor *actor)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (actor)->priv;
/* destroy all our children */
g_list_foreach (priv->children, (GFunc) clutter_actor_destroy, NULL);
CLUTTER_ACTOR_CLASS (clutter_box_parent_class)->destroy (actor);
}
static inline void
set_layout_manager (ClutterBox *self,
ClutterLayoutManager *manager)
{
ClutterBoxPrivate *priv = self->priv;
if (priv->manager == manager)
return;
if (priv->manager != NULL)
{
if (priv->changed_id != 0)
g_signal_handler_disconnect (priv->manager, priv->changed_id);
clutter_layout_manager_set_container (priv->manager, NULL);
g_object_unref (priv->manager);
priv->manager = NULL;
priv->changed_id = 0;
}
if (manager != NULL)
{
priv->manager = g_object_ref_sink (manager);
clutter_layout_manager_set_container (manager,
CLUTTER_CONTAINER (self));
priv->changed_id =
g_signal_connect_swapped (priv->manager, "layout-changed",
G_CALLBACK (clutter_actor_queue_relayout),
self);
}
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
g_object_notify (G_OBJECT (self), "layout-manager");
}
static void
clutter_box_dispose (GObject *gobject)
{
ClutterBox *self = CLUTTER_BOX (gobject);
set_layout_manager (self, NULL);
G_OBJECT_CLASS (clutter_box_parent_class)->dispose (gobject);
}
static void
clutter_box_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterBox *self = CLUTTER_BOX (gobject);
switch (prop_id)
{
case PROP_LAYOUT_MANAGER:
set_layout_manager (self, g_value_get_object (value));
break;
case PROP_COLOR:
clutter_box_set_color (self, clutter_value_get_color (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_box_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterBoxPrivate *priv = CLUTTER_BOX (gobject)->priv;
switch (prop_id)
{
case PROP_LAYOUT_MANAGER:
g_value_set_object (value, priv->manager);
break;
case PROP_COLOR:
clutter_value_set_color (value, &priv->color);
break;
case PROP_COLOR_SET:
g_value_set_boolean (value, priv->color_set);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_box_class_init (ClutterBoxClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (ClutterBoxPrivate));
actor_class->get_preferred_width = clutter_box_real_get_preferred_width;
actor_class->get_preferred_height = clutter_box_real_get_preferred_height;
actor_class->allocate = clutter_box_real_allocate;
actor_class->paint = clutter_box_real_paint;
actor_class->pick = clutter_box_real_pick;
actor_class->destroy = clutter_box_destroy;
gobject_class->set_property = clutter_box_set_property;
gobject_class->get_property = clutter_box_get_property;
gobject_class->dispose = clutter_box_dispose;
/**
* ClutterBox:layout-manager:
*
* The #ClutterLayoutManager used by the #ClutterBox
*
* Since: 1.2
*/
pspec = g_param_spec_object ("layout-manager",
"Layout Manager",
"The layout manager used by the box",
CLUTTER_TYPE_LAYOUT_MANAGER,
CLUTTER_PARAM_READWRITE |
G_PARAM_CONSTRUCT);
g_object_class_install_property (gobject_class,
PROP_LAYOUT_MANAGER,
pspec);
/**
* ClutterBox:color:
*
* The color to be used to paint the background of the
* #ClutterBox. Setting this property will set the
* #ClutterBox:color-set property as a side effect
*
* Since: 1.2
*/
pspec = clutter_param_spec_color ("color",
"Color",
"The background color of the box",
&default_box_color,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_COLOR, pspec);
/**
* ClutterBox:color-set:
*
* Whether the #ClutterBox:color property has been set
*
* Since: 1.2
*/
pspec = g_param_spec_boolean ("color-set",
"Color Set",
"Whether the background color is set",
FALSE,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_COLOR_SET, pspec);
}
static void
clutter_box_init (ClutterBox *self)
{
self->priv = CLUTTER_BOX_GET_PRIVATE (self);
self->priv->color = default_box_color;
}
/**
* clutter_box_new:
* @manager: a #ClutterLayoutManager
*
* Creates a new #ClutterBox. The children of the box will be layed
* out by the passed @manager
*
* Return value: the newly created #ClutterBox actor
*
* Since: 1.0
*/
ClutterActor *
clutter_box_new (ClutterLayoutManager *manager)
{
g_return_val_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager), NULL);
return g_object_new (CLUTTER_TYPE_BOX,
"layout-manager", manager,
NULL);
}
/**
* clutter_box_set_layout_manager:
* @box: a #ClutterBox
* @manager: a #ClutterLayoutManager
*
* Sets the #ClutterLayoutManager for @box
*
* A #ClutterLayoutManager is a delegate object that controls the
* layout of the children of @box
*
* Since: 1.2
*/
void
clutter_box_set_layout_manager (ClutterBox *box,
ClutterLayoutManager *manager)
{
g_return_if_fail (CLUTTER_IS_BOX (box));
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
set_layout_manager (box, manager);
}
/**
* clutter_box_get_layout_manager:
* @box: a #ClutterBox
*
* Retrieves the #ClutterLayoutManager instance used by @box
*
* Return value: a #ClutterLayoutManager
*
* Since: 1.2
*/
ClutterLayoutManager *
clutter_box_get_layout_manager (ClutterBox *box)
{
g_return_val_if_fail (CLUTTER_IS_BOX (box), NULL);
return box->priv->manager;
}
/**
* clutter_box_packv:
* @box: a #ClutterBox
* @actor: a #ClutterActor
* @n_properties: the number of properties to set
* @properties: (array length=n_properties) (element-type utf8): a vector
* containing the property names to set
* @values: (array length=n_properties): a vector containing the property
* values to set
*
* Vector-based variant of clutter_box_pack(), intended for language
* bindings to use
*
* Since: 1.2
*/
void
clutter_box_packv (ClutterBox *box,
ClutterActor *actor,
guint n_properties,
const gchar * const properties[],
const GValue *values)
{
ClutterContainer *container;
ClutterBoxPrivate *priv;
ClutterLayoutMeta *meta;
GObjectClass *klass;
gint i;
g_return_if_fail (CLUTTER_IS_BOX (box));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
container = CLUTTER_CONTAINER (box);
clutter_container_add_actor (container, actor);
priv = box->priv;
meta = clutter_layout_manager_get_child_meta (priv->manager,
container,
actor);
if (meta == NULL)
return;
klass = G_OBJECT_GET_CLASS (meta);
for (i = 0; i < n_properties; i++)
{
const gchar *pname = properties[i];
GParamSpec *pspec;
pspec = g_object_class_find_property (klass, pname);
if (pspec == NULL)
{
g_warning ("%s: the layout property '%s' for managers "
"of type '%s' (meta type '%s') does not exist",
G_STRLOC,
pname,
G_OBJECT_TYPE_NAME (priv->manager),
G_OBJECT_TYPE_NAME (meta));
break;
}
if (!(pspec->flags & G_PARAM_WRITABLE))
{
g_warning ("%s: the layout property '%s' for managers "
"of type '%s' (meta type '%s') is not writable",
G_STRLOC,
pspec->name,
G_OBJECT_TYPE_NAME (priv->manager),
G_OBJECT_TYPE_NAME (meta));
break;
}
clutter_layout_manager_child_set_property (priv->manager,
container, actor,
pname, &values[i]);
}
}
/**
* clutter_box_pack:
* @box: a #ClutterBox
* @actor: a #ClutterActor
* @first_property: the name of the first property to set, or %NULL
* @Varargs: a list of property name and value pairs, terminated by %NULL
*
* Adds @actor to @box and sets layout properties at the same time,
* if the #ClutterLayoutManager used by @box has them
*
* This function is a wrapper around clutter_container_add_actor()
* and clutter_layout_manager_child_set()
*
* Language bindings should use the vector-based clutter_box_addv()
* variant instead
*
* Since: 1.2
*/
void
clutter_box_pack (ClutterBox *box,
ClutterActor *actor,
const gchar *first_property,
...)
{
ClutterBoxPrivate *priv;
ClutterContainer *container;
ClutterLayoutMeta *meta;
GObjectClass *klass;
const gchar *pname;
va_list var_args;
g_return_if_fail (CLUTTER_IS_BOX (box));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
container = CLUTTER_CONTAINER (box);
clutter_container_add_actor (container, actor);
if (first_property == NULL || *first_property == '\0')
return;
priv = box->priv;
meta = clutter_layout_manager_get_child_meta (priv->manager,
container,
actor);
if (meta == NULL)
return;
klass = G_OBJECT_GET_CLASS (meta);
va_start (var_args, first_property);
pname = first_property;
while (pname)
{
GValue value = { 0, };
GParamSpec *pspec;
gchar *error;
pspec = g_object_class_find_property (klass, pname);
if (pspec == NULL)
{
g_warning ("%s: the layout property '%s' for managers "
"of type '%s' (meta type '%s') does not exist",
G_STRLOC,
pname,
G_OBJECT_TYPE_NAME (priv->manager),
G_OBJECT_TYPE_NAME (meta));
break;
}
if (!(pspec->flags & G_PARAM_WRITABLE))
{
g_warning ("%s: the layout property '%s' for managers "
"of type '%s' (meta type '%s') is not writable",
G_STRLOC,
pspec->name,
G_OBJECT_TYPE_NAME (priv->manager),
G_OBJECT_TYPE_NAME (meta));
break;
}
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
G_VALUE_COLLECT (&value, var_args, 0, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error);
g_free (error);
break;
}
clutter_layout_manager_child_set_property (priv->manager,
container, actor,
pspec->name, &value);
g_value_unset (&value);
pname = va_arg (var_args, gchar*);
}
va_end (var_args);
}
/**
* clutter_box_set_color:
* @box: a #ClutterBox
* @color: (allow-none): the background color, or %NULL to unset
*
* Sets (or unsets) the background color for @box
*
* Since: 1.2
*/
void
clutter_box_set_color (ClutterBox *box,
const ClutterColor *color)
{
ClutterBoxPrivate *priv;
g_return_if_fail (CLUTTER_IS_BOX (box));
priv = box->priv;
if (color)
{
priv->color = *color;
priv->color_set = TRUE;
}
else
priv->color_set = FALSE;
clutter_actor_queue_redraw (CLUTTER_ACTOR (box));
g_object_notify (G_OBJECT (box), "color-set");
g_object_notify (G_OBJECT (box), "color");
}
/**
* clutter_box_get_color:
* @box: a #ClutterBox
* @color: (out): return location for a #ClutterColor
*
* Retrieves the background color of @box
*
* If the #ClutterBox:color-set property is set to %FALSE the
* returned #ClutterColor is undefined
*
* Since: 1.2
*/
void
clutter_box_get_color (ClutterBox *box,
ClutterColor *color)
{
g_return_if_fail (CLUTTER_IS_BOX (box));
g_return_if_fail (color != NULL);
*color = box->priv->color;
}

62
clutter/clutter-box.h Normal file
View File

@ -0,0 +1,62 @@
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_BOX_H__
#define __CLUTTER_BOX_H__
#include <clutter/clutter-actor.h>
#include <clutter/clutter-container.h>
#include <clutter/clutter-layout-manager.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_BOX (clutter_box_get_type ())
#define CLUTTER_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BOX, ClutterBox))
#define CLUTTER_IS_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BOX))
#define CLUTTER_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BOX, ClutterBoxClass))
#define CLUTTER_IS_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BOX))
#define CLUTTER_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BOX, ClutterBoxClass))
typedef struct _ClutterBox ClutterBox;
typedef struct _ClutterBoxPrivate ClutterBoxPrivate;
typedef struct _ClutterBoxClass ClutterBoxClass;
struct _ClutterBox
{
ClutterActor parent_instance;
ClutterBoxPrivate *priv;
};
struct _ClutterBoxClass
{
ClutterActorClass parent_class;
};
GType clutter_box_get_type (void) G_GNUC_CONST;
ClutterActor * clutter_box_new (ClutterLayoutManager *manager);
void clutter_box_set_layout_manager (ClutterBox *box,
ClutterLayoutManager *manager);
ClutterLayoutManager *clutter_box_get_layout_manager (ClutterBox *box);
void clutter_box_set_color (ClutterBox *box,
const ClutterColor *color);
void clutter_box_get_color (ClutterBox *box,
ClutterColor *color);
void clutter_box_pack (ClutterBox *box,
ClutterActor *actor,
const gchar *first_property,
...) G_GNUC_NULL_TERMINATED;
void clutter_box_packv (ClutterBox *box,
ClutterActor *actor,
guint n_properties,
const gchar * const properties[],
const GValue *values);
G_END_DECLS
#endif /* __CLUTTER_BOX_H__ */

View File

@ -0,0 +1,186 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009 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>
*
* Based on the fixed layout code inside clutter-group.c
*/
/**
* SECTION:clutter-fixed-layout
* @short_description: A fixed layout manager
*
* #ClutterFixedLayout is a layout manager implementing the same
* layout policies as #ClutterGroup.
*
* #ClutterFixedLayout is available since Clutter 1.2
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-debug.h"
#include "clutter-fixed-layout.h"
#include "clutter-private.h"
G_DEFINE_TYPE (ClutterFixedLayout,
clutter_fixed_layout,
CLUTTER_TYPE_LAYOUT_MANAGER);
static void
clutter_fixed_layout_get_preferred_width (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_height,
gfloat *min_width_p,
gfloat *nat_width_p)
{
GList *children, *l;
gdouble min_right;
gdouble natural_right;
min_right = 0;
natural_right = 0;
children = clutter_container_get_children (container);
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
gfloat child_x, child_min, child_natural;
child_x = clutter_actor_get_x (child);
clutter_actor_get_preferred_size (child,
&child_min, NULL,
&child_natural, NULL);
if (child_x + child_min > min_right)
min_right = child_x + child_min;
if (child_x + child_natural > natural_right)
natural_right = child_x + child_natural;
}
g_list_free (children);
if (min_width_p)
*min_width_p = min_right;
if (nat_width_p)
*nat_width_p = natural_right;
}
static void
clutter_fixed_layout_get_preferred_height (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_width,
gfloat *min_height_p,
gfloat *nat_height_p)
{
GList *children, *l;
gdouble min_bottom;
gdouble natural_bottom;
min_bottom = 0;
natural_bottom = 0;
children = clutter_container_get_children (container);
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
gfloat child_y, child_min, child_natural;
child_y = clutter_actor_get_y (child);
clutter_actor_get_preferred_size (child,
NULL, &child_min,
NULL, &child_natural);
if (child_y + child_min > min_bottom)
min_bottom = child_y + child_min;
if (child_y + child_natural > natural_bottom)
natural_bottom = child_y + child_natural;
}
g_list_free (children);
if (min_height_p)
*min_height_p = min_bottom;
if (nat_height_p)
*nat_height_p = natural_bottom;
}
static void
clutter_fixed_layout_allocate (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
{
GList *children, *l;
children = clutter_container_get_children (container);
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
clutter_actor_allocate_preferred_size (child, flags);
}
g_list_free (children);
}
static void
clutter_fixed_layout_class_init (ClutterFixedLayoutClass *klass)
{
ClutterLayoutManagerClass *manager_class =
CLUTTER_LAYOUT_MANAGER_CLASS (klass);
manager_class->get_preferred_width =
clutter_fixed_layout_get_preferred_width;
manager_class->get_preferred_height =
clutter_fixed_layout_get_preferred_height;
manager_class->allocate = clutter_fixed_layout_allocate;
}
static void
clutter_fixed_layout_init (ClutterFixedLayout *self)
{
}
/**
* clutter_fixed_layout_new:
*
* Creates a new #ClutterFixedLayout
*
* Return value: the newly created #ClutterFixedLayout
*
* Since: 1.2
*/
ClutterLayoutManager *
clutter_fixed_layout_new (void)
{
return g_object_new (CLUTTER_TYPE_FIXED_LAYOUT, NULL);
}

View File

@ -0,0 +1,80 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009 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>
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_FIXED_LAYOUT_H__
#define __CLUTTER_FIXED_LAYOUT_H__
#include <clutter/clutter-layout-manager.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_FIXED_LAYOUT (clutter_fixed_layout_get_type ())
#define CLUTTER_FIXED_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_FIXED_LAYOUT, ClutterFixedLayout))
#define CLUTTER_IS_FIXED_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_FIXED_LAYOUT))
#define CLUTTER_FIXED_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_FIXED_LAYOUT, ClutterFixedLayoutClass))
#define CLUTTER_IS_FIXED_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_FIXED_LAYOUT))
#define CLUTTER_FIXED_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_FIXED_LAYOUT, ClutterFixedLayoutClass))
typedef struct _ClutterFixedLayout ClutterFixedLayout;
typedef struct _ClutterFixedLayoutClass ClutterFixedLayoutClass;
/**
* ClutterFixedLayout:
*
* The #ClutterFixedLayout structure contains only private data and
* it should be accessed using the provided API
*
* Since: 1.2
*/
struct _ClutterFixedLayout
{
/*< private >*/
ClutterLayoutManager parent_instance;
};
/**
* ClutterFixedLayoutClass:
*
* The #ClutterFixedLayoutClass structure contains only private data
* and it should be accessed using the provided API
*
* Since: 1.2
*/
struct _ClutterFixedLayoutClass
{
/*< private >*/
ClutterLayoutManagerClass parent_class;
};
GType clutter_fixed_layout_get_type (void) G_GNUC_CONST;
ClutterLayoutManager *clutter_fixed_layout_new (void);
G_END_DECLS
#endif /* __CLUTTER_FIXED_LAYOUT_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,127 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009 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>
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_FLOW_LAYOUT_H__
#define __CLUTTER_FLOW_LAYOUT_H__
#include <clutter/clutter-layout-manager.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_FLOW_LAYOUT (clutter_flow_layout_get_type ())
#define CLUTTER_FLOW_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_FLOW_LAYOUT, ClutterFlowLayout))
#define CLUTTER_IS_FLOW_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_FLOW_LAYOUT))
#define CLUTTER_FLOW_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_FLOW_LAYOUT, ClutterFlowLayoutClass))
#define CLUTTER_IS_FLOW_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_FLOW_LAYOUT))
#define CLUTTER_FLOW_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_FLOW_LAYOUT, ClutterFlowLayoutClass))
typedef struct _ClutterFlowLayout ClutterFlowLayout;
typedef struct _ClutterFlowLayoutPrivate ClutterFlowLayoutPrivate;
typedef struct _ClutterFlowLayoutClass ClutterFlowLayoutClass;
/**
* ClutterFlowOrientation:
* @CLUTTER_FLOW_HORIZONTAL: Arrange the children of the flow layout
* horizontally first
* @CLUTTER_FLOW_VERTICAL: Arrange the children of the flow layout
* vertically first
*
* The direction of the arrangement of the children inside
* a #ClutterFlowLayout
*
* Since: 1.2
*/
typedef enum { /*< prefix=CLUTTER_FLOW >*/
CLUTTER_FLOW_HORIZONTAL,
CLUTTER_FLOW_VERTICAL
} ClutterFlowOrientation;
/**
* ClutterFlowLayout:
*
* The #ClutterFlowLayout structure contains only private data
* and should be accessed using the provided API
*
* Since: 1.2
*/
struct _ClutterFlowLayout
{
/*< private >*/
ClutterLayoutManager parent_instance;
ClutterFlowLayoutPrivate *priv;
};
/**
* ClutterFlowLayoutClass:
*
* The #ClutterFlowLayoutClass structure contains only private data
* and should be accessed using the provided API
*
* Since: 1.2
*/
struct _ClutterFlowLayoutClass
{
/*< private >*/
ClutterLayoutManagerClass parent_class;
};
GType clutter_flow_layout_get_type (void) G_GNUC_CONST;
ClutterLayoutManager * clutter_flow_layout_new (ClutterFlowOrientation orientation);
void clutter_flow_layout_set_orientation (ClutterFlowLayout *layout,
ClutterFlowOrientation orientation);
ClutterFlowOrientation clutter_flow_layout_get_orientation (ClutterFlowLayout *layout);
void clutter_flow_layout_set_homogeneous (ClutterFlowLayout *layout,
gboolean homogeneous);
gboolean clutter_flow_layout_get_homogeneous (ClutterFlowLayout *layout);
void clutter_flow_layout_set_column_spacing (ClutterFlowLayout *layout,
gfloat spacing);
gfloat clutter_flow_layout_get_column_spacing (ClutterFlowLayout *layout);
void clutter_flow_layout_set_row_spacing (ClutterFlowLayout *layout,
gfloat spacing);
gfloat clutter_flow_layout_get_row_spacing (ClutterFlowLayout *layout);
void clutter_flow_layout_set_column_width (ClutterFlowLayout *layout,
gfloat min_width,
gfloat max_width);
void clutter_flow_layout_get_column_width (ClutterFlowLayout *layout,
gfloat *min_width,
gfloat *max_width);
void clutter_flow_layout_set_row_height (ClutterFlowLayout *layout,
gfloat min_height,
gfloat max_height);
void clutter_flow_layout_get_row_height (ClutterFlowLayout *layout,
gfloat *min_height,
gfloat *max_height);
G_END_DECLS
#endif /* __CLUTTER_FLOW_LAYOUT_H__ */

View File

@ -45,6 +45,7 @@
#include "clutter-group.h"
#include "clutter-container.h"
#include "clutter-fixed-layout.h"
#include "clutter-main.h"
#include "clutter-private.h"
#include "clutter-debug.h"
@ -75,6 +76,8 @@ G_DEFINE_TYPE_WITH_CODE (ClutterGroup,
struct _ClutterGroupPrivate
{
GList *children;
ClutterLayoutManager *layout;
};
@ -126,111 +129,17 @@ clutter_group_pick (ClutterActor *actor,
}
}
static void
clutter_fixed_layout_get_preferred_width (GList *children,
gfloat *min_width_p,
gfloat *natural_width_p)
{
GList *l;
gdouble min_right, natural_right;
/* We will always be at least 0 sized (ie, if all of the actors are
to the left of the origin we won't return a negative size) */
min_right = 0;
natural_right = 0;
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
gfloat child_x, child_min, child_natural;
child_x = clutter_actor_get_x (child);
clutter_actor_get_preferred_size (child,
&child_min, NULL,
&child_natural, NULL);
/* Track the rightmost edge */
if (child_x + child_min > min_right)
min_right = child_x + child_min;
if (child_x + child_natural > natural_right)
natural_right = child_x + child_natural;
}
/* The size is defined as the distance from the origin to the
right-hand edge of the rightmost actor */
if (min_width_p)
*min_width_p = min_right;
if (natural_width_p)
*natural_width_p = natural_right;
}
static void
clutter_fixed_layout_get_preferred_height (GList *children,
gfloat *min_height_p,
gfloat *natural_height_p)
{
GList *l;
gdouble min_bottom, natural_bottom;
/* We will always be at least 0 sized (ie, if all of the actors are
above the origin we won't return a negative size) */
min_bottom = 0;
natural_bottom = 0;
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
gfloat child_y, child_min, child_natural;
child_y = clutter_actor_get_y (child);
clutter_actor_get_preferred_size (child,
NULL, &child_min,
NULL, &child_natural);
/* Track the bottommost edge */
if (child_y + child_min > min_bottom)
min_bottom = child_y + child_min;
if (child_y + child_natural > natural_bottom)
natural_bottom = child_y + child_natural;
}
/* The size is defined as the distance from the origin to the bottom
edge of the bottommost actor */
if (min_height_p)
*min_height_p = min_bottom;
if (natural_height_p)
*natural_height_p = natural_bottom;
}
static void
clutter_fixed_layout_allocate (GList *children,
ClutterAllocationFlags flags)
{
GList *l;
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
clutter_actor_allocate_preferred_size (child, flags);
}
}
static void
clutter_group_get_preferred_width (ClutterActor *self,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ClutterContainer *container = CLUTTER_CONTAINER (self);
ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
/* for_height is irrelevant to the fixed layout, so it's not used */
clutter_fixed_layout_get_preferred_width (priv->children,
clutter_layout_manager_get_preferred_width (priv->layout, container,
for_height,
min_width_p,
natural_width_p);
}
@ -241,10 +150,11 @@ clutter_group_get_preferred_height (ClutterActor *self,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ClutterContainer *container = CLUTTER_CONTAINER (self);
ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
/* for_width is irrelevant to the fixed layout, so it's not used */
clutter_fixed_layout_get_preferred_height (priv->children,
clutter_layout_manager_get_preferred_width (priv->layout, container,
for_width,
min_height_p,
natural_height_p);
}
@ -254,17 +164,16 @@ clutter_group_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterContainer *container = CLUTTER_CONTAINER (self);
ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
/* chain up to set actor->allocation */
CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->allocate (self, box, flags);
/* Note that fixed-layout allocation of children does not care what
* allocation the container received, so "box" is not passed in
* here. We do not require that children's allocations are completely
* contained by our own.
*/
clutter_fixed_layout_allocate (priv->children, flags);
if (priv->children == NULL)
return;
clutter_layout_manager_allocate (priv->layout, container, box, flags);
}
static void
@ -281,6 +190,12 @@ clutter_group_dispose (GObject *object)
priv->children = NULL;
}
if (priv->layout)
{
g_object_unref (priv->layout);
priv->layout = NULL;
}
G_OBJECT_CLASS (clutter_group_parent_class)->dispose (object);
}
@ -468,8 +383,10 @@ sort_z_order (gconstpointer a,
if (depth_a < depth_b)
return -1;
if (depth_a > depth_b)
return 1;
return 0;
}
@ -521,6 +438,9 @@ static void
clutter_group_init (ClutterGroup *self)
{
self->priv = CLUTTER_GROUP_GET_PRIVATE (self);
self->priv->layout = clutter_fixed_layout_new ();
g_object_ref_sink (self->priv->layout);
}
/**

View File

@ -0,0 +1,887 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009 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-layout-manager
* @short_description: Layout managers base class
*
* #ClutterLayoutManager is a base abstract class for layout managers. A
* layout manager implements the layouting policy for a composite or a
* container actor: it controls the preferred size of the actor to which
* it has been paired, and it controls the allocation of its children.
*
* Any composite or container #ClutterActor subclass can delegate the
* layouting of its children to a #ClutterLayoutManager. Clutter provides
* a generic container using #ClutterLayoutManager called #ClutterBox.
*
* Clutter provides some simple #ClutterLayoutManager sub-classes, like
* #ClutterFixedLayout and #ClutterBinLayout.
*
* <refsect2 id="ClutterLayoutManager-use-in-Actor">
* <title>Using ClutterLayoutManager inside an Actor</title>
* <para>In order to use a #ClutterLayoutManager inside a #ClutterActor
* sub-class you should invoke clutter_layout_manager_get_preferred_width()
* inside the <structname>ClutterActor</structname>::get_preferred_width()
* virtual function and clutter_layout_manager_get_preferred_height()
* inside the <structname>ClutterActor</structname>::get_preferred_height()
* virtual function implementations. You should also call
* clutter_layout_manager_allocate() inside the implementation of the
* <structname>ClutterActor</structname>::allocate() virtual
* function.</para>
* <para>In order to receive notifications for changes in the layout
* manager policies you should also connect to the
* #ClutterLayoutManager::layout-changed signal and queue a relayout
* on your actor. The following code should be enough if the actor
* does not need to perform specific operations whenever a layout
* manager changes:</para>
* <informalexample><programlisting>
* g_signal_connect_swapped (layout_manager,
* "layout-changed",
* G_CALLBACK (clutter_actor_queue_relayout),
* actor);
* </programlisting></informalexample>
* </refsect2>
*
* <refsect2 id="ClutterLayoutManager-implementation">
* <title>Implementing a ClutterLayoutManager</title>
* <para>The implementation of a layout manager does not differ from
* the implementation of the size requisition and allocation bits of
* #ClutterActor, so you should read the relative documentation
* <link linkend="clutter-subclassing-ClutterActor">for subclassing
* ClutterActor</link>.</para>
* <para>The layout manager implementation can hold a back reference
* to the #ClutterContainer by implementing the set_container()
* virtual function. The layout manager should not hold a reference
* on the container actor, to avoid reference cycles.</para>
* <para>If the layout manager has properties affecting the layout
* policies then it should emit the #ClutterLayoutManager::layout-changed
* signal on itself by using the clutter_layout_manager_layout_changed()
* function.</para>
* </refsect2>
*
* #ClutterLayoutManager is available since Clutter 1.2
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib-object.h>
#include <gobject/gvaluecollector.h>
#include "clutter-debug.h"
#include "clutter-layout-manager.h"
#include "clutter-layout-meta.h"
#include "clutter-marshal.h"
#include "clutter-private.h"
#define LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED(m,method) G_STMT_START { \
GObject *_obj = G_OBJECT (m); \
g_warning ("Layout managers of type %s do not implement " \
"the ClutterLayoutManager::%s method", \
G_OBJECT_TYPE_NAME (_obj), \
(method)); } G_STMT_END
enum
{
LAYOUT_CHANGED,
LAST_SIGNAL
};
G_DEFINE_ABSTRACT_TYPE (ClutterLayoutManager,
clutter_layout_manager,
G_TYPE_INITIALLY_UNOWNED);
static GQuark quark_layout_meta = 0;
static guint manager_signals[LAST_SIGNAL] = { 0, };
static void
layout_manager_real_get_preferred_width (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_height,
gfloat *min_width_p,
gfloat *nat_width_p)
{
LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, "get_preferred_width");
if (min_width_p)
*min_width_p = 0.0;
if (nat_width_p)
*nat_width_p = 0.0;
}
static void
layout_manager_real_get_preferred_height (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_width,
gfloat *min_height_p,
gfloat *nat_height_p)
{
LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, "get_preferred_height");
if (min_height_p)
*min_height_p = 0.0;
if (nat_height_p)
*nat_height_p = 0.0;
}
static void
layout_manager_real_allocate (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
{
LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, "allocate");
}
static ClutterLayoutMeta *
layout_manager_real_create_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor)
{
return NULL;
}
static void
clutter_layout_manager_class_init (ClutterLayoutManagerClass *klass)
{
quark_layout_meta =
g_quark_from_static_string ("clutter-layout-manager-child-meta");
klass->get_preferred_width = layout_manager_real_get_preferred_width;
klass->get_preferred_height = layout_manager_real_get_preferred_height;
klass->allocate = layout_manager_real_allocate;
klass->create_child_meta = layout_manager_real_create_child_meta;
/**
* ClutterLayoutManager::layout-changed:
* @manager: the #ClutterLayoutManager that emitted the signal
*
* The ::layout-changed signal is emitted each time a layout manager
* has been changed. Every #ClutterActor using the @manager instance
* as a layout manager should connect a handler to the ::layout-changed
* signal and queue a relayout on themselves:
*
* |[
* static void layout_changed (ClutterLayoutManager *manager,
* ClutterActor *self)
* {
* clutter_actor_queue_relayout (self);
* }
* ...
* self->manager = g_object_ref_sink (manager);
* g_signal_connect (self->manager, "layout-changed",
* G_CALLBACK (layout_changed),
* self);
* ]|
*
* Sub-classes of #ClutterLayoutManager that implement a layout that
* can be controlled or changed using parameters should emit the
* ::layout-changed signal whenever one of the parameters changes,
* by using clutter_layout_manager_layout_changed().
*
* Since: 1.2
*/
manager_signals[LAYOUT_CHANGED] =
g_signal_new (I_("layout-changed"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterLayoutManagerClass,
layout_changed),
NULL, NULL,
clutter_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
clutter_layout_manager_init (ClutterLayoutManager *manager)
{
}
/**
* clutter_layout_manager_get_preferred_width:
* @manager: a #ClutterLayoutManager
* @container: the #ClutterContainer using @manager
* @for_height: the height for which the width should be computed, or -1
* @min_width_p: (out) (allow-none): return location for the minimum width
* of the layout, or %NULL
* @nat_width_p: (out) (allow-none): return location for the natural width
* of the layout, or %NULL
*
* Computes the minimum and natural widths of the @container according
* to @manager.
*
* See also clutter_actor_get_preferred_width()
*
* Since: 1.2
*/
void
clutter_layout_manager_get_preferred_width (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_height,
gfloat *min_width_p,
gfloat *nat_width_p)
{
ClutterLayoutManagerClass *klass;
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
g_return_if_fail (CLUTTER_IS_CONTAINER (container));
klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager);
klass->get_preferred_width (manager, container, for_height,
min_width_p,
nat_width_p);
}
/**
* clutter_layout_manager_get_preferred_height:
* @manager: a #ClutterLayoutManager
* @container: the #ClutterContainer using @manager
* @for_width: the width for which the height should be computed, or -1
* @min_height_p: (out) (allow-none): return location for the minimum height
* of the layout, or %NULL
* @nat_height_p: (out) (allow-none): return location for the natural height
* of the layout, or %NULL
*
* Computes the minimum and natural heights of the @container according
* to @manager.
*
* See also clutter_actor_get_preferred_height()
*
* Since: 1.2
*/
void
clutter_layout_manager_get_preferred_height (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_width,
gfloat *min_height_p,
gfloat *nat_height_p)
{
ClutterLayoutManagerClass *klass;
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
g_return_if_fail (CLUTTER_IS_CONTAINER (container));
klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager);
klass->get_preferred_height (manager, container, for_width,
min_height_p,
nat_height_p);
}
/**
* clutter_layout_manager_allocate:
* @manager: a #ClutterLayoutManager
* @container: the #ClutterContainer using @manager
* @allocation: the #ClutterActorBox containing the allocated area
* of @container
* @flags: the allocation flags
*
* Allocates the children of @container given an area
*
* See also clutter_actor_allocate()
*
* Since: 1.2
*/
void
clutter_layout_manager_allocate (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
{
ClutterLayoutManagerClass *klass;
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
g_return_if_fail (CLUTTER_IS_CONTAINER (container));
g_return_if_fail (allocation != NULL);
klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager);
klass->allocate (manager, container, allocation, flags);
}
/**
* clutter_layout_manager_layout_changed:
* @manager: a #ClutterLayoutManager
*
* Emits the #ClutterLayoutManager::layout-changed signal on @manager
*
* This function should only be called by implementations of the
* #ClutterLayoutManager class
*
* Since: 1.2
*/
void
clutter_layout_manager_layout_changed (ClutterLayoutManager *manager)
{
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
g_signal_emit (manager, manager_signals[LAYOUT_CHANGED], 0);
}
/**
* clutter_layout_manager_set_container:
* @manager: a #ClutterLayoutManager
* @container: (allow-none): a #ClutterContainer using @manager
*
* If the #ClutterLayoutManager sub-class allows it, allow
* adding a weak reference of the @container using @manager
* from within the layout manager
*
* The layout manager should not increase the reference
* count of the @container
*
* Since: 1.2
*/
void
clutter_layout_manager_set_container (ClutterLayoutManager *manager,
ClutterContainer *container)
{
ClutterLayoutManagerClass *klass;
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
g_return_if_fail (container == NULL || CLUTTER_IS_CONTAINER (container));
klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager);
if (klass->set_container)
klass->set_container (manager, container);
}
static inline ClutterLayoutMeta *
create_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor)
{
ClutterLayoutManagerClass *klass;
klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager);
return klass->create_child_meta (manager, container, actor);
}
static inline ClutterLayoutMeta *
get_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor)
{
ClutterLayoutMeta *layout = NULL;
layout = g_object_get_qdata (G_OBJECT (actor), quark_layout_meta);
if (layout != NULL)
{
ClutterChildMeta *child = CLUTTER_CHILD_META (layout);
if (layout->manager == manager &&
child->container == container &&
child->actor == actor)
return layout;
/* if the LayoutMeta referenced is not attached to the
* layout manager then we simply ask the layout manager
* to replace it with the right one
*/
layout = create_child_meta (manager, container, actor);
if (layout != NULL)
{
g_assert (CLUTTER_IS_LAYOUT_META (layout));
g_object_set_qdata_full (G_OBJECT (actor), quark_layout_meta,
layout,
(GDestroyNotify) g_object_unref);
}
return layout;
}
return NULL;
}
/**
* clutter_layout_manager_get_child_meta:
* @manager: a #ClutterLayoutManager
* @container: a #ClutterContainer using @manager
* @actor: a #ClutterActor child of @container
*
* Retrieves the #ClutterLayoutMeta that the layout @manager associated
* to the @actor child of @container
*
* Return value: a #ClutterLayoutMeta or %NULL
*
* Since: 1.0
*/
ClutterLayoutMeta *
clutter_layout_manager_get_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor)
{
g_return_val_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager), NULL);
g_return_val_if_fail (CLUTTER_IS_CONTAINER (container), NULL);
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
return get_child_meta (manager, container, actor);
}
/**
* clutter_layout_manager_add_child_meta:
* @manager: a #ClutterLayoutManager
* @container: a #ClutterContainer using @manager
* @actor: a #ClutterActor child of @container
*
* Creates and binds a #ClutterLayoutMeta for @manager to
* a child of @container
*
* This function should only be used when implementing containers
* using #ClutterLayoutManager and not by application code
*
* Typically, containers should bind a #ClutterLayoutMeta created
* by a #ClutterLayoutManager when adding a new child, e.g.:
*
* |[
* static void
* my_container_add (ClutterContainer *container,
* ClutterActor *actor)
* {
* MyContainer *self = MY_CONTAINER (container);
*
* self->children = g_slist_append (self->children, actor);
* clutter_actor_set_parent (actor, CLUTTER_ACTOR (self));
*
* clutter_layout_manager_add_child_meta (self->layout,
* container,
* actor);
*
* clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
*
* g_signal_emit_by_name (container, "actor-added");
* }
* ]|
*
* The #ClutterLayoutMeta should be removed when removing an
* actor; see clutter_layout_manager_remove_child_meta()
*
* Since: 1.2
*/
void
clutter_layout_manager_add_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor)
{
ClutterLayoutMeta *meta;
meta = create_child_meta (manager, container, actor);
if (meta == NULL)
return;
g_object_set_qdata_full (G_OBJECT (actor), quark_layout_meta,
meta,
(GDestroyNotify) g_object_unref);
}
/**
* clutter_layout_manager_remove_child_meta:
* @manager: a #ClutterLayoutManager
* @container: a #ClutterContainer using @manager
* @actor: a #ClutterActor child of @container
*
* Unbinds and unrefs a #ClutterLayoutMeta for @manager from
* a child of @container
*
* This function should only be used when implementing containers
* using #ClutterLayoutManager and not by application code
*
* Typically, containers should remove a #ClutterLayoutMeta created
* by a #ClutterLayoutManager when removing a child, e.g.:
*
* |[
* static void
* my_container_remove (ClutterContainer *container,
* ClutterActor *actor)
* {
* MyContainer *self = MY_CONTAINER (container);
*
* g_object_ref (actor);
*
* self->children = g_slist_remove (self->children, actor);
* clutter_actor_unparent (actor);
*
* clutter_layout_manager_remove_child_meta (self->layout,
* container,
* actor);
*
* clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
*
* g_signal_emit_by_name (container, "actor-removed");
*
* g_object_unref (actor);
* }
* ]|
*
* See also clutter_layout_manager_add_child_meta()
*
* Since: 1.2
*/
void
clutter_layout_manager_remove_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor)
{
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
g_return_if_fail (CLUTTER_IS_CONTAINER (container));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
if (get_child_meta (manager, container, actor))
g_object_set_qdata (G_OBJECT (actor), quark_layout_meta, NULL);
}
static inline gboolean
layout_set_property_internal (ClutterLayoutManager *manager,
GObject *gobject,
GParamSpec *pspec,
const GValue *value)
{
if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
{
g_warning ("%s: Child property '%s' of the layout manager of "
"type '%s' is constructor-only",
G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (manager));
return FALSE;
}
if (!(pspec->flags & G_PARAM_WRITABLE))
{
g_warning ("%s: Child property '%s' of the layout manager of "
"type '%s' is not writable",
G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (manager));
return FALSE;
}
g_object_set_property (gobject, pspec->name, value);
return TRUE;
}
static inline gboolean
layout_get_property_internal (ClutterLayoutManager *manager,
GObject *gobject,
GParamSpec *pspec,
GValue *value)
{
if (!(pspec->flags & G_PARAM_READABLE))
{
g_warning ("%s: Child property '%s' of the layout manager of "
"type '%s' is not readable",
G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (manager));
return FALSE;
}
g_object_get_property (gobject, pspec->name, value);
return TRUE;
}
/**
* clutter_layout_manager_child_set:
* @manager: a #ClutterLayoutManager
* @container: a #ClutterContainer using @manager
* @actor: a #ClutterActor child of @container
* @first_property: the first property name
* @Varargs: a list of property name and value pairs
*
* Sets a list of properties and their values on the #ClutterLayoutMeta
* associated by @manager to a child of @container
*
* Languages bindings should use clutter_layout_manager_child_set_property()
* instead
*
* Since: 1.2
*/
void
clutter_layout_manager_child_set (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor,
const gchar *first_property,
...)
{
ClutterLayoutMeta *meta;
GObjectClass *klass;
const gchar *pname;
va_list var_args;
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
g_return_if_fail (CLUTTER_IS_CONTAINER (container));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
g_return_if_fail (first_property != NULL);
meta = get_child_meta (manager, container, actor);
if (meta == NULL)
{
g_warning ("Layout managers of type '%s' do not support "
"child metadata",
g_type_name (G_OBJECT_TYPE (manager)));
return;
}
klass = G_OBJECT_GET_CLASS (meta);
va_start (var_args, first_property);
pname = first_property;
while (pname)
{
GValue value = { 0, };
GParamSpec *pspec;
gchar *error;
gboolean res;
pspec = g_object_class_find_property (klass, pname);
if (pspec == NULL)
{
g_warning ("%s: Layout managers of type '%s' have no child "
"property named '%s'",
G_STRLOC, G_OBJECT_TYPE_NAME (manager), pname);
break;
}
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
G_VALUE_COLLECT (&value, var_args, 0, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error);
g_free (error);
break;
}
res = layout_set_property_internal (manager, G_OBJECT (meta),
pspec,
&value);
g_value_unset (&value);
if (!res)
break;
pname = va_arg (var_args, gchar*);
}
va_end (var_args);
}
/**
* clutter_layout_manager_child_set_property:
* @manager: a #ClutterLayoutManager
* @container: a #ClutterContainer using @manager
* @actor: a #ClutterActor child of @container
* @property_name: the name of the property to set
* @value: a #GValue with the value of the property to set
*
* Sets a property on the #ClutterLayoutMeta created by @manager and
* attached to a child of @container
*
* Since: 1.2
*/
void
clutter_layout_manager_child_set_property (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor,
const gchar *property_name,
const GValue *value)
{
ClutterLayoutMeta *meta;
GObjectClass *klass;
GParamSpec *pspec;
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
g_return_if_fail (CLUTTER_IS_CONTAINER (container));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
g_return_if_fail (property_name != NULL);
g_return_if_fail (value != NULL);
meta = get_child_meta (manager, container, actor);
if (meta == NULL)
{
g_warning ("Layout managers of type '%s' do not support "
"child metadata",
g_type_name (G_OBJECT_TYPE (manager)));
return;
}
klass = G_OBJECT_GET_CLASS (meta);
pspec = g_object_class_find_property (klass, property_name);
if (pspec == NULL)
{
g_warning ("%s: Layout managers of type '%s' have no child "
"property named '%s'",
G_STRLOC, G_OBJECT_TYPE_NAME (manager), property_name);
return;
}
layout_set_property_internal (manager, G_OBJECT (meta), pspec, value);
}
/**
* clutter_layout_manager_child_get:
* @manager: a #ClutterLayoutManager
* @container: a #ClutterContainer using @manager
* @actor: a #ClutterActor child of @container
* @first_property: the name of the first property
* @Varargs: a list of property name and return location for the value pairs
*
* Retrieves the values for a list of properties out of the
* #ClutterLayoutMeta created by @manager and attached to the
* child of a @container
*
* Since: 1.2
*/
void
clutter_layout_manager_child_get (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor,
const gchar *first_property,
...)
{
ClutterLayoutMeta *meta;
GObjectClass *klass;
const gchar *pname;
va_list var_args;
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
g_return_if_fail (CLUTTER_IS_CONTAINER (container));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
g_return_if_fail (first_property != NULL);
meta = get_child_meta (manager, container, actor);
if (meta == NULL)
{
g_warning ("Layout managers of type '%s' do not support "
"child metadata",
g_type_name (G_OBJECT_TYPE (manager)));
return;
}
klass = G_OBJECT_GET_CLASS (meta);
va_start (var_args, first_property);
pname = first_property;
while (pname)
{
GValue value = { 0, };
GParamSpec *pspec;
gchar *error;
gboolean res;
pspec = g_object_class_find_property (klass, pname);
if (pspec == NULL)
{
g_warning ("%s: Layout managers of type '%s' have no child "
"property named '%s'",
G_STRLOC, G_OBJECT_TYPE_NAME (manager), pname);
break;
}
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
res = layout_get_property_internal (manager, G_OBJECT (meta),
pspec,
&value);
if (!res)
{
g_value_unset (&value);
break;
}
G_VALUE_LCOPY (&value, var_args, 0, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error);
g_free (error);
g_value_unset (&value);
break;
}
g_value_unset (&value);
pname = va_arg (var_args, gchar*);
}
va_end (var_args);
}
/**
* clutter_layout_manager_child_get_property:
* @manager: a #ClutterLayoutManager
* @container: a #ClutterContainer using @manager
* @actor: a #ClutterActor child of @container
* @property_name: the name of the property to get
* @value: a #GValue with the value of the property to get
*
* Gets a property on the #ClutterLayoutMeta created by @manager and
* attached to a child of @container
*
* The #GValue must already be initialized to the type of the property
* and has to be unset with g_value_unset() after extracting the real
* value out of it
*
* Since: 1.2
*/
void
clutter_layout_manager_child_get_property (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor,
const gchar *property_name,
GValue *value)
{
ClutterLayoutMeta *meta;
GObjectClass *klass;
GParamSpec *pspec;
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
g_return_if_fail (CLUTTER_IS_CONTAINER (container));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
g_return_if_fail (property_name != NULL);
g_return_if_fail (value != NULL);
meta = get_child_meta (manager, container, actor);
if (meta == NULL)
{
g_warning ("Layout managers of type %s do not support "
"child metadata",
g_type_name (G_OBJECT_TYPE (manager)));
return;
}
klass = G_OBJECT_GET_CLASS (meta);
pspec = g_object_class_find_property (klass, property_name);
if (pspec == NULL)
{
g_warning ("%s: Layout managers of type '%s' have no child "
"property named '%s'",
G_STRLOC, G_OBJECT_TYPE_NAME (manager), property_name);
return;
}
layout_get_property_internal (manager, G_OBJECT (meta), pspec, value);
}

View File

@ -0,0 +1,187 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009 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>
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_LAYOUT_MANAGER_H__
#define __CLUTTER_LAYOUT_MANAGER_H__
#include <clutter/clutter-actor.h>
#include <clutter/clutter-container.h>
#include <clutter/clutter-types.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_LAYOUT_MANAGER (clutter_layout_manager_get_type ())
#define CLUTTER_LAYOUT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_LAYOUT_MANAGER, ClutterLayoutManager))
#define CLUTTER_IS_LAYOUT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_LAYOUT_MANAGER))
#define CLUTTER_LAYOUT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_LAYOUT_MANAGER, ClutterLayoutManagerClass))
#define CLUTTER_IS_LAYOUT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_LAYOUT_MANAGER))
#define CLUTTER_LAYOUT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_LAYOUT_MANAGER, ClutterLayoutManagerClass))
typedef struct _ClutterLayoutManager ClutterLayoutManager;
typedef struct _ClutterLayoutManagerClass ClutterLayoutManagerClass;
/**
* ClutterLayoutManager:
*
* The #ClutterLayoutManager structure contains only private data
* and should be accessed using the provided API
*
* Since: 1.2
*/
struct _ClutterLayoutManager
{
/*< private >*/
GInitiallyUnowned parent_instance;
/* padding for future expansion */
gpointer dummy;
};
/**
* ClutterLayoutManagerClass:
* @get_preferred_width: virtual function; override to provide a preferred
* width for the layout manager. See also the get_preferred_width()
* virtual function in #ClutterActor
* @get_preferred_height: virtual function; override to provide a preferred
* height for the layout manager. See also the get_preferred_height()
* virtual function in #ClutterActor
* @allocate: virtual function; override to allocate the children of the
* layout manager. See also the allocate() virtual function in
* #ClutterActor
* @set_container: virtual function; override to set a back pointer
* on the #ClutterContainer using the layout manager. The implementation
* should not take a reference on the container, but just take a weak
* reference, to avoid potential leaks due to reference cycles
* @create_child_meta: virtual function; override to create a
* #ClutterChildMeta instance associated to a #ClutterContainer and a
* child #ClutterActor, used to maintain layout manager specific properties
* @layout_changed: class handler for the #ClutterLayoutManager::layout-changed
* signal
*
* The #ClutterLayoutManagerClass structure contains only private
* data and should be accessed using the provided API
*
* Since: 1.2
*/
struct _ClutterLayoutManagerClass
{
/*< private >*/
GInitiallyUnownedClass parent_class;
/*< public >*/
void (* get_preferred_width) (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_height,
gfloat *minimum_width_p,
gfloat *natural_width_p);
void (* get_preferred_height) (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_width,
gfloat *minimum_height_p,
gfloat *natural_height_p);
void (* allocate) (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags);
void (* set_container) (ClutterLayoutManager *manager,
ClutterContainer *container);
ClutterLayoutMeta *(* create_child_meta) (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor);
void (* layout_changed) (ClutterLayoutManager *manager);
/*< private >*/
/* padding for future expansion */
void (* _clutter_padding_1) (void);
void (* _clutter_padding_2) (void);
void (* _clutter_padding_3) (void);
void (* _clutter_padding_4) (void);
void (* _clutter_padding_5) (void);
void (* _clutter_padding_6) (void);
void (* _clutter_padding_7) (void);
void (* _clutter_padding_8) (void);
};
GType clutter_layout_manager_get_type (void) G_GNUC_CONST;
void clutter_layout_manager_get_preferred_width (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_height,
gfloat *min_width_p,
gfloat *nat_width_p);
void clutter_layout_manager_get_preferred_height (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_width,
gfloat *min_height_p,
gfloat *nat_height_p);
void clutter_layout_manager_allocate (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags);
void clutter_layout_manager_set_container (ClutterLayoutManager *manager,
ClutterContainer *container);
void clutter_layout_manager_layout_changed (ClutterLayoutManager *manager);
ClutterLayoutMeta *clutter_layout_manager_get_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor);
void clutter_layout_manager_add_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor);
void clutter_layout_manager_remove_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor);
void clutter_layout_manager_child_set (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor,
const gchar *first_property,
...) G_GNUC_NULL_TERMINATED;
void clutter_layout_manager_child_get (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor,
const gchar *first_property,
...) G_GNUC_NULL_TERMINATED;
void clutter_layout_manager_child_set_property (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor,
const gchar *property_name,
const GValue *value);
void clutter_layout_manager_child_get_property (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor,
const gchar *property_name,
GValue *value);
G_END_DECLS
#endif /* __CLUTTER_LAYOUT_MANAGER_H__ */

View File

@ -0,0 +1,142 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009 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-layout-meta
* @short_description: Wrapper for actors inside a layout manager
*
* #ClutterLayoutMeta is a wrapper object created by #ClutterLayoutManager
* implementations in order to store child-specific data and properties.
*
* A #ClutterLayoutMeta wraps a #ClutterActor inside a #ClutterContainer
* using a #ClutterLayoutManager.
*
* #ClutterLayoutMeta is available since Clutter 1.2
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-layout-meta.h"
#include "clutter-debug.h"
#include "clutter-private.h"
G_DEFINE_ABSTRACT_TYPE (ClutterLayoutMeta,
clutter_layout_meta,
CLUTTER_TYPE_CHILD_META);
enum
{
PROP_0,
PROP_MANAGER
};
static void
clutter_layout_meta_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterLayoutMeta *layout_meta = CLUTTER_LAYOUT_META (object);
switch (prop_id)
{
case PROP_MANAGER:
layout_meta->manager = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_layout_meta_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterLayoutMeta *layout_meta = CLUTTER_LAYOUT_META (object);
switch (prop_id)
{
case PROP_MANAGER:
g_value_set_object (value, layout_meta->manager);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_layout_meta_class_init (ClutterLayoutMetaClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
gobject_class->set_property = clutter_layout_meta_set_property;
gobject_class->get_property = clutter_layout_meta_get_property;
/**
* ClutterLayoutMeta:manager:
*
* The #ClutterLayoutManager that created this #ClutterLayoutMeta.
*
* Since: 1.2
*/
pspec = g_param_spec_object ("manager",
"Manager",
"The manager that created this data",
CLUTTER_TYPE_LAYOUT_MANAGER,
G_PARAM_CONSTRUCT_ONLY |
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_MANAGER, pspec);
}
static void
clutter_layout_meta_init (ClutterLayoutMeta *self)
{
}
/**
* clutter_layout_meta_get_manager:
* @data: a #ClutterLayoutMeta
*
* Retrieves the actor wrapped by @data
*
* Return value: (transfer none): a #ClutterLayoutManager
*
* Since: 1.2
*/
ClutterLayoutManager *
clutter_layout_meta_get_manager (ClutterLayoutMeta *data)
{
g_return_val_if_fail (CLUTTER_IS_LAYOUT_META (data), NULL);
return data->manager;
}

View File

@ -0,0 +1,85 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009 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>
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_LAYOUT_META_H__
#define __CLUTTER_LAYOUT_META_H__
#include <clutter/clutter-types.h>
#include <clutter/clutter-child-meta.h>
#include <clutter/clutter-layout-manager.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_LAYOUT_META (clutter_layout_meta_get_type ())
#define CLUTTER_LAYOUT_META(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_LAYOUT_META, ClutterLayoutMeta))
#define CLUTTER_IS_LAYOUT_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_LAYOUT_META))
#define CLUTTER_LAYOUT_META_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_LAYOUT_META, ClutterLayoutMetaClass))
#define CLUTTER_IS_LAYOUT_META_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_LAYOUT_META))
#define CLUTTER_LAYOUT_META_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_LAYOUT_META, ClutterLayoutMetaClass))
/* ClutterLayoutMeta is defined in clutter-types.h */
typedef struct _ClutterLayoutMetaClass ClutterLayoutMetaClass;
/**
* ClutterLayoutMeta
* @manager: the layout manager handling this data
*
* Sub-class of #ClutterChildMeta specific for layout managers
*
* A #ClutterLayoutManager sub-class should create a #ClutterLayoutMeta
* instance by overriding the #ClutterLayoutManager::create_child_meta()
* virtual function
*
* Since: 1.2
*/
struct _ClutterLayoutMeta
{
/*< private >*/
ClutterChildMeta parent_instance;
/*< public >*/
ClutterLayoutManager *manager;
/*< private >*/
/* padding */
gpointer dummy;
};
struct _ClutterLayoutMetaClass
{
ClutterChildMetaClass parent_class;
};
GType clutter_layout_meta_get_type (void) G_GNUC_CONST;
ClutterLayoutManager *clutter_layout_meta_get_manager (ClutterLayoutMeta *data);
G_END_DECLS
#endif /* __CLUTTER_LAYOUT_META_H__ */

View File

@ -43,6 +43,7 @@ typedef struct _ClutterActor ClutterActor;
typedef struct _ClutterStage ClutterStage;
typedef struct _ClutterContainer ClutterContainer; /* dummy */
typedef struct _ClutterChildMeta ClutterChildMeta;
typedef struct _ClutterLayoutMeta ClutterLayoutMeta;
/**
* ClutterGravity:

View File

@ -43,6 +43,9 @@
#include "clutter-behaviour-rotate.h"
#include "clutter-behaviour-scale.h"
#include "clutter-binding-pool.h"
#include "clutter-bin-layout.h"
#include "clutter-box.h"
#include "clutter-box-layout.h"
#include "clutter-cairo-texture.h"
#include "clutter-child-meta.h"
#include "clutter-clone.h"
@ -50,10 +53,14 @@
#include "clutter-container.h"
#include "clutter-event.h"
#include "clutter-feature.h"
#include "clutter-fixed-layout.h"
#include "clutter-flow-layout.h"
#include "clutter-frame-source.h"
#include "clutter-group.h"
#include "clutter-interval.h"
#include "clutter-keysyms.h"
#include "clutter-layout-manager.h"
#include "clutter-layout-meta.h"
#include "clutter-list-model.h"
#include "clutter-main.h"
#include "clutter-media.h"

View File

@ -55,6 +55,8 @@
<xi:include href="xml/clutter-container.xml"/>
<xi:include href="xml/clutter-child-meta.xml"/>
<xi:include href="xml/clutter-media.xml"/>
<xi:include href="xml/clutter-layout-manager.xml"/>
<xi:include href="xml/clutter-layout-meta.xml"/>
</chapter>
<chapter>
@ -71,6 +73,16 @@
<xi:include href="xml/clutter-group.xml"/>
<xi:include href="xml/clutter-stage.xml"/>
<xi:include href="xml/clutter-box.xml"/>
</chapter>
<chapter>
<title>Layout managers</title>
<xi:include href="xml/clutter-fixed-layout.xml"/>
<xi:include href="xml/clutter-bin-layout.xml"/>
<xi:include href="xml/clutter-flow-layout.xml"/>
<xi:include href="xml/clutter-box-layout.xml"/>
</chapter>
</part>
@ -198,13 +210,13 @@
<chapter id="clutterobjecthierarchy">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml"/>
<xi:include href="xml/tree_index.sgml"><xi:fallback /></xi:include>
</chapter>
<chapter id="clutterobjectindex">
<title>Object Index</title>
<xi:include href="xml/object_index.sgml"/>
<xi:include href="xml/object_index.sgml"><xi:fallback /></xi:include>
</chapter>
</part>

View File

@ -305,6 +305,8 @@ clutter_actor_get_preferred_width
clutter_actor_get_preferred_height
clutter_actor_set_fixed_position_set
clutter_actor_get_fixed_position_set
clutter_actor_set_request_mode
clutter_actor_get_request_mode
<SUBSECTION>
clutter_actor_set_geometry
@ -1726,3 +1728,195 @@ CLUTTER_STAGE_MANAGER_GET_CLASS
<SUBSECTION Private>
clutter_stage_manager_get_type
</SECTION>
<SECTION>
<TITLE>Layout Managers</TITLE>
<FILE>clutter-layout-manager</FILE>
ClutterLayoutManager
ClutterLayoutManagerClass
clutter_layout_manager_get_preferred_width
clutter_layout_manager_get_preferred_height
clutter_layout_manager_allocate
clutter_layout_manager_layout_changed
clutter_layout_manager_set_container
<SUBSECTION>
clutter_layout_manager_add_child_meta
clutter_layout_manager_remove_child_meta
clutter_layout_manager_get_child_meta
clutter_layout_manager_child_set
clutter_layout_manager_child_set_property
clutter_layout_manager_child_get
clutter_layout_manager_child_get_property
<SUBSECTION Standard>
CLUTTER_TYPE_LAYOUT_MANAGER
CLUTTER_LAYOUT_MANAGER
CLUTTER_LAYOUT_MANAGER_CLASS
CLUTTER_IS_LAYOUT_MANAGER
CLUTTER_IS_LAYOUT_MANAGER_CLASS
CLUTTER_LAYOUT_MANAGER_GET_CLASS
<SUBSECTION Private>
clutter_layout_manager_get_type
</SECTION>
<SECTION>
<TITLE>ClutterFixedLayout</TITLE>
<FILE>clutter-fixed-layout</FILE>
ClutterFixedLayout
ClutterFixedLayoutClass
clutter_fixed_layout_new
<SUBSECTION Standard>
CLUTTER_TYPE_FIXED_LAYOUT
CLUTTER_FIXED_LAYOUT
CLUTTER_FIXED_LAYOUT_CLASS
CLUTTER_IS_FIXED_LAYOUT
CLUTTER_IS_FIXED_LAYOUT_CLASS
CLUTTER_FIXED_LAYOUT_GET_CLASS
<SUBSECTION Private>
clutter_fixed_layout_get_type
</SECTION>
<SECTION>
<TITLE>ClutterBinLayout</TITLE>
<FILE>clutter-bin-layout</FILE>
ClutterBinAlignment
ClutterBinLayout
ClutterBinLayoutClass
clutter_bin_layout_new
clutter_bin_layout_set_alignment
clutter_bin_layout_get_alignment
clutter_bin_layout_add
<SUBSECTION Standard>
CLUTTER_TYPE_BIN_LAYOUT
CLUTTER_BIN_LAYOUT
CLUTTER_BIN_LAYOUT_CLASS
CLUTTER_IS_BIN_LAYOUT
CLUTTER_IS_BIN_LAYOUT_CLASS
CLUTTER_BIN_LAYOUT_GET_CLASS
<SUBSECTION Private>
ClutterBinLayoutPrivate
clutter_bin_layout_get_type
</SECTION>
<SECTION>
<TITLE>ClutterBox</TITLE>
<FILE>clutter-box</FILE>
ClutterBox
ClutterBoxClass
clutter_box_new
clutter_box_set_layout_manager
clutter_box_get_layout_manager
clutter_box_set_color
clutter_box_get_color
<SUBSECTION>
clutter_box_pack
clutter_box_packv
<SUBSECTION Standard>
CLUTTER_TYPE_BOX
CLUTTER_BOX
CLUTTER_BOX_CLASS
CLUTTER_IS_BOX
CLUTTER_IS_BOX_CLASS
CLUTTER_BOX_GET_CLASS
<SUBSECTION Private>
ClutterBoxPrivate
clutter_box_get_type
</SECTION>
<SECTION>
<TITLE>ClutterLayoutMeta</TITLE>
<FILE>clutter-layout-meta</FILE>
ClutterLayoutMeta
ClutterLayoutMetaClass
clutter_layout_meta_get_manager
<SUBSECTION Standard>
CLUTTER_TYPE_LAYOUT_META
CLUTTER_LAYOUT_META
CLUTTER_LAYOUT_META_CLASS
CLUTTER_IS_LAYOUT_META
CLUTTER_IS_LAYOUT_META_CLASS
CLUTTER_LAYOUT_META_GET_CLASS
<SUBSECTION Private>
clutter_layout_meta_get_type
</SECTION>
<SECTION>
<FILE>clutter-flow-layout</FILE>
<TITLE>ClutterFlowLayout</TITLE>
ClutterFlowOrientation
ClutterFlowLayout
ClutterFlowLayoutClass
clutter_flow_layout_new
clutter_flow_layout_set_orientation
clutter_flow_layout_get_orientation
<SUBSECTION>
clutter_flow_layout_set_column_spacing
clutter_flow_layout_get_column_spacing
clutter_flow_layout_set_row_spacing
clutter_flow_layout_get_row_spacing
clutter_flow_layout_set_column_width
clutter_flow_layout_get_column_width
clutter_flow_layout_set_row_height
clutter_flow_layout_get_row_height
<SUBSECTION Standard>
CLUTTER_TYPE_FLOW_LAYOUT
CLUTTER_FLOW_LAYOUT
CLUTTER_FLOW_LAYOUT_CLASS
CLUTTER_IS_FLOW_LAYOUT
CLUTTER_IS_FLOW_LAYOUT_CLASS
CLUTTER_FLOW_LAYOUT_GET_CLASS
<SUBSECTION Private>
ClutterFlowLayoutPrivate
clutter_flow_layout_get_type
</SECTION>
<SECTION>
<TITLE>ClutterBoxLayout</TITLE>
<FILE>clutter-box-layout</FILE>
ClutterBoxAlignment
ClutterBoxLayout
ClutterBoxLayoutClass
clutter_box_layout_new
clutter_box_layout_set_pack_start
clutter_box_layout_get_pack_start
clutter_box_layout_set_spacing
clutter_box_layout_get_spacing
clutter_box_layout_set_vertical
clutter_box_layout_get_vertical
<SUBSECTION>
clutter_box_layout_pack
<SUBSECTION>
clutter_box_layout_set_alignment
clutter_box_layout_get_alignment
clutter_box_layout_set_expand
clutter_box_layout_get_expand
clutter_box_layout_set_fill
clutter_box_layout_get_fill
<SUBSECTION Standard>
CLUTTER_TYPE_BOX_LAYOUT
CLUTTER_BOX_LAYOUT
CLUTTER_BOX_LAYOUT_CLASS
CLUTTER_IS_BOX_LAYOUT
CLUTTER_IS_BOX_LAYOUT_CLASS
CLUTTER_BOX_LAYOUT_GET_CLASS
<SUBSECTION Private>
ClutterBoxLayoutPrivate
clutter_box_layout_get_type
</SECTION>

View File

@ -33,3 +33,10 @@ clutter_animation_get_type
clutter_interval_get_type
clutter_stage_manager_get_type
clutter_binding_pool_get_type
clutter_box_get_type
clutter_layout_manager_get_type
clutter_layout_meta_get_type
clutter_fixed_layout_get_type
clutter_bin_layout_get_type
clutter_flow_layout_get_type
clutter_box_layout_get_type

View File

@ -43,7 +43,10 @@ UNIT_TESTS = \
test-text.c \
test-text-field.c \
test-clutter-cairo-flowers.c \
test-cogl-vertex-buffer.c
test-cogl-vertex-buffer.c \
test-bin-layout.c \
test-flow-layout.c \
test-box-layout.c
if X11_TESTS
UNIT_TESTS += test-pixmap.c

View File

@ -0,0 +1,185 @@
#include <stdlib.h>
#include <gmodule.h>
#include <cairo/cairo.h>
#include <clutter/clutter.h>
static ClutterActor *
make_background (const ClutterColor *color,
gfloat width,
gfloat height)
{
ClutterActor *tex = clutter_cairo_texture_new (width, height);
cairo_t *cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (tex));
cairo_pattern_t *pat;
gfloat x, y;
#define BG_ROUND_RADIUS 12
x = y = 0;
cairo_move_to (cr, BG_ROUND_RADIUS, y);
cairo_line_to (cr, width - BG_ROUND_RADIUS, y);
cairo_curve_to (cr, width, y, width, y, width, BG_ROUND_RADIUS);
cairo_line_to (cr, width, height - BG_ROUND_RADIUS);
cairo_curve_to (cr, width, height, width, height, width - BG_ROUND_RADIUS, height);
cairo_line_to (cr, BG_ROUND_RADIUS, height);
cairo_curve_to (cr, x, height, x, height, x, height - BG_ROUND_RADIUS);
cairo_line_to (cr, x, BG_ROUND_RADIUS);
cairo_curve_to (cr, x, y, x, y, BG_ROUND_RADIUS, y);
cairo_close_path (cr);
clutter_cairo_set_source_color (cr, color);
cairo_stroke (cr);
x += 4;
y += 4;
width -= 4;
height -= 4;
cairo_move_to (cr, BG_ROUND_RADIUS, y);
cairo_line_to (cr, width - BG_ROUND_RADIUS, y);
cairo_curve_to (cr, width, y, width, y, width, BG_ROUND_RADIUS);
cairo_line_to (cr, width, height - BG_ROUND_RADIUS);
cairo_curve_to (cr, width, height, width, height, width - BG_ROUND_RADIUS, height);
cairo_line_to (cr, BG_ROUND_RADIUS, height);
cairo_curve_to (cr, x, height, x, height, x, height - BG_ROUND_RADIUS);
cairo_line_to (cr, x, BG_ROUND_RADIUS);
cairo_curve_to (cr, x, y, x, y, BG_ROUND_RADIUS, y);
cairo_close_path (cr);
pat = cairo_pattern_create_linear (0, 0, 0, height);
cairo_pattern_add_color_stop_rgba (pat, 1, .85, .85, .85, 1);
cairo_pattern_add_color_stop_rgba (pat, .95, 1, 1, 1, 1);
cairo_pattern_add_color_stop_rgba (pat, .05, 1, 1, 1, 1);
cairo_pattern_add_color_stop_rgba (pat, 0, .85, .85, .85, 1);
cairo_set_source (cr, pat);
cairo_fill (cr);
cairo_pattern_destroy (pat);
cairo_destroy (cr);
#undef BG_ROUND_RADIUS
return tex;
}
static gboolean
on_box_enter (ClutterActor *box,
ClutterEvent *event,
ClutterActor *emblem)
{
clutter_actor_animate (emblem, CLUTTER_LINEAR, 150,
"opacity", 255,
NULL);
return TRUE;
}
static gboolean
on_box_leave (ClutterActor *box,
ClutterEvent *event,
ClutterActor *emblem)
{
clutter_actor_animate (emblem, CLUTTER_LINEAR, 150,
"opacity", 0,
NULL);
return TRUE;
}
G_MODULE_EXPORT int
test_bin_layout_main (int argc, char *argv[])
{
ClutterActor *stage, *box, *rect;
ClutterLayoutManager *layout;
ClutterColor stage_color = { 0xe0, 0xf2, 0xfc, 0xff };
ClutterColor bg_color = { 0xcc, 0xcc, 0xcc, 0x99 };
ClutterColor *color;
clutter_init (&argc, &argv);
stage = clutter_stage_get_default ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Box test");
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
clutter_actor_set_size (stage, 640, 480);
layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER);
box = clutter_box_new (layout);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
clutter_actor_set_anchor_point_from_gravity (box, CLUTTER_GRAVITY_CENTER);
clutter_actor_set_position (box, 320, 240);
clutter_actor_set_reactive (box, TRUE);
clutter_actor_set_name (box, "box");
rect = make_background (&bg_color, 200, 200);
/* first method: use clutter_box_pack() */
clutter_box_pack (CLUTTER_BOX (box), rect,
"x-align", CLUTTER_BIN_ALIGNMENT_FILL,
"y-align", CLUTTER_BIN_ALIGNMENT_FILL,
NULL);
clutter_actor_lower_bottom (rect);
clutter_actor_set_name (rect, "background");
{
ClutterActor *tex;
GError *error;
error = NULL;
tex = clutter_texture_new_from_file ("redhand.png", &error);
if (error)
g_error ("Unable to create texture: %s", error->message);
clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (tex), TRUE);
/* second method: use clutter_bin_layout_add() */
clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), tex,
CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER);
clutter_actor_raise (tex, rect);
clutter_actor_set_width (tex, 175);
clutter_actor_set_name (tex, "texture");
}
color = clutter_color_new (g_random_int_range (0, 255),
g_random_int_range (0, 255),
g_random_int_range (0, 255),
224);
rect = clutter_rectangle_new_with_color (color);
/* third method: container_add() and set_alignment() */
clutter_container_add_actor (CLUTTER_CONTAINER (box), rect);
clutter_bin_layout_set_alignment (CLUTTER_BIN_LAYOUT (layout), rect,
CLUTTER_BIN_ALIGNMENT_END,
CLUTTER_BIN_ALIGNMENT_END);
clutter_actor_set_size (rect, 50, 50);
clutter_actor_set_opacity (rect, 0);
clutter_actor_raise_top (rect);
clutter_actor_set_name (rect, "emblem");
g_signal_connect (box,
"enter-event", G_CALLBACK (on_box_enter),
rect);
g_signal_connect (box,
"leave-event", G_CALLBACK (on_box_leave),
rect);
clutter_actor_show_all (stage);
clutter_main ();
clutter_color_free (color);
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,207 @@
/*
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
static ClutterActor *hover_actor = NULL;
static void
enter_event (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
ClutterColor color = { 0x00, 0x00, 0x00, 0xff };
clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (actor), 2);
clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (actor), &color);
hover_actor = actor;
}
static void
leave_event (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (actor), 0);
hover_actor = NULL;
}
static gboolean
button_release_event (ClutterActor *actor,
ClutterEvent *event,
ClutterBoxLayout *box)
{
gboolean xfill, yfill;
ClutterBoxAlignment xalign, yalign;
gint button;
button = clutter_event_get_button (event);
if (button == 1)
{
clutter_box_layout_get_fill (box, actor, &xfill, &yfill);
clutter_box_layout_set_fill (box, actor,
xfill ? FALSE : TRUE,
yfill ? FALSE : TRUE);
}
else
{
clutter_box_layout_get_alignment (box, actor, &xalign, &yalign);
if (xalign < 2)
xalign += 1;
else
xalign = 0;
if (yalign < 2)
yalign += 1;
else
yalign = 0;
clutter_box_layout_set_alignment (box, actor, xalign, yalign);
}
return TRUE;
}
static void
add_actor (ClutterBoxLayout *box)
{
ClutterActor *rect;
ClutterColor color = { 0xff, 0xff, 0xff, 255 };
static gboolean expand = TRUE;
clutter_color_from_hls (&color,
g_random_double_range (0.0, 360.0),
0.5,
0.5);
rect = clutter_rectangle_new_with_color (&color);
clutter_actor_set_size (rect, 32, 64);
clutter_box_layout_pack (box, rect, expand,
FALSE, /* x-fill */
FALSE, /* y-fill */
CLUTTER_BOX_ALIGNMENT_CENTER,
CLUTTER_BOX_ALIGNMENT_CENTER);
clutter_actor_set_reactive (rect, TRUE);
g_signal_connect (rect, "enter-event", G_CALLBACK (enter_event), NULL);
g_signal_connect (rect, "leave-event", G_CALLBACK (leave_event), NULL);
g_signal_connect (rect, "button-release-event",
G_CALLBACK (button_release_event),
box);
expand = !expand;
}
static gboolean
key_release_cb (ClutterActor *actor,
ClutterEvent *event,
ClutterBoxLayout *layout)
{
gboolean toggle;
guint spacing;
switch (clutter_event_get_key_symbol (event))
{
case CLUTTER_v:
toggle = clutter_box_layout_get_vertical (layout);
clutter_box_layout_set_vertical (layout, !toggle);
break;
case CLUTTER_p:
toggle = clutter_box_layout_get_pack_start (layout);
clutter_box_layout_set_pack_start (layout, !toggle);
break;
case CLUTTER_s:
spacing = clutter_box_layout_get_spacing (layout);
if (spacing > 12)
spacing = 0;
else
spacing++;
clutter_box_layout_set_spacing (layout, spacing);
break;
case '+':
add_actor (layout);
break;
default:
return FALSE;
}
return TRUE;
}
static void
stage_size_changed_cb (ClutterActor *stage,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags,
ClutterActor *box)
{
gfloat width, height;
clutter_actor_box_get_size (allocation, &width, &height);
clutter_actor_set_size (box, width - 100, height - 100);
}
G_MODULE_EXPORT int
test_box_layout_main (int argc, char *argv[])
{
ClutterActor *stage, *box;
ClutterLayoutManager *layout;
gint i;
clutter_init (&argc, &argv);
stage = clutter_stage_get_default ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Box Layout");
clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
clutter_actor_set_size (stage, 640, 480);
layout = clutter_box_layout_new ();
box = clutter_box_new (layout);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
for (i = 0; i < 5; i++)
add_actor (CLUTTER_BOX_LAYOUT (layout));
g_signal_connect (stage, "key-release-event",
G_CALLBACK (key_release_cb),
layout);
g_signal_connect (stage, "allocation-changed",
G_CALLBACK (stage_size_changed_cb),
box);
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,171 @@
#include <stdlib.h>
#include <gmodule.h>
#include <cairo/cairo.h>
#include <clutter/clutter.h>
#define N_RECTS 20
static gboolean is_homogeneous = FALSE;
static gboolean vertical = FALSE;
static gboolean random_size = FALSE;
static gint n_rects = N_RECTS;
static gint x_spacing = 0;
static gint y_spacing = 0;
static GOptionEntry entries[] = {
{
"random-size", 'r',
0,
G_OPTION_ARG_NONE,
&random_size,
"Randomly size the rectangles", NULL
},
{
"num-rects", 'n',
0,
G_OPTION_ARG_INT,
&n_rects,
"Number of rectangles", "RECTS"
},
{
"vertical", 'v',
0,
G_OPTION_ARG_NONE,
&vertical,
"Set vertical orientation", NULL
},
{
"homogeneous", 'h',
0,
G_OPTION_ARG_NONE,
&is_homogeneous,
"Whether the layout should be homogeneous", NULL
},
{
"x-spacing", 0,
0,
G_OPTION_ARG_INT,
&x_spacing,
"Horizontal spacing between elements", "PX"
},
{
"y-spacing", 0,
0,
G_OPTION_ARG_INT,
&y_spacing,
"Vertical spacing between elements", "PX"
},
{ NULL }
};
static void
on_stage_resize (ClutterActor *stage,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags,
ClutterActor *box)
{
gfloat width, height;
clutter_actor_box_get_size (allocation, &width, &height);
if (vertical)
clutter_actor_set_height (box, height);
else
clutter_actor_set_width (box, width);
}
G_MODULE_EXPORT int
test_flow_layout_main (int argc, char *argv[])
{
ClutterActor *stage, *box;
ClutterLayoutManager *layout;
ClutterColor stage_color = { 0xe0, 0xf2, 0xfc, 0xff };
ClutterColor box_color = { 255, 255, 255, 255 };
GError *error;
gint i;
error = NULL;
clutter_init_with_args (&argc, &argv,
NULL,
entries,
NULL,
&error);
if (error)
{
g_print ("Unable to run test-flow: %s", error->message);
g_error_free (error);
return EXIT_FAILURE;
}
stage = clutter_stage_get_default ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Flow Layout");
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
clutter_actor_set_size (stage, 640, 480);
layout = clutter_flow_layout_new (vertical ? CLUTTER_FLOW_VERTICAL
: CLUTTER_FLOW_HORIZONTAL);
clutter_flow_layout_set_homogeneous (CLUTTER_FLOW_LAYOUT (layout),
is_homogeneous);
clutter_flow_layout_set_column_spacing (CLUTTER_FLOW_LAYOUT (layout),
x_spacing);
clutter_flow_layout_set_row_spacing (CLUTTER_FLOW_LAYOUT (layout),
y_spacing);
box = clutter_box_new (layout);
clutter_box_set_color (CLUTTER_BOX (box), &box_color);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
clutter_actor_set_position (box, 0, 0);
if (vertical)
clutter_actor_set_height (box, 480);
else
clutter_actor_set_width (box, 640);
clutter_actor_set_name (box, "box");
for (i = 0; i < n_rects; i++)
{
ClutterColor color = { 255, 255, 255, 224 };
ClutterActor *rect;
gchar *name;
gfloat width, height;
name = g_strdup_printf ("rect%02d", i);
clutter_color_from_hls (&color,
360.0 / n_rects * i,
0.5,
0.8);
rect = clutter_rectangle_new_with_color (&color);
clutter_container_add_actor (CLUTTER_CONTAINER (box), rect);
if (random_size)
{
width = g_random_int_range (50, 100);
height = g_random_int_range (50, 100);
}
else
{
width = height = 50;
}
clutter_actor_set_size (rect, width, height);
clutter_actor_set_name (rect, name);
g_free (name);
}
g_signal_connect (stage,
"allocation-changed", G_CALLBACK (on_stage_resize),
box);
clutter_actor_show_all (stage);
clutter_main ();
return EXIT_SUCCESS;
}