aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--widgets/misc/ChangeLog5
-rw-r--r--widgets/misc/e-clipped-label.c159
-rw-r--r--widgets/misc/e-clipped-label.h11
3 files changed, 105 insertions, 70 deletions
diff --git a/widgets/misc/ChangeLog b/widgets/misc/ChangeLog
index ec3aac924c..de287fd8de 100644
--- a/widgets/misc/ChangeLog
+++ b/widgets/misc/ChangeLog
@@ -1,3 +1,8 @@
+2002-12-09 Chris Toshok <toshok@ximian.com>
+
+ * e-clipped-label.[ch]: rework this to be faster and deal more
+ correctly with the ellipsis.
+
2002-12-03 Not Zed <NotZed@Ximian.com>
* e-search-bar.c (impl_dispose): dispose can be run multiple times
diff --git a/widgets/misc/e-clipped-label.c b/widgets/misc/e-clipped-label.c
index cb0c5ba478..e650b4ee96 100644
--- a/widgets/misc/e-clipped-label.c
+++ b/widgets/misc/e-clipped-label.c
@@ -51,9 +51,10 @@ static void e_clipped_label_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gint e_clipped_label_expose (GtkWidget *widget,
GdkEventExpose *event);
-static void e_clipped_label_recalc_chars_displayed (EClippedLabel *label, PangoLayout *layout);
+static void e_clipped_label_recalc_chars_displayed (EClippedLabel *label);
static void e_clipped_label_finalize (GObject *object);
+static void build_layout (EClippedLabel *label, const char *text);
static GtkMiscClass *parent_class;
@@ -133,39 +134,45 @@ GtkWidget *
e_clipped_label_new (const gchar *text)
{
GtkWidget *label;
+ EClippedLabel *clipped;
label = GTK_WIDGET (gtk_type_new (e_clipped_label_get_type ()));
+ clipped = E_CLIPPED_LABEL (label);
+
+ build_layout (clipped, e_clipped_label_ellipsis);
+ pango_layout_get_pixel_size (clipped->layout, &clipped->ellipsis_width, NULL);
+
if (text && *text)
- e_clipped_label_set_text (E_CLIPPED_LABEL (label), text);
+ e_clipped_label_set_text (clipped, text);
return label;
}
-static PangoLayout*
-build_layout (GtkWidget *widget, char *text)
+static void
+build_layout (EClippedLabel *label, const char *text)
{
- PangoLayout *layout;
-
- layout = gtk_widget_create_pango_layout (widget, text);
-
+ if (!label->layout) {
+ label->layout = gtk_widget_create_pango_layout (GTK_WIDGET (label), text);
#ifdef FROB_FONT_DESC
- {
- /* this makes the font used a little bigger than the
- default style for this widget, as well as makes it
- bold... */
- GtkStyle *style = gtk_widget_get_style (widget);
- PangoFontDescription *desc = pango_font_description_copy (style->font_desc);
- pango_font_description_set_size (desc,
- pango_font_description_get_size (desc) * 1.2);
+ {
+ /* this makes the font used a little bigger than the
+ default style for this widget, as well as makes it
+ bold... */
+ GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (label));
+ PangoFontDescription *desc = pango_font_description_copy (style->font_desc);
+ pango_font_description_set_size (desc,
+ pango_font_description_get_size (desc) * 1.2);
- pango_font_description_set_weight (desc, PANGO_WEIGHT_BOLD);
- pango_layout_set_font_description (layout, desc);
- pango_font_description_free (desc);
- }
+ pango_font_description_set_weight (desc, PANGO_WEIGHT_BOLD);
+ pango_layout_set_font_description (layout, desc);
+ pango_font_description_free (desc);
+ }
#endif
-
- return layout;
+ }
+ else {
+ pango_layout_set_text (label->layout, text, -1);
+ }
}
static void
@@ -174,21 +181,18 @@ e_clipped_label_size_request (GtkWidget *widget,
{
EClippedLabel *label;
GdkFont *font;
- PangoLayout *layout;
int height;
+ int width;
g_return_if_fail (E_IS_CLIPPED_LABEL (widget));
g_return_if_fail (requisition != NULL);
label = E_CLIPPED_LABEL (widget);
- layout = build_layout (widget, label->label);
- pango_layout_get_pixel_size (layout, NULL, &height);
+ pango_layout_get_pixel_size (label->layout, &width, &height);
requisition->width = 0;
requisition->height = height + 2 * GTK_MISC (widget)->ypad;
-
- g_object_unref (layout);
}
@@ -215,7 +219,6 @@ e_clipped_label_expose (GtkWidget *widget,
GtkMisc *misc;
gint x, y;
gchar *tmp_str, tmp_ch;
- PangoLayout *layout;
PangoRectangle rect;
g_return_val_if_fail (E_IS_CLIPPED_LABEL (widget), FALSE);
@@ -229,13 +232,9 @@ e_clipped_label_expose (GtkWidget *widget,
|| !label->label || (*label->label == '\0'))
return TRUE;
- layout = build_layout (widget, label->label);
-
/* Recalculate the number of characters displayed, if necessary. */
if (label->chars_displayed == E_CLIPPED_LABEL_NEED_RECALC)
- e_clipped_label_recalc_chars_displayed (label, layout);
-
- pango_layout_set_text (layout, label->label, strlen (label->label));
+ e_clipped_label_recalc_chars_displayed (label);
/*
* GC Clipping
@@ -245,12 +244,7 @@ e_clipped_label_expose (GtkWidget *widget,
gdk_gc_set_clip_rectangle (widget->style->fg_gc[widget->state],
&event->area);
- pango_layout_get_pixel_extents (layout, &rect, NULL);
-
- y = floor (widget->allocation.y + (gint)misc->ypad
- + (((gint)widget->allocation.height - 2 * (gint)misc->ypad
- + (gint)PANGO_ASCENT (rect) - PANGO_DESCENT(rect))
- * misc->yalign) + 0.5);
+ pango_layout_get_pixel_extents (label->layout, &rect, NULL);
if (label->chars_displayed == E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL) {
x = floor (widget->allocation.x + (gint)misc->xpad
@@ -259,33 +253,38 @@ e_clipped_label_expose (GtkWidget *widget,
* misc->xalign) + 0.5);
gdk_draw_layout (widget->window, widget->style->fg_gc[widget->state],
- x, y, layout);
+ x, label->label_y, label->layout);
} else {
int layout_width;
x = widget->allocation.x + (gint)misc->xpad;
- pango_layout_set_text (layout, label->label, label->chars_displayed);
+ /* trim the layout to the number of characters we're displaying */
+ pango_layout_set_text (label->layout, label->label, label->chars_displayed);
+ /* draw it */
gdk_draw_layout (widget->window, widget->style->fg_gc[widget->state],
- x, y, layout);
+ x, label->label_y, label->layout);
- pango_layout_get_pixel_size (layout, &layout_width, NULL);
+ pango_layout_get_pixel_size (label->layout, &layout_width, NULL);
+ /* offset the X position for the ellipsis */
x = widget->allocation.x + (gint)misc->xpad
+ label->ellipsis_x;
- pango_layout_set_text (layout, e_clipped_label_ellipsis, strlen (e_clipped_label_ellipsis));
+ /* then draw the ellipsis */
+ pango_layout_set_text (label->layout, e_clipped_label_ellipsis, strlen (e_clipped_label_ellipsis));
gdk_draw_layout (widget->window, widget->style->fg_gc[widget->state],
- x, y, layout);
+ x, label->label_y, label->layout);
+
+ /* then reset the layout to our original label text */
+ pango_layout_set_text (label->layout, label->label, -1);
}
gdk_gc_set_clip_mask (widget->style->white_gc, NULL);
gdk_gc_set_clip_mask (widget->style->fg_gc[widget->state], NULL);
- g_object_unref (layout);
-
return TRUE;
}
@@ -301,6 +300,8 @@ e_clipped_label_finalize (GObject *object)
g_free (label->label);
+ g_object_unref (label->layout);
+
(* G_OBJECT_CLASS (parent_class)->finalize) (object);
}
@@ -346,6 +347,8 @@ e_clipped_label_set_text (EClippedLabel *label,
if (text)
label->label = g_strdup (text);
+ build_layout (label, text);
+
/* Reset the number of characters displayed, so it is
recalculated when needed. */
label->chars_displayed = E_CLIPPED_LABEL_NEED_RECALC;
@@ -358,10 +361,16 @@ e_clipped_label_set_text (EClippedLabel *label,
static void
-e_clipped_label_recalc_chars_displayed (EClippedLabel *label, PangoLayout *layout)
+e_clipped_label_recalc_chars_displayed (EClippedLabel *label)
{
gint max_width, width, ch, last_width, ellipsis_width;
-
+ GSList *lines;
+ PangoLayoutLine *line;
+ int index;
+ PangoRectangle rect;
+ GtkWidget *widget = GTK_WIDGET (label);
+ GtkMisc *misc = GTK_MISC (label);
+
max_width = GTK_WIDGET (label)->allocation.width
- 2 * GTK_MISC (label)->xpad;
@@ -371,40 +380,50 @@ e_clipped_label_recalc_chars_displayed (EClippedLabel *label, PangoLayout *layou
}
/* See if the entire label fits in the allocated width. */
- pango_layout_get_pixel_size (layout, &label->label_width, NULL);
+ pango_layout_set_text (label->layout, label->label, -1);
+
+ pango_layout_get_pixel_extents (label->layout, &rect, NULL);
+
+ label->label_y = floor (widget->allocation.y + (gint)misc->ypad
+ + (((gint)widget->allocation.height - 2 * (gint)misc->ypad
+ + (gint)PANGO_ASCENT (rect) - PANGO_DESCENT(rect))
+ * misc->yalign) + 0.5);
+
+ pango_layout_get_pixel_size (label->layout, &label->label_width, NULL);
if (label->label_width <= max_width) {
label->chars_displayed = E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL;
return;
}
- /* Calculate the width of the ellipsis string. */
- pango_layout_set_text (layout, e_clipped_label_ellipsis, strlen (e_clipped_label_ellipsis));
- pango_layout_get_pixel_size (layout, &ellipsis_width, NULL);
- max_width -= ellipsis_width;
-
if (max_width <= 0) {
label->chars_displayed = 0;
label->ellipsis_x = 0;
return;
}
- /* Step through the label, adding on the widths of the
- characters, until we can't fit any more in. */
- width = last_width = 0;
- for (ch = 0; ch < strlen (label->label); ch++) {
- pango_layout_set_text (layout, label->label, ch);
- pango_layout_get_pixel_size (layout, &width, NULL);
-
- if (width > max_width) {
- label->chars_displayed = ch;
- label->ellipsis_x = last_width;
- return;
- }
+ max_width -= label->ellipsis_width;
- last_width = width;
+ lines = pango_layout_get_lines (label->layout);
+ line = lines->data;
+
+ if (!pango_layout_line_x_to_index (line,
+ max_width * PANGO_SCALE,
+ &index,
+ NULL)) {
+ g_warning ("pango_layout_line_x_to_index returned false");
+ return;
}
- g_warning ("Clipped label width not exceeded as expected");
- label->chars_displayed = E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL;
+#if 0
+ g_slist_foreach (lines, (GFunc)pango_layout_line_unref, NULL);
+ g_slist_free (lines);
+#endif
+
+ label->chars_displayed = index;
+
+ pango_layout_set_text (label->layout, label->label, label->chars_displayed);
+ pango_layout_get_pixel_size (label->layout, &width, NULL);
+
+ label->ellipsis_x = width;
}
diff --git a/widgets/misc/e-clipped-label.h b/widgets/misc/e-clipped-label.h
index 6649fee366..ab0d741ebf 100644
--- a/widgets/misc/e-clipped-label.h
+++ b/widgets/misc/e-clipped-label.h
@@ -51,9 +51,17 @@ struct _EClippedLabel
gchar *label;
+ /* Our PangoLayout */
+ PangoLayout *layout;
+
/* This is the width of the entire label string, in pixels. */
gint label_width;
+ /* This is the label's y coord. we store it here so it won't
+ change as the label's baseline changes (for example if we
+ ellide the 'y' from 'Summary' the baseline drops) */
+ gint label_y;
+
/* This is the number of characters we can fit in, or
E_CLIPPED_LABEL_NEED_RECALC if it needs to be recalculated, or
E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL to show the entire label. */
@@ -62,6 +70,9 @@ struct _EClippedLabel
/* This is the x position to display the ellipsis string, e.g. '...',
relative to the start of the label. */
gint ellipsis_x;
+
+ /* This is the width of the ellipsis, in pixels */
+ gint ellipsis_width;
};
struct _EClippedLabelClass