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>
|
2002-12-03 Not Zed <NotZed@Ximian.com>
|
||||||
|
|
||||||
* e-search-bar.c (impl_dispose): dispose can be run multiple times
|
* 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);
|
GtkAllocation *allocation);
|
||||||
static gint e_clipped_label_expose (GtkWidget *widget,
|
static gint e_clipped_label_expose (GtkWidget *widget,
|
||||||
GdkEventExpose *event);
|
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 e_clipped_label_finalize (GObject *object);
|
||||||
|
|
||||||
|
static void build_layout (EClippedLabel *label, const char *text);
|
||||||
|
|
||||||
static GtkMiscClass *parent_class;
|
static GtkMiscClass *parent_class;
|
||||||
|
|
||||||
@ -133,28 +134,32 @@ GtkWidget *
|
|||||||
e_clipped_label_new (const gchar *text)
|
e_clipped_label_new (const gchar *text)
|
||||||
{
|
{
|
||||||
GtkWidget *label;
|
GtkWidget *label;
|
||||||
|
EClippedLabel *clipped;
|
||||||
|
|
||||||
label = GTK_WIDGET (gtk_type_new (e_clipped_label_get_type ()));
|
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)
|
if (text && *text)
|
||||||
e_clipped_label_set_text (E_CLIPPED_LABEL (label), text);
|
e_clipped_label_set_text (clipped, text);
|
||||||
|
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PangoLayout*
|
static void
|
||||||
build_layout (GtkWidget *widget, char *text)
|
build_layout (EClippedLabel *label, const char *text)
|
||||||
{
|
{
|
||||||
PangoLayout *layout;
|
if (!label->layout) {
|
||||||
|
label->layout = gtk_widget_create_pango_layout (GTK_WIDGET (label), text);
|
||||||
layout = gtk_widget_create_pango_layout (widget, text);
|
|
||||||
|
|
||||||
#ifdef FROB_FONT_DESC
|
#ifdef FROB_FONT_DESC
|
||||||
{
|
{
|
||||||
/* this makes the font used a little bigger than the
|
/* this makes the font used a little bigger than the
|
||||||
default style for this widget, as well as makes it
|
default style for this widget, as well as makes it
|
||||||
bold... */
|
bold... */
|
||||||
GtkStyle *style = gtk_widget_get_style (widget);
|
GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (label));
|
||||||
PangoFontDescription *desc = pango_font_description_copy (style->font_desc);
|
PangoFontDescription *desc = pango_font_description_copy (style->font_desc);
|
||||||
pango_font_description_set_size (desc,
|
pango_font_description_set_size (desc,
|
||||||
pango_font_description_get_size (desc) * 1.2);
|
pango_font_description_get_size (desc) * 1.2);
|
||||||
@ -164,8 +169,10 @@ build_layout (GtkWidget *widget, char *text)
|
|||||||
pango_font_description_free (desc);
|
pango_font_description_free (desc);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
return layout;
|
else {
|
||||||
|
pango_layout_set_text (label->layout, text, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -174,21 +181,18 @@ e_clipped_label_size_request (GtkWidget *widget,
|
|||||||
{
|
{
|
||||||
EClippedLabel *label;
|
EClippedLabel *label;
|
||||||
GdkFont *font;
|
GdkFont *font;
|
||||||
PangoLayout *layout;
|
|
||||||
int height;
|
int height;
|
||||||
|
int width;
|
||||||
|
|
||||||
g_return_if_fail (E_IS_CLIPPED_LABEL (widget));
|
g_return_if_fail (E_IS_CLIPPED_LABEL (widget));
|
||||||
g_return_if_fail (requisition != NULL);
|
g_return_if_fail (requisition != NULL);
|
||||||
|
|
||||||
label = E_CLIPPED_LABEL (widget);
|
label = E_CLIPPED_LABEL (widget);
|
||||||
|
|
||||||
layout = build_layout (widget, label->label);
|
pango_layout_get_pixel_size (label->layout, &width, &height);
|
||||||
pango_layout_get_pixel_size (layout, NULL, &height);
|
|
||||||
|
|
||||||
requisition->width = 0;
|
requisition->width = 0;
|
||||||
requisition->height = height + 2 * GTK_MISC (widget)->ypad;
|
requisition->height = height + 2 * GTK_MISC (widget)->ypad;
|
||||||
|
|
||||||
g_object_unref (layout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -215,7 +219,6 @@ e_clipped_label_expose (GtkWidget *widget,
|
|||||||
GtkMisc *misc;
|
GtkMisc *misc;
|
||||||
gint x, y;
|
gint x, y;
|
||||||
gchar *tmp_str, tmp_ch;
|
gchar *tmp_str, tmp_ch;
|
||||||
PangoLayout *layout;
|
|
||||||
PangoRectangle rect;
|
PangoRectangle rect;
|
||||||
|
|
||||||
g_return_val_if_fail (E_IS_CLIPPED_LABEL (widget), FALSE);
|
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'))
|
|| !label->label || (*label->label == '\0'))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
layout = build_layout (widget, label->label);
|
|
||||||
|
|
||||||
/* Recalculate the number of characters displayed, if necessary. */
|
/* Recalculate the number of characters displayed, if necessary. */
|
||||||
if (label->chars_displayed == E_CLIPPED_LABEL_NEED_RECALC)
|
if (label->chars_displayed == E_CLIPPED_LABEL_NEED_RECALC)
|
||||||
e_clipped_label_recalc_chars_displayed (label, layout);
|
e_clipped_label_recalc_chars_displayed (label);
|
||||||
|
|
||||||
pango_layout_set_text (layout, label->label, strlen (label->label));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GC Clipping
|
* GC Clipping
|
||||||
@ -245,12 +244,7 @@ e_clipped_label_expose (GtkWidget *widget,
|
|||||||
gdk_gc_set_clip_rectangle (widget->style->fg_gc[widget->state],
|
gdk_gc_set_clip_rectangle (widget->style->fg_gc[widget->state],
|
||||||
&event->area);
|
&event->area);
|
||||||
|
|
||||||
pango_layout_get_pixel_extents (layout, &rect, NULL);
|
pango_layout_get_pixel_extents (label->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);
|
|
||||||
|
|
||||||
if (label->chars_displayed == E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL) {
|
if (label->chars_displayed == E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL) {
|
||||||
x = floor (widget->allocation.x + (gint)misc->xpad
|
x = floor (widget->allocation.x + (gint)misc->xpad
|
||||||
@ -259,33 +253,38 @@ e_clipped_label_expose (GtkWidget *widget,
|
|||||||
* misc->xalign) + 0.5);
|
* misc->xalign) + 0.5);
|
||||||
|
|
||||||
gdk_draw_layout (widget->window, widget->style->fg_gc[widget->state],
|
gdk_draw_layout (widget->window, widget->style->fg_gc[widget->state],
|
||||||
x, y, layout);
|
x, label->label_y, label->layout);
|
||||||
} else {
|
} else {
|
||||||
int layout_width;
|
int layout_width;
|
||||||
|
|
||||||
x = widget->allocation.x + (gint)misc->xpad;
|
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],
|
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
|
x = widget->allocation.x + (gint)misc->xpad
|
||||||
+ label->ellipsis_x;
|
+ 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],
|
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->white_gc, NULL);
|
||||||
gdk_gc_set_clip_mask (widget->style->fg_gc[widget->state], NULL);
|
gdk_gc_set_clip_mask (widget->style->fg_gc[widget->state], NULL);
|
||||||
|
|
||||||
g_object_unref (layout);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,6 +300,8 @@ e_clipped_label_finalize (GObject *object)
|
|||||||
|
|
||||||
g_free (label->label);
|
g_free (label->label);
|
||||||
|
|
||||||
|
g_object_unref (label->layout);
|
||||||
|
|
||||||
(* G_OBJECT_CLASS (parent_class)->finalize) (object);
|
(* G_OBJECT_CLASS (parent_class)->finalize) (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,6 +347,8 @@ e_clipped_label_set_text (EClippedLabel *label,
|
|||||||
if (text)
|
if (text)
|
||||||
label->label = g_strdup (text);
|
label->label = g_strdup (text);
|
||||||
|
|
||||||
|
build_layout (label, text);
|
||||||
|
|
||||||
/* Reset the number of characters displayed, so it is
|
/* Reset the number of characters displayed, so it is
|
||||||
recalculated when needed. */
|
recalculated when needed. */
|
||||||
label->chars_displayed = E_CLIPPED_LABEL_NEED_RECALC;
|
label->chars_displayed = E_CLIPPED_LABEL_NEED_RECALC;
|
||||||
@ -358,9 +361,15 @@ e_clipped_label_set_text (EClippedLabel *label,
|
|||||||
|
|
||||||
|
|
||||||
static void
|
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;
|
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
|
max_width = GTK_WIDGET (label)->allocation.width
|
||||||
- 2 * GTK_MISC (label)->xpad;
|
- 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. */
|
/* 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) {
|
if (label->label_width <= max_width) {
|
||||||
label->chars_displayed = E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL;
|
label->chars_displayed = E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL;
|
||||||
return;
|
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) {
|
if (max_width <= 0) {
|
||||||
label->chars_displayed = 0;
|
label->chars_displayed = 0;
|
||||||
label->ellipsis_x = 0;
|
label->ellipsis_x = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step through the label, adding on the widths of the
|
max_width -= label->ellipsis_width;
|
||||||
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) {
|
lines = pango_layout_get_lines (label->layout);
|
||||||
label->chars_displayed = ch;
|
line = lines->data;
|
||||||
label->ellipsis_x = last_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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_width = width;
|
#if 0
|
||||||
}
|
g_slist_foreach (lines, (GFunc)pango_layout_line_unref, NULL);
|
||||||
|
g_slist_free (lines);
|
||||||
|
#endif
|
||||||
|
|
||||||
g_warning ("Clipped label width not exceeded as expected");
|
label->chars_displayed = index;
|
||||||
label->chars_displayed = E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL;
|
|
||||||
|
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;
|
gchar *label;
|
||||||
|
|
||||||
|
/* Our PangoLayout */
|
||||||
|
PangoLayout *layout;
|
||||||
|
|
||||||
/* This is the width of the entire label string, in pixels. */
|
/* This is the width of the entire label string, in pixels. */
|
||||||
gint label_width;
|
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
|
/* 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_NEED_RECALC if it needs to be recalculated, or
|
||||||
E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL to show the entire label. */
|
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. '...',
|
/* This is the x position to display the ellipsis string, e.g. '...',
|
||||||
relative to the start of the label. */
|
relative to the start of the label. */
|
||||||
gint ellipsis_x;
|
gint ellipsis_x;
|
||||||
|
|
||||||
|
/* This is the width of the ellipsis, in pixels */
|
||||||
|
gint ellipsis_width;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _EClippedLabelClass
|
struct _EClippedLabelClass
|
||||||
|
Reference in New Issue
Block a user