diff options
author | Federico Mena Quintero <federico@helixcode.com> | 2000-12-03 01:35:22 +0800 |
---|---|---|
committer | Federico Mena Quintero <federico@src.gnome.org> | 2000-12-03 01:35:22 +0800 |
commit | f70c74f37110d1bcb23227c720965a058cabf61c (patch) | |
tree | 0cd81472b7a6e231f6160f6beece3d6c3a61bce5 /widgets | |
parent | 4cffa30b1b778f3fa2b7e597e7bae589fc271a4e (diff) | |
download | gsoc2013-evolution-f70c74f37110d1bcb23227c720965a058cabf61c.tar.gz gsoc2013-evolution-f70c74f37110d1bcb23227c720965a058cabf61c.tar.zst gsoc2013-evolution-f70c74f37110d1bcb23227c720965a058cabf61c.zip |
Federico gets into pixel-perfect neurosis. Xmag is my best friend.
2000-12-01 Federico Mena Quintero <federico@helixcode.com>
Federico gets into pixel-perfect neurosis. Xmag is my best friend.
* e-table-item.c (eti_draw): Set the focus_gc stipple origin to
match the upper-left corner of the focus rectangle. This way
focusing will look consistent even among rows/columns with odd
pixel sizes. Also, make the focus rectangle span the whole cell;
there was one blank pixel column to the left of the rectangle.
* e-table-header-utils.c: New file with utilities for drawing
header buttons. This is so that ETableHeaderItem and
ETableFieldChooserItem can share the same code.
(e_table_header_compute_height): New function to compute the
height of a column button.
(make_composite_pixmap): New function to composite a pixbuf
against a solid background and make a pixmap out of the result.
This does some ultra-fancy fading-out of the original pixbuf if
the destination area is smaller than the source.
(compute_elision_length): New function to compute the elision
length in O(n log n) instead of O(n^2), for n = strlen (str).
(e_table_header_draw_button): New function to draw a header
button.
(e_table_draw_elided_string): New function to draw a string elided
to a maximum width.
* e-table-defines.h (HEADER_PADDING): Made the default padding be
1; now a header button's height is
content_height + 2 * (HEADER_PADDING + style->ythickness). This
is the correct way to measure button heights.
* e-table-field-chooser-item.c (etfci_find_button): Use
e_table_header_compute_height().
(etfci_reflow): Likewise.
(etfci_draw): Use e_table_header_draw_button().
(etfci_start_drag): Likewise.
(etfci_draw): Likewise.
(etfci_start_drag): Likewise.
(etfci_button_height): Removed function.
(draw_button): Removed function.
* e-table-header-item.c (draw_button): Removed function.
(e_table_header_item_get_height): Use e_table_header_compute_height().
(ethi_draw): e_table_header_draw_button().
(ethi_start_drag): Likewise.
(make_shaped_window_from_xpm): Fixed misspelling in function name.
(draw_button): Removed function.
* Makefile.am: Added e-table-header-utils.[ch].
svn path=/trunk/; revision=6766
Diffstat (limited to 'widgets')
-rw-r--r-- | widgets/table/e-table-defines.h | 4 | ||||
-rw-r--r-- | widgets/table/e-table-field-chooser-item.c | 153 | ||||
-rw-r--r-- | widgets/table/e-table-header-item.c | 197 | ||||
-rw-r--r-- | widgets/table/e-table-header-utils.c | 419 | ||||
-rw-r--r-- | widgets/table/e-table-header-utils.h | 43 | ||||
-rw-r--r-- | widgets/table/e-table-item.c | 3 |
6 files changed, 546 insertions, 273 deletions
diff --git a/widgets/table/e-table-defines.h b/widgets/table/e-table-defines.h index ba87a8e560..a1232911a7 100644 --- a/widgets/table/e-table-defines.h +++ b/widgets/table/e-table-defines.h @@ -5,8 +5,8 @@ #define BUTTON_PADDING 2 #define GROUP_INDENT (BUTTON_HEIGHT + (BUTTON_PADDING * 2)) -/* Padding above and below of the string in the header display */ -#define HEADER_PADDING 2 +/* Padding around the contents of a header button */ +#define HEADER_PADDING 1 #define MIN_ARROW_SIZE 10 diff --git a/widgets/table/e-table-field-chooser-item.c b/widgets/table/e-table-field-chooser-item.c index 4bb0653fef..47a7b01195 100644 --- a/widgets/table/e-table-field-chooser-item.c +++ b/widgets/table/e-table-field-chooser-item.c @@ -22,6 +22,7 @@ #include "e-table-header.h" #include "e-table-col-dnd.h" #include "e-table-defines.h" +#include "e-table-header-utils.h" #include "e-table-field-chooser-item.h" @@ -62,39 +63,22 @@ etfci_destroy (GtkObject *object){ (*GTK_OBJECT_CLASS (etfci_parent_class)->destroy) (object); } -static double -etfci_button_height (ETableFieldChooserItem *etfci, gint col) -{ - ETableCol *ecol = e_table_header_get_column (etfci->full_header, col); - double height; - - if (etfci->font) { - height = etfci->font->ascent + etfci->font->descent + HEADER_PADDING + 1; - } else { - /* FIXME: Default??? */ - height = 16; - } - - if (ecol->is_pixbuf) { - height = MAX (height, gdk_pixbuf_get_height (ecol->pixbuf) + HEADER_PADDING + 1); - } - - if (height < MIN_ARROW_SIZE + 1 + HEADER_PADDING) - height = MIN_ARROW_SIZE + 1 + HEADER_PADDING; - - return height; -} - static gint etfci_find_button (ETableFieldChooserItem *etfci, double loc) { int i; int count; double height = 0; - + GtkStyle *style; + + style = GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas)->style; + count = e_table_header_count(etfci->full_header); for (i = 0; i < count; i++) { - height += etfci_button_height(etfci, i); + ETableCol *ecol; + + ecol = e_table_header_get_column (etfci->full_header, i); + height += e_table_header_compute_height (ecol, style, etfci->font); if (height > loc) return i; } @@ -109,12 +93,18 @@ etfci_reflow (GnomeCanvasItem *item, gint flags) int i; int count; double height = 0; + GtkStyle *style; + + style = GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas)->style; old_height = etfci->height; count = e_table_header_count(etfci->full_header); for (i = 0; i < count; i++) { - height += etfci_button_height(etfci, i); + ETableCol *ecol; + + ecol = e_table_header_get_column (etfci->full_header, i); + height += e_table_header_compute_height (ecol, style, etfci->font); } etfci->height = height; @@ -348,77 +338,6 @@ etfci_unrealize (GnomeCanvasItem *item) } static void -draw_button (ETableFieldChooserItem *etfci, int col, - GdkDrawable *drawable, GtkStyle *style, - int x, int y, int width, int height) -{ - int xtra; - GdkRectangle area; - ETableCol *ecol = e_table_header_get_column(etfci->full_header, col); - double button_height = etfci_button_height(etfci, col); - GdkRectangle clip; - - GtkWidget *widget = GTK_WIDGET(GNOME_CANVAS_ITEM(etfci)->canvas); - - gdk_window_clear_area (drawable, x, y, width, height); - - area.x = x; - area.y = y; - area.width = width; - area.height = height; - - gtk_paint_box (style, drawable, - GTK_STATE_NORMAL, GTK_SHADOW_OUT, - &area, widget, "button", - x, y, width, height); - - clip.x = x + HEADER_PADDING / 2; - clip.y = y + HEADER_PADDING / 2; - clip.width = width - HEADER_PADDING; - clip.height = button_height - HEADER_PADDING; - - if (ecol->is_pixbuf){ - xtra = (clip.width - gdk_pixbuf_get_width (ecol->pixbuf))/2; - if (xtra < 0) - xtra = 0; - - xtra += HEADER_PADDING / 2; - - gdk_pixbuf_render_to_drawable_alpha (ecol->pixbuf, - drawable, - 0, 0, - x + xtra, y + (clip.height - gdk_pixbuf_get_height (ecol->pixbuf)) / 2, - gdk_pixbuf_get_width (ecol->pixbuf), - gdk_pixbuf_get_height(ecol->pixbuf), - GDK_PIXBUF_ALPHA_FULL, 128, - GDK_RGB_DITHER_NORMAL, - 0, 0); - } else { - int y_xtra; - GdkGC *gc = style->text_gc[GTK_STATE_NORMAL]; - - gdk_gc_set_clip_rectangle (gc, &clip); - - /* Center the thing */ - xtra = (clip.width - gdk_string_measure (etfci->font, ecol->text))/2; - - /* Skip over border */ - if (xtra < 0) - xtra = 0; - - xtra += HEADER_PADDING / 2; - - y_xtra = (button_height + etfci->font->ascent - etfci->font->descent) / 2; - - gdk_draw_text ( - drawable, etfci->font, - gc, x + xtra, y + y_xtra, - ecol->text, strlen (ecol->text)); - gdk_gc_set_clip_rectangle (gc, NULL); - } -} - -static void etfci_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) { ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item); @@ -426,20 +345,33 @@ etfci_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int widt const int rows = e_table_header_count (etfci->full_header); int y1, y2; int row; + GtkStyle *style; + GtkStateType state; + + style = GTK_WIDGET (canvas)->style; + state = GTK_WIDGET_STATE (canvas); y1 = y2 = 0; for (row = 0; row < rows; row++, y1 = y2){ - y2 += etfci_button_height(etfci, row); + ETableCol *ecol; + + ecol = e_table_header_get_column (etfci->full_header, row); + + y2 += e_table_header_compute_height (ecol, style, etfci->font); if (y1 > (y + height)) break; if (y2 < y) continue; - - draw_button (etfci, row, drawable, - GTK_WIDGET (canvas)->style, - - x, y1 - y, etfci->width, y2 - y1); + + e_table_header_draw_button (drawable, ecol, + style, etfci->font, state, + GTK_WIDGET (canvas), style->fg_gc[GTK_STATE_NORMAL], + -x, y1 - y, + width, height, + etfci->width, y2 - y1, + E_TABLE_COL_ARROW_NONE); } } @@ -473,7 +405,7 @@ etfci_start_drag (ETableFieldChooserItem *etfci, GdkEvent *event, double x, doub ETableCol *ecol; GdkPixmap *pixmap; int drag_col; - double button_height; + int button_height; GtkTargetEntry etfci_drag_types [] = { { TARGET_ETABLE_COL_TYPE, 0, TARGET_ETABLE_COL_HEADER }, @@ -493,12 +425,17 @@ etfci_start_drag (ETableFieldChooserItem *etfci, GdkEvent *event, double x, doub context = gtk_drag_begin (widget, list, GDK_ACTION_MOVE, 1, event); g_free(etfci_drag_types[0].target); - - button_height = etfci_button_height(etfci, drag_col); + button_height = e_table_header_compute_height (ecol, widget->style, etfci->font); pixmap = gdk_pixmap_new (widget->window, etfci->width, button_height, -1); - draw_button (etfci, drag_col, pixmap, - widget->style, - 0, 0, etfci->width, button_height); + + e_table_header_draw_button (pixmap, e_table_header_get_column (etfci->full_header, drag_col), + widget->style, etfci->font, GTK_WIDGET_STATE (widget), + widget, widget->style->fg_gc[GTK_STATE_NORMAL], + 0, 0, + etfci->width, button_height, + etfci->width, button_height, + E_TABLE_COL_ARROW_NONE); + gtk_drag_set_icon_pixmap (context, gdk_window_get_colormap (widget->window), pixmap, diff --git a/widgets/table/e-table-header-item.c b/widgets/table/e-table-header-item.c index 14ac50f5aa..932846b6a0 100644 --- a/widgets/table/e-table-header-item.c +++ b/widgets/table/e-table-header-item.c @@ -21,6 +21,7 @@ #include "gal/widgets/e-popup-menu.h" #include "e-table-header.h" #include "e-table-header-item.h" +#include "e-table-header-utils.h" #include "e-table-col-dnd.h" #include "e-table-defines.h" #include "e-table-field-chooser-dialog.h" @@ -102,6 +103,7 @@ e_table_header_item_get_height (ETableHeaderItem *ethi) ETableHeader *eth; int numcols, col; int maxheight; + GtkStyle *style; g_return_val_if_fail (ethi != NULL, 0); g_return_val_if_fail (E_IS_TABLE_HEADER_ITEM (ethi), 0); @@ -109,22 +111,19 @@ e_table_header_item_get_height (ETableHeaderItem *ethi) eth = ethi->eth; numcols = e_table_header_count (eth); - if (ethi->font) { - maxheight = ethi->font->ascent + ethi->font->descent + HEADER_PADDING + 1; - } else { - /* FIXME: Default??? */ - maxheight = 16; - } + maxheight = 0; + + style = GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas)->style; + for (col = 0; col < numcols; col++) { ETableCol *ecol = e_table_header_get_column (eth, col); - - if (ecol->is_pixbuf) { - maxheight = MAX (maxheight, gdk_pixbuf_get_height (ecol->pixbuf) + HEADER_PADDING + 1); - } - } + int height; - if (maxheight < MIN_ARROW_SIZE + 1 + HEADER_PADDING) - maxheight = MIN_ARROW_SIZE + 1 + HEADER_PADDING; + height = e_table_header_compute_height (ecol, style, ethi->font); + + if (height > maxheight) + maxheight = height; + } return maxheight; } @@ -396,7 +395,7 @@ ethi_remove_drop_marker (ETableHeaderItem *ethi) } static GtkWidget * -make_shapped_window_from_xpm (const char **xpm) +make_shaped_window_from_xpm (const char **xpm) { GdkPixbuf *pixbuf; GdkPixmap *pixmap; @@ -439,8 +438,8 @@ ethi_add_drop_marker (ETableHeaderItem *ethi, int col) x += ethi->group_indent_width; if (!arrow_up){ - arrow_up = make_shapped_window_from_xpm (arrow_up_xpm); - arrow_down = make_shapped_window_from_xpm (arrow_down_xpm); + arrow_up = make_shaped_window_from_xpm (arrow_up_xpm); + arrow_down = make_shaped_window_from_xpm (arrow_down_xpm); } gdk_window_get_origin ( @@ -758,144 +757,10 @@ ethi_unrealize (GnomeCanvasItem *item) } static void -draw_button (ETableHeaderItem *ethi, ETableCol *col, - GdkDrawable *drawable, GdkGC *gc, GtkStyle *style, - int x, int y, int width, int height, ETableColArrow arrow) -{ - GdkRectangle clip; - int xtra; - - clip.x = x; - clip.y = y; - clip.width = width; - clip.height = height; - - gdk_window_set_back_pixmap (GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas)->window, NULL, FALSE); - - gtk_paint_box (style, drawable, - GTK_STATE_NORMAL, GTK_SHADOW_OUT, - &clip, GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas), - "button", x, y, width, height); - - clip.x = x + HEADER_PADDING / 2; - clip.y = y + HEADER_PADDING / 2; - clip.width = width - HEADER_PADDING; - clip.height = ethi->height - HEADER_PADDING; - - gdk_gc_set_clip_rectangle (ethi->gc, &clip); - - switch (arrow){ - case E_TABLE_COL_ARROW_NONE: - break; - - case E_TABLE_COL_ARROW_UP: - case E_TABLE_COL_ARROW_DOWN: - if (!col->is_pixbuf || - (clip.width > (gdk_pixbuf_get_width (col->pixbuf) + MIN_ARROW_SIZE))) { - gtk_paint_arrow (gtk_widget_get_style (GTK_WIDGET(GNOME_CANVAS_ITEM(ethi)->canvas)), - drawable, - GTK_STATE_NORMAL, - GTK_SHADOW_IN, - &clip, - GTK_WIDGET(GNOME_CANVAS_ITEM(ethi)->canvas), - "header", - (arrow == E_TABLE_COL_ARROW_UP) ? GTK_ARROW_UP : GTK_ARROW_DOWN, - TRUE, - x + HEADER_PADDING / 2 + clip.width - MIN_ARROW_SIZE - 2, - y + (ethi->height - MIN_ARROW_SIZE) / 2, - MIN_ARROW_SIZE, - MIN_ARROW_SIZE); - - clip.width -= (MIN_ARROW_SIZE + 2 + HEADER_PADDING); - break; - } - } - - if (col->is_pixbuf){ - xtra = (clip.width - gdk_pixbuf_get_width (col->pixbuf))/2; - if (xtra < 0) - xtra = 0; - - xtra += HEADER_PADDING / 2; - - gdk_pixbuf_render_to_drawable_alpha (col->pixbuf, - drawable, - 0, 0, - x + xtra, y + (clip.height - gdk_pixbuf_get_height (col->pixbuf)) / 2, - gdk_pixbuf_get_width (col->pixbuf), - gdk_pixbuf_get_height (col->pixbuf), - GDK_PIXBUF_ALPHA_FULL, 128, - GDK_RGB_DITHER_NORMAL, - 0, 0); - } else { - int str_width, ellipsis_width, text_len; - int y_xtra; - - text_len = strlen (col->text); - ellipsis_width = gdk_text_width (ethi->font, "...", 3); - - str_width = gdk_text_width (ethi->font, col->text, text_len); - /* y_xtra = ethi->height / 2 + (ethi->font->ascent + ethi->font->descent) / 2 - ethi->font->descent; */ - y_xtra = (ethi->height + ethi->font->ascent - ethi->font->descent) / 2; - - if (str_width < clip.width) { - - /* Center the thing */ - xtra = (clip.width - gdk_string_measure (ethi->font, col->text))/2; - - /* Skip over border */ - if (xtra < 0) - xtra = 0; - - xtra += HEADER_PADDING / 2; - - gdk_draw_text (drawable, ethi->font, - ethi->gc, clip.x + xtra, y + y_xtra, - col->text, text_len); - } else { - /* Need ellipsis */ - gchar *p; - int ellipsis_length = 0; - - for (p = col->text; p && *p && (p - col->text) < text_len; p++) { - if (gdk_text_width (ethi->font, col->text, p - col->text) + ellipsis_width <= clip.width) - ellipsis_length = p - col->text; - else - break; - } - - xtra = (clip.width - gdk_text_measure (ethi->font, col->text, ellipsis_length) - gdk_string_measure (ethi->font, "..."))/2; - - if (xtra < 0) - xtra = 0; - - xtra += HEADER_PADDING / 2; - - - gdk_draw_text (drawable, ethi->font, ethi->gc, - x + xtra, y + y_xtra, - col->text, ellipsis_length); - gdk_draw_string (drawable, ethi->font, ethi->gc, - x + xtra + gdk_text_width (ethi->font, - col->text, - ellipsis_length), - y + y_xtra, - "..."); - } - } - - if (col->pixbuf){ - if ((gdk_pixbuf_get_width (col->pixbuf) + MIN_ARROW_SIZE + 4) > width) - return; - } -} - -static void ethi_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) { ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item); GnomeCanvas *canvas = item->canvas; - GdkGC *gc; const int cols = e_table_header_count (ethi->eth); int x1, x2; int col; @@ -940,14 +805,18 @@ ethi_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width if (x2 < x) continue; - - gc = GTK_WIDGET (canvas)->style->bg_gc [GTK_STATE_NORMAL]; - draw_button (ethi, ecol, drawable, gc, - GTK_WIDGET (canvas)->style, - x1 - x, - y, x2 - x1, ethi->height, - (ETableColArrow) g_hash_table_lookup (arrows, (gpointer) ecol->col_idx)); + e_table_header_draw_button (drawable, ecol, + GTK_WIDGET (canvas)->style, ethi->font, + GTK_WIDGET_STATE (canvas), + GTK_WIDGET (canvas), ethi->gc, + x1 - x, -y, + width, height, + x2 - x1, ethi->height, + (ETableColArrow) g_hash_table_lookup ( + arrows, (gpointer) ecol->col_idx)); } + g_hash_table_destroy (arrows); } @@ -1074,7 +943,6 @@ ethi_start_drag (ETableHeaderItem *ethi, GdkEvent *event) ETableCol *ecol; int col_width; GdkPixmap *pixmap; - GdkGC *gc; int group_indent = 0; GHashTable *arrows = g_hash_table_new (NULL, NULL); @@ -1118,11 +986,16 @@ ethi_start_drag (ETableHeaderItem *ethi, GdkEvent *event) ecol = e_table_header_get_column (ethi->eth, ethi->drag_col); col_width = ecol->width; pixmap = gdk_pixmap_new (widget->window, col_width, ethi->height, -1); - gc = widget->style->bg_gc [GTK_STATE_ACTIVE]; - draw_button (ethi, ecol, pixmap, gc, - widget->style, - 0, 0, col_width, ethi->height, - (ETableColArrow) g_hash_table_lookup (arrows, (gpointer) ecol->col_idx)); + + e_table_header_draw_button (pixmap, ecol, + widget->style, ethi->font, + GTK_WIDGET_STATE (widget), + widget, ethi->gc, + 0, 0, + col_width, ethi->height, + col_width, ethi->height, + (ETableColArrow) g_hash_table_lookup ( + arrows, (gpointer) ecol->col_idx)); gtk_drag_set_icon_pixmap (context, gdk_window_get_colormap (widget->window), pixmap, diff --git a/widgets/table/e-table-header-utils.c b/widgets/table/e-table-header-utils.c new file mode 100644 index 0000000000..99fdba680f --- /dev/null +++ b/widgets/table/e-table-header-utils.c @@ -0,0 +1,419 @@ +/* ETable widget - utilities for drawing table header buttons + * + * Copyright (C) 2000 Helix Code, Inc. + * + * Authors: Chris Lahey <clahey@helixcode.com> + * Miguel de Icaza <miguel@helixcode.com> + * Federico Mena-Quintero <federico@helixcode.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib.h> +#include "e-table-defines.h" +#include "e-table-header-utils.h" + + + +/** + * e_table_header_compute_height: + * @ecol: Table column description. + * @style: Style for the button's bevel. + * @font: Font for the button's text, or NULL if no font is available. + * + * Computes the minimum height required for a table header button. + * + * Return value: The height of the button, in pixels. + **/ +int +e_table_header_compute_height (ETableCol *ecol, GtkStyle *style, GdkFont *font) +{ + int ythick; + int height; + + g_return_val_if_fail (ecol != NULL, -1); + g_return_val_if_fail (E_IS_TABLE_COL (ecol), -1); + g_return_val_if_fail (style != NULL, -1); + + ythick = style->klass->ythickness; + + if (font) + height = font->ascent + font->descent; + else + height = 16; /* FIXME: default? */ + + if (ecol->is_pixbuf) { + g_assert (ecol->pixbuf != NULL); + height = MAX (height, gdk_pixbuf_get_height (ecol->pixbuf)); + } + + height = MAX (height, MIN_ARROW_SIZE); + + height += 2 * (ythick + HEADER_PADDING); + + return height; +} + +/* Creates a pixmap that is a composite of a background color and the upper-left + * corner rectangle of a pixbuf. + */ +static GdkPixmap * +make_composite_pixmap (GdkDrawable *drawable, GdkGC *gc, + GdkPixbuf *pixbuf, GdkColor *bg, int width, int height, + int dither_xofs, int dither_yofs) +{ + int pwidth, pheight; + GdkPixmap *pixmap; + GdkPixbuf *tmp; + int color; + + pwidth = gdk_pixbuf_get_width (pixbuf); + pheight = gdk_pixbuf_get_height (pixbuf); + g_assert (width <= pwidth && height <= pheight); + + color = ((bg->red & 0xff00) << 8) | (bg->green & 0xff00) | ((bg->blue & 0xff00) >> 8); + + if (width >= pwidth && height >= pheight) { + tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); + if (!tmp) + return NULL; + + gdk_pixbuf_composite_color (pixbuf, tmp, + 0, 0, + width, height, + 0, 0, + 1.0, 1.0, + GDK_INTERP_NEAREST, + 255, + 0, 0, + 16, + color, color); + } else { + int x, y, rowstride; + GdkPixbuf *fade; + guchar *pixels; + + /* Do a nice fade of the pixbuf down and to the right */ + + fade = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); + if (!fade) + return NULL; + + gdk_pixbuf_copy_area (pixbuf, + 0, 0, + width, height, + fade, + 0, 0); + + rowstride = gdk_pixbuf_get_rowstride (fade); + pixels = gdk_pixbuf_get_pixels (fade); + + for (y = 0; y < height; y++) { + guchar *p; + int yfactor; + + p = pixels + y * rowstride; + + if (height < pheight) + yfactor = height - y; + else + yfactor = height; + + for (x = 0; x < width; x++) { + int xfactor; + + if (width < pwidth) + xfactor = width - x; + else + xfactor = width; + + p[3] = ((int) p[3] * xfactor * yfactor / (width * height)); + p += 4; + } + } + + tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); + if (!tmp) { + gdk_pixbuf_unref (fade); + return NULL; + } + + gdk_pixbuf_composite_color (fade, tmp, + 0, 0, + width, height, + 0, 0, + 1.0, 1.0, + GDK_INTERP_NEAREST, + 255, + 0, 0, + 16, + color, color); + + gdk_pixbuf_unref (fade); + } + + pixmap = gdk_pixmap_new (drawable, width, height, gdk_rgb_get_visual ()->depth); + gdk_draw_rgb_image_dithalign (pixmap, gc, + 0, 0, + width, height, + GDK_RGB_DITHER_NORMAL, + gdk_pixbuf_get_pixels (tmp), + gdk_pixbuf_get_rowstride (tmp), + dither_xofs, dither_yofs); + gdk_pixbuf_unref (tmp); + + return pixmap; +} + +/** + * e_table_header_draw_button: + * @drawable: Destination drawable. + * @ecol: Table column for the header information. + * @style: Style to use for drawing the button. + * @font: Font for the button's text. + * @state: State of the table widget. + * @widget: The table widget. + * @gc: GC to use for drawing. + * @x: Leftmost coordinate of the button. + * @y: Topmost coordinate of the button. + * @width: Width of the region to draw. + * @height: Height of the region to draw. + * @button_width: Width for the complete button. + * @button_height: Height for the complete button. + * @arrow: Arrow type to use as a sort indicator. + * + * Draws a button suitable for a table header. + **/ +void +e_table_header_draw_button (GdkDrawable *drawable, ETableCol *ecol, + GtkStyle *style, GdkFont *font, GtkStateType state, + GtkWidget *widget, GdkGC *gc, + int x, int y, int width, int height, + int button_width, int button_height, + ETableColArrow arrow) +{ + int xthick, ythick; + int inner_x, inner_y; + int inner_width, inner_height; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (ecol != NULL); + g_return_if_fail (E_IS_TABLE_COL (ecol)); + g_return_if_fail (style != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (button_width > 0 && button_height > 0); + + xthick = style->klass->xthickness; + ythick = style->klass->ythickness; + + /* Button bevel */ + + gtk_paint_box (style, drawable, state, GTK_SHADOW_OUT, + NULL, widget, "button", + x, y, button_width, button_height); + + /* Inside area */ + + inner_width = button_width - 2 * (xthick + HEADER_PADDING); + inner_height = button_height - 2 * (ythick + HEADER_PADDING); + + if (inner_width < 1 || inner_height < 1) + return; /* nothing fits */ + + inner_x = x + xthick + HEADER_PADDING; + inner_y = y + ythick + HEADER_PADDING; + + /* Arrow */ + + switch (arrow) { + case E_TABLE_COL_ARROW_NONE: + break; + + case E_TABLE_COL_ARROW_UP: + case E_TABLE_COL_ARROW_DOWN: { + int arrow_width, arrow_height; + + arrow_width = MIN (MIN_ARROW_SIZE, inner_width); + arrow_height = MIN (MIN_ARROW_SIZE, inner_height); + + gtk_paint_arrow (style, drawable, state, + GTK_SHADOW_IN, NULL, widget, "header", + (arrow == E_TABLE_COL_ARROW_UP) ? GTK_ARROW_UP : GTK_ARROW_DOWN, + TRUE, + inner_x + inner_width - arrow_width, + inner_y + (inner_height - arrow_height) / 2, + arrow_width, arrow_height); + + inner_width -= arrow_width + HEADER_PADDING; + break; + } + + default: + g_assert_not_reached (); + return; + } + + if (inner_width < 1) + return; /* nothing else fits */ + + /* Pixbuf or label */ + + if (ecol->is_pixbuf) { + int pwidth, pheight; + int clip_width, clip_height; + GdkPixmap *pixmap; + + g_assert (ecol->pixbuf != NULL); + + pwidth = gdk_pixbuf_get_width (ecol->pixbuf); + pheight = gdk_pixbuf_get_height (ecol->pixbuf); + + clip_width = MIN (pwidth, inner_width); + clip_height = MIN (pheight, inner_height); + + pixmap = make_composite_pixmap (drawable, gc, + ecol->pixbuf, &style->bg[state], + clip_width, clip_height, + inner_x, + inner_y + (inner_height - clip_height) / 2); + if (pixmap) { + gdk_draw_pixmap (drawable, gc, pixmap, + 0, 0, + inner_x, + inner_y + (inner_height - clip_height) / 2, + clip_width, clip_height); + gdk_pixmap_unref (pixmap); + } + } else { + int ypos; + + ypos = inner_y + (inner_height - font->ascent - font->descent) / 2 + font->ascent; + + e_table_draw_elided_string (drawable, font, gc, + inner_x, ypos, + ecol->text, inner_width, TRUE); + } +} + +/* Computes the length of a string that needs to be trimmed for elision */ +static int +compute_elision_length (GdkFont *font, const char *str, int max_width) +{ + int len; + int l, left, right; + int rbearing; + + len = strlen (str); + g_assert (len > 0); + + left = 0; + right = len; + + while (left < right) { + l = (left + right) / 2; + gdk_text_extents (font, str, l, NULL, &rbearing, NULL, NULL, NULL); + + if (rbearing < max_width) + left = l + 1; + else if (rbearing > max_width) + right = l; + else + return l; + } + + if (rbearing > max_width) + return MAX (0, l - 1); + else + return l; +} + +/* Default width of the elision arrow in pixels */ +#define ARROW_WIDTH 4 + +/** + * e_table_draw_elided_string: + * @drawable: Destination drawable. + * @font: Font for the text. + * @gc: GC to use for drawing. + * @x: X insertion point for the string. + * @y: Y insertion point for the string's baseline. + * @str: String to draw. + * @max_width: Maximum width in which the string must fit. + * @center: Whether to center the string in the available area if it does fit. + * + * Draws a string, possibly trimming it so that it fits inside the specified + * maximum width. If it does not fit, an elision indicator is drawn after the + * last character that does fit. + **/ +void +e_table_draw_elided_string (GdkDrawable *drawable, GdkFont *font, GdkGC *gc, + int x, int y, const char *str, int max_width, gboolean center) +{ + int rbearing; + int width; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (str != NULL); + g_return_if_fail (max_width >= 0); + + gdk_string_extents (font, str, NULL, &rbearing, &width, NULL, NULL); + + if (rbearing <= max_width) { + int xpos; + + if (center) + xpos = x + (max_width - width) / 2; + else + xpos = x; + + gdk_draw_string (drawable, font, gc, xpos, y, str); + } else { + int arrow_width; + int len; + int i; + + if (max_width < ARROW_WIDTH + 1) + arrow_width = max_width - 1; + else + arrow_width = ARROW_WIDTH; + + len = compute_elision_length (font, str, max_width - arrow_width - 1); + gdk_draw_text (drawable, font, gc, x, y, str, len); + + gdk_text_extents (font, str, len, NULL, &rbearing, NULL, NULL, NULL); + + y -= font->ascent; + + for (i = 0; i < arrow_width; i++) { + int h; + + h = 2 * i + 1; + + gdk_draw_line (drawable, gc, + x + rbearing + arrow_width - i, + y + (font->ascent + font->descent - h) / 2, + x + rbearing + arrow_width - i, + y + (font->ascent + font->descent - h) / 2 + h - 1); + } + } +} diff --git a/widgets/table/e-table-header-utils.h b/widgets/table/e-table-header-utils.h new file mode 100644 index 0000000000..bbfb1ee17b --- /dev/null +++ b/widgets/table/e-table-header-utils.h @@ -0,0 +1,43 @@ +/* ETable widget - utilities for drawing table header buttons + * + * Copyright (C) 2000 Helix Code, Inc. + * + * Authors: Chris Lahey <clahey@helixcode.com> + * Miguel de Icaza <miguel@helixcode.com> + * Federico Mena-Quintero <federico@helixcode.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef E_TABLE_HEADER_UTILS_H +#define E_TABLE_HEADER_UTILS_H + +#include <gal/e-table/e-table-col.h> + +int e_table_header_compute_height (ETableCol *ecol, GtkStyle *style, GdkFont *font); + +void e_table_header_draw_button (GdkDrawable *drawable, ETableCol *ecol, + GtkStyle *style, GdkFont *font, GtkStateType state, + GtkWidget *widget, GdkGC *gc, + int x, int y, int width, int height, + int button_width, int button_height, + ETableColArrow arrow); + +void e_table_draw_elided_string (GdkDrawable *drawable, GdkFont *font, GdkGC *gc, + int x, int y, const char *str, int max_width, gboolean center); + + + +#endif diff --git a/widgets/table/e-table-item.c b/widgets/table/e-table-item.c index 8a927ed11b..8e6103427a 100644 --- a/widgets/table/e-table-item.c +++ b/widgets/table/e-table-item.c @@ -1338,8 +1338,9 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, * Draw focus */ if (f_found && eti->draw_focus){ + gdk_gc_set_ts_origin (eti->focus_gc, f_x1, f_y1); gdk_draw_rectangle (drawable, eti->focus_gc, FALSE, - f_x1 + 1, f_y1, f_x2 - f_x1 - 2, f_y2 - f_y1 - 1); + f_x1, f_y1, f_x2 - f_x1 - 1, f_y2 - f_y1 - 1); } } |