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 }