diff options
Diffstat (limited to 'e-util/e-table-header-utils.c')
-rw-r--r-- | e-util/e-table-header-utils.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/e-util/e-table-header-utils.c b/e-util/e-table-header-utils.c new file mode 100644 index 0000000000..d3ee1aca38 --- /dev/null +++ b/e-util/e-table-header-utils.c @@ -0,0 +1,282 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Authors: + * Chris Lahey <clahey@ximian.com> + * Miguel de Icaza <miguel@ximian.com> + * Federico Mena-Quintero <federico@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "e-table-header-utils.h" + +#include <string.h> /* strlen() */ + +#include <gtk/gtk.h> + +#include "e-table-defines.h" +#include "e-unicode.h" + +static void +get_button_padding (GtkWidget *widget, + GtkBorder *padding) +{ + GtkStyleContext *context; + GtkStateFlags state_flags; + + context = gtk_widget_get_style_context (widget); + state_flags = gtk_widget_get_state_flags (widget); + + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON); + gtk_style_context_get_padding (context, state_flags, padding); + + gtk_style_context_restore (context); +} + +/** + * e_table_header_compute_height: + * @ecol: Table column description. + * @widget: The widget from which to build the PangoLayout. + * + * Computes the minimum height required for a table header button. + * + * Return value: The height of the button, in pixels. + **/ +gdouble +e_table_header_compute_height (ETableCol *ecol, + GtkWidget *widget) +{ + gint height; + PangoLayout *layout; + GtkBorder padding; + + g_return_val_if_fail (ecol != NULL, -1); + g_return_val_if_fail (E_IS_TABLE_COL (ecol), -1); + g_return_val_if_fail (GTK_IS_WIDGET (widget), -1); + + get_button_padding (widget, &padding); + + layout = gtk_widget_create_pango_layout (widget, ecol->text); + + pango_layout_get_pixel_size (layout, NULL, &height); + + if (ecol->icon_name != NULL) { + g_return_val_if_fail (ecol->pixbuf != NULL, -1); + height = MAX (height, gdk_pixbuf_get_height (ecol->pixbuf)); + } + + height = MAX (height, MIN_ARROW_SIZE); + height += padding.top + padding.bottom + 2 * HEADER_PADDING; + + g_object_unref (layout); + + return height; +} + +gdouble +e_table_header_width_extras (GtkWidget *widget) +{ + GtkBorder padding; + + get_button_padding (widget, &padding); + return padding.left + padding.right + 2 * HEADER_PADDING; +} + +/** + * e_table_header_draw_button: + * @drawable: Destination drawable. + * @ecol: Table column for the header information. + * @widget: The table widget. + * @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 (cairo_t *cr, + ETableCol *ecol, + GtkWidget *widget, + gint x, + gint y, + gint width, + gint height, + gint button_width, + gint button_height, + ETableColArrow arrow) +{ + gint inner_x, inner_y; + gint inner_width, inner_height; + gint arrow_width = 0, arrow_height = 0; + PangoContext *pango_context; + PangoLayout *layout; + GtkStyleContext *context; + GtkBorder padding; + GtkStateFlags state_flags; + + g_return_if_fail (cr != NULL); + g_return_if_fail (ecol != NULL); + g_return_if_fail (E_IS_TABLE_COL (ecol)); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (button_width > 0 && button_height > 0); + + /* Button bevel */ + context = gtk_widget_get_style_context (widget); + state_flags = gtk_widget_get_state_flags (widget); + + gtk_style_context_save (context); + gtk_style_context_set_state (context, state_flags); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON); + + gtk_style_context_get_padding (context, state_flags, &padding); + + gtk_render_background ( + context, cr, x, y, + button_width, button_height); + gtk_render_frame ( + context, cr, x, y, + button_width, button_height); + + /* Inside area */ + + inner_width = + button_width - + (padding.left + padding.right + 2 * HEADER_PADDING); + inner_height = + button_height - + (padding.top + padding.bottom + 2 * HEADER_PADDING); + + if (inner_width < 1 || inner_height < 1) { + return; /* nothing fits */ + } + + inner_x = x + padding.left + HEADER_PADDING; + inner_y = y + padding.top + HEADER_PADDING; + + /* Arrow space */ + + switch (arrow) { + case E_TABLE_COL_ARROW_NONE: + break; + + case E_TABLE_COL_ARROW_UP: + case E_TABLE_COL_ARROW_DOWN: + arrow_width = MIN (MIN_ARROW_SIZE, inner_width); + arrow_height = MIN (MIN_ARROW_SIZE, inner_height); + + if (ecol->icon_name == NULL) + inner_width -= arrow_width + HEADER_PADDING; + break; + default: + cairo_restore (cr); + g_return_if_reached (); + } + + if (inner_width < 1) { + gtk_style_context_restore (context); + return; /* nothing else fits */ + } + + pango_context = gtk_widget_create_pango_context (widget); + layout = pango_layout_new (pango_context); + g_object_unref (pango_context); + + pango_layout_set_text (layout, ecol->text, -1); + pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); + + /* Pixbuf or label */ + if (ecol->icon_name != NULL) { + gint pwidth, pheight; + gint clip_height; + gint xpos; + + g_return_if_fail (ecol->pixbuf != NULL); + + pwidth = gdk_pixbuf_get_width (ecol->pixbuf); + pheight = gdk_pixbuf_get_height (ecol->pixbuf); + + clip_height = MIN (pheight, inner_height); + + xpos = inner_x; + + if (inner_width - pwidth > 11) { + gint ypos; + + pango_layout_get_pixel_size (layout, &width, NULL); + + if (width < inner_width - (pwidth + 1)) { + xpos = inner_x + (inner_width - width - (pwidth + 1)) / 2; + } + + ypos = inner_y; + + pango_layout_set_width ( + layout, (inner_width - (xpos - inner_x)) * + PANGO_SCALE); + + gtk_render_layout ( + context, cr, xpos + pwidth + 1, + ypos, layout); + } + + gtk_render_icon ( + context, cr, ecol->pixbuf, xpos, + inner_y + (inner_height - clip_height) / 2); + + } else { + pango_layout_set_width (layout, inner_width * PANGO_SCALE); + + gtk_render_layout (context, cr, inner_x, inner_y, layout); + } + + switch (arrow) { + case E_TABLE_COL_ARROW_NONE: + break; + + case E_TABLE_COL_ARROW_UP: + case E_TABLE_COL_ARROW_DOWN: { + if (ecol->icon_name == NULL) + inner_width += arrow_width + HEADER_PADDING; + + gtk_render_arrow ( + context, cr, + (arrow == E_TABLE_COL_ARROW_UP) ? 0 : G_PI, + inner_x + inner_width - arrow_width, + inner_y + (inner_height - arrow_height) / 2, + MAX (arrow_width, arrow_height)); + + break; + } + + default: + cairo_restore (cr); + g_return_if_reached (); + } + + g_object_unref (layout); + gtk_style_context_restore (context); +} |