rework this to be faster and deal more correctly with the ellipsis.
2002-12-09 Chris Toshok <toshok@ximian.com> * e-clipped-label.[ch]: rework this to be faster and deal more correctly with the ellipsis. svn path=/trunk/; revision=19076
This commit is contained in:

committed by
Chris Toshok

parent
d2971bf645
commit
bdd9cae5e9
@ -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
|
||||
|
@ -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);
|
||||
max_width -= label->ellipsis_width;
|
||||
|
||||
if (width > max_width) {
|
||||
label->chars_displayed = ch;
|
||||
label->ellipsis_x = last_width;
|
||||
return;
|
||||
}
|
||||
lines = pango_layout_get_lines (label->layout);
|
||||
line = lines->data;
|
||||
|
||||
last_width = width;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user