No issues found
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * rb-cell-renderer-rating.c
4 *
5 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
6 * Copyright (C) 2002 Olivier Martin <olive.martin@gmail.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301 USA.
22 *
23 */
24
25 #include <config.h>
26
27 #include <stdlib.h>
28
29 #include <glib/gi18n.h>
30 #include <gtk/gtk.h>
31
32 #include "rb-cell-renderer-rating.h"
33 #include "rb-marshal.h"
34 #include "rb-rating-helper.h"
35
36 static void rb_cell_renderer_rating_get_property (GObject *object,
37 guint param_id,
38 GValue *value,
39 GParamSpec *pspec);
40 static void rb_cell_renderer_rating_set_property (GObject *object,
41 guint param_id,
42 const GValue *value,
43 GParamSpec *pspec);
44 static void rb_cell_renderer_rating_init (RBCellRendererRating *celltext);
45 static void rb_cell_renderer_rating_class_init (RBCellRendererRatingClass *class);
46 static void rb_cell_renderer_rating_get_size (GtkCellRenderer *cell,
47 GtkWidget *widget,
48 const GdkRectangle *rectangle,
49 gint *x_offset,
50 gint *y_offset,
51 gint *width,
52 gint *height);
53 static void rb_cell_renderer_rating_render (GtkCellRenderer *cell,
54 cairo_t *cr,
55 GtkWidget *widget,
56 const GdkRectangle *background_area,
57 const GdkRectangle *cell_area,
58 GtkCellRendererState flags);
59 static gboolean rb_cell_renderer_rating_activate (GtkCellRenderer *cell,
60 GdkEvent *event,
61 GtkWidget *widget,
62 const gchar *path,
63 const GdkRectangle *background_area,
64 const GdkRectangle *cell_area,
65 GtkCellRendererState flags);
66
67 struct RBCellRendererRatingPrivate
68 {
69 double rating;
70 };
71
72 struct RBCellRendererRatingClassPrivate
73 {
74 RBRatingPixbufs *pixbufs;
75 };
76
77 G_DEFINE_TYPE (RBCellRendererRating, rb_cell_renderer_rating, GTK_TYPE_CELL_RENDERER)
78 #define RB_CELL_RENDERER_RATING_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
79 RB_TYPE_CELL_RENDERER_RATING, \
80 RBCellRendererRatingPrivate))
81
82
83 /**
84 * SECTION:rb-cell-renderer-rating
85 * @short_description: a #GtkCellRenderer for displaying song ratings
86 *
87 * This cell renderer is used to display song ratings in the #RBEntryView,
88 * and allows the user to modify ratings directly in the track listing.
89 */
90
91 enum
92 {
93 PROP_0,
94 PROP_RATING
95 };
96
97 enum
98 {
99 RATED,
100 LAST_SIGNAL
101 };
102
103 static guint rb_cell_renderer_rating_signals[LAST_SIGNAL] = { 0 };
104
105 static void
106 rb_cell_renderer_rating_init (RBCellRendererRating *cellrating)
107 {
108
109 cellrating->priv = RB_CELL_RENDERER_RATING_GET_PRIVATE (cellrating);
110
111 /* set the renderer able to be activated */
112 g_object_set (cellrating,
113 "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
114 NULL);
115
116 /* create the needed icons */
117 }
118
119 static void
120 rb_cell_renderer_rating_class_init (RBCellRendererRatingClass *class)
121 {
122 GObjectClass *object_class = G_OBJECT_CLASS (class);
123 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
124
125 object_class->get_property = rb_cell_renderer_rating_get_property;
126 object_class->set_property = rb_cell_renderer_rating_set_property;
127
128 cell_class->get_size = rb_cell_renderer_rating_get_size;
129 cell_class->render = rb_cell_renderer_rating_render;
130 cell_class->activate = rb_cell_renderer_rating_activate;
131
132 class->priv = g_new0 (RBCellRendererRatingClassPrivate, 1);
133 class->priv->pixbufs = rb_rating_pixbufs_new ();
134
135 /**
136 * RBCellRendererRating:rating:
137 *
138 * The rating displayed by the renderer, as a floating point value
139 * between 0.0 and 5.0.
140 */
141 rb_rating_install_rating_property (object_class, PROP_RATING);
142
143 /**
144 * RBCellRendererRating::rated:
145 * @renderer: the #RBCellRendererRating
146 * @score: the new rating
147 * @path: string form of the #GtkTreePath to the row that was changed
148 *
149 * Emitted when the user changes the rating.
150 */
151 rb_cell_renderer_rating_signals[RATED] =
152 g_signal_new ("rated",
153 G_OBJECT_CLASS_TYPE (object_class),
154 G_SIGNAL_RUN_LAST,
155 G_STRUCT_OFFSET (RBCellRendererRatingClass, rated),
156 NULL, NULL,
157 rb_marshal_VOID__STRING_DOUBLE,
158 G_TYPE_NONE,
159 2,
160 G_TYPE_STRING,
161 G_TYPE_DOUBLE);
162
163 g_type_class_add_private (class, sizeof (RBCellRendererRatingPrivate));
164 }
165
166 static void
167 rb_cell_renderer_rating_get_property (GObject *object,
168 guint param_id,
169 GValue *value,
170 GParamSpec *pspec)
171 {
172 RBCellRendererRating *cellrating = RB_CELL_RENDERER_RATING (object);
173
174 switch (param_id) {
175 case PROP_RATING:
176 g_value_set_double (value, cellrating->priv->rating);
177 break;
178 default:
179 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
180 break;
181 }
182 }
183
184 static void
185 rb_cell_renderer_rating_set_property (GObject *object,
186 guint param_id,
187 const GValue *value,
188 GParamSpec *pspec)
189 {
190 RBCellRendererRating *cellrating= RB_CELL_RENDERER_RATING (object);
191
192 switch (param_id) {
193 case PROP_RATING:
194 cellrating->priv->rating = g_value_get_double (value);
195 if (cellrating->priv->rating < 0)
196 cellrating->priv->rating = 0;
197 break;
198 default:
199 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
200 break;
201 }
202 }
203
204 /**
205 * rb_cell_renderer_rating_new:
206 *
207 * create a cell renderer that will
208 * display some pixbufs for representing the rating of a song.
209 * It is also able to update the rating.
210 *
211 * Return value: the new cell renderer
212 **/
213 GtkCellRenderer *
214 rb_cell_renderer_rating_new ()
215 {
216 return GTK_CELL_RENDERER (g_object_new (rb_cell_renderer_rating_get_type (), NULL, NULL));
217 }
218
219 /* XXX implement get_preferred_height/width/height_for_width/width_for_height */
220 static void
221 rb_cell_renderer_rating_get_size (GtkCellRenderer *cell,
222 GtkWidget *widget,
223 const GdkRectangle *cell_area,
224 gint *x_offset,
225 gint *y_offset,
226 gint *width,
227 gint *height)
228 {
229 gint icon_width;
230 gint xpad, ypad;
231 RBCellRendererRating *cellrating = (RBCellRendererRating *) cell;
232
233 gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, NULL);
234 gtk_cell_renderer_get_padding (GTK_CELL_RENDERER (cellrating), &xpad, &ypad);
235
236 if (x_offset)
237 *x_offset = 0;
238
239 if (y_offset)
240 *y_offset = 0;
241
242 if (width)
243 *width = xpad * 2 + icon_width * RB_RATING_MAX_SCORE;
244
245 if (height)
246 *height = ypad * 2 + icon_width;
247 }
248
249 static void
250 rb_cell_renderer_rating_render (GtkCellRenderer *cell,
251 cairo_t *cr,
252 GtkWidget *widget,
253 const GdkRectangle *background_area,
254 const GdkRectangle *cell_area,
255 GtkCellRendererState flags)
256
257 {
258 gint xpad, ypad;
259 gboolean selected;
260 GdkRectangle pix_rect, draw_rect;
261 RBCellRendererRating *cellrating = (RBCellRendererRating *) cell;
262 RBCellRendererRatingClass *cell_class;
263
264 cellrating = RB_CELL_RENDERER_RATING (cell);
265 cell_class = RB_CELL_RENDERER_RATING_GET_CLASS (cellrating);
266 rb_cell_renderer_rating_get_size (cell, widget, cell_area,
267 &pix_rect.x,
268 &pix_rect.y,
269 &pix_rect.width,
270 &pix_rect.height);
271
272 pix_rect.x += cell_area->x;
273 pix_rect.y += cell_area->y;
274 gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
275 pix_rect.width -= xpad * 2;
276 pix_rect.height -= ypad * 2;
277
278 if (gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect) == FALSE)
279 return;
280
281 selected = (flags & GTK_CELL_RENDERER_SELECTED);
282
283 rb_rating_render_stars (widget, cr, cell_class->priv->pixbufs,
284 draw_rect.x - pix_rect.x,
285 draw_rect.y - pix_rect.y,
286 draw_rect.x, draw_rect.y,
287 cellrating->priv->rating, selected);
288 }
289
290 static gboolean
291 rb_cell_renderer_rating_activate (GtkCellRenderer *cell,
292 GdkEvent *event,
293 GtkWidget *widget,
294 const gchar *path,
295 const GdkRectangle *background_area,
296 const GdkRectangle *cell_area,
297 GtkCellRendererState flags)
298 {
299 int mouse_x, mouse_y;
300 double rating;
301
302 RBCellRendererRating *cellrating = (RBCellRendererRating *) cell;
303
304 g_return_val_if_fail (RB_IS_CELL_RENDERER_RATING (cellrating), FALSE);
305
306 gdk_window_get_device_position (gtk_widget_get_window (widget),
307 gdk_event_get_source_device (event),
308 &mouse_x,
309 &mouse_y,
310 NULL);
311 gtk_tree_view_convert_widget_to_bin_window_coords (GTK_TREE_VIEW (widget),
312 mouse_x, mouse_y,
313 &mouse_x, &mouse_y);
314
315 rating = rb_rating_get_rating_from_widget (widget,
316 mouse_x - cell_area->x,
317 cell_area->width,
318 cellrating->priv->rating);
319
320 if (rating != -1.0) {
321 g_signal_emit (G_OBJECT (cellrating),
322 rb_cell_renderer_rating_signals[RATED],
323 0, path, rating);
324 }
325
326 return TRUE;
327 }