Parent Directory | Revision Log
Initial import
1 | /* |
2 | * Copyright (C) 2008 Till Harbaum <till@harbaum.org>. |
3 | * |
4 | * This file is part of GPXView. |
5 | * |
6 | * GPXView is free software: you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation, either version 3 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * GPXView is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with GPXView. If not, see <http://www.gnu.org/licenses/>. |
18 | */ |
19 | |
20 | #include "gpxview.h" |
21 | #include "custom_size_renderer.h" |
22 | |
23 | /* http://scentric.net/tutorial/sec-custom-cell-renderers.html */ |
24 | /* https://stage.maemo.org/svn/maemo/projects/haf/trunk/gtk+/gtk/gtkcellrendererpixbuf.c */ |
25 | /* https://stage.maemo.org/svn/maemo/projects/haf/trunk/gtk+/gtk/gtkcellrenderertext.c */ |
26 | |
27 | /* This is based mainly on GtkCellRendererProgress |
28 | * in GAIM, written and (c) 2002 by Sean Egan |
29 | * (Licensed under the GPL), which in turn is |
30 | * based on Gtk's GtkCellRenderer[Text|Toggle|Pixbuf] |
31 | * implementation by Jonathan Blandford */ |
32 | |
33 | /* Some boring function declarations: GObject type system stuff */ |
34 | |
35 | static void custom_cell_renderer_size_init (CustomCellRendererSize *cellsize); |
36 | static void custom_cell_renderer_size_class_init (CustomCellRendererSizeClass *klass); |
37 | static void custom_cell_renderer_size_get_property (GObject *object, |
38 | guint param_id, |
39 | GValue *value, |
40 | GParamSpec *pspec); |
41 | static void custom_cell_renderer_size_set_property (GObject *object, |
42 | guint param_id, |
43 | const GValue *value, |
44 | GParamSpec *pspec); |
45 | static void custom_cell_renderer_size_finalize (GObject *gobject); |
46 | |
47 | |
48 | /* These functions are the heart of our custom cell renderer: */ |
49 | |
50 | static void custom_cell_renderer_size_get_size (GtkCellRenderer *cell, |
51 | GtkWidget *widget, |
52 | GdkRectangle *cell_area, |
53 | gint *x_offset, |
54 | gint *y_offset, |
55 | gint *width, |
56 | gint *height); |
57 | |
58 | static void custom_cell_renderer_size_render (GtkCellRenderer *cell, |
59 | GdkWindow *window, |
60 | GtkWidget *widget, |
61 | GdkRectangle *background_area, |
62 | GdkRectangle *cell_area, |
63 | GdkRectangle *expose_area, |
64 | guint flags); |
65 | |
66 | |
67 | enum { PROP_SIZE = 1, }; |
68 | |
69 | static const char *size_str[] = { |
70 | "Regular", "Small", "Micro", "Other", "Not chosen", "Large", "Virtual" |
71 | }; |
72 | |
73 | static gpointer parent_class; |
74 | |
75 | GType custom_cell_renderer_size_get_type (void) { |
76 | static GType cell_size_type = 0; |
77 | |
78 | if (cell_size_type == 0) |
79 | { |
80 | static const GTypeInfo cell_size_info = |
81 | { |
82 | sizeof (CustomCellRendererSizeClass), |
83 | NULL, /* base_init */ |
84 | NULL, /* base_finalize */ |
85 | (GClassInitFunc) custom_cell_renderer_size_class_init, |
86 | NULL, /* class_finalize */ |
87 | NULL, /* class_data */ |
88 | sizeof (CustomCellRendererSize), |
89 | 0, /* n_preallocs */ |
90 | (GInstanceInitFunc) custom_cell_renderer_size_init, |
91 | }; |
92 | |
93 | /* Derive from GtkCellRenderer */ |
94 | cell_size_type = g_type_register_static (GTK_TYPE_CELL_RENDERER, |
95 | "CustomCellRendererSize", |
96 | &cell_size_info, |
97 | 0); |
98 | } |
99 | return cell_size_type; |
100 | } |
101 | |
102 | |
103 | /*************************************************************************** |
104 | * |
105 | * custom_cell_renderer_size_init: set some default properties of the |
106 | * parent (GtkCellRenderer). |
107 | * |
108 | ***************************************************************************/ |
109 | |
110 | static void |
111 | custom_cell_renderer_size_init (CustomCellRendererSize *cellrenderersize) |
112 | { |
113 | GTK_CELL_RENDERER(cellrenderersize)->mode = GTK_CELL_RENDERER_MODE_INERT; |
114 | GTK_CELL_RENDERER(cellrenderersize)->xpad = 0; |
115 | GTK_CELL_RENDERER(cellrenderersize)->ypad = 0; |
116 | } |
117 | |
118 | |
119 | /*************************************************************************** |
120 | * |
121 | * custom_cell_renderer_size_class_init: |
122 | * |
123 | * set up our own get_property and set_property functions, and |
124 | * override the parent's functions that we need to implement. |
125 | * And make our new "size" property known to the type system. |
126 | * If you want cells that can be activated on their own (ie. not |
127 | * just the whole row selected) or cells that are editable, you |
128 | * will need to override 'activate' and 'start_editing' as well. |
129 | * |
130 | ***************************************************************************/ |
131 | |
132 | static void |
133 | custom_cell_renderer_size_class_init (CustomCellRendererSizeClass *klass) { |
134 | GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(klass); |
135 | GObjectClass *object_class = G_OBJECT_CLASS(klass); |
136 | |
137 | parent_class = g_type_class_peek_parent (klass); |
138 | object_class->finalize = custom_cell_renderer_size_finalize; |
139 | |
140 | /* Hook up functions to set and get our |
141 | * custom cell renderer properties */ |
142 | object_class->get_property = custom_cell_renderer_size_get_property; |
143 | object_class->set_property = custom_cell_renderer_size_set_property; |
144 | |
145 | /* Override the two crucial functions that are the heart |
146 | * of a cell renderer in the parent class */ |
147 | cell_class->get_size = custom_cell_renderer_size_get_size; |
148 | cell_class->render = custom_cell_renderer_size_render; |
149 | |
150 | /* Install our very own properties */ |
151 | g_object_class_install_property (object_class, PROP_SIZE, |
152 | g_param_spec_int ("size", "Size", "Container size", -1, CACHE_CONT_MAX, 0, |
153 | G_PARAM_READWRITE)); |
154 | } |
155 | |
156 | |
157 | /*************************************************************************** |
158 | * |
159 | * custom_cell_renderer_size_finalize: free any resources here |
160 | * |
161 | ***************************************************************************/ |
162 | |
163 | static void custom_cell_renderer_size_finalize (GObject *object) { |
164 | (* G_OBJECT_CLASS (parent_class)->finalize) (object); |
165 | } |
166 | |
167 | |
168 | /*************************************************************************** |
169 | * |
170 | * custom_cell_renderer_size_get_property: as it says |
171 | * |
172 | ***************************************************************************/ |
173 | |
174 | static void |
175 | custom_cell_renderer_size_get_property (GObject *object, |
176 | guint param_id, |
177 | GValue *value, |
178 | GParamSpec *psec) { |
179 | CustomCellRendererSize *cellsize = CUSTOM_CELL_RENDERER_SIZE(object); |
180 | |
181 | switch (param_id) { |
182 | case PROP_SIZE: |
183 | g_value_set_int(value, cellsize->size); |
184 | break; |
185 | |
186 | default: |
187 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, psec); |
188 | break; |
189 | } |
190 | } |
191 | |
192 | |
193 | /*************************************************************************** |
194 | * |
195 | * custom_cell_renderer_size_set_property: as it says |
196 | * |
197 | ***************************************************************************/ |
198 | |
199 | static void |
200 | custom_cell_renderer_size_set_property (GObject *object, |
201 | guint param_id, |
202 | const GValue *value, |
203 | GParamSpec *pspec) { |
204 | CustomCellRendererSize *cellsize = CUSTOM_CELL_RENDERER_SIZE (object); |
205 | |
206 | switch (param_id) { |
207 | case PROP_SIZE: |
208 | cellsize->size = g_value_get_int(value); |
209 | break; |
210 | |
211 | default: |
212 | G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); |
213 | break; |
214 | } |
215 | } |
216 | |
217 | /*************************************************************************** |
218 | * |
219 | * custom_cell_renderer_size_new: return a new cell renderer instance |
220 | * |
221 | ***************************************************************************/ |
222 | |
223 | GtkCellRenderer *custom_cell_renderer_size_new (void) { |
224 | return g_object_new(CUSTOM_TYPE_CELL_RENDERER_SIZE, NULL); |
225 | } |
226 | |
227 | static PangoLayout *new_layout(GtkWidget *widget, const char *str) { |
228 | #ifndef USE_MAEMO |
229 | return gtk_widget_create_pango_layout(widget, str); |
230 | #else |
231 | #ifdef USE_PANNABLE_AREA |
232 | char *tmp = g_strdup_printf("<span size=\"x-small\">%s</span>", str); |
233 | #else |
234 | char *tmp = g_strdup_printf("<span size=\"xx-small\">%s</span>", str); |
235 | #endif |
236 | PangoLayout *layout = gtk_widget_create_pango_layout(widget, NULL); |
237 | pango_layout_set_markup(layout, tmp, strlen(tmp)); |
238 | g_free(tmp); |
239 | return layout; |
240 | #endif |
241 | } |
242 | |
243 | static void |
244 | custom_cell_renderer_size_get_size (GtkCellRenderer *cell, |
245 | GtkWidget *widget, GdkRectangle *cell_area, gint *x_offset, |
246 | gint *y_offset, gint *width, gint *height) { |
247 | GdkPixbuf *pixbuf = NULL; |
248 | CustomCellRendererSize *cellsize = CUSTOM_CELL_RENDERER_SIZE (cell); |
249 | |
250 | if(cellsize->size < 0) return; |
251 | |
252 | pixbuf = icon_get(ICON_CACHE_SIZE, cellsize->size); |
253 | if (!pixbuf) return; |
254 | |
255 | pixbuf = icon_get(ICON_CACHE_SIZE, cellsize->size); |
256 | gint calc_width = (gint) gdk_pixbuf_get_width(pixbuf); |
257 | gint calc_height = (gint) gdk_pixbuf_get_height(pixbuf); |
258 | |
259 | /* do the text */ |
260 | PangoLayout *layout = new_layout(widget, size_str[cellsize->size]); |
261 | |
262 | PangoRectangle rect; |
263 | pango_layout_get_pixel_extents(layout, NULL, &rect); |
264 | g_object_unref (layout); |
265 | |
266 | calc_height += rect.height; |
267 | if(rect.width > calc_width) calc_width = rect.width; |
268 | |
269 | // printf("req size = %d*%d\n", calc_width, calc_height); |
270 | |
271 | if (x_offset) *x_offset = 0; |
272 | if (y_offset) *y_offset = 0; |
273 | |
274 | if (cell_area) { |
275 | // printf("cell size = %d*%d\n", cell_area->width, cell_area->height); |
276 | |
277 | if (x_offset) |
278 | *x_offset = (cell_area->width - calc_width)/2; |
279 | |
280 | if (y_offset) |
281 | *y_offset = (cell_area->height - calc_height)/2; |
282 | } |
283 | |
284 | if (width) *width = calc_width; |
285 | if (height) *height = calc_height; |
286 | } |
287 | |
288 | |
289 | /*************************************************************************** |
290 | * |
291 | * custom_cell_renderer_size_render: crucial - do the rendering. |
292 | * |
293 | ***************************************************************************/ |
294 | |
295 | static void |
296 | custom_cell_renderer_size_render (GtkCellRenderer *cell, |
297 | GdkWindow *window, |
298 | GtkWidget *widget, |
299 | GdkRectangle *background_area, |
300 | GdkRectangle *cell_area, |
301 | GdkRectangle *expose_area, |
302 | guint flags) |
303 | { |
304 | CustomCellRendererSize *cellsize = CUSTOM_CELL_RENDERER_SIZE (cell); |
305 | GdkPixbuf *pixbuf = NULL; |
306 | GdkRectangle all_rect; |
307 | GdkRectangle draw_rect; |
308 | |
309 | if(cellsize->size < 0) return; |
310 | |
311 | pixbuf = icon_get(ICON_CACHE_SIZE, cellsize->size); |
312 | if (!pixbuf) return; |
313 | |
314 | gint pix_width = gdk_pixbuf_get_width(pixbuf); |
315 | gint pix_height = gdk_pixbuf_get_height(pixbuf); |
316 | |
317 | |
318 | custom_cell_renderer_size_get_size (cell, widget, cell_area, |
319 | &all_rect.x, &all_rect.y, |
320 | &all_rect.width, &all_rect.height); |
321 | |
322 | all_rect.x += cell_area->x; |
323 | all_rect.y += cell_area->y; |
324 | |
325 | if (!gdk_rectangle_intersect (cell_area, &all_rect, &draw_rect) || |
326 | !gdk_rectangle_intersect (expose_area, &draw_rect, &draw_rect)) |
327 | return; |
328 | |
329 | /* do the text */ |
330 | PangoLayout *layout = new_layout(widget, size_str[cellsize->size]); |
331 | PangoRectangle rect; |
332 | pango_layout_get_pixel_extents(layout, NULL, &rect); |
333 | // printf("cell width = %d, text width = %d\n", all_rect.width, rect.width); |
334 | |
335 | int yoff = (all_rect.height - (rect.height + pix_height))/2; |
336 | |
337 | gtk_paint_layout(widget->style, window, GTK_STATE_NORMAL, |
338 | TRUE, expose_area, widget, "cellrenderersize", |
339 | all_rect.x + (all_rect.width - rect.width)/2, |
340 | all_rect.y + yoff, |
341 | layout); |
342 | |
343 | g_object_unref (layout); |
344 | |
345 | /* draw the bitmap */ |
346 | cairo_t *cr = gdk_cairo_create(window); |
347 | gdk_cairo_set_source_pixbuf(cr, pixbuf, |
348 | all_rect.x + (all_rect.width - pix_width)/2, |
349 | all_rect.y + rect.height + yoff); |
350 | gdk_cairo_rectangle(cr, &draw_rect); |
351 | cairo_fill(cr); |
352 | cairo_destroy(cr); |
353 | } |