Further fixed base outputs of GtkLabel desired geometries.

Now (when wrapping), if no "width-chars" was specified for a minimum
width, default to the width guessed by gtk_label_ensure_layout(), small
specified widths will otherwise result in very large height requests.
This commit is contained in:
Tristan Van Berkom 2010-04-18 18:13:56 -04:00
parent da318411dc
commit 3cbd9e9313

View File

@ -239,7 +239,7 @@ static void gtk_label_ensure_select_info (GtkLabel *label);
static void gtk_label_clear_select_info (GtkLabel *label);
static void gtk_label_update_cursor (GtkLabel *label);
static void gtk_label_clear_layout (GtkLabel *label);
static void gtk_label_ensure_layout (GtkLabel *label);
static void gtk_label_ensure_layout (GtkLabel *label, gboolean guess_wrap_width);
static void gtk_label_invalidate_wrap_width (GtkLabel *label);
static void gtk_label_select_region_index (GtkLabel *label,
gint anchor_index,
@ -2934,9 +2934,9 @@ gtk_label_clear_layout (GtkLabel *label)
static void
get_label_char_width (GtkLabel *label,
gint *minimum,
gint *natural)
get_label_width (GtkLabel *label,
gint *minimum,
gint *natural)
{
GtkWidgetAuxInfo *aux_info;
GtkLabelPrivate *priv;
@ -2944,7 +2944,7 @@ get_label_char_width (GtkLabel *label,
PangoContext *context;
PangoFontMetrics *metrics;
PangoRectangle rect;
gint char_width, digit_width, char_pixels, text_width, ellipsize_chars;
gint char_width, digit_width, char_pixels, text_width, ellipsize_chars, guess_width;
priv = GTK_LABEL_GET_PRIVATE (label);
aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (label), FALSE);
@ -2959,10 +2959,15 @@ get_label_char_width (GtkLabel *label,
char_pixels = MAX (char_width, digit_width);
pango_font_metrics_unref (metrics);
/* Fetch the length of the complete unwrapped text */
pango_layout_set_width (layout, -1);
pango_layout_get_extents (layout, NULL, &rect);
text_width = rect.width;
/* Fetch the width that was guessed by gtk_label_ensure_layout() */
pango_layout_get_extents (label->layout, NULL, &rect);
guess_width = rect.width;
/* enforce minimum width for ellipsized labels at ~3 chars */
if (label->ellipsize)
ellipsize_chars = 3;
@ -2976,14 +2981,30 @@ get_label_char_width (GtkLabel *label,
* "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 (label->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.
*
* In *any* case the minimum width is completely overridden if an explicit width
* request was provided.
*/
/* Minimums/Naturals can differ for labels who resize dynamically */
if (label->ellipsize || label->wrap)
{
rect.width = char_pixels * MAX (priv->width_chars, ellipsize_chars);
*minimum = char_pixels * MAX (priv->width_chars, ellipsize_chars);
*minimum = rect.width;
/* Default to the minimum width regularly guessed by GTK+ if no minimum
* width was specified, only allow unwrapping of these labels.
*
* Note that when specifying a small width_chars for a long text;
* an accordingly large size will be required for the label height.
*/
if (label->wrap && priv->width_chars <= 0)
*minimum = guess_width;
if (priv->max_width_chars < 0)
{
@ -2999,11 +3020,9 @@ get_label_char_width (GtkLabel *label,
* (note that we dont want to limit the minimum width for wrapping text).
*/
if (label->ellipsize)
{
*minimum = MIN (text_width, max_width);
}
*minimum = MIN (text_width, max_width);
*natural = MAX (rect.width, max_width);
*natural = MAX (*minimum, max_width);
}
}
else
@ -3044,10 +3063,36 @@ get_label_wrap_width (GtkLabel *label)
{
if (priv->width_chars > 0 || priv->max_width_chars > 0)
{
gint dummy;
PangoLayout *layout;
PangoContext *context;
PangoFontMetrics *metrics;
PangoRectangle rect;
gint char_width, digit_width, char_pixels, text_width;
get_label_char_width (label, &dummy, &priv->wrap_width);
priv->wrap_width = PANGO_PIXELS (priv->wrap_width);
layout = pango_layout_copy (label->layout);
context = pango_layout_get_context (layout);
metrics = pango_context_get_metrics (context, GTK_WIDGET (label)->style->font_desc,
pango_context_get_language (context));
char_width = pango_font_metrics_get_approximate_char_width (metrics);
digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
char_pixels = MAX (char_width, digit_width);
pango_font_metrics_unref (metrics);
pango_layout_set_width (layout, -1);
pango_layout_get_extents (layout, NULL, &rect);
g_object_unref (layout);
text_width = rect.width;
if (priv->max_width_chars < 0)
{
priv->wrap_width = PANGO_PIXELS (MAX (text_width, char_pixels * priv->width_chars));
}
else
{
priv->wrap_width = PANGO_PIXELS (MIN (text_width, char_pixels * priv->max_width_chars));
}
}
else
{
@ -3064,7 +3109,7 @@ get_label_wrap_width (GtkLabel *label)
}
static void
gtk_label_ensure_layout (GtkLabel *label)
gtk_label_ensure_layout (GtkLabel *label, gboolean guess_wrap_width)
{
GtkWidget *widget;
PangoRectangle logical_rect;
@ -3142,7 +3187,8 @@ gtk_label_ensure_layout (GtkLabel *label)
if (aux_info && aux_info->width > 0)
pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
else if (widget->allocation.width > 1)
else if (guess_wrap_width == FALSE &&
widget->allocation.width > 1)
{
width = widget->allocation.width - label->misc.xpad * 2;
@ -3256,7 +3302,7 @@ get_size_for_allocation (GtkLabel *label,
gint aux_size;
gint text_height;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
layout = pango_layout_copy (label->layout);
if (aux_info)
@ -3295,19 +3341,6 @@ gtk_label_get_desired_size (GtkExtendedLayout *layout,
PangoRectangle required_rect;
PangoRectangle natural_rect;
/*
* If word wrapping is on, then the height requisition can depend
* on:
*
* - Any width set on the widget via gtk_widget_set_size_request().
* - The padding of the widget (xpad, set by gtk_misc_set_padding)
*
* Instead of trying to detect changes to these quantities, if we
* are wrapping, we just rewrap for each size request. Since
* size requisitions are cached by the GTK+ core, this is not
* expensive.
*/
/* "width-chars" Hard-coded minimum width:
* - minimum size should be MAX (width-chars, strlen ("..."));
* - natural size should be MAX (width-chars, strlen (label->text));
@ -3323,19 +3356,19 @@ gtk_label_get_desired_size (GtkExtendedLayout *layout,
/* Refresh layout if needed */
if (label->wrap)
gtk_label_clear_layout (label);
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, TRUE);
/* Start off with the pixel extents of the rendered layout */
pango_layout_get_extents (label->layout, NULL, &required_rect);
required_rect.x = required_rect.y = 0;
natural_rect = required_rect;
if (label->single_line_mode)
if (label->single_line_mode || label->wrap)
required_rect.height = get_single_line_height (GTK_WIDGET (label), label->layout);
natural_rect = required_rect;
/* Calculate text width itself based on GtkLabel property rules */
get_label_char_width (label, &required_rect.width, &natural_rect.width);
get_label_width (label, &required_rect.width, &natural_rect.width);
/* Now that we have minimum and natural sizes in pango extents, apply a possible transform */
if (label->have_transform)
@ -3370,7 +3403,6 @@ gtk_label_get_desired_size (GtkExtendedLayout *layout,
}
}
required_rect.width = PANGO_PIXELS_CEIL (required_rect.width);
required_rect.height = PANGO_PIXELS_CEIL (required_rect.height);
@ -3384,14 +3416,17 @@ gtk_label_get_desired_size (GtkExtendedLayout *layout,
}
else
{
/* Just return something contextual to width calculation when queried for the height. */
if (!label->have_transform)
/* When wrapping, just return a height contextual to the minimum width
* (minimum widths can only be specified by explicitly setting width-chars).
*/
if (label->wrap && !label->have_transform)
get_size_for_allocation (label, GTK_ORIENTATION_HORIZONTAL,
(natural_rect.width + label->misc.xpad * 2), minimum_size, natural_size);
(required_rect.width + label->misc.xpad * 2), minimum_size, natural_size);
else
{
/* If there is no wrapping, the height is static */
*minimum_size = required_rect.height + label->misc.ypad * 2;
*natural_size = natural_rect.height + label->misc.ypad * 2;
*natural_size = *minimum_size;
}
}
}
@ -3469,7 +3504,7 @@ gtk_label_size_allocate (GtkWidget *widget,
if (label->wrap)
gtk_label_clear_layout (label);
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
if (label->ellipsize)
{
@ -3748,7 +3783,7 @@ get_cursor_direction (GtkLabel *label)
g_assert (label->select_info);
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
for (l = pango_layout_get_lines_readonly (label->layout); l; l = l->next)
{
@ -3793,7 +3828,7 @@ gtk_label_draw_cursor (GtkLabel *label, gint xoffset, gint yoffset)
keymap_direction = gdk_keymap_get_direction (gdk_keymap_get_for_display (gtk_widget_get_display (widget)));
cursor_direction = get_cursor_direction (label);
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
pango_layout_get_cursor_pos (label->layout, label->select_info->selection_end,
&strong_pos, &weak_pos);
@ -3877,7 +3912,7 @@ gtk_label_expose (GtkWidget *widget,
GtkLabelSelectionInfo *info = label->select_info;
gint x, y;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
if (gtk_widget_get_visible (widget) && gtk_widget_get_mapped (widget) &&
label->text && (*label->text != '\0'))
@ -4290,7 +4325,7 @@ get_layout_index (GtkLabel *label,
*index = 0;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
window_to_layout_coords (label, &x, &y);
@ -5334,7 +5369,7 @@ gtk_label_get_layout (GtkLabel *label)
{
g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
return label->layout;
}
@ -5361,7 +5396,7 @@ gtk_label_get_layout_offsets (GtkLabel *label,
{
g_return_if_fail (GTK_IS_LABEL (label));
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
get_layout_location (label, x, y);
}
@ -5506,7 +5541,7 @@ get_better_cursor (GtkLabel *label,
"gtk-split-cursor", &split_cursor,
NULL);
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
pango_layout_get_cursor_pos (label->layout, index,
&strong_pos, &weak_pos);
@ -5546,7 +5581,7 @@ gtk_label_move_logically (GtkLabel *label,
gint n_attrs;
gint length;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
length = g_utf8_strlen (label->text, -1);
@ -5590,7 +5625,7 @@ gtk_label_move_visually (GtkLabel *label,
gboolean split_cursor;
gboolean strong;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
"gtk-split-cursor", &split_cursor,
@ -5643,7 +5678,7 @@ gtk_label_move_forward_word (GtkLabel *label,
PangoLogAttr *log_attrs;
gint n_attrs;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
@ -5671,7 +5706,7 @@ gtk_label_move_backward_word (GtkLabel *label,
PangoLogAttr *log_attrs;
gint n_attrs;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);