mirror of
https://github.com/brl/mutter.git
synced 2024-11-22 16:10:41 -05:00
[layout] Add BinLayout
A BinLayout is a simple layout manager that allocates a single cell, providing alignment on both the horizontal and vertical axis. If the container associated to the BinLayout has more than one child, the preferred size returned by the layout manager will be as big as the maximum of the children preferred sizes; the allocation will be applied to all children - but it will still depend on each child preferred size and the BinLayout horizontal and vertical alignment properties. The supported alignment properties are: * center: align the child by centering it * start: align the child at the top or left border of the layout * end: align the child at the bottom or right border of the layout * fill: expand the child to fill the size of the layout * fixed: let the child position itself
This commit is contained in:
parent
6d4cc13f7c
commit
1061ebeac9
@ -65,6 +65,7 @@ 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-cairo-texture.h \
|
||||
$(srcdir)/clutter-child-meta.h \
|
||||
@ -132,6 +133,7 @@ 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-cairo-texture.c \
|
||||
$(srcdir)/clutter-child-meta.c \
|
||||
|
397
clutter/clutter-bin-layout.c
Normal file
397
clutter/clutter-bin-layout.c
Normal file
@ -0,0 +1,397 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-actor.h"
|
||||
#include "clutter-animatable.h"
|
||||
#include "clutter-bin-layout.h"
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-enum-types.h"
|
||||
#include "clutter-private.h"
|
||||
|
||||
#define CLUTTER_BIN_LAYOUT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_BIN_LAYOUT, ClutterBinLayoutPrivate))
|
||||
|
||||
struct _ClutterBinLayoutPrivate
|
||||
{
|
||||
ClutterBinAlignment x_align;
|
||||
ClutterBinAlignment y_align;
|
||||
|
||||
gdouble x_factor;
|
||||
gdouble y_factor;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_X_ALIGN,
|
||||
PROP_Y_ALIGN
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ClutterBinLayout,
|
||||
clutter_bin_layout,
|
||||
CLUTTER_TYPE_LAYOUT_MANAGER);
|
||||
|
||||
|
||||
static void
|
||||
set_x_align (ClutterBinLayout *self,
|
||||
ClutterBinAlignment alignment)
|
||||
{
|
||||
ClutterBinLayoutPrivate *priv = self->priv;
|
||||
|
||||
if (priv->x_align != alignment)
|
||||
{
|
||||
priv->x_align = alignment;
|
||||
|
||||
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)
|
||||
{
|
||||
priv->y_align = alignment;
|
||||
|
||||
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)
|
||||
{
|
||||
ClutterBinLayoutPrivate *priv = CLUTTER_BIN_LAYOUT (manager)->priv;
|
||||
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;
|
||||
ClutterActorBox child_alloc = { 0, };
|
||||
gfloat child_width, child_height;
|
||||
ClutterRequestMode request;
|
||||
|
||||
if (priv->x_align == CLUTTER_BIN_ALIGNMENT_FILL)
|
||||
{
|
||||
child_alloc.x1 = (int) 0;
|
||||
child_alloc.x2 = (int) available_w;
|
||||
}
|
||||
|
||||
if (priv->y_align == CLUTTER_BIN_ALIGNMENT_FILL)
|
||||
{
|
||||
child_alloc.y1 = (int) 0;
|
||||
child_alloc.y2 = (int) available_h;
|
||||
}
|
||||
|
||||
/* if we are filling horizontally and vertically then we
|
||||
* can break here because we already have a full allocation
|
||||
*/
|
||||
if (priv->x_align == CLUTTER_BIN_ALIGNMENT_FILL &&
|
||||
priv->y_align == CLUTTER_BIN_ALIGNMENT_FILL)
|
||||
{
|
||||
clutter_actor_allocate (child, &child_alloc, flags);
|
||||
break;
|
||||
}
|
||||
|
||||
request = CLUTTER_REQUEST_HEIGHT_FOR_WIDTH;
|
||||
g_object_get (G_OBJECT (child), "request-mode", &request, NULL);
|
||||
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 (priv->x_align == CLUTTER_BIN_ALIGNMENT_FIXED)
|
||||
{
|
||||
child_alloc.x1 = (int) clutter_actor_get_x (child);
|
||||
child_alloc.x2 = (int) child_alloc.x1 + child_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
gdouble x_align = get_bin_alignment_factor (priv->x_align);
|
||||
|
||||
if (priv->x_align != CLUTTER_BIN_ALIGNMENT_FILL)
|
||||
{
|
||||
child_alloc.x1 = (int) ((available_w - child_width) * x_align);
|
||||
child_alloc.x2 = (int) child_alloc.x1 + child_width;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->y_align == CLUTTER_BIN_ALIGNMENT_FIXED)
|
||||
{
|
||||
child_alloc.y1 = (int) clutter_actor_get_y (child);
|
||||
child_alloc.y2 = (int) child_alloc.y1 + child_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
gdouble y_align = get_bin_alignment_factor (priv->y_align);
|
||||
|
||||
if (priv->y_align != CLUTTER_BIN_ALIGNMENT_FILL)
|
||||
{
|
||||
child_alloc.y1 = (int) ((available_h - child_height) * y_align);
|
||||
child_alloc.y2 = (int) child_alloc.y1 + child_height;
|
||||
}
|
||||
}
|
||||
|
||||
clutter_actor_allocate (child, &child_alloc, flags);
|
||||
}
|
||||
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_bin_layout_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_X_ALIGN:
|
||||
set_x_align (CLUTTER_BIN_LAYOUT (gobject),
|
||||
g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
case PROP_Y_ALIGN:
|
||||
set_y_align (CLUTTER_BIN_LAYOUT (gobject),
|
||||
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;
|
||||
|
||||
pspec = g_param_spec_enum ("x-align",
|
||||
"X Align",
|
||||
"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);
|
||||
|
||||
pspec = g_param_spec_enum ("y-align",
|
||||
"Y Align",
|
||||
"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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_bin_layout_set_alignment (ClutterBinLayout *self,
|
||||
ClutterBinAlignment x_align,
|
||||
ClutterBinAlignment y_align)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
|
||||
|
||||
set_x_align (self, x_align);
|
||||
set_y_align (self, y_align);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_bin_layout_get_alignment (ClutterBinLayout *self,
|
||||
ClutterBinAlignment *x_align,
|
||||
ClutterBinAlignment *y_align)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
|
||||
|
||||
if (x_align)
|
||||
*x_align = self->priv->x_align;
|
||||
|
||||
if (y_align)
|
||||
*y_align = self->priv->y_align;
|
||||
}
|
50
clutter/clutter-bin-layout.h
Normal file
50
clutter/clutter-bin-layout.h
Normal file
@ -0,0 +1,50 @@
|
||||
#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;
|
||||
|
||||
typedef enum {
|
||||
CLUTTER_BIN_ALIGNMENT_FIXED,
|
||||
CLUTTER_BIN_ALIGNMENT_FILL,
|
||||
CLUTTER_BIN_ALIGNMENT_START,
|
||||
CLUTTER_BIN_ALIGNMENT_END,
|
||||
CLUTTER_BIN_ALIGNMENT_CENTER
|
||||
} ClutterBinAlignment;
|
||||
|
||||
struct _ClutterBinLayout
|
||||
{
|
||||
ClutterLayoutManager parent_instance;
|
||||
|
||||
ClutterBinLayoutPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ClutterBinLayoutClass
|
||||
{
|
||||
ClutterLayoutManagerClass parent_class;
|
||||
};
|
||||
|
||||
GType clutter_bin_layout_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterLayoutManager *clutter_bin_layout_new (ClutterBinAlignment align_x,
|
||||
ClutterBinAlignment align_y);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_BIN_LAYOUT_H__ */
|
@ -43,6 +43,7 @@
|
||||
#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-cairo-texture.h"
|
||||
#include "clutter-child-meta.h"
|
||||
|
Loading…
Reference in New Issue
Block a user