Merge branch 'wip/otte/for-master' into 'master'

lots of sizing fixes

See merge request GNOME/gtk!4131
This commit is contained in:
Benjamin Otte 2021-11-09 03:15:00 +00:00
commit 08d48201e9
13 changed files with 324 additions and 100 deletions

View File

@ -2923,7 +2923,7 @@ microphone-sensitivity-medium-symbolic</property>
<property name="resizable">0</property> <property name="resizable">0</property>
<property name="modal">1</property> <property name="modal">1</property>
<property name="text" translatable="1">Do something?</property> <property name="text" translatable="1">Do something?</property>
<property name="secondary-text" translatable="1">If you do something, <property name="secondary-text" translatable="1">If you don't do something,
bad things might happen.</property> bad things might happen.</property>
<property name="hide-on-close">1</property> <property name="hide-on-close">1</property>
<child type="action"> <child type="action">

View File

@ -288,6 +288,64 @@ gtk_box_layout_compute_opposite_size (GtkBoxLayout *self,
*natural = largest_nat; *natural = largest_nat;
} }
static int
distribute_remaining_size (GtkRequestedSize *sizes,
gsize n_sizes,
GtkOrientation orientation,
int available,
int min,
int max)
{
int total_size = 0;
gsize i;
if (n_sizes == 0)
return available;
for (i = 0; i < n_sizes; i++)
{
gtk_widget_measure (sizes[i].data,
orientation,
min,
&sizes[i].minimum_size, &sizes[i].natural_size,
NULL, NULL);
total_size += sizes[i].minimum_size;
}
if (total_size <= available)
return available - total_size;
/* total_size > available happens when we last ran for values too big,
* rerun for the correct value min == max in that case */
while (min < max || total_size > available)
{
int test;
if (max == G_MAXINT)
test = min * 2;
else
test = (min + max) / 2;
total_size = 0;
for (i = 0; i < n_sizes; i++)
{
gtk_widget_measure (sizes[i].data,
orientation,
test,
&sizes[i].minimum_size, &sizes[i].natural_size,
NULL, NULL);
total_size += sizes[i].minimum_size;
}
if (total_size > available)
min = test + 1;
else
max = test;
}
return available - total_size;
}
static void static void
gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self,
GtkWidget *widget, GtkWidget *widget,
@ -305,13 +363,12 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self,
int computed_minimum_below = 0, computed_natural_below = 0; int computed_minimum_below = 0, computed_natural_below = 0;
int computed_minimum_baseline = -1, computed_natural_baseline = -1; int computed_minimum_baseline = -1, computed_natural_baseline = -1;
GtkRequestedSize *sizes; GtkRequestedSize *sizes;
int extra_space, size_given_to_child, i; int available, size_given_to_child, i;
int children_minimum_size = 0;
int child_size, child_minimum, child_natural; int child_size, child_minimum, child_natural;
int child_minimum_baseline, child_natural_baseline; int child_minimum_baseline, child_natural_baseline;
int n_extra_widgets = 0; int n_extra_widgets = 0;
int spacing; int spacing;
gboolean have_baseline; gboolean have_baseline = FALSE;
count_expand_children (widget, self->orientation, &nvis_children, &nexpand_children); count_expand_children (widget, self->orientation, &nvis_children, &nexpand_children);
@ -320,96 +377,132 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self,
spacing = get_spacing (self, gtk_widget_get_css_node (widget)); spacing = get_spacing (self, gtk_widget_get_css_node (widget));
sizes = g_newa (GtkRequestedSize, nvis_children); sizes = g_newa (GtkRequestedSize, nvis_children);
extra_space = MAX (0, for_size - (nvis_children - 1) * spacing); g_assert ((nvis_children - 1) * spacing <= for_size);
available = for_size - (nvis_children - 1) * spacing;
if (self->homogeneous)
{
size_given_to_child = available / nvis_children;
n_extra_widgets = available % nvis_children;
for (child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (!gtk_widget_should_layout (child))
continue;
child_size = size_given_to_child;
if (n_extra_widgets)
{
child_size++;
n_extra_widgets--;
}
child_minimum_baseline = child_natural_baseline = -1;
/* Assign the child's position. */
gtk_widget_measure (child,
OPPOSITE_ORIENTATION (self->orientation),
child_size,
&child_minimum, &child_natural,
&child_minimum_baseline, &child_natural_baseline);
if (child_minimum_baseline >= 0)
{
have_baseline = TRUE;
computed_minimum_below = MAX (computed_minimum_below, child_minimum - child_minimum_baseline);
computed_natural_below = MAX (computed_natural_below, child_natural - child_natural_baseline);
computed_minimum_above = MAX (computed_minimum_above, child_minimum_baseline);
computed_natural_above = MAX (computed_natural_above, child_natural_baseline);
}
else
{
computed_minimum = MAX (computed_minimum, child_minimum);
computed_natural = MAX (computed_natural, child_natural);
}
}
}
else
{
int min_size = 0, child_min_size;
int n_inconstant = 0;
/* Retrieve desired size for visible children */ /* Retrieve desired size for visible children */
for (i = 0, child = _gtk_widget_get_first_child (widget); for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL; child != NULL;
child = _gtk_widget_get_next_sibling (child)) child = _gtk_widget_get_next_sibling (child))
{ {
int min_opposite, nat_for_min;
if (!gtk_widget_should_layout (child)) if (!gtk_widget_should_layout (child))
continue; continue;
if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_CONSTANT_SIZE)
{
gtk_widget_measure (child, gtk_widget_measure (child,
self->orientation, self->orientation,
-1, -1,
&sizes[i].minimum_size, &sizes[i].natural_size, &sizes[i].minimum_size, &sizes[i].natural_size,
NULL, NULL); NULL, NULL);
/* Don't just use the natural size as the max size, sizes[i].data = child;
* the natural size is the ideal size, not necessarily g_assert (available >= sizes[i].minimum_size);
* the maximum size. available -= sizes[i].minimum_size;
* Also check the nat size for opposite min size. i++;
*/
gtk_widget_measure (child,
OPPOSITE_ORIENTATION (self->orientation),
-1,
&min_opposite, NULL,
NULL, NULL);
gtk_widget_measure (child,
self->orientation,
min_opposite,
NULL, &nat_for_min,
NULL, NULL);
sizes[i].natural_size = MAX (sizes[i].natural_size, nat_for_min);
children_minimum_size += sizes[i].minimum_size;
i += 1;
}
if (self->homogeneous)
{
/* We still need to run the above loop to populate the minimum sizes for
* children that aren't going to fill.
*/
size_given_to_child = extra_space / nvis_children;
n_extra_widgets = extra_space % nvis_children;
} }
else else
{ {
gtk_widget_measure (child,
OPPOSITE_ORIENTATION (self->orientation),
-1,
&child_min_size, NULL,
NULL, NULL);
min_size = MAX (min_size, child_min_size);
n_inconstant++;
sizes[nvis_children - n_inconstant].data = child;
}
}
available = distribute_remaining_size (sizes + nvis_children - n_inconstant,
n_inconstant,
self->orientation,
available,
min_size,
G_MAXINT);
/* Bring children up to size first */ /* Bring children up to size first */
extra_space -= children_minimum_size; available = gtk_distribute_natural_allocation (available, nvis_children, sizes);
extra_space = MAX (0, extra_space);
extra_space = gtk_distribute_natural_allocation (extra_space, nvis_children, sizes);
/* Calculate space which hasn't distributed yet, /* Calculate space which hasn't distributed yet,
* and is available for expanding children. * and is available for expanding children.
*/ */
if (nexpand_children > 0) if (nexpand_children > 0)
{ {
size_given_to_child = extra_space / nexpand_children; size_given_to_child = available / nexpand_children;
n_extra_widgets = extra_space % nexpand_children; n_extra_widgets = available % nexpand_children;
} }
else else
{ {
size_given_to_child = 0; size_given_to_child = 0;
} }
}
have_baseline = FALSE; i = 0;
for (i = 0, child = _gtk_widget_get_first_child (widget); n_inconstant = 0;
for (child = _gtk_widget_get_first_child (widget);
child != NULL; child != NULL;
child = _gtk_widget_get_next_sibling (child)) child = _gtk_widget_get_next_sibling (child))
{ {
if (!gtk_widget_should_layout (child)) if (!gtk_widget_should_layout (child))
continue; continue;
/* Assign the child's size. */ if (sizes[i].data == child)
if (self->homogeneous)
{ {
child_size = size_given_to_child; child_size = sizes[i].minimum_size;
i++;
if (n_extra_widgets > 0)
{
child_size++;
n_extra_widgets--;
}
} }
else else
{ {
child_size = sizes[i].minimum_size; n_inconstant++;
g_assert (sizes[nvis_children - n_inconstant].data == child);
child_size = sizes[nvis_children - n_inconstant].minimum_size;
}
if (gtk_widget_compute_expand (child, self->orientation)) if (gtk_widget_compute_expand (child, self->orientation))
{ {
@ -421,7 +514,6 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self,
n_extra_widgets--; n_extra_widgets--;
} }
} }
}
child_minimum_baseline = child_natural_baseline = -1; child_minimum_baseline = child_natural_baseline = -1;
/* Assign the child's position. */ /* Assign the child's position. */
@ -444,7 +536,7 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self,
computed_minimum = MAX (computed_minimum, child_minimum); computed_minimum = MAX (computed_minimum, child_minimum);
computed_natural = MAX (computed_natural, child_natural); computed_natural = MAX (computed_natural, child_natural);
} }
i += 1; }
} }
if (have_baseline) if (have_baseline)

