diff options
Diffstat (limited to 'gtk/gtkextendedlayout.c')
-rw-r--r-- | gtk/gtkextendedlayout.c | 381 |
1 files changed, 346 insertions, 35 deletions
diff --git a/gtk/gtkextendedlayout.c b/gtk/gtkextendedlayout.c index a8293e32de..0da095342b 100644 --- a/gtk/gtkextendedlayout.c +++ b/gtk/gtkextendedlayout.c @@ -24,9 +24,14 @@ #include <config.h> #include "gtkextendedlayout.h" #include "gtksizegroup.h" +#include "gtkprivate.h" #include "gtkintl.h" #include "gtkalias.h" + +#define DEBUG_EXTENDED_LAYOUT 0 + + GType gtk_extended_layout_get_type (void) { @@ -45,32 +50,40 @@ gtk_extended_layout_get_type (void) return extended_layout_type; } -/** - * gtk_extended_layout_get_desired_size: - * @layout: a #GtkExtendedLayout instance - * @minimum_size: location for storing the minimum size, or %NULL - * @natural_size: location for storing the preferred size, or %NULL - * - * Retreives a widget's minimum and natural size and caches the values. - * - * <note><para>This api will consider any restrictions imposed by - * #GtkSizeGroup<!-- -->s or previous calls to gtk_widget_set_size_request(). - * </para></note> - * - * Since: 3.0 - */ -void -gtk_extended_layout_get_desired_size (GtkExtendedLayout *layout, - GtkRequisition *minimum_size, - GtkRequisition *natural_size) + + + +/* looks for a cached size request for this for_size. If not + * found, returns the oldest entry so it can be overwritten */ +static gboolean +_gtk_extended_layout_get_cached_desired_size (gfloat for_size, + GtkDesiredSize *cached_sizes, + GtkDesiredSize **result) { - g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout)); - g_return_if_fail (NULL != minimum_size || NULL != natural_size); + guint i; - _gtk_size_group_compute_desired_size (GTK_WIDGET (layout), minimum_size, natural_size); -} + *result = &cached_sizes[0]; + for (i = 0; i < GTK_N_CACHED_SIZES; i++) + { + GtkDesiredSize *cs; + cs = &cached_sizes[i]; + + if (cs->age > 0 && + cs->for_size == for_size) + { + *result = cs; + return TRUE; + } + else if (cs->age < (*result)->age) + { + *result = cs; + } + } + + return FALSE; +} /** * gtk_extended_layout_is_height_for_width: @@ -99,6 +112,147 @@ gtk_extended_layout_is_height_for_width (GtkExtendedLayout *layout) return TRUE; } +/** + * gtk_extended_layout_get_desired_width: + * @layout: a #GtkExtendedLayout instance + * @minimum_width: location to store the minimum size, or %NULL + * @natural_width: location to store the natural size, or %NULL + * + * Retreives a widget's minimum and natural size in a single dimension. + * + * Since: 3.0 + */ +void +gtk_extended_layout_get_desired_width (GtkExtendedLayout *layout, + gint *minimum_width, + gint *natural_width) +{ + GtkWidgetAuxInfo *aux_info; + gboolean found_in_cache = FALSE; + GtkDesiredSize *cached_size; + + g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout)); + g_return_if_fail (minimum_width != NULL || natural_width != NULL); + + aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (layout), TRUE); + + cached_size = &aux_info->desired_widths[0]; + + if (GTK_WIDGET_WIDTH_REQUEST_NEEDED (layout) == FALSE) + found_in_cache = _gtk_extended_layout_get_cached_desired_size (-1, aux_info->desired_widths, + &cached_size); + + if (!found_in_cache) + { + GtkRequisition requisition; + gint minimum_width = 0, natural_width = 0; + + /* Unconditionally envoke size-request and use those return values as + * the base end of our values */ + _gtk_size_group_compute_requisition (GTK_WIDGET (layout), &requisition); + + /* Envoke this after, default GtkWidgetClass will simply copy over widget->requisition + */ + GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_width (layout, + &minimum_width, + &natural_width); + + + cached_size->minimum_size = MAX (minimum_width, requisition.width); + cached_size->natural_size = MAX (natural_width, requisition.width); + cached_size->for_size = -1; + cached_size->age = aux_info->cached_width_age; + + aux_info->cached_width_age ++; + + GTK_PRIVATE_UNSET_FLAG (layout, GTK_WIDTH_REQUEST_NEEDED); + } + + if (minimum_width) + *minimum_width = cached_size->minimum_size; + + if (natural_width) + *natural_width = cached_size->natural_size; + +#if DEBUG_EXTENDED_LAYOUT + g_message ("%s returning minimum width: %d and natural width: %d", + G_OBJECT_TYPE_NAME (layout), + cached_size->minimum_size, + cached_size->natural_size); +#endif +} + + +/** + * gtk_extended_layout_get_desired_height: + * @layout: a #GtkExtendedLayout instance + * @minimum_width: location to store the minimum size, or %NULL + * @natural_width: location to store the natural size, or %NULL + * + * Retreives a widget's minimum and natural size in a single dimension. + * + * Since: 3.0 + */ +void +gtk_extended_layout_get_desired_height (GtkExtendedLayout *layout, + gint *minimum_height, + gint *natural_height) +{ + GtkWidgetAuxInfo *aux_info; + gboolean found_in_cache = FALSE; + GtkDesiredSize *cached_size; + + g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout)); + g_return_if_fail (minimum_height != NULL || natural_height != NULL); + + aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (layout), TRUE); + + cached_size = &aux_info->desired_heights[0]; + + if (GTK_WIDGET_HEIGHT_REQUEST_NEEDED (layout) == FALSE) + found_in_cache = _gtk_extended_layout_get_cached_desired_size (-1, aux_info->desired_heights, + &cached_size); + + if (!found_in_cache) + { + GtkRequisition requisition; + gint minimum_height = 0, natural_height = 0; + + /* Unconditionally envoke size-request and use those return values as + * the base end of our values */ + _gtk_size_group_compute_requisition (GTK_WIDGET (layout), &requisition); + + /* Envoke this after, default GtkWidgetClass will simply copy over widget->requisition + */ + GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_height (layout, + &minimum_height, + &natural_height); + + cached_size->minimum_size = MAX (minimum_height, requisition.height); + cached_size->natural_size = MAX (natural_height, requisition.height); + cached_size->for_size = -1; + cached_size->age = aux_info->cached_height_age; + + aux_info->cached_height_age ++; + + GTK_PRIVATE_UNSET_FLAG (layout, GTK_HEIGHT_REQUEST_NEEDED); + } + + if (minimum_height) + *minimum_height = cached_size->minimum_size; + + if (natural_height) + *natural_height = cached_size->natural_size; + + +#if DEBUG_EXTENDED_LAYOUT + g_message ("%s returning minimum height: %d and natural height: %d", + G_OBJECT_TYPE_NAME (layout), + cached_size->minimum_size, + cached_size->natural_size); +#endif +} + /** @@ -106,7 +260,7 @@ gtk_extended_layout_is_height_for_width (GtkExtendedLayout *layout) * @layout: a #GtkExtendedLayout instance * @height: the size which is available for allocation * @minimum_size: location for storing the minimum size, or %NULL - * @natural_size: location for storing the preferred size, or %NULL + * @natural_size: location for storing the natural size, or %NULL * * Retreives a widget's desired width if it would be given * the specified @height. @@ -119,20 +273,61 @@ gtk_extended_layout_get_width_for_height (GtkExtendedLayout *layout, gint *minimum_width, gint *natural_width) { - GtkExtendedLayoutIface *iface; + GtkWidgetAuxInfo *aux_info; + gboolean found_in_cache = FALSE; + GtkDesiredSize *cached_size; g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout)); + g_return_if_fail (minimum_width != NULL || natural_width != NULL); - /* XXX Maybe here we do _gtk_size_group_compute_width_for_height() - * and return hard coded minimum widths/heights for for widgets with - * explicit size requests as well as fetch the common minimum/natural - * widths/heights for size grouped widgets. - */ + aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (layout), TRUE); - iface = GTK_EXTENDED_LAYOUT_GET_IFACE (layout); - iface->get_width_for_height (layout, height, minimum_width, natural_width); + cached_size = &aux_info->desired_widths[0]; + + if (GTK_WIDGET_WIDTH_REQUEST_NEEDED (layout) == FALSE) + found_in_cache = _gtk_extended_layout_get_cached_desired_size (height, aux_info->desired_widths, + &cached_size); + + if (!found_in_cache) + { + GtkRequisition requisition; + gint minimum_width = 0, natural_width = 0; + + /* Unconditionally envoke size-request and use those return values as + * the base end of our values */ + _gtk_size_group_compute_requisition (GTK_WIDGET (layout), &requisition); + + GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_width_for_height (layout, + height, + &minimum_width, + &natural_width); + + cached_size->minimum_size = MAX (minimum_width, requisition.width); + cached_size->natural_size = MAX (natural_width, requisition.width); + cached_size->for_size = height; + cached_size->age = aux_info->cached_width_age; + + aux_info->cached_width_age++; + + GTK_PRIVATE_UNSET_FLAG (layout, GTK_WIDTH_REQUEST_NEEDED); + } + + + if (minimum_width) + *minimum_width = cached_size->minimum_size; + + if (natural_width) + *natural_width = cached_size->natural_size; g_assert (!minimum_width || !natural_width || *minimum_width <= *natural_width); + +#if DEBUG_EXTENDED_LAYOUT + g_message ("%s width for height: %d is minimum %d and natural: %d", + G_OBJECT_TYPE_NAME (layout), height, + cached_size->minimum_size, + cached_size->natural_size); +#endif + } /** @@ -140,7 +335,7 @@ gtk_extended_layout_get_width_for_height (GtkExtendedLayout *layout, * @layout: a #GtkExtendedLayout instance * @width: the size which is available for allocation * @minimum_size: location for storing the minimum size, or %NULL - * @natural_size: location for storing the preferred size, or %NULL + * @natural_size: location for storing the natural size, or %NULL * * Retreives a widget's desired height if it would be given * the specified @width. @@ -153,15 +348,131 @@ gtk_extended_layout_get_height_for_width (GtkExtendedLayout *layout, gint *minimum_height, gint *natural_height) { - GtkExtendedLayoutIface *iface; + GtkWidgetAuxInfo *aux_info; + gboolean found_in_cache = FALSE; + GtkDesiredSize *cached_size; g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout)); + g_return_if_fail (minimum_height != NULL || natural_height != NULL); - iface = GTK_EXTENDED_LAYOUT_GET_IFACE (layout); - iface->get_height_for_width (layout, width, minimum_height, natural_height); + aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (layout), TRUE); + + cached_size = &aux_info->desired_heights[0]; + + if (GTK_WIDGET_HEIGHT_REQUEST_NEEDED (layout) == FALSE) + found_in_cache = _gtk_extended_layout_get_cached_desired_size (width, aux_info->desired_heights, + &cached_size); + + if (!found_in_cache) + { + GtkRequisition requisition; + gint minimum_height = 0, natural_height = 0; + + /* Unconditionally envoke size-request and use those return values as + * the base end of our values */ + _gtk_size_group_compute_requisition (GTK_WIDGET (layout), &requisition); + + GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_height_for_width (layout, + width, + &minimum_height, + &natural_height); + + cached_size->minimum_size = MAX (minimum_height, requisition.height); + cached_size->natural_size = MAX (natural_height, requisition.height); + cached_size->for_size = width; + cached_size->age = aux_info->cached_height_age; + + aux_info->cached_height_age++; + + GTK_PRIVATE_UNSET_FLAG (layout, GTK_HEIGHT_REQUEST_NEEDED); + } + + + if (minimum_height) + *minimum_height = cached_size->minimum_size; + + if (natural_height) + *natural_height = cached_size->natural_size; g_assert (!minimum_height || !natural_height || *minimum_height <= *natural_height); + +#if DEBUG_EXTENDED_LAYOUT + g_message ("%s height for width: %d is minimum %d and natural: %d", + G_OBJECT_TYPE_NAME (layout), width, + cached_size->minimum_size, + cached_size->natural_size); +#endif } + + + +/** + * gtk_extended_layout_get_desired_size: + * @layout: a #GtkExtendedLayout instance + * @width: the size which is available for allocation + * @minimum_size: location for storing the minimum size, or %NULL + * @natural_size: location for storing the natural size, or %NULL + * + * Retreives the minimum and natural size of a widget taking + * into account the widget's preference for height-for-width management. + * + * This is used to retreive a suitable size by container widgets whom dont + * impose any restrictions on the child placement, examples of these are + * #GtkWindow and #GtkScrolledWindow. + * + * Since: 3.0 + */ +void +gtk_extended_layout_get_desired_size (GtkExtendedLayout *layout, + GtkRequisition *minimum_size, + GtkRequisition *natural_size) +{ + gint min_width, nat_width; + gint min_height, nat_height; + + g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout)); + + if (gtk_extended_layout_is_height_for_width (layout)) + { + gtk_extended_layout_get_desired_width (layout, &min_width, &nat_width); + gtk_extended_layout_get_height_for_width (layout, nat_width, &min_height, &nat_height); + + /* The minimum size here is the minimum height for the natrual width */ + if (minimum_size) + { + minimum_size->width = nat_width; + minimum_size->height = min_height; + } + + } + else + { + gtk_extended_layout_get_desired_height (layout, &min_height, &nat_height); + gtk_extended_layout_get_height_for_width (layout, nat_height, &min_width, &nat_width); + + /* The minimum size here is the minimum width for the natrual height */ + if (minimum_size) + { + minimum_size->width = min_width; + minimum_size->height = nat_height; + } + } + + if (natural_size) + { + natural_size->width = nat_width; + natural_size->height = nat_height; + } + + +#if DEBUG_EXTENDED_LAYOUT + g_message ("get_desired_size called on a %s; minimum width: %d natural width: %d minimum height %d natural height %d", + G_OBJECT_TYPE_NAME (layout), min_width, nat_width, min_height, nat_height); +#endif +} + + + #define __GTK_EXTENDED_LAYOUT_C__ #include "gtkaliasdef.c" |