mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-09-20 05:50:11 +00:00
Fixed problems with combination of height-for-width apis and
alignment/margin vfuncs adjust_size_request/allocation Now get_height_for_width() will internally update the for_width before passing it to the real height_for_width() vfunc, allowing margins and extra space for alignments to be stripped, thus requesting sufficient height for greater than natural widths (and also accounting for margins properly). Test case adjusted in testadjustsize to ensure proper behavior.
This commit is contained in:
parent
a46dec176e
commit
d26ac6421b
@ -323,11 +323,13 @@ static void gtk_container_map (GtkWidget *widget);
|
||||
static void gtk_container_unmap (GtkWidget *widget);
|
||||
static void gtk_container_adjust_size_request (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
gint for_size,
|
||||
gint *minimum_size,
|
||||
gint *natural_size);
|
||||
static void gtk_container_adjust_size_allocation (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
GtkOrientation orientation,
|
||||
gint *natural_size,
|
||||
gint *allocated_pos,
|
||||
gint *allocated_size);
|
||||
|
||||
static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
|
||||
GtkWidget *child);
|
||||
@ -1776,7 +1778,6 @@ gtk_container_resize_children (GtkContainer *container)
|
||||
static void
|
||||
gtk_container_adjust_size_request (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
gint for_size,
|
||||
gint *minimum_size,
|
||||
gint *natural_size)
|
||||
{
|
||||
@ -1797,28 +1798,33 @@ gtk_container_adjust_size_request (GtkWidget *widget,
|
||||
/* chain up last so gtk_widget_set_size_request() values
|
||||
* will have a chance to overwrite our border width.
|
||||
*/
|
||||
parent_class->adjust_size_request (widget, orientation, for_size,
|
||||
parent_class->adjust_size_request (widget, orientation,
|
||||
minimum_size, natural_size);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_container_adjust_size_allocation (GtkWidget *widget,
|
||||
GtkAllocation *allocation)
|
||||
GtkOrientation orientation,
|
||||
gint *natural_size,
|
||||
gint *allocated_pos,
|
||||
gint *allocated_size)
|
||||
{
|
||||
GtkContainer *container;
|
||||
int border_width;
|
||||
|
||||
container = GTK_CONTAINER (widget);
|
||||
|
||||
parent_class->adjust_size_allocation (widget, allocation);
|
||||
|
||||
if (!GTK_CONTAINER_GET_CLASS (widget)->handle_border_width)
|
||||
return;
|
||||
{
|
||||
parent_class->adjust_size_allocation (widget, orientation,
|
||||
natural_size, allocated_pos,
|
||||
allocated_size);
|
||||
return;
|
||||
}
|
||||
|
||||
border_width = container->priv->border_width;
|
||||
|
||||
allocation->width -= border_width * 2;
|
||||
allocation->height -= border_width * 2;
|
||||
*allocated_size -= border_width * 2;
|
||||
|
||||
/* If we get a pathological too-small allocation to hold
|
||||
* even the border width, leave all allocation to the actual
|
||||
@ -1828,23 +1834,26 @@ gtk_container_adjust_size_allocation (GtkWidget *widget,
|
||||
* As long as we have space, set x,y properly.
|
||||
*/
|
||||
|
||||
if (allocation->width < 1)
|
||||
if (*allocated_size < 1)
|
||||
{
|
||||
allocation->width += border_width * 2;
|
||||
*allocated_size += border_width * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
allocation->x += border_width;
|
||||
*allocated_pos += border_width;
|
||||
*natural_size -= border_width * 2;
|
||||
}
|
||||
|
||||
if (allocation->height < 1)
|
||||
{
|
||||
allocation->height += border_width * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
allocation->y += border_width;
|
||||
}
|
||||
/* Chain up to GtkWidgetClass *after* removing our border width from
|
||||
* the proposed allocation size. This is because it's possible that the
|
||||
* widget was allocated more space than it needs in a said orientation,
|
||||
* if GtkWidgetClass does any alignments and thus limits the size to the
|
||||
* natural size... then we need that to be done *after* removing any margins
|
||||
* and padding values.
|
||||
*/
|
||||
parent_class->adjust_size_allocation (widget, orientation,
|
||||
natural_size, allocated_pos,
|
||||
allocated_size);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,20 +226,56 @@ compute_size_for_orientation (GtkWidget *request,
|
||||
requisition_size = requisition.width;
|
||||
|
||||
if (for_size < 0)
|
||||
GTK_WIDGET_GET_CLASS (request)->get_preferred_width (request, &min_size, &nat_size);
|
||||
{
|
||||
GTK_WIDGET_GET_CLASS (request)->get_preferred_width (request, &min_size, &nat_size);
|
||||
}
|
||||
else
|
||||
GTK_WIDGET_GET_CLASS (request)->get_preferred_width_for_height (request, for_size,
|
||||
&min_size, &nat_size);
|
||||
{
|
||||
int ignored_position = 0;
|
||||
int natural_height;
|
||||
|
||||
/* Pull the base natural height from the cache as it's needed to adjust
|
||||
* the proposed 'for_size' */
|
||||
gtk_widget_get_preferred_height (widget, NULL, &natural_height);
|
||||
|
||||
/* convert for_size to unadjusted height (for_size is a proposed allocation) */
|
||||
GTK_WIDGET_GET_CLASS (request)->adjust_size_allocation (widget,
|
||||
GTK_ORIENTATION_VERTICAL,
|
||||
&natural_height,
|
||||
&ignored_position,
|
||||
&for_size);
|
||||
|
||||
GTK_WIDGET_GET_CLASS (request)->get_preferred_width_for_height (request, for_size,
|
||||
&min_size, &nat_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
requisition_size = requisition.height;
|
||||
|
||||
if (for_size < 0)
|
||||
GTK_WIDGET_GET_CLASS (request)->get_preferred_height (request, &min_size, &nat_size);
|
||||
{
|
||||
GTK_WIDGET_GET_CLASS (request)->get_preferred_height (request, &min_size, &nat_size);
|
||||
}
|
||||
else
|
||||
GTK_WIDGET_GET_CLASS (request)->get_preferred_height_for_width (request, for_size,
|
||||
&min_size, &nat_size);
|
||||
{
|
||||
int ignored_position = 0;
|
||||
int natural_width;
|
||||
|
||||
/* Pull the base natural width from the cache as it's needed to adjust
|
||||
* the proposed 'for_size' */
|
||||
gtk_widget_get_preferred_width (widget, NULL, &natural_width);
|
||||
|
||||
/* convert for_size to unadjusted width (for_size is a proposed allocation) */
|
||||
GTK_WIDGET_GET_CLASS (request)->adjust_size_allocation (widget,
|
||||
GTK_ORIENTATION_HORIZONTAL,
|
||||
&natural_width,
|
||||
&ignored_position,
|
||||
&for_size);
|
||||
|
||||
GTK_WIDGET_GET_CLASS (request)->get_preferred_height_for_width (request, for_size,
|
||||
&min_size, &nat_size);
|
||||
}
|
||||
}
|
||||
pop_recursion_check (request, orientation);
|
||||
|
||||
@ -270,7 +306,6 @@ compute_size_for_orientation (GtkWidget *request,
|
||||
orientation == GTK_SIZE_GROUP_HORIZONTAL ?
|
||||
GTK_ORIENTATION_HORIZONTAL :
|
||||
GTK_ORIENTATION_VERTICAL,
|
||||
cached_size->for_size,
|
||||
&adjusted_min,
|
||||
&adjusted_natural);
|
||||
|
||||
|
187
gtk/gtkwidget.c
187
gtk/gtkwidget.c
@ -685,11 +685,13 @@ static void gtk_widget_queue_tooltip_query (GtkWidget *widg
|
||||
|
||||
static void gtk_widget_real_adjust_size_request (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
gint for_size,
|
||||
gint *minimum_size,
|
||||
gint *natural_size);
|
||||
static void gtk_widget_real_adjust_size_allocation (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
GtkOrientation orientation,
|
||||
gint *natural_size,
|
||||
gint *allocated_pos,
|
||||
gint *allocated_size);
|
||||
|
||||
static void gtk_widget_set_usize_internal (GtkWidget *widget,
|
||||
gint width,
|
||||
@ -4609,6 +4611,8 @@ gtk_widget_size_allocate (GtkWidget *widget,
|
||||
gboolean alloc_needed;
|
||||
gboolean size_changed;
|
||||
gboolean position_changed;
|
||||
gint natural_width, natural_height;
|
||||
gint min_width, min_height;
|
||||
|
||||
priv = widget->priv;
|
||||
|
||||
@ -4645,7 +4649,37 @@ gtk_widget_size_allocate (GtkWidget *widget,
|
||||
real_allocation = *allocation;
|
||||
|
||||
adjusted_allocation = real_allocation;
|
||||
GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget, &adjusted_allocation);
|
||||
if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
|
||||
{
|
||||
/* Go ahead and request the height for allocated width, note that the internals
|
||||
* of get_height_for_width will internally limit the for_size to natural size
|
||||
* when aligning implicitly.
|
||||
*/
|
||||
gtk_widget_get_preferred_width (widget, &min_width, &natural_width);
|
||||
gtk_widget_get_preferred_height_for_width (widget, real_allocation.width, NULL, &natural_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Go ahead and request the width for allocated height, note that the internals
|
||||
* of get_width_for_height will internally limit the for_size to natural size
|
||||
* when aligning implicitly.
|
||||
*/
|
||||
gtk_widget_get_preferred_height (widget, &min_height, &natural_height);
|
||||
gtk_widget_get_preferred_width_for_height (widget, real_allocation.height, NULL, &natural_width);
|
||||
}
|
||||
|
||||
/* Now that we have the right natural height and width, go ahead and remove any margins from the
|
||||
* allocated sizes and possibly limit them to the natural sizes */
|
||||
GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget,
|
||||
GTK_ORIENTATION_HORIZONTAL,
|
||||
&natural_width,
|
||||
&adjusted_allocation.x,
|
||||
&adjusted_allocation.width);
|
||||
GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget,
|
||||
GTK_ORIENTATION_VERTICAL,
|
||||
&natural_height,
|
||||
&adjusted_allocation.y,
|
||||
&adjusted_allocation.height);
|
||||
|
||||
if (adjusted_allocation.x < real_allocation.x ||
|
||||
adjusted_allocation.y < real_allocation.y ||
|
||||
@ -4920,140 +4954,76 @@ gtk_widget_real_size_allocate (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static void
|
||||
get_span_inside_border (GtkWidget *widget,
|
||||
GtkAlign align,
|
||||
int start_pad,
|
||||
int end_pad,
|
||||
int allocated_outside_size,
|
||||
int natural_inside_size,
|
||||
int *coord_inside_p,
|
||||
int *size_inside_p)
|
||||
adjust_for_align(GtkAlign align,
|
||||
gint *natural_size,
|
||||
gint *allocated_pos,
|
||||
gint *allocated_size)
|
||||
{
|
||||
int inside_allocated;
|
||||
int content_size;
|
||||
int coord, size;
|
||||
|
||||
inside_allocated = allocated_outside_size - start_pad - end_pad;
|
||||
|
||||
content_size = natural_inside_size;
|
||||
if (content_size > inside_allocated)
|
||||
{
|
||||
/* didn't get full natural size */
|
||||
content_size = inside_allocated;
|
||||
}
|
||||
|
||||
coord = size = 0; /* silence compiler */
|
||||
switch (align)
|
||||
{
|
||||
case GTK_ALIGN_FILL:
|
||||
coord = start_pad;
|
||||
size = inside_allocated;
|
||||
/* change nothing */
|
||||
break;
|
||||
case GTK_ALIGN_START:
|
||||
coord = start_pad;
|
||||
size = content_size;
|
||||
/* keep *allocated_pos where it is */
|
||||
*allocated_size = MIN (*allocated_size, *natural_size);
|
||||
break;
|
||||
case GTK_ALIGN_END:
|
||||
coord = allocated_outside_size - end_pad - content_size;
|
||||
size = content_size;
|
||||
if (*allocated_size > *natural_size)
|
||||
{
|
||||
*allocated_pos += (*allocated_size - *natural_size);
|
||||
*allocated_size = *natural_size;
|
||||
}
|
||||
break;
|
||||
case GTK_ALIGN_CENTER:
|
||||
coord = start_pad + (inside_allocated - content_size) / 2;
|
||||
size = content_size;
|
||||
if (*allocated_size > *natural_size)
|
||||
{
|
||||
*allocated_pos += (*allocated_size - *natural_size) / 2;
|
||||
*allocated_size = MIN (*allocated_size, *natural_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (coord_inside_p)
|
||||
*coord_inside_p = coord;
|
||||
|
||||
if (size_inside_p)
|
||||
*size_inside_p = size;
|
||||
}
|
||||
|
||||
static void
|
||||
get_span_inside_border_horizontal (GtkWidget *widget,
|
||||
const GtkWidgetAuxInfo *aux_info,
|
||||
int allocated_outside_width,
|
||||
int natural_inside_width,
|
||||
int *x_inside_p,
|
||||
int *width_inside_p)
|
||||
adjust_for_margin(gint start_margin,
|
||||
gint end_margin,
|
||||
gint *natural_size,
|
||||
gint *allocated_pos,
|
||||
gint *allocated_size)
|
||||
{
|
||||
get_span_inside_border (widget,
|
||||
aux_info->halign,
|
||||
aux_info->margin.left,
|
||||
aux_info->margin.right,
|
||||
allocated_outside_width,
|
||||
natural_inside_width,
|
||||
x_inside_p,
|
||||
width_inside_p);
|
||||
}
|
||||
|
||||
static void
|
||||
get_span_inside_border_vertical (GtkWidget *widget,
|
||||
const GtkWidgetAuxInfo *aux_info,
|
||||
int allocated_outside_height,
|
||||
int natural_inside_height,
|
||||
int *y_inside_p,
|
||||
int *height_inside_p)
|
||||
{
|
||||
get_span_inside_border (widget,
|
||||
aux_info->valign,
|
||||
aux_info->margin.top,
|
||||
aux_info->margin.bottom,
|
||||
allocated_outside_height,
|
||||
natural_inside_height,
|
||||
y_inside_p,
|
||||
height_inside_p);
|
||||
*natural_size -= (start_margin + end_margin);
|
||||
*allocated_pos += start_margin;
|
||||
*allocated_size -= (start_margin + end_margin);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_widget_real_adjust_size_allocation (GtkWidget *widget,
|
||||
GtkAllocation *allocation)
|
||||
GtkOrientation orientation,
|
||||
gint *natural_size,
|
||||
gint *allocated_pos,
|
||||
gint *allocated_size)
|
||||
{
|
||||
const GtkWidgetAuxInfo *aux_info;
|
||||
gint natural_width;
|
||||
gint natural_height;
|
||||
int x, y, w, h;
|
||||
|
||||
aux_info = _gtk_widget_get_aux_info_or_defaults (widget);
|
||||
|
||||
if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
gtk_widget_get_preferred_width (widget, NULL, &natural_width);
|
||||
get_span_inside_border_horizontal (widget,
|
||||
aux_info,
|
||||
allocation->width,
|
||||
natural_width,
|
||||
&x, &w);
|
||||
|
||||
gtk_widget_get_preferred_height_for_width (widget, w, NULL, &natural_height);
|
||||
get_span_inside_border_vertical (widget,
|
||||
aux_info,
|
||||
allocation->height,
|
||||
natural_height,
|
||||
&y, &h);
|
||||
adjust_for_margin (aux_info->margin.left,
|
||||
aux_info->margin.right,
|
||||
natural_size, allocated_pos, allocated_size);
|
||||
adjust_for_align (aux_info->halign,
|
||||
natural_size, allocated_pos, allocated_size);
|
||||
}
|
||||
else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */
|
||||
else
|
||||
{
|
||||
gtk_widget_get_preferred_height (widget, NULL, &natural_height);
|
||||
get_span_inside_border_vertical (widget,
|
||||
aux_info,
|
||||
allocation->height,
|
||||
natural_height,
|
||||
&y, &h);
|
||||
|
||||
gtk_widget_get_preferred_width_for_height (widget, h, NULL, &natural_width);
|
||||
get_span_inside_border_horizontal (widget,
|
||||
aux_info,
|
||||
allocation->width,
|
||||
natural_width,
|
||||
&x, &w);
|
||||
adjust_for_margin (aux_info->margin.top,
|
||||
aux_info->margin.bottom,
|
||||
natural_size, allocated_pos, allocated_size);
|
||||
adjust_for_align (aux_info->valign,
|
||||
natural_size, allocated_pos, allocated_size);
|
||||
}
|
||||
|
||||
allocation->x += x;
|
||||
allocation->y += y;
|
||||
allocation->width = w;
|
||||
allocation->height = h;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -9960,7 +9930,6 @@ gtk_widget_real_size_request (GtkWidget *widget,
|
||||
static void
|
||||
gtk_widget_real_adjust_size_request (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
gint for_size,
|
||||
gint *minimum_size,
|
||||
gint *natural_size)
|
||||
{
|
||||
|
@ -157,7 +157,10 @@ struct _GtkWidget
|
||||
* and alignment properties of #GtkWidget. Chain up
|
||||
* <emphasis>before</emphasis> performing your own adjustments so your
|
||||
* own adjustments remove more allocation after the #GtkWidget base
|
||||
* class has already removed margin and alignment.
|
||||
* class has already removed margin and alignment. The natural size
|
||||
* passed in should be adjusted in the same way as the allocated size,
|
||||
* which allows adjustments to perform alignments or other changes
|
||||
* based on natural size.
|
||||
*/
|
||||
struct _GtkWidgetClass
|
||||
{
|
||||
@ -372,11 +375,13 @@ struct _GtkWidgetClass
|
||||
|
||||
void (* adjust_size_request) (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
gint for_size,
|
||||
gint *minimum_size,
|
||||
gint *natural_size);
|
||||
void (* adjust_size_allocation) (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
GtkOrientation orientation,
|
||||
gint *natural_size,
|
||||
gint *allocated_pos,
|
||||
gint *allocated_size);
|
||||
|
||||
/*< private >*/
|
||||
|
||||
|
@ -408,6 +408,9 @@ open_valigned_label_window (void)
|
||||
gtk_widget_show (box);
|
||||
gtk_container_add (GTK_CONTAINER (window), box);
|
||||
|
||||
label = gtk_label_new ("Both labels expand");
|
||||
gtk_widget_show (label);
|
||||
gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
|
||||
|
||||
label = gtk_label_new ("Some wrapping text with width-chars = 15 and max-width-chars = 35");
|
||||
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||
@ -421,7 +424,7 @@ open_valigned_label_window (void)
|
||||
gtk_container_add (GTK_CONTAINER (frame), label);
|
||||
|
||||
gtk_widget_set_valign (frame, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_halign (frame, GTK_ALIGN_FILL);
|
||||
gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (box), frame, TRUE, TRUE, 0);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user