Implemented gtk_extended_layout_is_height_for_width() and added another guess algorithm

This patch adds another commented algorythm to find the collective
minimum and natural height for a said width of a horizontally oriented
box (or the opposite). The algorithm works quite well and can be optimized
a bit more - currently its commented because GtkLabel cannot effectively
do width-for-height calculations (doh).

Further, this patch returns an is_height_for_width() preference depending
on the boxes orientation (vertical boxes are width-for-height).
This commit is contained in:
Tristan Van Berkom 2010-04-10 22:39:11 -04:00
parent 639e396147
commit 6b89f05a99

View File

@ -113,6 +113,7 @@ static void gtk_box_extended_layout_init (GtkExtendedLayoutIface *iface);
static void gtk_box_get_desired_size (GtkExtendedLayout *layout,
GtkRequisition *minimum_size,
GtkRequisition *natural_size);
static gboolean gtk_box_is_height_for_width (GtkExtendedLayout *layout);
static void gtk_box_get_width_for_height (GtkExtendedLayout *layout,
gint height,
gint *minimum_width,
@ -122,7 +123,7 @@ static void gtk_box_get_height_for_width (GtkExtendedLayout *layout,
gint *minimum_height,
gint *natural_height);
GtkExtendedLayoutIface *parent_extended_layout_iface;
static GtkExtendedLayoutIface *parent_extended_layout_iface;
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkBox, gtk_box, GTK_TYPE_CONTAINER,
G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
@ -747,11 +748,20 @@ gtk_box_extended_layout_init (GtkExtendedLayoutIface *iface)
{
parent_extended_layout_iface = g_type_interface_peek_parent (iface);
iface->is_height_for_width = gtk_box_is_height_for_width;
iface->get_desired_size = gtk_box_get_desired_size;
iface->get_height_for_width = gtk_box_get_height_for_width;
iface->get_width_for_height = gtk_box_get_width_for_height;
}
static gboolean
gtk_box_is_height_for_width (GtkExtendedLayout *layout)
{
GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (layout);
return (private->orientation == GTK_ORIENTATION_HORIZONTAL);
}
static void
gtk_box_get_desired_size (GtkExtendedLayout *layout,
GtkRequisition *minimum_size,
@ -949,22 +959,61 @@ size_fits_for_dimension (GtkBox *box,
static void
gtk_box_compute_size_for_awkward_orientation (GtkBox *box,
gint avail_size,
gint *minimum_size,
gint *natural_size)
gtk_box_bisect_for_size_in_opposing_orientation (GtkBox *box,
gboolean check_natural,
gint avail_size,
gint floor,
gint ceiling,
gint *size)
{
if (ceiling - floor <= 1)
*size = ceiling;
else
{
gint check_size = floor + (ceiling - floor) / 2;
if (size_fits_for_dimension (box, avail_size, check_size, check_natural))
/* If check_size is large enough for box to fit into avail_size, we go on
* to check between the given floor and check_size as the new ceiling
*/
gtk_box_bisect_for_size_in_opposing_orientation (box, check_natural, avail_size,
floor, check_size, size);
else
gtk_box_bisect_for_size_in_opposing_orientation (box, check_natural, avail_size,
check_size, ceiling, size);
}
}
static void
gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
gint avail_size,
gint *minimum_size,
gint *natural_size)
{
gint minimum, natural;
gint min_ceiling, nat_ceiling;
gint step = 200;
/* Find the smallest possible fit in the orientation of 'box' where 'avail_size' is the available
* size in the opposing orientation
/* First a large gap to search inside of
*/
for (minimum = 1; !size_fits_for_dimension (box, avail_size, minimum, FALSE); minimum++);
for (min_ceiling = (step + 1); !size_fits_for_dimension (box, avail_size, min_ceiling, FALSE); min_ceiling += step);
/* Starting from the minimum available size, do the same to find the smallest allocation where
* all children receive their natural size
/* This will find the minimum sizes by halfing the guesses until they are found
*/
for (natural = minimum; !size_fits_for_dimension (box, avail_size, natural, TRUE); natural++);
gtk_box_bisect_for_size_in_opposing_orientation (box, FALSE, avail_size,
min_ceiling - step,
min_ceiling,
&minimum);
/* Basing the natural size on the found minimum, do the same operation for the natural size */
for (nat_ceiling = minimum + step; !size_fits_for_dimension (box, avail_size, nat_ceiling, TRUE); nat_ceiling += step);
gtk_box_bisect_for_size_in_opposing_orientation (box, TRUE, avail_size,
nat_ceiling - step,
nat_ceiling,
&natural);
if (minimum_size)
*minimum_size = minimum;
@ -1050,9 +1099,14 @@ gtk_box_get_width_for_height (GtkExtendedLayout *layout,
GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (layout);
if (private->orientation == GTK_ORIENTATION_VERTICAL)
/* gtk_box_compute_size_for_awkward_orientation (box, height, minimum_width, natural_width); */
{
#if 0
gtk_box_compute_size_for_opposing_orientation (box, height, minimum_width, natural_width);
#else
/* Have the base class return the values previously computed by get_desired_size() */
parent_extended_layout_iface->get_width_for_height (layout, height, minimum_width, natural_width);
#endif
}
else
gtk_box_compute_size_for_orientation (box, height, minimum_width, natural_width);
}
@ -1067,9 +1121,14 @@ gtk_box_get_height_for_width (GtkExtendedLayout *layout,
GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (layout);
if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
/* gtk_box_compute_size_for_awkward_orientation (box, width, minimum_height, natural_height); */
/* Have the base class return the values previously computed by get_desired_size() */
parent_extended_layout_iface->get_height_for_width (layout, width, minimum_height, natural_height);
{
#if 0
gtk_box_compute_size_for_opposing_orientation (box, width, minimum_height, natural_height);
#else
/* Have the base class return the values previously computed by get_desired_size() */
parent_extended_layout_iface->get_height_for_width (layout, width, minimum_height, natural_height);
#endif
}
else
gtk_box_compute_size_for_orientation (box, width, minimum_height, natural_height);
}