View File

@ -1077,14 +1077,15 @@ get_static_size (GtkLabel *self,
int *minimum_baseline, int *minimum_baseline,
int *natural_baseline) int *natural_baseline)
{ {
int minimum_default, natural_default;
PangoLayout *layout; PangoLayout *layout;
layout = gtk_label_get_measuring_layout (self, NULL, -1); get_default_widths (self, &minimum_default, &natural_default);
layout = gtk_label_get_measuring_layout (self, NULL, self->ellipsize ? natural_default : -1);
if (orientation == GTK_ORIENTATION_HORIZONTAL) if (orientation == GTK_ORIENTATION_HORIZONTAL)
{ {
int minimum_default, natural_default;
pango_layout_get_size (layout, natural, NULL); pango_layout_get_size (layout, natural, NULL);
if (self->ellipsize) if (self->ellipsize)
{ {
@ -1096,11 +1097,8 @@ get_static_size (GtkLabel *self,
else else
*minimum = *natural; *minimum = *natural;
get_default_widths (self, &minimum_default, &natural_default);
if (minimum_default > *minimum) if (minimum_default > *minimum)
*minimum = minimum_default; *minimum = minimum_default;
if (natural_default > -1)
*natural = natural_default;
*natural = MAX (*minimum, *natural); *natural = MAX (*minimum, *natural);
} }
else else
@ -1180,7 +1178,6 @@ get_width_for_height (GtkLabel *self,
/* Natural width is natural width - or as wide as possible */ /* Natural width is natural width - or as wide as possible */
layout = gtk_label_get_measuring_layout (self, layout, natural_default); layout = gtk_label_get_measuring_layout (self, layout, natural_default);
pango_layout_get_size (layout, natural_width, NULL); pango_layout_get_size (layout, natural_width, NULL);
*natural_width = MAX (*natural_width, natural_default);
*natural_width = MAX (*natural_width, *minimum_width); *natural_width = MAX (*natural_width, *minimum_width);
} }
else else

View File

@ -139,7 +139,6 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
int *minimum_baseline, int *minimum_baseline,
int *natural_baseline) int *natural_baseline)
{ {
const gboolean baselines_requested = (minimum_baseline != NULL || natural_baseline != NULL);
SizeRequestCache *cache; SizeRequestCache *cache;
int min_size = 0; int min_size = 0;
int nat_size = 0; int nat_size = 0;
@ -361,7 +360,7 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
nat_size = adjusted_natural; nat_size = adjusted_natural;
} }
if (baselines_requested && (min_baseline != -1 || nat_baseline != -1)) if (min_baseline != -1 || nat_baseline != -1)
{ {
if (orientation == GTK_ORIENTATION_HORIZONTAL) if (orientation == GTK_ORIENTATION_HORIZONTAL)
{ {

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window1">
<property name="decorated">0</property>
<child>
<object class="GtkLabel" id="label1">
<property name="label">Hello World</property>
</object>
</child>
</object>
</interface>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window1">
<property name="decorated">0</property>
<child>
<object class="GtkLabel" id="label1">
<property name="label">Hello World</property>
<property name="max-width-chars">1000</property>
</object>
</child>
</object>
</interface>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window1">
<property name="decorated">0</property>
<child>
<object class="GtkLabel" id="label1">
<property name="label">Hello World</property>
</object>
</child>
</object>
</interface>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window1">
<property name="decorated">0</property>
<child>
<object class="GtkLabel" id="label1">
<property name="label">Hello World</property>
<property name="max-width-chars">2</property>
</object>
</child>
</object>
</interface>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window1">
<property name="decorated">0</property>
<child>
<object class="GtkLabel" id="label1">
<property name="label">Hello World</property>
<property name="wrap">1</property>
</object>
</child>
</object>
</interface>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window1">
<property name="decorated">0</property>
<child>
<object class="GtkLabel" id="label1">
<property name="label">Hello World</property>
<property name="max-width-chars">1000</property>
<property name="wrap">1</property>
</object>
</child>
</object>
</interface>

View File

@ -347,6 +347,8 @@ testdata = [
'label-fonts.css', 'label-fonts.css',
'label-fonts.ref.ui', 'label-fonts.ref.ui',
'label-fonts.ui', 'label-fonts.ui',
'label-huge-max-width-chars.ref.ui',
'label-huge-max-width-chars.ui',
'label-max-width-chars-and-halign-and-infinite-width.ui', 'label-max-width-chars-and-halign-and-infinite-width.ui',
'label-max-width-chars-and-halign-and-infinite-width.ref.ui', 'label-max-width-chars-and-halign-and-infinite-width.ref.ui',
'label-shadows.css', 'label-shadows.css',
@ -357,6 +359,8 @@ testdata = [
'label-sizing.ui', 'label-sizing.ui',
'label-small-ellipsized.ref.ui', 'label-small-ellipsized.ref.ui',
'label-small-ellipsized.ui', 'label-small-ellipsized.ui',
'label-small-max-width-chars.ref.ui',
'label-small-max-width-chars.ui',
'label-text-shadow-clipping.css', 'label-text-shadow-clipping.css',
'label-text-shadow-clipping.ref.ui', 'label-text-shadow-clipping.ref.ui',
'label-text-shadow-clipping.ui', 'label-text-shadow-clipping.ui',
@ -365,6 +369,8 @@ testdata = [
'label-text-shadow-changes-modify-clip.ui', 'label-text-shadow-changes-modify-clip.ui',
'label-width-chars-dont-shrink.ref.ui', 'label-width-chars-dont-shrink.ref.ui',
'label-width-chars-dont-shrink.ui', 'label-width-chars-dont-shrink.ui',
'label-wrapped-huge-max-width-chars.ref.ui',
'label-wrapped-huge-max-width-chars.ui',
# this seems to make assumptions on text positioning # this seems to make assumptions on text positioning
# that are not valid with subpixel positioning # that are not valid with subpixel positioning
#'label-wrap-justify.ref.ui', #'label-wrap-justify.ref.ui',
@ -500,6 +506,8 @@ testdata = [
'unresolvable.css', 'unresolvable.css',
'unresolvable.ref.ui', 'unresolvable.ref.ui',
'unresolvable.ui', 'unresolvable.ui',
'vbox-with-2-wrapping-labels-where-one-should-wrap.ref.ui',
'vbox-with-2-wrapping-labels-where-one-should-wrap.ui',
'vbox-with-max-width-chars-label.ref.ui', 'vbox-with-max-width-chars-label.ref.ui',
'vbox-with-max-width-chars-label.ui', 'vbox-with-max-width-chars-label.ui',
'window-border-width.ref.ui', 'window-border-width.ref.ui',

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk40">
<object class="GtkWindow">
<property name="decorated">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkBox">
<property name="orientation">1</property>
<child>
<object class="GtkLabel">
<property name="label">Hello
World</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Hi Ho</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk40">
<object class="GtkWindow">
<property name="decorated">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkBox">
<property name="orientation">1</property>
<child>
<object class="GtkLabel">
<property name="label">Hello World</property>
<property name="wrap">1</property>
<property name="max-width-chars">1</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Hi Ho</property>
<property name="wrap">1</property>
<property name="max-width-chars">1</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>