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="modal">1</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>
<property name="hide-on-close">1</property>
<child type="action">

View File

@ -288,6 +288,64 @@ gtk_box_layout_compute_opposite_size (GtkBoxLayout *self,
*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
gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self,
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_baseline = -1, computed_natural_baseline = -1;
GtkRequestedSize *sizes;
int extra_space, size_given_to_child, i;
int children_minimum_size = 0;
int available, size_given_to_child, i;
int child_size, child_minimum, child_natural;
int child_minimum_baseline, child_natural_baseline;
int n_extra_widgets = 0;
int spacing;
gboolean have_baseline;
gboolean have_baseline = FALSE;
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));
sizes = g_newa (GtkRequestedSize, nvis_children);
extra_space = MAX (0, for_size - (nvis_children - 1) * spacing);
/* Retrieve desired size for visible children */
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
int min_opposite, nat_for_min;
if (!gtk_widget_should_layout (child))
continue;
gtk_widget_measure (child,
self->orientation,
-1,
&sizes[i].minimum_size, &sizes[i].natural_size,
NULL, NULL);
/* Don't just use the natural size as the max size,
* the natural size is the ideal size, not necessarily
* the maximum size.
* Also check the nat size for opposite min size.
*/
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;
}
g_assert ((nvis_children - 1) * spacing <= for_size);
available = for_size - (nvis_children - 1) * spacing;
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 = available / nvis_children;
n_extra_widgets = available % nvis_children;
size_given_to_child = extra_space / nvis_children;
n_extra_widgets = extra_space % 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 */
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (!gtk_widget_should_layout (child))
continue;
if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_CONSTANT_SIZE)
{
gtk_widget_measure (child,
self->orientation,
-1,
&sizes[i].minimum_size, &sizes[i].natural_size,
NULL, NULL);
sizes[i].data = child;
g_assert (available >= sizes[i].minimum_size);
available -= sizes[i].minimum_size;
i++;
}
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 */
extra_space -= children_minimum_size;
extra_space = MAX (0, extra_space);
extra_space = gtk_distribute_natural_allocation (extra_space, nvis_children, sizes);
available = gtk_distribute_natural_allocation (available, nvis_children, sizes);
/* Calculate space which hasn't distributed yet,
* and is available for expanding children.
*/
if (nexpand_children > 0)
{
size_given_to_child = extra_space / nexpand_children;
n_extra_widgets = extra_space % nexpand_children;
size_given_to_child = available / nexpand_children;
n_extra_widgets = available % nexpand_children;
}
else
{
size_given_to_child = 0;
}
}
have_baseline = FALSE;
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (!gtk_widget_should_layout (child))
continue;
/* Assign the child's size. */
if (self->homogeneous)
i = 0;
n_inconstant = 0;
for (child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
child_size = size_given_to_child;
if (!gtk_widget_should_layout (child))
continue;
if (n_extra_widgets > 0)
if (sizes[i].data == child)
{
child_size++;
n_extra_widgets--;
child_size = sizes[i].minimum_size;
i++;
}
else
{
n_inconstant++;
g_assert (sizes[nvis_children - n_inconstant].data == child);
child_size = sizes[nvis_children - n_inconstant].minimum_size;
}
}
else
{
child_size = sizes[i].minimum_size;
if (gtk_widget_compute_expand (child, self->orientation))
{
@ -421,30 +514,29 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self,
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);
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);
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
{
computed_minimum = MAX (computed_minimum, child_minimum);
computed_natural = MAX (computed_natural, child_natural);
}
i += 1;
}
if (have_baseline)

View File

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

View File

@ -139,7 +139,6 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
int *minimum_baseline,
int *natural_baseline)
{
const gboolean baselines_requested = (minimum_baseline != NULL || natural_baseline != NULL);
SizeRequestCache *cache;
int min_size = 0;
int nat_size = 0;
@ -361,7 +360,7 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
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)
{

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.ref.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.ref.ui',
'label-shadows.css',
@ -357,6 +359,8 @@ testdata = [
'label-sizing.ui',
'label-small-ellipsized.ref.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.ref.ui',
'label-text-shadow-clipping.ui',
@ -365,6 +369,8 @@ testdata = [
'label-text-shadow-changes-modify-clip.ui',
'label-width-chars-dont-shrink.ref.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
# that are not valid with subpixel positioning
#'label-wrap-justify.ref.ui',
@ -500,6 +506,8 @@ testdata = [
'unresolvable.css',
'unresolvable.ref.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.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>