From 42ebf073bd2a95d98db67160da582a0a38313704 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 7 Jun 2007 19:23:04 +0000 Subject: [PATCH] Don't forget files when committing, stoopeed --- clutter/clutter-container.c | 379 ++++++++++++++++++++++++++++++++++++ clutter/clutter-container.h | 98 ++++++++++ clutter/clutter-layout.c | 378 +++++++++++++++++++++++++++++++++++ clutter/clutter-layout.h | 134 +++++++++++++ 4 files changed, 989 insertions(+) create mode 100644 clutter/clutter-container.c create mode 100644 clutter/clutter-container.h create mode 100644 clutter/clutter-layout.c create mode 100644 clutter/clutter-layout.h diff --git a/clutter/clutter-container.c b/clutter/clutter-container.c new file mode 100644 index 000000000..c277aca49 --- /dev/null +++ b/clutter/clutter-container.c @@ -0,0 +1,379 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Matthew Allum + * + * Copyright (C) 2006 OpenedHand + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * ClutterContainer: Generic actor container interface. + * Author: Emmanuele Bassi + */ + +#include "config.h" + +#include +#include + +#include "clutter-container.h" + +#include "clutter-debug.h" +#include "clutter-main.h" +#include "clutter-marshal.h" +#include "clutter-private.h" +#include "clutter-enum-types.h" + +/** + * SECTION:clutter-container + * @short_description: An interface for implementing container actors + * + * #ClutterContainer is an interface for writing actors containing other + * #ClutterActors. It provides a standard API for adding, removing + * and iterating on every contained actor. + * + * An actor implementing #ClutterContainer is #ClutterGroup. + * + * #ClutterContainer is available since Clutter 0.4 + */ + +enum +{ + ACTOR_ADDED, + ACTOR_REMOVED, + + LAST_SIGNAL +}; + +static guint container_signals[LAST_SIGNAL] = { 0, }; + +static void +clutter_container_base_init (gpointer g_iface) +{ + static gboolean initialised = FALSE; + + if (!initialised) + { + GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); + + initialised = TRUE; + + /** + * ClutterContainer::actor-added: + * @container: the actor which received the signal + * @actor: the new child that has been added to @container + * + * The ::actor-added signal is emitted each time an actor + * has been added to @container. + * + * Since: 0.4 + */ + container_signals[ACTOR_ADDED] = + g_signal_new ("actor-added", + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (ClutterContainerIface, actor_added), + NULL, NULL, + clutter_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CLUTTER_TYPE_ACTOR); + /** + * ClutterContainer::actor-removed: + * @container: the actor which received the signal + * @actor: the child that has been removed from @container + * + * The ::actor-removed signal is emitted each time an actor + * is removed from @container. + * + * Since: 0.4 + */ + container_signals[ACTOR_REMOVED] = + g_signal_new ("actor-removed", + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (ClutterContainerIface, actor_removed), + NULL, NULL, + clutter_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CLUTTER_TYPE_ACTOR); + } +} + +GType +clutter_container_get_type (void) +{ + static GType container_type = 0; + + if (G_UNLIKELY (!container_type)) + { + GTypeInfo container_info = + { + sizeof (ClutterContainerIface), + clutter_container_base_init, + NULL, /* iface_finalize */ + }; + + container_type = g_type_register_static (G_TYPE_INTERFACE, + "ClutterContainer", + &container_info, 0); + + g_type_interface_add_prerequisite (container_type, CLUTTER_TYPE_ACTOR); + } + + return container_type; +} + +/** + * clutter_container_add: + * @container: a #ClutterContainer + * @first_actor: the first #ClutterActor to add + * @Varargs: %NULL terminated list of actors to add + * + * Adds a list of #ClutterActors to @container. Each time and + * actor is added, the "actor-added" signal is emitted. Each actor should + * be parented to @container, which takes a reference on the actor. You + * cannot add a #ClutterActor to more than one #ClutterContainer. + * + * Since: 0.4 + */ +void +clutter_container_add (ClutterContainer *container, + ClutterActor *first_actor, + ...) +{ + va_list var_args; + + g_return_if_fail (CLUTTER_IS_CONTAINER (container)); + g_return_if_fail (CLUTTER_IS_ACTOR (first_actor)); + + va_start (var_args, first_actor); + clutter_container_add_valist (container, first_actor, var_args); + va_end (var_args); +} + +/** + * clutter_container_add_actor: + * @container: a #ClutterContainer + * @actor: the first #ClutterActor to add + * + * Adds a #ClutterActor to @container. This function will emit the + * "actor-added" signal is emitted. The actor should be parented to + * @container. You cannot add a #ClutterActor to more than one + * #ClutterContainer. + * + * Since: 0.4 + */ +void +clutter_container_add_actor (ClutterContainer *container, + ClutterActor *actor) +{ + ClutterActor *parent; + + g_return_if_fail (CLUTTER_IS_CONTAINER (container)); + g_return_if_fail (CLUTTER_IS_ACTOR (actor)); + + parent = clutter_actor_get_parent (actor); + if (parent) + { + g_warning ("Attempting to add actor of type `%s' to a " + "group of type `%s', but the actor has already " + "a parent of type `%s'.", + g_type_name (G_OBJECT_TYPE (actor)), + g_type_name (G_OBJECT_TYPE (container)), + g_type_name (G_OBJECT_TYPE (parent))); + return; + } + + CLUTTER_CONTAINER_GET_IFACE (container)->add (container, actor); +} + +/** + * clutter_container_add: + * @container: a #ClutterContainer + * @first_actor: the first #ClutterActor to add + * @var_args: list of actors to add, followed by %NULL + * + * Alternative va_list version of clutter_container_add(). + * + * Since: 0.4 + */ +void +clutter_container_add_valist (ClutterContainer *container, + ClutterActor *first_actor, + va_list var_args) +{ + ClutterActor *actor; + + g_return_if_fail (CLUTTER_IS_CONTAINER (container)); + g_return_if_fail (CLUTTER_IS_ACTOR (first_actor)); + + actor = first_actor; + while (actor) + { + clutter_container_add_actor (container, actor); + actor = va_arg (var_args, ClutterActor*); + } +} + +/** + * clutter_container_remove: + * @container: a #ClutterContainer + * @first_actor: first #ClutterActor to remove + * @Varargs: a %NULL-terminated list of actors to remove + * + * Removes a %NULL terminated list of #ClutterActors from + * @container. Each actor should be unparented, so if you want to keep it + * around you must hold a reference to it yourself, using g_object_ref(). + * Each time an actor is removed, the "actor-removed" signal is + * emitted by @container. + * + * Since: 0.4 + */ +void +clutter_container_remove (ClutterContainer *container, + ClutterActor *first_actor, + ...) +{ + va_list var_args; + + g_return_if_fail (CLUTTER_IS_CONTAINER (container)); + g_return_if_fail (CLUTTER_IS_ACTOR (first_actor)); + + va_start (var_args, first_actor); + clutter_container_remove_valist (container, first_actor, var_args); + va_end (var_args); +} + +/** + * clutter_container_remove_actor: + * @container: a #ClutterContainer + * @actor: a #ClutterActor + * + * Removes @actor from @container. The actor should be unparented, so + * if you want to keep it around you must hold a reference to it + * yourself, using g_object_ref(). When the actor has been removed, + * the "actor-removed" signal is emitted by @container. + * + * Since: 0.4 + */ +void +clutter_container_remove_actor (ClutterContainer *container, + ClutterActor *actor) +{ + ClutterActor *parent; + + g_return_if_fail (CLUTTER_IS_CONTAINER (container)); + g_return_if_fail (CLUTTER_IS_ACTOR (actor)); + + parent = clutter_actor_get_parent (actor); + if (parent != CLUTTER_ACTOR (container)) + { + g_warning ("Attempting to remove actor of type `%s' from " + "group of class `%s', but the group is not the " + "actor's parent.", + g_type_name (G_OBJECT_TYPE (actor)), + g_type_name (G_OBJECT_TYPE (container))); + return; + } + + CLUTTER_CONTAINER_GET_IFACE (container)->remove (container, actor); +} + +/** + * clutter_container_remove_valist: + * @container: a #ClutterContainer + * @first_actor: the first #ClutterActor to add + * @var_args: list of actors to remove, followed by %NULL + * + * Alternative va_list version of clutter_container_remove(). + * + * Since: 0.4 + */ +void +clutter_container_remove_valist (ClutterContainer *container, + ClutterActor *first_actor, + va_list var_args) +{ + ClutterActor *actor; + + g_return_if_fail (CLUTTER_IS_CONTAINER (container)); + g_return_if_fail (CLUTTER_IS_ACTOR (first_actor)); + + actor = first_actor; + while (actor) + { + clutter_container_remove_actor (container, actor); + + actor = va_arg (var_args, ClutterActor*); + } +} + +static void +get_children_cb (ClutterActor *child, + gpointer data) +{ + GList **children = data; + + *children = g_list_prepend (*children, child); +} + +/** + * clutter_container_get_children: + * @container: a #ClutterContainer + * + * Retrieves all the children of @container. + * + * Return value: a list of #ClutterActors. Use g_list_free() + * on the returned list when done. + * + * Since: 0.4 + */ +GList * +clutter_container_get_children (ClutterContainer *container) +{ + GList *retval; + + g_return_val_if_fail (CLUTTER_IS_CONTAINER (container), NULL); + + retval = NULL; + clutter_container_foreach (container, get_children_cb, &retval); + + return g_list_reverse (retval); +} + +/** + * clutter_container_foreach: + * @container: a #ClutterContainer + * @callback: a function to be called for each child + * @user_data: data to be passed to the function, or %NULL + * + * Calls @callback for each child of @container. + * + * Since: 0.4 + */ +void +clutter_container_foreach (ClutterContainer *container, + ClutterCallback callback, + gpointer user_data) +{ + g_return_if_fail (CLUTTER_IS_CONTAINER (container)); + g_return_if_fail (callback != NULL); + + CLUTTER_CONTAINER_GET_IFACE (container)->foreach (container, callback, user_data); +} + diff --git a/clutter/clutter-container.h b/clutter/clutter-container.h new file mode 100644 index 000000000..4d59c9b0d --- /dev/null +++ b/clutter/clutter-container.h @@ -0,0 +1,98 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Matthew Allum + * + * Copyright (C) 2006 OpenedHand + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * ClutterContainer: Generic actor container interface. + * Author: Emmanuele Bassi + */ + +#ifndef __CLUTTER_CONTAINER_H__ +#define __CLUTTER_CONTAINER_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_CONTAINER (clutter_container_get_type ()) +#define CLUTTER_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CONTAINER, ClutterContainer)) +#define CLUTTER_IS_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CONTAINER)) +#define CLUTTER_CONTAINER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_CONTAINER, ClutterContainerIface)) + +typedef struct _ClutterContainer ClutterContainer; /* dummy */ +typedef struct _ClutterContainerIface ClutterContainerIface; + +struct _ClutterContainerIface +{ + GTypeInterface g_iface; + + void (* add) (ClutterContainer *container, + ClutterActor *actor); + void (* remove) (ClutterContainer *container, + ClutterActor *actor); + void (* foreach) (ClutterContainer *container, + ClutterCallback callback, + gpointer user_data); + + /* signals */ + void (* actor_added) (ClutterContainer *container, + ClutterActor *actor); + void (* actor_removed) (ClutterContainer *container, + ClutterActor *actor); + + /* padding, for future expansion */ + void (*_clutter_reserved1) (void); + void (*_clutter_reserved2) (void); + void (*_clutter_reserved3) (void); + void (*_clutter_reserved4) (void); + void (*_clutter_reserved5) (void); + void (*_clutter_reserved6) (void); + void (*_clutter_reserved7) (void); + void (*_clutter_reserved8) (void); +}; + +GType clutter_container_get_type (void) G_GNUC_CONST; + +void clutter_container_add (ClutterContainer *container, + ClutterActor *first_actor, + ...) G_GNUC_NULL_TERMINATED; +void clutter_container_add_actor (ClutterContainer *container, + ClutterActor *actor); +void clutter_container_add_valist (ClutterContainer *container, + ClutterActor *first_actor, + va_list varargs); +void clutter_container_remove (ClutterContainer *container, + ClutterActor *first_actor, + ...) G_GNUC_NULL_TERMINATED; +void clutter_container_remove_actor (ClutterContainer *container, + ClutterActor *actor); +void clutter_container_remove_valist (ClutterContainer *container, + ClutterActor *first_actor, + va_list varargs); +GList *clutter_container_get_children (ClutterContainer *container); +void clutter_container_foreach (ClutterContainer *container, + ClutterCallback callback, + gpointer user_data); + +G_END_DECLS + +#endif /* __CLUTTER_CONTAINER_H__ */ diff --git a/clutter/clutter-layout.c b/clutter/clutter-layout.c new file mode 100644 index 000000000..cbd1e280f --- /dev/null +++ b/clutter/clutter-layout.c @@ -0,0 +1,378 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Matthew Allum + * + * Copyright (C) 2006 OpenedHand + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * ClutterLayout: interface to be implemented by actors providing + * extended layouts. + * + * Author: Emmanuele Bassi + */ + +#include "config.h" + +#include "clutter-layout.h" +#include "clutter-main.h" +#include "clutter-private.h" +#include "clutter-units.h" +#include "clutter-debug.h" +#include "clutter-enum-types.h" + +#define MAX_TUNE_REQUESTS 3 + +/** + * SECTION:clutter-layout + * @short_description: An interface for implementing layouts + * + * #ClutterLayout is an interface that #ClutterActors might + * implement to provide complex or extended layouts. The default + * size allocation of a #ClutterActor inside a #ClutterGroup is to + * make the group size allocation grow enough to contain the actor. + * A #ClutterActor implementing the #ClutterLayout interface will + * be queried for its size when it is added to a #ClutterGroup subclass + * that honours the #ClutterLayout interface; the resulting size + * allocation will depend on the #ClutterLayoutFlags that the actor + * supports. + * + * There are various types of layout available for actors implementing + * the #ClutterLayout interface: %CLUTTER_LAYOUT_WIDTH_FOR_HEIGHT will + * ask the actor for its width given the height allocated by the + * container; %CLUTTER_LAYOUT_HEIGHT_FOR_WIDTH will ask the actor for + * its height given the width allocated by the container. These two + * layout types are especially useful for labels and unidirectional + * container types, like vertical and horizontal boxes. + * + * Another layout available is %CLUTTER_LAYOUT_NATURAL, which will + * query the actor for its natural (default) width and height; the + * container actor will then try to allocate as much as it can, + * and might resort to scaling the actor to fit the allocation. This + * layout type is suited for #ClutterTextures and shapes. + * + * Finally, the %CLUTTER_LAYOUT_TUNABLE is an iterative layout. An actor + * will be queried multiple times until it's satisfied with the size + * given. + * + * A #ClutterGroup subclass that honours the #ClutterLayout interface + * should check whether an actor is implementing this interface when + * adding it, by using the %CLUTTER_IS_LAYOUT type check macro. If the + * actor does implement the interface, the #ClutterGroup should get + * the supported layouts using clutter_layout_get_layout_flags() and + * verify which layout is compatible with the group's own layout; for + * instance, vertical containers should check for actors implementing the + * %CLUTTER_LAYOUT_WIDTH_FOR_HEIGHT layout management, while horizontal + * containers should check for actors implementing the + * %CLUTTER_LAYOUT_HEIGHT_FOR_WIDTH layout management. If the actor + * satisfies the layout requirements, the container actor should query + * the actor for a geometry request using the appropriate function and + * allocate space for the newly added actor accordingly. + * + * #ClutterLayout is available since Clutter 0.4 + */ + +static void +clutter_layout_base_init (gpointer g_iface) +{ + static gboolean initialised = FALSE; + + if (G_UNLIKELY (!initialised)) + { + initialised = TRUE; + + /** + * ClutterLayout:layout-flags: + * + * The layout types that the #ClutterLayout supports. + * + * Since: 0.4 + */ + g_object_interface_install_property (g_iface, + g_param_spec_flags ("layout-flags", + "Layout Flags", + "Supported layouts", + CLUTTER_TYPE_LAYOUT_FLAGS, + CLUTTER_LAYOUT_NONE, + CLUTTER_PARAM_READABLE)); + } +} + +GType +clutter_layout_get_type (void) +{ + static GType layout_type = 0; + + if (!layout_type) + { + GTypeInfo layout_info = + { + sizeof (ClutterLayoutIface), + clutter_layout_base_init, + NULL, + }; + + layout_type = g_type_register_static (G_TYPE_INTERFACE, "ClutterLayout", + &layout_info, 0); + g_type_interface_add_prerequisite (layout_type, CLUTTER_TYPE_ACTOR); + } + + return layout_type; +} + +/* + * Public API + */ + +/** + * clutter_layout_get_layout_flags: + * @layout: a #ClutterLayout + * + * Retrieves the supported layout types from the #ClutterLayout + * + * Return value: bitwise or of #ClutterLayoutFlags + * + * Since: 0.4 + */ +ClutterLayoutFlags +clutter_layout_get_layout_flags (ClutterLayout *layout) +{ + g_return_val_if_fail (CLUTTER_IS_LAYOUT (layout), CLUTTER_LAYOUT_NONE); + + if (CLUTTER_LAYOUT_GET_IFACE (layout)->get_layout_flags) + return CLUTTER_LAYOUT_GET_IFACE (layout)->get_layout_flags (layout); + + return CLUTTER_LAYOUT_NONE; +} + +/** + * clutter_layout_width_for_height: + * @layout: a #ClutterLayout + * @width: return location for the width + * @height: height allocated by the parent + * + * Queries a #ClutterLayout actor for its width with a known height. + * + * Since: 0.4 + */ +void +clutter_layout_width_for_height (ClutterLayout *layout, + gint *width, + gint height) +{ + ClutterLayoutFlags layout_type; + + g_return_if_fail (CLUTTER_IS_LAYOUT (layout)); + + layout_type = clutter_layout_get_layout_flags (layout); + if (layout_type & CLUTTER_LAYOUT_WIDTH_FOR_HEIGHT) + { + ClutterUnit u_width, u_height; + + u_height = CLUTTER_UNITS_FROM_INT (height); + CLUTTER_LAYOUT_GET_IFACE (layout)->width_for_height (layout, + &u_width, + u_height); + + if (width) + *width = CLUTTER_UNITS_TO_INT (u_width); + } + else + { + g_warning ("Actor queried for width with a given height, but " + "actors of type `%s' do not support width-for-height " + "layouts.", + g_type_name (G_OBJECT_TYPE (layout))); + + if (width) + *width = -1; + } +} + +/** + * clutter_layout_height_for_width: + * @layout: a #ClutterLayout + * @width: width allocated by the parent + * @height: return location for the height + * + * Queries a #ClutterLayout actor for its height with a known width. + * + * Since: 0.4 + */ +void +clutter_layout_height_for_width (ClutterLayout *layout, + gint width, + gint *height) +{ + ClutterLayoutFlags layout_type; + + g_return_if_fail (CLUTTER_IS_LAYOUT (layout)); + + layout_type = clutter_layout_get_layout_flags (layout); + if (layout_type & CLUTTER_LAYOUT_HEIGHT_FOR_WIDTH) + { + ClutterUnit u_width, u_height; + + u_width = CLUTTER_UNITS_FROM_INT (width); + CLUTTER_LAYOUT_GET_IFACE (layout)->height_for_width (layout, + u_width, + &u_height); + + if (height) + *height = CLUTTER_UNITS_TO_INT (u_height); + } + else + { + g_warning ("Actor queried for height with a given width, but " + "actors of type `%s' do not support height-for-width " + "layouts.", + g_type_name (G_OBJECT_TYPE (layout))); + + if (height) + *height = -1; + } +} + +/** + * clutter_layout_natural_request: + * @layout: a #ClutterLayout + * @width: return location for the natural width + * @height: return location for the natural height + * + * Queries a #ClutterLayout actor for its natural (default) width + * and height. + * + * Since: 0.4 + */ +void +clutter_layout_natural_request (ClutterLayout *layout, + gint *width, + gint *height) +{ + ClutterLayoutFlags layout_type; + + g_return_if_fail (CLUTTER_IS_LAYOUT (layout)); + + layout_type = clutter_layout_get_layout_flags (layout); + if (layout_type & CLUTTER_LAYOUT_NATURAL) + { + ClutterUnit u_width, u_height; + + CLUTTER_LAYOUT_GET_IFACE (layout)->natural_request (layout, + &u_width, + &u_height); + + if (width) + *width = CLUTTER_UNITS_TO_INT (u_width); + + if (height) + *height = CLUTTER_UNITS_TO_INT (u_height); + } + else + { + g_warning ("Actor queried for natural size, but actors of type `%s' " + "do not support natural-size layouts.", + g_type_name (G_OBJECT_TYPE (layout))); + + if (width) + *width = -1; + if (height) + *height = -1; + } +} + +/** + * clutter_layout_tune_request: + * @layout: a #ClutterLayout + * @given_width: width allocated by the parent + * @given_height: height allocated by the parent + * @width: return location for the new width + * @height: return location for the new height + * + * Iteratively queries a #ClutterLayout actor until it finds + * its desired size, given a width and height tuple. + * + * Since: 0.4 + */ +void +clutter_layout_tune_request (ClutterLayout *layout, + gint given_width, + gint given_height, + gint *width, + gint *height) +{ + ClutterLayoutFlags layout_type; + gint tries; + ClutterUnit try_width, try_height; + ClutterUnit new_width, new_height; + + g_return_if_fail (CLUTTER_IS_LAYOUT (layout)); + + layout_type = clutter_layout_get_layout_flags (layout); + if ((layout_type & CLUTTER_LAYOUT_TUNABLE) == 0) + { + g_warning ("Actor queried for tunable size size but actors of " + "type `%s' do not support tunable layouts.", + g_type_name (G_OBJECT_TYPE (layout))); + + if (width) + *width = -1; + + if (height) + *height = -1; + + return; + } + + tries = 0; + try_width = CLUTTER_UNITS_FROM_INT (given_width); + try_height = CLUTTER_UNITS_FROM_INT (given_height); + new_width = new_height = 0; + + do + { + gboolean res; + + res = CLUTTER_LAYOUT_GET_IFACE (layout)->tune_request (layout, + try_width, + try_height, + &new_width, + &new_height); + + if (res) + break; + + if (new_width) + try_width = new_width; + + if (new_height) + try_height = new_height; + + new_width = new_height = 0; + + tries += 1; + } + while (tries <= MAX_TUNE_REQUESTS); + + if (width) + *width = CLUTTER_UNITS_TO_INT (new_width); + + if (height) + *height = CLUTTER_UNITS_TO_INT (new_height); +} diff --git a/clutter/clutter-layout.h b/clutter/clutter-layout.h new file mode 100644 index 000000000..de08eedd9 --- /dev/null +++ b/clutter/clutter-layout.h @@ -0,0 +1,134 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Matthew Allum + * + * Copyright (C) 2006 OpenedHand + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * ClutterLayout: interface to be implemented by actors providing + * extended layouts. + * + * Author: Emmanuele Bassi + */ + +#ifndef __CLUTTER_LAYOUT_H__ +#define __CLUTTER_LAYOUT_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_LAYOUT (clutter_layout_get_type ()) +#define CLUTTER_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_LAYOUT, ClutterLayout)) +#define CLUTTER_IS_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_LAYOUT)) +#define CLUTTER_LAYOUT_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_LAYOUT, ClutterLayoutIface)) + +/** + * ClutterLayoutFlags + * + * Type of layouts supported by an actor. + * + * @CLUTTER_LAYOUT_NONE: No layout (default behaviour) + * @CLUTTER_LAYOUT_WIDTH_FOR_HEIGHT: Width-for-height + * @CLUTTER_LAYOUT_HEIGHT_FOR_WIDTH: Height-for-width + * @CLUTTER_LAYOUT_NATURAL: Natural size request + * @CLUTTER_LAYOUT_TUNABLE: Tunable size request + * + * Since: 0.4 + */ +typedef enum { + CLUTTER_LAYOUT_NONE = 0, + CLUTTER_LAYOUT_WIDTH_FOR_HEIGHT = 1 << 0, + CLUTTER_LAYOUT_HEIGHT_FOR_WIDTH = 1 << 1, + CLUTTER_LAYOUT_NATURAL = 1 << 2, + CLUTTER_LAYOUT_TUNABLE = 1 << 3 +} ClutterLayoutFlags; + +typedef struct _ClutterLayout ClutterLayout; /* dummy */ +typedef struct _ClutterLayoutIface ClutterLayoutIface; + +struct _ClutterLayoutIface +{ + GTypeInterface g_iface; + + /* Retrieve the layout mode used by the actor */ + ClutterLayoutFlags (* get_layout_flags) (ClutterLayout *layout); + + /* Width-for-Height and Height-for-Width: one size is known + * and the other is queried. useful for labels and unidirectional + * containers, like vertical and horizontal boxes. + */ + void (* width_for_height) (ClutterLayout *layout, + ClutterUnit *width, + ClutterUnit height); + void (* height_for_width) (ClutterLayout *layout, + ClutterUnit width, + ClutterUnit *height); + + /* Natural size request: the actor is queried for its natural + * size and the container can decide to either scale the actor + * or to resize itself to make it fit. useful for textures + * or shapes. + */ + void (* natural_request) (ClutterLayout *layout, + ClutterUnit *width, + ClutterUnit *height); + + /* Iterative allocation: the actor is iteratively queried + * for its size, until it finds it. + */ + gboolean (* tune_request) (ClutterLayout *layout, + ClutterUnit given_width, + ClutterUnit given_height, + ClutterUnit *width, + ClutterUnit *height); + + /* padding, for future expansion */ + void (*_clutter_layout1) (void); + void (*_clutter_layout2) (void); + void (*_clutter_layout3) (void); + void (*_clutter_layout4) (void); + void (*_clutter_layout5) (void); + void (*_clutter_layout6) (void); + void (*_clutter_layout7) (void); + void (*_clutter_layout8) (void); +}; + +GType clutter_layout_get_type (void) G_GNUC_CONST; + +ClutterLayoutFlags clutter_layout_get_layout_flags (ClutterLayout *layout); +void clutter_layout_width_for_height (ClutterLayout *layout, + gint *width, + gint height); +void clutter_layout_height_for_width (ClutterLayout *layout, + gint width, + gint *height); +void clutter_layout_natural_request (ClutterLayout *layout, + gint *width, + gint *height); +void clutter_layout_tune_request (ClutterLayout *layout, + gint given_width, + gint given_height, + gint *width, + gint *height); + +G_END_DECLS + +#endif /* __CLUTTER_LAYOUT_H__ */