Merge lp:~sgringwe/beat-box/rating-merge into lp:beat-box

Proposed by Scott Ringwelski
Status: Merged
Merged at revision: 621
Proposed branch: lp:~sgringwe/beat-box/rating-merge
Merge into: lp:beat-box
Diff against target: 780 lines (+420/-135)
11 files modified
src/Lists/GenericList.vala (+18/-2)
src/Lists/MusicList.vala (+2/-2)
src/Lists/PodcastList.vala (+2/-2)
src/Lists/RadioList.vala (+2/-2)
src/Views/NowPlayingView.vala (+1/-1)
src/Views/PopupListView.vala (+1/-1)
src/Widgets/InfoPanel.vala (+1/-1)
src/Widgets/RatingWidget.vala (+390/-121)
src/Windows/Editors/PodcastEditor.vala (+1/-1)
src/Windows/Editors/SongEditor.vala (+1/-1)
src/Windows/Editors/StationEditor.vala (+1/-1)
To merge this branch: bzr merge lp:~sgringwe/beat-box/rating-merge
Reviewer Review Type Date Requested Status
Victor Martinez (community) Approve
Review via email: mp+111132@code.launchpad.net

Description of the change

Merged your new rating widget.
I'm holding off on using the renderer though because it needs to behave as the widget does when hovering, otherwise it feels odd.

To post a comment you must log in.
Revision history for this message
Victor Martinez (victored) wrote :

