Contents of /trunk/src/custom_rating_renderer.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Sat Jun 20 11:08:47 2009 UTC (14 years, 11 months ago) by harbaum
File MIME type: text/plain
File size: 13885 byte(s)
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_rating_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_rating_init (CustomCellRendererRating *cellrating);
36 static void custom_cell_renderer_rating_class_init (CustomCellRendererRatingClass *klass);
37 static void custom_cell_renderer_rating_get_property (GObject *object,
38 guint param_id,
39 GValue *value,
40 GParamSpec *pspec);
41 static void custom_cell_renderer_rating_set_property (GObject *object,
42 guint param_id,
43 const GValue *value,
44 GParamSpec *pspec);
45 static void custom_cell_renderer_rating_finalize (GObject *gobject);
46
47
48 /* These functions are the heart of our custom cell renderer: */
49
50 static void custom_cell_renderer_rating_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_rating_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_RATING = 1, };
68
69 static gpointer parent_class;
70
71 GType custom_cell_renderer_rating_get_type (void) {
72 static GType cell_rating_type = 0;
73
74 if (cell_rating_type == 0)
75 {
76 static const GTypeInfo cell_rating_info =
77 {
78 sizeof (CustomCellRendererRatingClass),
79 NULL, /* base_init */
80 NULL, /* base_finalize */
81 (GClassInitFunc) custom_cell_renderer_rating_class_init,
82 NULL, /* class_finalize */
83 NULL, /* class_data */
84 sizeof (CustomCellRendererRating),
85 0, /* n_preallocs */
86 (GInstanceInitFunc) custom_cell_renderer_rating_init,
87 };
88
89 /* Derive from GtkCellRenderer */
90 cell_rating_type = g_type_register_static (GTK_TYPE_CELL_RENDERER,
91 "CustomCellRendererRating",
92 &cell_rating_info,
93 0);
94 }
95 return cell_rating_type;
96 }
97
98
99 /***************************************************************************
100 *
101 * custom_cell_renderer_rating_init: set some default properties of the
102 * parent (GtkCellRenderer).
103 *
104 ***************************************************************************/
105
106 static void
107 custom_cell_renderer_rating_init (CustomCellRendererRating *cellrendererrating)
108 {
109 GTK_CELL_RENDERER(cellrendererrating)->mode = GTK_CELL_RENDERER_MODE_INERT;
110 GTK_CELL_RENDERER(cellrendererrating)->xpad = 0;
111 GTK_CELL_RENDERER(cellrendererrating)->ypad = 0;
112 }
113
114
115 /***************************************************************************
116 *
117 * custom_cell_renderer_rating_class_init:
118 *
119 * set up our own get_property and set_property functions, and
120 * override the parent's functions that we need to implement.
121 * And make our new "size" property known to the type system.
122 * If you want cells that can be activated on their own (ie. not
123 * just the whole row selected) or cells that are editable, you
124 * will need to override 'activate' and 'start_editing' as well.
125 *
126 ***************************************************************************/
127
128 static void
129 custom_cell_renderer_rating_class_init (CustomCellRendererRatingClass *klass) {
130 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(klass);
131 GObjectClass *object_class = G_OBJECT_CLASS(klass);
132
133 parent_class = g_type_class_peek_parent (klass);
134 object_class->finalize = custom_cell_renderer_rating_finalize;
135
136 /* Hook up functions to set and get our
137 * custom cell renderer properties */
138 object_class->get_property = custom_cell_renderer_rating_get_property;
139 object_class->set_property = custom_cell_renderer_rating_set_property;
140
141 /* Override the two crucial functions that are the heart
142 * of a cell renderer in the parent class */
143 cell_class->get_size = custom_cell_renderer_rating_get_size;
144 cell_class->render = custom_cell_renderer_rating_render;
145
146 /* Install our very own properties */
147 g_object_class_install_property (object_class, PROP_RATING,
148 g_param_spec_int ("rating", "Rating", "Cache rating", 0, 1600, 0,
149 G_PARAM_READWRITE));
150 }
151
152
153 /***************************************************************************
154 *
155 * custom_cell_renderer_rating_finalize: free any resources here
156 *
157 ***************************************************************************/
158
159 static void custom_cell_renderer_rating_finalize (GObject *object) {
160 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
161 }
162
163
164 /***************************************************************************
165 *
166 * custom_cell_renderer_rating_get_property: as it says
167 *
168 ***************************************************************************/
169
170 static void
171 custom_cell_renderer_rating_get_property (GObject *object,
172 guint param_id,
173 GValue *value,
174 GParamSpec *psec) {
175 CustomCellRendererRating *cellrating = CUSTOM_CELL_RENDERER_RATING(object);
176
177 switch (param_id) {
178 case PROP_RATING:
179 g_value_set_int(value, 100 * cellrating->difficulty + cellrating->terrain);
180 break;
181
182 default:
183 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, psec);
184 break;
185 }
186 }
187
188
189 /***************************************************************************
190 *
191 * custom_cell_renderer_rating_set_property: as it says
192 *
193 ***************************************************************************/
194
195 static void
196 custom_cell_renderer_rating_set_property (GObject *object,
197 guint param_id,
198 const GValue *value,
199 GParamSpec *pspec) {
200 CustomCellRendererRating *cellrating = CUSTOM_CELL_RENDERER_RATING (object);
201
202 switch (param_id) {
203 case PROP_RATING:
204 {
205 int i = g_value_get_int(value);
206 cellrating->difficulty = i / 100;
207 cellrating->terrain = i % 100;
208 }
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_rating_new: return a new cell renderer instance
220 *
221 ***************************************************************************/
222
223 GtkCellRenderer *custom_cell_renderer_rating_new (void) {
224 return g_object_new(CUSTOM_TYPE_CELL_RENDERER_RATING, 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 char tmp[48];
232 snprintf(tmp, sizeof(tmp), "<span size=\"xx-small\">%s</span>", str);
233 PangoLayout *layout = gtk_widget_create_pango_layout(widget, NULL);
234 pango_layout_set_markup(layout, tmp, strlen(tmp));
235 return layout;
236 #endif
237 }
238
239 static void
240 custom_cell_renderer_rating_get_size (GtkCellRenderer *cell,
241 GtkWidget *widget, GdkRectangle *cell_area, gint *x_offset,
242 gint *y_offset, gint *width, gint *height) {
243 GdkPixbuf *pixbuf = icon_get(ICON_STARS, 0); // all icons have the same size
244 /* do the text */
245 PangoLayout *layout = new_layout(widget, "D:");
246 PangoRectangle rect;
247 pango_layout_get_pixel_extents(layout, NULL, &rect);
248 g_object_unref (layout);
249
250 /* width is text width + icon width */
251 gint calc_width = (gint)gdk_pixbuf_get_width(pixbuf) + rect.width;
252 /* height is 2*MAX(icon-height, text-height) */
253 gint calc_height = (gint) 2 * MAX(gdk_pixbuf_get_height(pixbuf), rect.height);
254
255 if (x_offset) *x_offset = 0;
256 if (y_offset) *y_offset = 0;
257
258 if (cell_area) {
259 if (x_offset)
260 *x_offset = (cell_area->width - calc_width)/2;
261
262 if (y_offset)
263 *y_offset = (cell_area->height - calc_height)/2;
264 }
265
266 if (width) *width = calc_width;
267 if (height) *height = calc_height;
268 }
269
270
271 /***************************************************************************
272 *
273 * custom_cell_renderer_rating_render: crucial - do the rendering.
274 *
275 ***************************************************************************/
276
277 static void
278 custom_cell_renderer_rating_render (GtkCellRenderer *cell,
279 GdkWindow *window,
280 GtkWidget *widget,
281 GdkRectangle *background_area,
282 GdkRectangle *cell_area,
283 GdkRectangle *expose_area,
284 guint flags)
285 {
286 CustomCellRendererRating *cellrating = CUSTOM_CELL_RENDERER_RATING (cell);
287 GdkPixbuf *dpixbuf = icon_get(ICON_STARS, cellrating->difficulty);
288 GdkPixbuf *tpixbuf = icon_get(ICON_STARS, cellrating->terrain);
289 GdkRectangle all_rect;
290 GdkRectangle draw_rect;
291
292 gint pix_width = gdk_pixbuf_get_width(dpixbuf);
293 gint pix_height = gdk_pixbuf_get_height(dpixbuf);
294
295 if ((!dpixbuf) || (!tpixbuf)) return;
296
297 custom_cell_renderer_rating_get_size (cell, widget, cell_area,
298 &all_rect.x, &all_rect.y,
299 &all_rect.width, &all_rect.height);
300
301 all_rect.x += cell_area->x;
302 all_rect.y += cell_area->y;
303
304 if (!gdk_rectangle_intersect (cell_area, &all_rect, &draw_rect) ||
305 !gdk_rectangle_intersect (expose_area, &draw_rect, &draw_rect))
306 return;
307
308 /* do the text */
309 PangoLayout *tlayout = new_layout(widget, "T:");
310 PangoLayout *dlayout = new_layout(widget, "D:");
311 PangoRectangle text_rect;
312 pango_layout_get_pixel_extents(dlayout, NULL, &text_rect);
313
314 int xoff = (all_rect.width - (text_rect.width + pix_width))/2;
315 if(xoff < 0) xoff = 0;
316 int yoff = all_rect.height/2 - MAX(text_rect.height, pix_height);
317
318 /* if text is heigher, icon needs additional vertical offset and vice versa */
319 int tyoff = 0, iyoff = 0;
320
321 if(text_rect.height > pix_height) iyoff = (text_rect.height - pix_height)/2;
322 else tyoff = (pix_height - text_rect.height)/2;
323
324 gtk_paint_layout(widget->style, window, GTK_STATE_NORMAL,
325 TRUE, expose_area, widget, "cellrendererrating",
326 all_rect.x + xoff, all_rect.y + yoff + tyoff, dlayout);
327
328 gtk_paint_layout(widget->style, window, GTK_STATE_NORMAL,
329 TRUE, expose_area, widget, "cellrendererrating",
330 all_rect.x + xoff, all_rect.y + MAX(text_rect.height, pix_height) + yoff + tyoff, tlayout);
331
332 g_object_unref(dlayout);
333 g_object_unref(tlayout);
334
335 /* draw the bitmap */
336 cairo_t *cr = gdk_cairo_create(window);
337 gdk_cairo_set_source_pixbuf(cr, dpixbuf,
338 all_rect.x + xoff + text_rect.width,
339 all_rect.y + yoff + iyoff);
340 gdk_cairo_rectangle(cr, &draw_rect);
341 cairo_fill(cr);
342
343 gdk_cairo_set_source_pixbuf(cr, tpixbuf,
344 all_rect.x + xoff + text_rect.width,
345 all_rect.y + MAX(text_rect.height, pix_height) + yoff + iyoff);
346 gdk_cairo_rectangle(cr, &draw_rect);
347 cairo_fill(cr);
348
349 cairo_destroy(cr);
350 }