diff --git a/gtk/gtkboxlayout.c b/gtk/gtkboxlayout.c index f080748830..99feca37e5 100644 --- a/gtk/gtkboxlayout.c +++ b/gtk/gtkboxlayout.c @@ -256,11 +256,46 @@ gtk_box_layout_compute_size (GtkBoxLayout *self, static void gtk_box_layout_compute_opposite_size (GtkBoxLayout *self, GtkWidget *widget, - int for_size, int *minimum, int *natural, int *min_baseline, int *nat_baseline) +{ + GtkWidget *child; + int largest_min = 0, largest_nat = 0; + + for (child = gtk_widget_get_first_child (widget); + child != NULL; + child = gtk_widget_get_next_sibling (child)) + { + int child_min = 0; + int child_nat = 0; + + if (!gtk_widget_should_layout (child)) + continue; + + gtk_widget_measure (child, + OPPOSITE_ORIENTATION (self->orientation), + -1, + &child_min, &child_nat, + NULL, NULL); + + largest_min = MAX (largest_min, child_min); + largest_nat = MAX (largest_nat, child_nat); + } + + *minimum = largest_min; + *natural = largest_nat; +} + +static void +gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, + GtkWidget *widget, + int for_size, + int *minimum, + int *natural, + int *min_baseline, + int *nat_baseline) { GtkWidget *child; int nvis_children; @@ -437,9 +472,18 @@ gtk_box_layout_measure (GtkLayoutManager *layout_manager, if (self->orientation != orientation) { - gtk_box_layout_compute_opposite_size (self, widget, for_size, - minimum, natural, - min_baseline, nat_baseline); + if (for_size < 0) + { + gtk_box_layout_compute_opposite_size (self, widget, + minimum, natural, + min_baseline, nat_baseline); + } + else + { + gtk_box_layout_compute_opposite_size_for_size (self, widget, for_size, + minimum, natural, + min_baseline, nat_baseline); + } } else { diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 661902a275..3580deae1e 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -1018,8 +1018,7 @@ gtk_label_get_measuring_layout (GtkLabel *self, } static int -get_char_pixels (GtkWidget *self, - PangoLayout *layout) +get_char_pixels (PangoLayout *layout) { PangoContext *context; PangoFontMetrics *metrics; @@ -1034,6 +1033,88 @@ get_char_pixels (GtkWidget *self, return MAX (char_width, digit_width); } +static void +get_default_widths (GtkLabel *self, + int *minimum, + int *natural) +{ + int char_pixels; + + if (self->width_chars < 0 && self->max_width_chars < 0) + { + if (minimum) + *minimum = -1; + if (natural) + *natural = -1; + return; + } + + gtk_label_ensure_layout (self); + char_pixels = get_char_pixels (self->layout); + + if (minimum) + { + if (self->width_chars < 0) + *minimum = -1; + else + *minimum = char_pixels * self->width_chars; + } + + if (natural) + { + if (self->max_width_chars < 0) + *natural = -1; + else + *natural = char_pixels * MAX (self->width_chars, self->max_width_chars); + } +} + +static void +get_static_size (GtkLabel *self, + GtkOrientation orientation, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + PangoLayout *layout; + + layout = gtk_label_get_measuring_layout (self, NULL, -1); + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + int minimum_default, natural_default; + + pango_layout_get_size (layout, natural, NULL); + if (self->ellipsize) + { + layout = gtk_label_get_measuring_layout (self, layout, 0); + pango_layout_get_size (layout, minimum, NULL); + /* yes, Pango ellipsizes even when that needs more space */ + *minimum = MIN (*minimum, *natural); + } + 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 + { + pango_layout_get_size (layout, NULL, minimum); + *minimum_baseline = pango_layout_get_baseline (layout); + + *natural = *minimum; + *natural_baseline = *minimum_baseline; + } + + g_object_unref (layout); +} + static void get_height_for_width (GtkLabel *self, int width, @@ -1043,165 +1124,95 @@ get_height_for_width (GtkLabel *self, int *natural_baseline) { PangoLayout *layout; - int text_height, baseline; + int natural_width, text_height, baseline; - width *= PANGO_SCALE; - if (self->max_width_chars > -1) + if (width < 0) { - int char_pixels, width_chars; - + /* Minimum height is assuming infinite width */ layout = gtk_label_get_measuring_layout (self, NULL, -1); - char_pixels = get_char_pixels (GTK_WIDGET (self), layout); - if (self->width_chars > self->max_width_chars) - width_chars = self->width_chars; - else - width_chars = self->max_width_chars; - width = MIN (char_pixels * width_chars, width); + pango_layout_get_size (layout, NULL, minimum_height); + baseline = pango_layout_get_baseline (layout); + *minimum_baseline = baseline; + + /* Natural height is assuming natural width */ + get_default_widths (self, NULL, &natural_width); + + layout = gtk_label_get_measuring_layout (self, layout, natural_width); + pango_layout_get_size (layout, NULL, natural_height); + baseline = pango_layout_get_baseline (layout); + *natural_baseline = baseline; } - layout = gtk_label_get_measuring_layout (self, NULL, width); + else + { + /* minimum = natural for any given width */ + layout = gtk_label_get_measuring_layout (self, NULL, width); - pango_layout_get_pixel_size (layout, NULL, &text_height); + pango_layout_get_size (layout, NULL, &text_height); - *minimum_height = text_height; - *natural_height = text_height; + *minimum_height = text_height; + *natural_height = text_height; - baseline = pango_layout_get_baseline (layout) / PANGO_SCALE; - *minimum_baseline = baseline; - *natural_baseline = baseline; + baseline = pango_layout_get_baseline (layout); + *minimum_baseline = baseline; + *natural_baseline = baseline; + } g_object_unref (layout); } static void -gtk_label_get_preferred_layout_size (GtkLabel *self, - PangoRectangle *smallest, - PangoRectangle *widest, - int *smallest_baseline, - int *widest_baseline) +get_width_for_height (GtkLabel *self, + int height, + int *minimum_width, + int *natural_width) { PangoLayout *layout; - int char_pixels; + int minimum_default, natural_default; - /* "width-chars" Hard-coded minimum width: - * - minimum size should be MAX (width-chars, strlen ("...")); - * - natural size should be MAX (width-chars, strlen (self->text)); - * - * "max-width-chars" User specified maximum size requisition - * - minimum size should be MAX (width-chars, 0) - * - natural size should be MIN (max-width-chars, strlen (self->text)) - * - * For ellipsizing labels; if max-width-chars is specified: either it is used as - * a minimum size or the label text as a minimum size (natural size still overflows). - * - * For wrapping labels; A reasonable minimum size is useful to naturally layout - * interfaces automatically. In this case if no "width-chars" is specified, the minimum - * width will default to the wrap guess that gtk_label_ensure_layout() does. - */ + get_default_widths (self, &minimum_default, &natural_default); - /* Start off with the pixel extents of an as-wide-as-possible layout */ - layout = gtk_label_get_measuring_layout (self, NULL, -1); - - if (self->width_chars > -1 || self->max_width_chars > -1) - char_pixels = get_char_pixels (GTK_WIDGET (self), layout); - else - char_pixels = 0; - - pango_layout_get_extents (layout, NULL, widest); - widest->width = MAX (widest->width, char_pixels * self->width_chars); - widest->x = widest->y = 0; - *widest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE; - - if (self->ellipsize || self->wrap) + if (height < 0) { - /* a layout with width 0 will be as small as humanly possible */ - layout = gtk_label_get_measuring_layout (self, - layout, - self->width_chars > -1 ? char_pixels * self->width_chars - : 0); + /* Minimum width is as many line breaks as possible */ + layout = gtk_label_get_measuring_layout (self, NULL, MAX (minimum_default, 0)); + pango_layout_get_size (layout, minimum_width, NULL); - pango_layout_get_extents (layout, NULL, smallest); - smallest->width = MAX (smallest->width, char_pixels * self->width_chars); - smallest->x = smallest->y = 0; - - *smallest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE; - - if (self->max_width_chars > -1 && widest->width > char_pixels * self->max_width_chars) - { - layout = gtk_label_get_measuring_layout (self, - layout, - MAX (smallest->width, char_pixels * self->max_width_chars)); - pango_layout_get_extents (layout, NULL, widest); - widest->width = MAX (widest->width, char_pixels * self->width_chars); - widest->x = widest->y = 0; - - *widest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE; - } - - if (widest->width < smallest->width) - { - *smallest = *widest; - *smallest_baseline = *widest_baseline; - } + /* 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 { - *smallest = *widest; - *smallest_baseline = *widest_baseline; + int min, max, mid, text_width, text_height; + + /* binary search for the smallest width where the height doesn't + * eclipse the given height */ + min = MAX (minimum_default, 0); + layout = gtk_label_get_measuring_layout (self, NULL, -1); + pango_layout_get_size (layout, &max, NULL); + + while (min < max) + { + mid = (min + max) / 2; + layout = gtk_label_get_measuring_layout (self, layout, mid); + pango_layout_get_size (layout, &text_width, &text_height); + if (text_width > mid) + min = mid = text_width; + if (text_height > height) + min = mid + 1; + else + max = text_width; + } + + *minimum_width = min; + *natural_width = min; } g_object_unref (layout); } -static void -gtk_label_get_preferred_size (GtkWidget *widget, - GtkOrientation orientation, - int *minimum_size, - int *natural_size, - int *minimum_baseline, - int *natural_baseline) -{ - GtkLabel *self = GTK_LABEL (widget); - PangoRectangle widest_rect; - PangoRectangle smallest_rect; - int smallest_baseline; - int widest_baseline; - - gtk_label_get_preferred_layout_size (self, - &smallest_rect, &widest_rect, - &smallest_baseline, &widest_baseline); - - widest_rect.width = PANGO_PIXELS_CEIL (widest_rect.width); - widest_rect.height = PANGO_PIXELS_CEIL (widest_rect.height); - - smallest_rect.width = PANGO_PIXELS_CEIL (smallest_rect.width); - smallest_rect.height = PANGO_PIXELS_CEIL (smallest_rect.height); - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - /* Normal desired width */ - *minimum_size = smallest_rect.width; - *natural_size = widest_rect.width; - } - else /* GTK_ORIENTATION_VERTICAL */ - { - if (smallest_rect.height < widest_rect.height) - { - *minimum_size = smallest_rect.height; - *natural_size = widest_rect.height; - *minimum_baseline = smallest_baseline; - *natural_baseline = widest_baseline; - } - else - { - *minimum_size = widest_rect.height; - *natural_size = smallest_rect.height; - *minimum_baseline = widest_baseline; - *natural_baseline = smallest_baseline; - } - } -} - - static void gtk_label_measure (GtkWidget *widget, GtkOrientation orientation, @@ -1213,14 +1224,22 @@ gtk_label_measure (GtkWidget *widget, { GtkLabel *self = GTK_LABEL (widget); - if (orientation == GTK_ORIENTATION_VERTICAL && for_size != -1 && self->wrap) - { - gtk_label_clear_layout (self); + if (for_size > 0) + for_size *= PANGO_SCALE; - get_height_for_width (self, for_size, minimum, natural, minimum_baseline, natural_baseline); - } + if (!self->wrap) + get_static_size (self, orientation, minimum, natural, minimum_baseline, natural_baseline); + else if (orientation == GTK_ORIENTATION_VERTICAL) + get_height_for_width (self, for_size, minimum, natural, minimum_baseline, natural_baseline); else - gtk_label_get_preferred_size (widget, orientation, minimum, natural, minimum_baseline, natural_baseline); + get_width_for_height (self, for_size, minimum, natural); + + *minimum = PANGO_PIXELS_CEIL (*minimum); + *natural = PANGO_PIXELS_CEIL (*natural); + if (*minimum_baseline > 0) + *minimum_baseline = PANGO_PIXELS_CEIL (*minimum_baseline); + if (*natural_baseline > 0) + *natural_baseline = PANGO_PIXELS_CEIL (*natural_baseline); } static void diff --git a/gtk/gtkpicture.c b/gtk/gtkpicture.c index 7694888c68..6821ecacfb 100644 --- a/gtk/gtkpicture.c +++ b/gtk/gtkpicture.c @@ -884,6 +884,9 @@ gtk_picture_set_can_shrink (GtkPicture *self, return; self->can_shrink = can_shrink; + + gtk_widget_queue_resize (GTK_WIDGET (self)); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CAN_SHRINK]); } diff --git a/testsuite/reftests/label-max-width-chars-and-halign-and-infinite-width.ref.ui b/testsuite/reftests/label-max-width-chars-and-halign-and-infinite-width.ref.ui index 68c5d0a112..d3f075290b 100644 --- a/testsuite/reftests/label-max-width-chars-and-halign-and-infinite-width.ref.ui +++ b/testsuite/reftests/label-max-width-chars-and-halign-and-infinite-width.ref.ui @@ -8,9 +8,7 @@ start end 0 - ABCDE -ABCD - 4 + ABCDE ABCD diff --git a/testsuite/reftests/label-sizing.ref.ui b/testsuite/reftests/label-sizing.ref.ui index 1616ef4f2f..4235424e80 100644 --- a/testsuite/reftests/label-sizing.ref.ui +++ b/testsuite/reftests/label-sizing.ref.ui @@ -212,8 +212,7 @@ end end 0 - ABCDE -ABCD + ABCDE ABCD @@ -224,8 +223,7 @@ ABCD end start 0 - ABCDE -ABCD + ABCDE ABCD @@ -646,8 +644,7 @@ ABCD end end 0 - ABCDE -ABCD + ABCDE ABCD 4 @@ -659,8 +656,7 @@ ABCD end start 0 - ABCDE -ABCD + ABCDE ABCD 4 @@ -1092,8 +1088,7 @@ ABCD end end 0 - ABCDE -ABCD + ABCDE ABCD 8 @@ -1105,8 +1100,7 @@ ABCD end start 0 - ABCDE -ABCD + ABCDE ABCD 8 @@ -1982,8 +1976,7 @@ ABCD end end 0 - ABCDE -ABCD + ABCDE ABCD 4 @@ -1995,8 +1988,7 @@ ABCD end start 0 - ABCDE -ABCD + ABCDE ABCD 4 @@ -2016,8 +2008,7 @@ ABCD start end 0 - ABCDE -ABCD + ABCDE ABCD 4 @@ -2029,8 +2020,7 @@ ABCD start start 0 - ABCDE -ABCD + ABCDE ABCD 4 @@ -2434,8 +2424,7 @@ ABCD end end 0 - ABCDE -ABCD + ABCDE ABCD 4 4 @@ -2448,8 +2437,7 @@ ABCD end start 0 - ABCDE -ABCD + ABCDE ABCD 4 4 @@ -2470,8 +2458,7 @@ ABCD start end 0 - ABCDE -ABCD + ABCDE ABCD 4 4 @@ -2484,8 +2471,7 @@ ABCD start start 0 - ABCDE -ABCD + ABCDE ABCD 4 4 @@ -2898,8 +2884,7 @@ ABCD end end 0 - ABCDE -ABCD + ABCDE ABCD 8 4 @@ -2912,8 +2897,7 @@ ABCD end start 0 - ABCDE -ABCD + ABCDE ABCD 8 4 @@ -2934,8 +2918,7 @@ ABCD start end 0 - ABCDE -ABCD + ABCDE ABCD 8 4 @@ -2948,8 +2931,7 @@ ABCD start start 0 - ABCDE -ABCD + ABCDE ABCD 8 4 @@ -3818,8 +3800,7 @@ ABCD end end 0 - ABCDE -ABCD + ABCDE ABCD 8 @@ -3831,8 +3812,7 @@ ABCD end start 0 - ABCDE -ABCD + ABCDE ABCD 8 @@ -3852,8 +3832,7 @@ ABCD start end 0 - ABCDE -ABCD + ABCDE ABCD 8 @@ -3865,8 +3844,7 @@ ABCD start start 0 - ABCDE -ABCD + ABCDE ABCD 8 @@ -4270,8 +4248,7 @@ ABCD end end 0 - ABCDE -ABCD + ABCDE ABCD 4 8 @@ -4284,8 +4261,7 @@ ABCD end start 0 - ABCDE -ABCD + ABCDE ABCD 4 8 @@ -4306,8 +4282,7 @@ ABCD start end 0 - ABCDE -ABCD + ABCDE ABCD 4 8 @@ -4320,8 +4295,7 @@ ABCD start start 0 - ABCDE -ABCD + ABCDE ABCD 4 8 @@ -4734,8 +4708,7 @@ ABCD end end 0 - ABCDE -ABCD + ABCDE ABCD 8 8 @@ -4748,8 +4721,7 @@ ABCD end start 0 - ABCDE -ABCD + ABCDE ABCD 8 8 @@ -4770,8 +4742,7 @@ ABCD start end 0 - ABCDE -ABCD + ABCDE ABCD 8 8 @@ -4784,8 +4755,7 @@ ABCD start start 0 - ABCDE -ABCD + ABCDE ABCD 8 8 @@ -5654,8 +5624,7 @@ ABCD end end 0 - ABCDE -ABCD + ABCDE ABCD 12 @@ -5667,8 +5636,7 @@ ABCD end start 0 - ABCDE -ABCD + ABCDE ABCD 12 @@ -6104,8 +6072,7 @@ ABCD end end 0 - ABCDE -ABCD + ABCDE ABCD 4 12 @@ -6118,8 +6085,7 @@ ABCD end start 0 - ABCDE -ABCD + ABCDE ABCD 4 12 @@ -6566,8 +6532,7 @@ ABCD end end 0 - ABCDE -ABCD + ABCDE ABCD 8 12 @@ -6580,8 +6545,7 @@ ABCD end start 0 - ABCDE -ABCD + ABCDE ABCD 8 12 diff --git a/testsuite/reftests/meson.build b/testsuite/reftests/meson.build index b033760ed7..692a427438 100644 --- a/testsuite/reftests/meson.build +++ b/testsuite/reftests/meson.build @@ -498,6 +498,8 @@ testdata = [ 'unresolvable.css', 'unresolvable.ref.ui', 'unresolvable.ui', + 'vbox-with-max-width-chars-label.ref.ui', + 'vbox-with-max-width-chars-label.ui', 'window-border-width.ref.ui', 'window-border-width.ui', 'window-default-size.ref.ui', diff --git a/testsuite/reftests/vbox-with-max-width-chars-label.ref.ui b/testsuite/reftests/vbox-with-max-width-chars-label.ref.ui new file mode 100644 index 0000000000..aa732c608d --- /dev/null +++ b/testsuite/reftests/vbox-with-max-width-chars-label.ref.ui @@ -0,0 +1,18 @@ + + + + 0 + + + horizontal + + + Hello World + 1 + 1 + + + + + + diff --git a/testsuite/reftests/vbox-with-max-width-chars-label.ui b/testsuite/reftests/vbox-with-max-width-chars-label.ui new file mode 100644 index 0000000000..3a7d52e4a4 --- /dev/null +++ b/testsuite/reftests/vbox-with-max-width-chars-label.ui @@ -0,0 +1,18 @@ + + + + 0 + + + vertical + + + Hello World + 1 + 1 + + + + + +