Merge lp:~sgringwe/beat-box/rating-merge into lp:beat-box
- rating-merge
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Victor Martinez (community) | Approve | ||
Review via email: mp+111132@code.launchpad.net |
Commit message
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.
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); |
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.