summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTristan Van Berkom <tristan.van.berkom@gmail.com>2010-04-18 18:13:56 -0400
committerTristan Van Berkom <tristan.van.berkom@gmail.com>2010-04-18 18:13:56 -0400
commit3cbd9e9313061945d9868a8e3a01de51be07bfa1 (patch)
treeb71830fa30d3d2636077a24f032792fe04a7e996
parentda318411dca2e47d3327d10dac0408bf40a4abb0 (diff)
downloadgtk+-3cbd9e9313061945d9868a8e3a01de51be07bfa1.tar.gz
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.
-rw-r--r--gtk/gtklabel.c141
1 files changed, 88 insertions, 53 deletions
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 911b790e2e..31eb186874 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -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;
+
+ 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;
- get_label_char_width (label, &dummy, &priv->wrap_width);
- priv->wrap_width = PANGO_PIXELS (priv->wrap_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);