evolution-3.6.4/widgets/table/e-table-header-utils.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Chris Lahey <clahey@ximian.com>
 18  *      Miguel de Icaza <miguel@ximian.com>
 19  *      Federico Mena-Quintero <federico@ximian.com>
 20  *
 21  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 22  *
 23  */
 24 
 25 #ifdef HAVE_CONFIG_H
 26 #include <config.h>
 27 #endif
 28 
 29 #include <string.h> /* strlen() */
 30 
 31 #include <gtk/gtk.h>
 32 
 33 #include "e-util/e-unicode.h"
 34 
 35 #include "e-table-defines.h"
 36 #include "e-table-header-utils.h"
 37 
 38 static void
 39 get_button_padding (GtkWidget *widget,
 40                     GtkBorder *padding)
 41 {
 42 	GtkStyleContext *context;
 43 	GtkStateFlags state_flags;
 44 
 45 	context = gtk_widget_get_style_context (widget);
 46 	state_flags = gtk_widget_get_state_flags (widget);
 47 
 48 	gtk_style_context_save (context);
 49 	gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
 50 	gtk_style_context_get_padding (context, state_flags, padding);
 51 
 52 	gtk_style_context_restore (context);
 53 }
 54 
 55 /**
 56  * e_table_header_compute_height:
 57  * @ecol: Table column description.
 58  * @widget: The widget from which to build the PangoLayout.
 59  *
 60  * Computes the minimum height required for a table header button.
 61  *
 62  * Return value: The height of the button, in pixels.
 63  **/
 64 gdouble
 65 e_table_header_compute_height (ETableCol *ecol,
 66                                GtkWidget *widget)
 67 {
 68 	gint height;
 69 	PangoLayout *layout;
 70 	GtkBorder padding;
 71 
 72 	g_return_val_if_fail (ecol != NULL, -1);
 73 	g_return_val_if_fail (E_IS_TABLE_COL (ecol), -1);
 74 	g_return_val_if_fail (GTK_IS_WIDGET (widget), -1);
 75 
 76 	get_button_padding (widget, &padding);
 77 
 78 	layout = gtk_widget_create_pango_layout (widget, ecol->text);
 79 
 80 	pango_layout_get_pixel_size (layout, NULL, &height);
 81 
 82 	if (ecol->icon_name != NULL) {
 83 		g_return_val_if_fail (ecol->pixbuf != NULL, -1);
 84 		height = MAX (height, gdk_pixbuf_get_height (ecol->pixbuf));
 85 	}
 86 
 87 	height = MAX (height, MIN_ARROW_SIZE);
 88 	height += padding.top + padding.bottom + 2 * HEADER_PADDING;
 89 
 90 	g_object_unref (layout);
 91 
 92 	return height;
 93 }
 94 
 95 gdouble
 96 e_table_header_width_extras (GtkWidget *widget)
 97 {
 98 	GtkBorder padding;
 99 
100 	get_button_padding (widget, &padding);
101 	return padding.left + padding.right + 2 * HEADER_PADDING;
102 }
103 
104 /**
105  * e_table_header_draw_button:
106  * @drawable: Destination drawable.
107  * @ecol: Table column for the header information.
108  * @widget: The table widget.
109  * @x: Leftmost coordinate of the button.
110  * @y: Topmost coordinate of the button.
111  * @width: Width of the region to draw.
112  * @height: Height of the region to draw.
113  * @button_width: Width for the complete button.
114  * @button_height: Height for the complete button.
115  * @arrow: Arrow type to use as a sort indicator.
116  *
117  * Draws a button suitable for a table header.
118  **/
119 void
120 e_table_header_draw_button (cairo_t *cr,
121                             ETableCol *ecol,
122                             GtkWidget *widget,
123                             gint x,
124                             gint y,
125                             gint width,
126                             gint height,
127                             gint button_width,
128                             gint button_height,
129                             ETableColArrow arrow)
130 {
131 	gint inner_x, inner_y;
132 	gint inner_width, inner_height;
133 	gint arrow_width = 0, arrow_height = 0;
134 	PangoContext *pango_context;
135 	PangoLayout *layout;
136 	GtkStyleContext *context;
137 	GtkBorder padding;
138 	GtkStateFlags state_flags;
139 
140 	g_return_if_fail (cr != NULL);
141 	g_return_if_fail (ecol != NULL);
142 	g_return_if_fail (E_IS_TABLE_COL (ecol));
143 	g_return_if_fail (widget != NULL);
144 	g_return_if_fail (GTK_IS_WIDGET (widget));
145 	g_return_if_fail (button_width > 0 && button_height > 0);
146 
147 	/* Button bevel */
148 	context = gtk_widget_get_style_context (widget);
149 	state_flags = gtk_widget_get_state_flags (widget);
150 
151 	gtk_style_context_save (context);
152 	gtk_style_context_set_state (context, state_flags);
153 	gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
154 
155 	gtk_style_context_get_padding (context, state_flags, &padding);
156 
157 	gtk_render_background (
158 		context, cr, x, y,
159 		button_width, button_height);
160 	gtk_render_frame (
161 		context, cr, x, y,
162 		button_width, button_height);
163 
164 	/* Inside area */
165 
166 	inner_width =
167 		button_width -
168 		(padding.left + padding.right + 2 * HEADER_PADDING);
169 	inner_height =
170 		button_height -
171 		(padding.top + padding.bottom + 2 * HEADER_PADDING);
172 
173 	if (inner_width < 1 || inner_height < 1) {
174 		return; /* nothing fits */
175 	}
176 
177 	inner_x = x + padding.left + HEADER_PADDING;
178 	inner_y = y + padding.top + HEADER_PADDING;
179 
180 	/* Arrow space */
181 
182 	switch (arrow) {
183 	case E_TABLE_COL_ARROW_NONE:
184 		break;
185 
186 	case E_TABLE_COL_ARROW_UP:
187 	case E_TABLE_COL_ARROW_DOWN:
188 		arrow_width = MIN (MIN_ARROW_SIZE, inner_width);
189 		arrow_height = MIN (MIN_ARROW_SIZE, inner_height);
190 
191 		if (ecol->icon_name == NULL)
192 			inner_width -= arrow_width + HEADER_PADDING;
193 		break;
194 	default:
195 		cairo_restore (cr);
196 		g_return_if_reached ();
197 	}
198 
199 	if (inner_width < 1) {
200 		gtk_style_context_restore (context);
201 		return; /* nothing else fits */
202 	}
203 
204 	pango_context = gtk_widget_create_pango_context (widget);
205 	layout = pango_layout_new (pango_context);
206 	g_object_unref (pango_context);
207 
208 	pango_layout_set_text (layout, ecol->text, -1);
209 	pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
210 
211 	/* Pixbuf or label */
212 	if (ecol->icon_name != NULL) {
213 		gint pwidth, pheight;
214 		gint clip_height;
215 		gint xpos;
216 
217 		g_return_if_fail (ecol->pixbuf != NULL);
218 
219 		pwidth = gdk_pixbuf_get_width (ecol->pixbuf);
220 		pheight = gdk_pixbuf_get_height (ecol->pixbuf);
221 
222 		clip_height = MIN (pheight, inner_height);
223 
224 		xpos = inner_x;
225 
226 		if (inner_width - pwidth > 11) {
227 			gint ypos;
228 
229 			pango_layout_get_pixel_size (layout, &width, NULL);
230 
231 			if (width < inner_width - (pwidth + 1)) {
232 				xpos = inner_x + (inner_width - width - (pwidth + 1)) / 2;
233 			}
234 
235 			ypos = inner_y;
236 
237 			pango_layout_set_width (
238 				layout, (inner_width - (xpos - inner_x)) *
239 				PANGO_SCALE);
240 
241 			gtk_render_layout (
242 				context, cr, xpos + pwidth + 1,
243 				ypos, layout);
244 		}
245 
246 		gtk_render_icon (
247 			context, cr, ecol->pixbuf, xpos,
248 			inner_y + (inner_height - clip_height) / 2);
249 
250 	} else {
251 		pango_layout_set_width (layout, inner_width * PANGO_SCALE);
252 
253 		gtk_render_layout (context, cr, inner_x, inner_y, layout);
254 	}
255 
256 	switch (arrow) {
257 	case E_TABLE_COL_ARROW_NONE:
258 		break;
259 
260 	case E_TABLE_COL_ARROW_UP:
261 	case E_TABLE_COL_ARROW_DOWN: {
262 		if (ecol->icon_name == NULL)
263 			inner_width += arrow_width + HEADER_PADDING;
264 
265 		gtk_render_arrow (
266 			context, cr,
267 			(arrow == E_TABLE_COL_ARROW_UP) ? 0 : G_PI,
268 			inner_x + inner_width - arrow_width,
269 			inner_y + (inner_height - arrow_height) / 2,
270 			MAX (arrow_width, arrow_height));
271 
272 		break;
273 	}
274 
275 	default:
276 		cairo_restore (cr);
277 		g_return_if_reached ();
278 	}
279 
280 	g_object_unref (layout);
281 	gtk_style_context_restore (context);
282 }