diff --git a/clutter/Makefile.am b/clutter/Makefile.am index fdd5c7293..59128c6d8 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -75,6 +75,7 @@ source_h = \ $(srcdir)/clutter-event.h \ $(srcdir)/clutter-feature.h \ $(srcdir)/clutter-fixed.h \ + $(srcdir)/clutter-fixed-layout.h \ $(srcdir)/clutter-frame-source.h \ $(srcdir)/clutter-group.h \ $(srcdir)/clutter-interval.h \ @@ -141,6 +142,7 @@ source_c = \ $(srcdir)/clutter-event.c \ $(srcdir)/clutter-feature.c \ $(srcdir)/clutter-fixed.c \ + $(srcdir)/clutter-fixed-layout.c \ $(srcdir)/clutter-frame-source.c \ $(srcdir)/clutter-group.c \ $(srcdir)/clutter-id-pool.c \ diff --git a/clutter/clutter-fixed-layout.c b/clutter/clutter-fixed-layout.c new file mode 100644 index 000000000..f3e3d385d --- /dev/null +++ b/clutter/clutter-fixed-layout.c @@ -0,0 +1,217 @@ +#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_left, min_right; + gdouble natural_left, natural_right; + + min_left = 0; + min_right = 0; + natural_left = 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 (l == children) + { + /* First child */ + min_left = child_x; + natural_left = child_x; + min_right = min_left + child_min; + natural_right = natural_left + child_natural; + } + else + { + /* Union of extents with previous children */ + if (child_x < min_left) + min_left = child_x; + + if (child_x < natural_left) + natural_left = child_x; + + 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); + + /* The preferred size is defined as the width and height we want starting + * from our origin, since our allocation will set the origin; so we now + * need to remove any part of the request that is to the left of the origin. + */ + if (min_left < 0) + min_left = 0; + + if (natural_left < 0) + natural_left = 0; + + if (min_right < 0) + min_right = 0; + + if (natural_right < 0) + natural_right = 0; + + g_assert (min_right >= min_left); + g_assert (natural_right >= natural_left); + + if (min_width_p) + *min_width_p = min_right - min_left; + + if (nat_width_p) + *nat_width_p = natural_right - min_left; +} + +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_top, min_bottom; + gdouble natural_top, natural_bottom; + + min_top = 0; + min_bottom = 0; + natural_top = 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 (l == children) + { + /* First child */ + min_top = child_y; + natural_top = child_y; + min_bottom = min_top + child_min; + natural_bottom = natural_top + child_natural; + } + else + { + /* Union of extents with previous children */ + if (child_y < min_top) + min_top = child_y; + + if (child_y < natural_top) + natural_top = child_y; + + 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); + + /* The preferred size is defined as the width and height we want starting + * from our origin, since our allocation will set the origin; so we now + * need to remove any part of the request that is above the origin. + */ + if (min_top < 0) + min_top = 0; + + if (natural_top < 0) + natural_top = 0; + + if (min_bottom < 0) + min_bottom = 0; + + if (natural_bottom < 0) + natural_bottom = 0; + + g_assert (min_bottom >= min_top); + g_assert (natural_bottom >= natural_top); + + if (min_height_p) + *min_height_p = min_bottom - min_top; + + if (nat_height_p) + *nat_height_p = natural_bottom - min_top; +} + +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) +{ +} + +ClutterLayoutManager * +clutter_fixed_layout_new (void) +{ + return g_object_new (CLUTTER_TYPE_FIXED_LAYOUT, NULL); +} diff --git a/clutter/clutter-fixed-layout.h b/clutter/clutter-fixed-layout.h new file mode 100644 index 000000000..b8075172a --- /dev/null +++ b/clutter/clutter-fixed-layout.h @@ -0,0 +1,38 @@ +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_FIXED_LAYOUT_H__ +#define __CLUTTER_FIXED_LAYOUT_H__ + +#include + +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; + +struct _ClutterFixedLayout +{ + ClutterLayoutManager parent_instance; +}; + +struct _ClutterFixedLayoutClass +{ + 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__ */ diff --git a/clutter/clutter.h b/clutter/clutter.h index 0ffb6cca5..5c5edd261 100644 --- a/clutter/clutter.h +++ b/clutter/clutter.h @@ -51,6 +51,7 @@ #include "clutter-container.h" #include "clutter-event.h" #include "clutter-feature.h" +#include "clutter-fixed-layout.h" #include "clutter-frame-source.h" #include "clutter-group.h" #include "clutter-interval.h"