Contents of /trunk/src/custom_rating_renderer.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide 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 harbaum 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     }