Looks fine to me. I can implement the on-hover stuff by letting the renderer be aware of the treeview or treeview column. Well, that's for later.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Lists/GenericList.vala'
2--- src/Lists/GenericList.vala 2012-06-02 19:34:06 +0000
3+++ src/Lists/GenericList.vala 2012-06-20 02:00:29 +0000
4@@ -140,8 +140,11 @@
5 insert_column_with_data_func(-1, tvc.title, new CellRendererText(), cellHelper.dateTreeViewFiller);
6 else if(tvc.title == "Last Played")
7 insert_column_with_data_func(-1, tvc.title, new CellRendererText(), cellHelper.dateTreeViewFiller);
8- else if(tvc.title == "Rating")
9- insert_column_with_data_func(-1, tvc.title, new CellRendererPixbuf(), cellHelper.ratingTreeViewFiller);
10+ else if(tvc.title == "Rating") {
11+ //var rating_renderer = new CellRendererRating();
12+ //rating_renderer.rating_changed.connect(on_rating_cell_changed);
13+ insert_column_with_data_func(-1, tvc.title, new CellRendererPixbuf() , cellHelper.ratingTreeViewFiller);
14+ }
15 else if(tvc.title == "Year")
16 insert_column_with_data_func(-1, tvc.title, new CellRendererText(), cellHelper.intelligentTreeViewFiller);
17 else if(tvc.title == "#")
18@@ -290,6 +293,19 @@
19 }
20 }
21
22+ // When the user clicks over a cell in the rating column, that cell renderer
23+ // emits the rating_changed signal. We need to update that rating...
24+ /*void on_rating_cell_changed (int new_rating, Gtk.Widget widget, string path, Gtk.CellRendererState flags) {
25+ var m = get_media_from_index(int.parse(path));
26+
27+ if(m == null)
28+ return;
29+
30+ m.rating = new_rating;
31+
32+ lm.update_media(m, true, true, true);
33+ }*/
34+
35 public void* take_action () {
36 Media s = get_selected_medias().nth_data(0);
37 if(s == null)
38
39=== modified file 'src/Lists/MusicList.vala'
40--- src/Lists/MusicList.vala 2012-06-18 21:45:00 +0000
41+++ src/Lists/MusicList.vala 2012-06-20 02:00:29 +0000
42@@ -49,7 +49,7 @@
43 Gtk.MenuItem mediaMenuQueue;
44 Gtk.MenuItem mediaMenuNewPlaylist;
45 Gtk.MenuItem mediaMenuAddToPlaylist; // make menu on fly
46- RatingWidgetMenu mediaRateMedia;
47+ RatingMenuItem mediaRateMedia;
48 Gtk.MenuItem mediaRemove;
49 Gtk.MenuItem importToLibrary;
50 Gtk.MenuItem mediaScrollToCurrent;
51@@ -231,7 +231,7 @@
52 mediaRemove = new Gtk.MenuItem.with_label(_("Remove Song"));
53 importToLibrary = new Gtk.MenuItem.with_label(_("Import to Library"));
54 mediaScrollToCurrent = new Gtk.MenuItem.with_label(_("Scroll to Current Song"));
55- mediaRateMedia = new RatingWidgetMenu();
56+ mediaRateMedia = new RatingMenuItem();
57 mediaMenuActionMenu.append(mediaEditMedia);
58 mediaMenuActionMenu.append(mediaFileBrowse);
59 mediaMenuActionMenu.append(mediaRateMedia);
60
61=== modified file 'src/Lists/PodcastList.vala'
62--- src/Lists/PodcastList.vala 2012-06-18 21:45:00 +0000
63+++ src/Lists/PodcastList.vala 2012-06-20 02:00:29 +0000
64@@ -46,7 +46,7 @@
65 Gtk.MenuItem mediaMenuQueue;
66 Gtk.MenuItem mediaMenuNewPlaylist;
67 Gtk.MenuItem mediaMenuAddToPlaylist; // make menu on fly
68- RatingWidgetMenu mediaRateMedia;
69+ RatingMenuItem mediaRateMedia;
70 Gtk.MenuItem mediaRemove;
71 Gtk.MenuItem mediaSaveLocally;
72 Gtk.MenuItem importToLibrary;
73@@ -164,7 +164,7 @@
74 mediaRemove = new Gtk.MenuItem.with_label(_("Remove Episode"));
75 mediaSaveLocally = new Gtk.MenuItem.with_label(_("Download"));
76 importToLibrary = new Gtk.MenuItem.with_label(_("Import to Library"));
77- mediaRateMedia = new RatingWidgetMenu();
78+ mediaRateMedia = new RatingMenuItem();
79 mediaMenuActionMenu.append(mediaEditMedia);
80 mediaMenuActionMenu.append(mediaFileBrowse);
81 mediaMenuActionMenu.append(mediaSaveLocally);
82
83=== modified file 'src/Lists/RadioList.vala'
84--- src/Lists/RadioList.vala 2012-06-01 22:48:28 +0000
85+++ src/Lists/RadioList.vala 2012-06-20 02:00:29 +0000
86@@ -34,7 +34,7 @@
87 Gtk.Menu mediaMenuActionMenu;
88 Gtk.MenuItem mediaEditMedia;
89 Gtk.MenuItem mediaRemove;
90- RatingWidgetMenu mediaRateMedia;
91+ RatingMenuItem mediaRateMedia;
92
93 public enum RadioColumn {
94 ROWID = 0,
95@@ -100,7 +100,7 @@
96 mediaMenuActionMenu = new Gtk.Menu();
97 mediaEditMedia = new Gtk.MenuItem.with_label(_("Edit Station"));
98 mediaRemove = new Gtk.MenuItem.with_label(_("Remove Station"));
99- mediaRateMedia = new RatingWidgetMenu();
100+ mediaRateMedia = new RatingMenuItem();
101 mediaMenuActionMenu.append(mediaEditMedia);
102 mediaMenuActionMenu.append(mediaRateMedia);
103 mediaMenuActionMenu.append(new SeparatorMenuItem());
104
105=== modified file 'src/Views/NowPlayingView.vala'
106--- src/Views/NowPlayingView.vala 2012-06-13 23:54:06 +0000
107+++ src/Views/NowPlayingView.vala 2012-06-20 02:00:29 +0000
108@@ -208,7 +208,7 @@
109 HBox rate_box = new HBox(false, 0);
110 loveMedia = new Button();
111 banMedia = new Button();
112- rating = new RatingWidget(null, true, IconSize.MENU);
113+ rating = new RatingWidget(true, IconSize.MENU, false, null);
114 meta_year = new Label("");
115 summary_text = new Label("");
116 lyrics = new Label("");
117
118=== modified file 'src/Views/PopupListView.vala'
119--- src/Views/PopupListView.vala 2012-06-01 22:48:28 +0000
120+++ src/Views/PopupListView.vala 2012-06-20 02:00:29 +0000
121@@ -162,7 +162,7 @@
122 list_scroll.add(list);
123
124 // add rating
125- rating = new RatingWidget(get_style_context(), true, IconSize.BUTTON, true);
126+ rating = new RatingWidget(true, IconSize.BUTTON, true, get_style_context());
127 rating.set_transparent (true);
128
129 var all_area = new Box(Orientation.VERTICAL, 0);
130
131=== modified file 'src/Widgets/InfoPanel.vala'
132--- src/Widgets/InfoPanel.vala 2012-06-01 22:48:28 +0000
133+++ src/Widgets/InfoPanel.vala 2012-06-20 02:00:29 +0000
134@@ -67,7 +67,7 @@
135 banMedia = new Button();
136 coverArt = new Gtk.Image();
137 coverArt.set_size_request (Icons.ALBUM_VIEW_IMAGE_SIZE, Icons.ALBUM_VIEW_IMAGE_SIZE);
138- rating = new RatingWidget(null, true, IconSize.MENU);
139+ rating = new RatingWidget(true, IconSize.MENU, false, null);
140 album = new Label("Album");
141 year = new Label("Year");
142 ssv = new SimilarMediasView(lm, lw);
143
144=== modified file 'src/Widgets/RatingWidget.vala'
145--- src/Widgets/RatingWidget.vala 2012-05-03 04:19:07 +0000
146+++ src/Widgets/RatingWidget.vala 2012-06-20 02:00:29 +0000
147@@ -1,8 +1,9 @@
148+// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
149 /*-
150- * Copyright (c) 2011-2012 Scott Ringwelski <sgringwe@mtu.edu>
151+ * Copyright (c) 2012 BeatBox Developers
152 *
153- * Originally Written by Scott Ringwelski for BeatBox Music Player
154- * BeatBox Music Player: http://www.launchpad.net/beat-box
155+ * Originally written by Lucas Baudin for BeatBox Music Player
156+ * BeatBox Music Player: http://launchpad.net/beat-box
157 *
158 * This library is free software; you can redistribute it and/or
159 * modify it under the terms of the GNU Library General Public
160@@ -18,36 +19,73 @@
161 * License along with this library; if not, write to the
162 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
163 * Boston, MA 02111-1307, USA.
164+ *
165+ * Authored by: Lucas Baudin <xapantu@gmail.com>
166+ * Victor Eduardo <victoreduardm@gmail.com>
167 */
168-using Cairo;
169-using Gtk;
170-using Gdk;
171
172+// When/if this widget ends up in Granite, we will use that.
173+// Until then, follow normal BeatBox class naming scheme.
174 public class BeatBox.RatingWidget : Gtk.EventBox {
175- internal int rating;
176-
177- private int hover_rating;
178-
179- private bool centered;
180- private bool menuItem;
181- private Pixbuf _canvas;
182- private Pixbuf not_starred;
183- private Pixbuf starred;
184-
185- public signal void rating_changed(int new_rating);
186-
187- public RatingWidget(Gtk.StyleContext? context, bool centered, IconSize size, bool symbolic = false) {
188+
189+ public signal void rating_changed (int new_rating);
190+
191+ private bool symbolic = false;
192+ private Gtk.IconSize size = Gtk.IconSize.MENU;
193+ private Gtk.StyleContext? context = null;
194+
195+ private int rating = 0;
196+ private int hover_rating = 0;
197+ private int n_stars = 5;
198+ private int spacing = 0;
199+
200+ private int item_width = -1;
201+ private int item_height = -1;
202+
203+ private bool centered = false;
204+ protected bool is_menu_item = false;
205+
206+ private Gdk.Pixbuf _canvas;
207+ private Gdk.Pixbuf not_starred;
208+ private Gdk.Pixbuf starred;
209+
210+ /**
211+ * It's not necessary to set a context. In most cases it should be 'null'.
212+ */
213+ public RatingWidget (bool centered, Gtk.IconSize size, bool symbolic = false, Gtk.StyleContext? ctx = null) {
214 this.centered = centered;
215-
216- if (context != null) {
217- menuItem = context.has_class (Gtk.STYLE_CLASS_MENUITEM);
218- Gdk.RGBA color = context.get_background_color(Gtk.StateFlags.NORMAL);
219- set_background_color (color);
220- } else {
221- menuItem = false;
222- set_transparent (true);
223- }
224-
225+ this.symbolic = symbolic;
226+ this.size = size;
227+
228+ if (ctx != null)
229+ this.context = ctx;
230+ else
231+ this.context = get_style_context ();
232+
233+ this.context.changed.connect (render_stars);
234+
235+ this.is_menu_item = this.context.has_class (Gtk.STYLE_CLASS_MENUITEM);
236+
237+ set_transparent (true);
238+ render_stars ();
239+
240+ // this handles size allocation and connects the draw signal as well
241+ set_star_spacing (3);
242+
243+ // force a redraw...
244+ redraw ();
245+
246+ add_events(Gdk.EventMask.BUTTON_PRESS_MASK
247+ | Gdk.EventMask.BUTTON_RELEASE_MASK
248+ | Gdk.EventMask.POINTER_MOTION_MASK
249+ | Gdk.EventMask.LEAVE_NOTIFY_MASK);
250+
251+ button_press_event.connect (on_button_press);
252+ state_flags_changed.connect (render_stars);
253+ }
254+
255+ private void render_stars () {
256+ // TODO: This needs to be icon-system-independent in order to be included in Granite.
257 if (symbolic) {
258 starred = Icons.STARRED_SYMBOLIC.render (size, context);
259 not_starred = Icons.NOT_STARRED_SYMBOLIC.render (size, context);
260@@ -57,92 +95,155 @@
261 not_starred = Icons.NOT_STARRED.render (size, null);
262 }
263
264- width_request = starred.width * 5;
265- height_request = starred.height;
266- _canvas = new Gdk.Pixbuf(Gdk.Colorspace.RGB, true, 8, width_request, height_request);
267-
268- set_rating(0);
269- updateRating(0);
270-
271- add_events(Gdk.EventMask.BUTTON_PRESS_MASK
272- | Gdk.EventMask.BUTTON_RELEASE_MASK
273- | Gdk.EventMask.POINTER_MOTION_MASK
274- | Gdk.EventMask.LEAVE_NOTIFY_MASK);
275- //motion_notify_event.connect(mouseOver);
276- button_press_event.connect(buttonPress);
277- draw.connect(exposeEvent);
278+ redraw ();
279+ }
280+
281+ internal Gdk.Pixbuf get_canvas () {
282+ return _canvas;
283 }
284
285 public void set_background_color (Gdk.RGBA color) {
286 override_background_color (Gtk.StateFlags.NORMAL, color);
287 override_background_color (Gtk.StateFlags.ACTIVE, color);
288 override_background_color (Gtk.StateFlags.PRELIGHT, color);
289+ redraw ();
290 }
291
292- public void set_transparent (bool val) {
293- // Make the eventbox transparent
294+ public void set_transparent (bool val) {
295+ // Make the eventbox transparent
296 this.set_above_child (val);
297 this.set_visible_window (!val);
298- }
299-
300- public override bool leave_notify_event(Gdk.EventCrossing ev) {
301- updateRating(rating);
302- return true;
303- }
304-
305- public void set_rating(int new_rating) {
306+ }
307+
308+ public void set_star_spacing (int spacing) {
309+ if (spacing < 0) {
310+ warning ("Spacing values must be equal or greater than 0");
311+ return;
312+ }
313+
314+ draw.disconnect (on_expose_event);
315+
316+ this.spacing = spacing;
317+
318+ // Decide size
319+ item_width = (starred.width > not_starred.width) ? starred.width : not_starred.width;
320+ item_height = (starred.height > not_starred.height) ? starred.height : not_starred.height;
321+
322+ width_request = item_width * n_stars + spacing * (n_stars - 1);
323+ height_request = item_height;
324+
325+ // Generate canvas pixbuf
326+ _canvas = new Gdk.Pixbuf (Gdk.Colorspace.RGB, true, 8, width_request, height_request);
327+
328+ draw.connect (on_expose_event);
329+
330+ redraw ();
331+ }
332+
333+ public void redraw () {
334+ // No need to duplicate code. update_rating() does exactly this
335+ // and also calls queue_draw().
336+ update_rating (rating);
337+ }
338+
339+ public int get_star_spacing () {
340+ return spacing;
341+ }
342+
343+ public void set_rating (int new_rating) {
344 if(rating == new_rating)
345 return;
346
347- rating = (new_rating > 5)? 5 : new_rating;
348- updateRating(rating);
349+ rating = (new_rating > n_stars) ? n_stars : new_rating;
350+ update_rating(rating);
351 rating_changed(rating);
352 }
353
354- public int get_rating() {
355+ public int get_rating () {
356 return rating;
357 }
358
359- /** just draw new rating **/
360- public override bool motion_notify_event(EventMotion event) {
361- hover_rating = get_new_rating(event.x);
362- updateRating(hover_rating);
363+ /**
364+ * Returns the total number of stars. It also represents the maximum possible rating.
365+ *
366+ * @return total number of stars.
367+ */
368+ public int get_n_stars () {
369+ return n_stars;
370+ }
371+
372+ /**
373+ * Sets the total number of stars. It also represents the maximum rating possible.
374+ * That is, possible ratings are between 0 and n_stars.
375+ *
376+ * @param n_stars total number of stars. Allowed values: >= 0. Default: 5.
377+ */
378+ public void set_n_stars (int n_stars) {
379+ if (this.n_stars == n_stars)
380+ return;
381+
382+ if (n_stars <= 0) {
383+ warning ("The number of stars must be greater than 0");
384+ return;
385+ }
386+
387+ this.n_stars = n_stars;
388+
389+ // Validate and potentially redraw current rating just in case...
390+ set_rating (rating);
391+
392+ // Allocate new area
393+ set_star_spacing (this.spacing);
394+
395+ redraw ();
396+ }
397+
398+
399+ /** Just draw new rating. Needed by menuitems **/
400+ public override bool motion_notify_event (Gdk.EventMotion event) {
401+ hover_rating = get_new_rating (event.x);
402+ update_rating (hover_rating);
403 return true;
404 }
405
406 /** draw new rating AND update rating **/
407- public virtual bool buttonPress(Gdk.EventButton event) {
408- set_rating(hover_rating);
409- return true;
410- }
411-
412- public void updateRating(int fake_rating) {
413- _canvas.fill((uint) 0xffffff00);
414-
415- /* generate the canvas image */
416-
417- for (int i = 0; i < 5; i++) {
418- if (i < fake_rating) {
419- starred.copy_area(0, 0, starred.width, starred.height, _canvas, i * starred.width, 0);
420- }
421- else {
422- not_starred.copy_area(0, 0, not_starred.width, not_starred.height, _canvas, i * not_starred.width, 0);
423- }
424- }
425-
426- queue_draw();
427+ public virtual bool on_button_press (Gdk.EventButton event) {
428+ set_rating (hover_rating);
429+ return true;
430+ }
431+
432+ public override bool leave_notify_event (Gdk.EventCrossing ev) {
433+ update_rating (rating);
434+ return true;
435+ }
436+
437+ internal void update_rating (int fake_rating) {
438+ if (_canvas == null)
439+ return;
440+
441+ _canvas.fill ((uint)0xffffff00);
442+
443+ /* generate the canvas image */
444+ for (int i = 0; i < n_stars; i++) {
445+ if (i < fake_rating)
446+ starred.copy_area (0, 0, item_width, item_height, _canvas, i * (item_width + (i > 0 ? spacing : 0)), 0);
447+ else
448+ not_starred.copy_area (0, 0, item_width, item_height, _canvas, i * (item_width + (i > 0 ? spacing : 0)), 0);
449 }
450
451+ queue_draw();
452+ }
453+
454 /** @override on_expose_event to paint our own custom widget **/
455- public virtual bool exposeEvent(Cairo.Context cairo) {
456- Allocation al;
457+ public virtual bool on_expose_event (Cairo.Context cairo) {
458+ Gtk.Allocation al;
459 get_allocation(out al);
460
461 if(centered) {
462- Gdk.cairo_set_source_pixbuf(cairo, _canvas, (al.width - width_request) / 2, (al.height - height_request) / 2);
463+ Gdk.cairo_set_source_pixbuf (cairo, _canvas, (al.width - width_request) / 2, (al.height - height_request) / 2);
464 }
465 else {
466- Gdk.cairo_set_source_pixbuf(cairo, _canvas, 0, 0);
467+ Gdk.cairo_set_source_pixbuf (cairo, _canvas, 0, (al.height - height_request) / 2);
468 }
469
470 cairo.paint();
471@@ -150,65 +251,233 @@
472 return true;
473 }
474
475- private int get_new_rating(double x) {
476+
477+ /**
478+ * Returns a new rating value between 0 and n_stars based on the cursor position
479+ * (relative to the left side of the widget - x=0).
480+ *
481+ * LEGEND:
482+ * X : A STAR
483+ * - : SPACE
484+ *
485+ * | x_offset | | spacing | | spacing | | spacing | | spacing ... | remaining space...
486+ * <-------------> X --------- X --------- X --------- X --------- ... X ------------->
487+ * ... 0 stars | 1 star | 2 stars | 3 stars | 4 stars ...| n_stars stars...
488+ *
489+ * The first row in the graphic above represents the values involved:
490+ * - x_offset : the value added in front of the first star.
491+ * - spacing : space inserted between stars.
492+ * - n_stars : total number of stars. It also represents the maximum rating.
493+ *
494+ * If you want the next star to be activated when the cursor is at least halfway
495+ * towards it, just modify x_offset. It should be similar for other cases as well.
496+ *
497+ * For instance:
498+ *
499+ * x_offset = ... // compute offset
500+ * x_offset -= spacing / 2;
501+ *
502+ * Now the next rating will start halfway earlier, rather than at the start of every star
503+ * (as shown in the representation above). Don't modify other values for this purpose!
504+ */
505+
506+ internal int get_new_rating (double x) {
507+ int x_offset = 0;
508+
509+ if (centered) {
510+ Gtk.Allocation al;
511+ get_allocation(out al);
512+ x_offset = (al.width - width_request) / 2;
513+ }
514+
515+ if (is_menu_item) // Workaround. Move the offset one star to the left for menuitems.
516+ x_offset += (item_width + spacing);
517+
518+ // If you want the next rating (value, not actual star!) to begin in the middle
519+ // between two stars, use:
520+ // x_offset -= (int) ((double)spacing / (1.0 - 1.0 / 2.0));
521+ // For it to start when the cursor is 2/3 towards the next rating, use:
522+ // x_offset -= (int) ((double)spacing * (1.0 - 2.0/3.0));
523+ // In general:
524+ // x_offset -= (int) ((double)spacing * (1.0 - f_num / f_den));
525+
526+ int cursor_x_pos = (int)x;
527 int new_rating = 0;
528
529- Allocation al;
530- get_allocation(out al);
531-
532- int offset = 0;
533- if(centered)
534- offset = (al.width - width_request) / 2;
535- else if(menuItem)
536- offset = (4 * starred.width) / 3;
537-
538- if((int)x - offset > 5)
539- new_rating = ((int)x - offset + 12) / starred.width;
540- else
541- new_rating = 0;
542+ for (int i = 0; i < n_stars; i++) {
543+ if (cursor_x_pos > x_offset + i * (item_width + spacing))
544+ new_rating ++;
545+ }
546
547 return new_rating;
548 }
549 }
550
551-public class BeatBox.RatingWidgetMenu : Gtk.MenuItem {
552- RatingWidget rating;
553- public bool already_drawn = false;
554+
555+public class BeatBox.RatingMenuItem : Gtk.MenuItem {
556+
557+ protected RatingWidget rating;
558
559 public int rating_value {
560 get {
561- return rating.get_rating();
562+ return rating.get_rating ();
563 }
564 set {
565- rating.set_rating(value);
566+ rating.set_rating (value);
567 }
568 }
569
570- public RatingWidgetMenu() {
571- get_style_context().add_class(Gtk.STYLE_CLASS_MENU);
572- rating = new RatingWidget(get_style_context(), false, IconSize.MENU);
573- add(rating);
574- }
575+ public RatingMenuItem () {
576+ rating = new RatingWidget (false, Gtk.IconSize.MENU, false, get_style_context ());
577+ add (rating);
578+
579+ // Force the NORMAL state flag
580+ this.state_flags_changed.connect ( () => {
581+ var current_flags = this.get_state_flags ();
582+ if (current_flags != Gtk.StateFlags.NORMAL)
583+ unset_state_flags (current_flags);
584+ });
585+ }
586+
587+ public void set_background_color (Gdk.RGBA color) {
588+ rating.set_background_color (color);
589+ }
590+
591+ public void set_transparent (bool val) {
592+ rating.set_transparent (val);
593+ }
594+
595+ public void set_star_spacing (int spacing) {
596+ rating.set_star_spacing (spacing);
597+ }
598+
599+ public int get_rating () {
600+ return rating.get_rating ();
601+ }
602+
603+ public void set_rating (int new_rating) {
604+ rating.set_rating (new_rating);
605+ }
606+
607+ public int get_star_spacing () {
608+ return rating.get_star_spacing ();
609+ }
610+
611+ public void set_n_stars (int n_stars) {
612+ rating.set_n_stars (n_stars);
613+ }
614+
615+ public int get_n_stars () {
616+ return rating.get_n_stars ();
617+ }
618+
619+ /**
620+ * /!\ Don't use these methods
621+ */
622
623 public override bool motion_notify_event(Gdk.EventMotion ev) {
624- rating.motion_notify_event(ev);
625+ rating.motion_notify_event (ev);
626 rating.queue_draw();
627 return true;
628 }
629
630- public override bool draw(Cairo.Context context) {
631- already_drawn = true;
632- return false;
633- }
634-
635 public override bool button_press_event(Gdk.EventButton ev) {
636- rating.button_press_event(ev);
637- return false;
638+ rating.button_press_event(ev);
639+ activate();
640+ return true;
641 }
642
643 public override bool leave_notify_event(Gdk.EventCrossing ev) {
644- rating.updateRating(rating.rating);
645- return true;
646- }
647-}
648-
649+ rating.update_rating (rating_value);
650+ return true;
651+ }
652+}
653+
654+public class BeatBox.CellRendererRating : Gtk.CellRendererPixbuf {
655+
656+ /** Only emmited when the rating changes by clicking over the cellrenderer **/
657+ public signal void rating_changed (int new_rating, Gtk.Widget widget, string path,
658+ Gtk.CellRendererState flags);
659+
660+ /**
661+ * This class is here to make setting the rating from a cell possible.
662+ * Unlike the other widgets, it only allows doing so by clicking over a
663+ * star, and it's not possible to get an in-hover preview (it actually is
664+ * but that would require this widget to be aware of the GtkTreeView).
665+ *
666+ * We use a normal rating widget. It does the drawing and all we need
667+ * internally, and after that we set the rendered image as this cell renderer's
668+ * pixbuf.
669+ */
670+ protected RatingWidget? rating = null;
671+
672+ public CellRendererRating (Gtk.IconSize icon_size = Gtk.IconSize.MENU) {
673+ rating = new RatingWidget (false, icon_size);
674+ this.pixbuf = rating.get_canvas ();
675+
676+ xalign = 0.0f; // left-aligned
677+
678+ // Make this cell renderer activatable. This allows receiving click (activate) events.
679+ this.mode = Gtk.CellRendererMode.ACTIVATABLE;
680+ }
681+
682+ /** Common Rating API functions **/
683+
684+ public void set_star_spacing (int spacing) {
685+ rating.set_star_spacing (spacing);
686+ this.pixbuf = rating.get_canvas ();
687+ this.width = this.pixbuf.width;
688+ }
689+
690+ public int get_star_spacing () {
691+ return rating.get_star_spacing ();
692+ }
693+
694+ public int get_rating () {
695+ return rating.get_rating ();
696+ }
697+
698+ public void set_rating (int new_rating) {
699+ rating.set_rating (new_rating);
700+ this.pixbuf = rating.get_canvas ();
701+ }
702+
703+ public void set_n_stars (int n_stars) {
704+ rating.set_n_stars (n_stars);
705+ this.pixbuf = rating.get_canvas ();
706+ this.width = this.pixbuf.width;
707+ }
708+
709+ public int get_n_stars () {
710+ return rating.get_n_stars ();
711+ }
712+
713+ /** Handles activate events (clicks) **/
714+ public override bool activate (Gdk.Event event, Gtk.Widget widget, string path,
715+ Gdk.Rectangle background_area, Gdk.Rectangle cell_area,
716+ Gtk.CellRendererState flags)
717+ {
718+ int old_rating = get_rating ();
719+ int new_rating = rating.get_new_rating (event.button.x - (double) cell_area.x);
720+
721+ /* If the user clicks again over the same star, decrease the rating
722+ * (i.e. "unset" the star)
723+ */
724+ if (new_rating == old_rating) {
725+ new_rating--;
726+ }
727+
728+ /* We don't re-draw automatically since doing so modifies the entire
729+ * treeview column in most cases. Let's pass off the responsability to the
730+ * rating_changed signal handler. It must take care of setting the new rating
731+ * on the proper cell.
732+ */
733+ // rating.set_rating (new_rating);
734+ //this.pixbuf = rating.get_canvas ();
735+
736+ // emit signal
737+ rating_changed (new_rating, widget, path, flags);
738+
739+ return true;
740+ }
741+}
742
743=== modified file 'src/Windows/Editors/PodcastEditor.vala'
744--- src/Windows/Editors/PodcastEditor.vala 2012-06-13 23:54:06 +0000
745+++ src/Windows/Editors/PodcastEditor.vala 2012-06-20 02:00:29 +0000
746@@ -140,7 +140,7 @@
747 fields.set("Genre", new FieldEditor("Genre", sum.genre, new Entry()));
748 fields.set("Comment", new FieldEditor("Comment", sum.comment, new TextView()));
749 fields.set("Episode", new FieldEditor("Track", sum.track.to_string(), new SpinButton.with_range(0, 500, 1)));
750- fields.set("Rating", new FieldEditor("Rating", sum.rating.to_string(), new RatingWidget(null, false, IconSize.MENU)));
751+ fields.set("Rating", new FieldEditor("Rating", sum.rating.to_string(), new RatingWidget(false, IconSize.MENU, false, null)));
752 fields.set("Media Type", new FieldEditor("Media Type", ((int)sum.mediatype).to_string(), new ComboBoxText()));
753
754 padding = new HBox(false, 10);
755
756=== modified file 'src/Windows/Editors/SongEditor.vala'
757--- src/Windows/Editors/SongEditor.vala 2012-06-13 23:54:06 +0000
758+++ src/Windows/Editors/SongEditor.vala 2012-06-20 02:00:29 +0000
759@@ -185,7 +185,7 @@
760 fields.set("Track", new FieldEditor("Track", sum.track.to_string(), new SpinButton.with_range(0, 500, 1)));
761 fields.set("Disc", new FieldEditor("Disc", sum.album_number.to_string(), new SpinButton.with_range(0, 500, 1)));
762 fields.set("Year", new FieldEditor("Year", sum.year.to_string(), new SpinButton.with_range(0, 9999, 1)));
763- fields.set("Rating", new FieldEditor("Rating", sum.rating.to_string(), new RatingWidget(null, false, IconSize.MENU)));
764+ fields.set("Rating", new FieldEditor("Rating", sum.rating.to_string(), new RatingWidget(false, IconSize.MENU, false, null)));
765 fields.set("Media Type", new FieldEditor("Media Type", ((int)sum.mediatype).to_string(), new ComboBoxText()));
766
767 content = new VBox(false, 10);
768
769=== modified file 'src/Windows/Editors/StationEditor.vala'
770--- src/Windows/Editors/StationEditor.vala 2012-05-03 04:19:07 +0000
771+++ src/Windows/Editors/StationEditor.vala 2012-06-20 02:00:29 +0000
772@@ -126,7 +126,7 @@
773
774 fields.set("Station", new FieldEditor("Station", sum.album_artist, new Entry()));
775 fields.set("Genre", new FieldEditor("Genre", sum.genre, new Entry()));
776- fields.set("Rating", new FieldEditor("Rating", sum.rating.to_string(), new RatingWidget(null, false, IconSize.MENU)));
777+ fields.set("Rating", new FieldEditor("Rating", sum.rating.to_string(), new RatingWidget(false, IconSize.MENU, false, null)));
778
779 padding = new HBox(false, 10);
780 vert = new VBox(false, 0);

Subscribers

People subscribed via source and target branches

to all changes: