hythmbox-2.98/widgets/rb-cell-renderer-rating.c

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 }