Re-add rating.
[gmpc.git] / src / browsers / gmpc-nowplaying2.vala
bloba906f9461d1dbfbaa634dedf631a1a51e464a44d
1 /* Gnome Music Player Client
2 * Copyright (C) 2011-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 using GLib;
20 using Gmpc;
21 using Gmpc.Plugin;
22 using Gmpc.Favorites;
24 private const bool use_transition_mb2 = Gmpc.use_transition;
25 private const string some_unique_name_mb2 = Config.VERSION;
26 private const string np2_LOG_DOMAIN = "NowPlaying";
28 /**
29 * This plugin implements an 'improved' now playing interface, modeled after the mockup found here
30 * http://gmpclient.org/wiki/GMPC_Mocup
33 /* create teh plugin of type Gmpc.Plugin.Base that implements the Browser interface */
34 namespace Gmpc
37 namespace Browsers
39 public class Nowplaying : Gmpc.Plugin.Base, Gmpc.Plugin.BrowserIface
41 private int max_albums = 10;
42 private bool theme_colors = (bool) config.get_int_with_default("Now Playing", "use-theme-color",1);
43 private string title_color = config.get_string_with_default("Now Playing", "title-color", "#4d90dd");
44 private string item_color = config.get_string_with_default("Now Playing", "item-color", "#304ab8");
45 private Gdk.Color background;
46 private Gdk.Color foreground;
48 private Gtk.Label bitrate_label = null;
49 private Gtk.TreeRowReference np_ref = null;
51 private bool use_backdrop = (bool) config.get_int_with_default("Now Playing", "use-backdrop",0);
54 construct
56 /* Set the plugin as Browser type*/
57 this.plugin_type = 2|8;
58 /* Track changed status */
59 gmpcconn.status_changed.connect(status_changed);
60 /* Track connect/disconnect */
61 gmpcconn.connection_changed.connect((source, connect) => {
62 /* If disconnect update the page */
63 if(connect == 0 && this.paned != null)
64 this.update_not_playing();
65 });
67 var background = config.get_string_with_default("Now Playing",
68 "background-color", "#000");
69 var foreground = config.get_string_with_default("Now Playing",
70 "foreground-color", "#FFF");
71 Gdk.Color.parse(background,out this.background);
72 Gdk.Color.parse(foreground,out this.foreground);
74 /* Register easycommand to switch to this browser */
75 easy_command.add_entry(
76 _("switch now playing"),
77 "",
78 _("Switch to Now Playing"),
79 (Gmpc.Easy.Command.Callback *)select_now_playing_browser,
80 this);
82 /* Version of the plugin*/
83 private const int[] version = {0,0,0};
84 public override unowned int[] get_version()
86 return version;
88 /* Name */
89 public override unowned string get_name()
91 return N_("Now Playing");
94 public override void set_enabled(bool state)
96 if(state)
98 if(paned == null)
100 browser_add( Gmpc.Playlist3.get_category_tree_view());
101 browser_init();
104 else
106 if(this.np_ref != null)
108 var path = np_ref.get_path();
109 if(path != null)
111 unowned int[] indices = path.get_indices();
112 config.set_int(this.get_name(), "position", indices[0]);
113 Gtk.ListStore model = (Gtk.ListStore) np_ref.get_model();
114 Gtk.TreeIter iter;
115 if(model.get_iter(out iter, path))
117 model.remove(iter);
121 if(this.paned != null)
123 this.paned.destroy();
124 this.paned = null;
125 this.song_checksum = null;
129 if(this.get_name() != null)
130 Gmpc.config.set_int(this.get_name(), "enabled", (int)state);
132 /* Save our position in the side-bar */
133 public override void save_yourself()
135 if(this.np_ref != null)
137 var path = np_ref.get_path();
138 if(path != null)
140 unowned int[] indices = path.get_indices();
141 config.set_int(this.get_name(), "position", indices[0]);
146 /* React MPD's status changed */
147 private
148 void
149 status_changed(Gmpc.Connection conn, MPD.Server server, MPD.Status.Changed what)
151 if(!this.get_enabled())return;
152 if(!this.selected) return;
153 /* If the state changes, update. */
154 if((what&MPD.Status.Changed.STATE) == MPD.Status.Changed.STATE)
156 this.update();
158 /* If the playlist changed, this might mean that the metadata of the currently playing song changed, update. */
159 else if ((what&(MPD.Status.Changed.SONGID|MPD.Status.Changed.PLAYLIST)) > 0)
161 this.update();
163 /* If the bitrate changed, update the bitrate label. */
164 if((what&(MPD.Status.Changed.BITRATE|MPD.Status.Changed.AUDIOFORMAT)) > 0)
166 if(bitrate_label != null)
168 var channels = MPD.Status.get_channels(Gmpc.server);
169 debug("bitrate changed");
170 var bitrate = MPD.Status.get_bitrate(Gmpc.server);
171 bitrate_label.set_markup(GLib.Markup.printf_escaped(
172 "<span color='%s' weight='bold'>%s:</span> %i %s, %.1f %s, %i %s",
173 this.item_color, _("Format"),
174 channels , GLib.ngettext(N_("Channel"),N_("Channels"), channels),
175 MPD.Status.get_samplerate(Gmpc.server)/1000.0, "kHz",
176 bitrate, "kbps"
183 /* Browser */
184 private Gtk.ScrolledWindow paned = null;
185 private Gtk.EventBox container = null;
186 private bool selected = false;
188 * Browser Interface bindings
190 public void browser_add (Gtk.Widget category_tree)
192 Gtk.TreeView tree = (Gtk.TreeView)category_tree;
193 Gtk.ListStore store = (Gtk.ListStore)tree.get_model();
194 Gtk.TreeModel model = tree.get_model();
195 Gtk.TreeIter iter;
196 Gmpc.Browser.insert(out iter, Gmpc.Playlist.BrowserType.TOP);
197 store.set(iter, 0, this.id, 1, this.get_name(), 3, "media-audiofile");
198 /* Create a row reference */
199 this.np_ref = new Gtk.TreeRowReference(model, model.get_path(iter));
201 /* Called by gmpc, telling the plugin to embed itself in container */
202 public void browser_selected (Gtk.Container container)
207 this.selected = true;
208 this.browser_init();
209 container.add(this.paned);
211 container.show_all();
212 container.ensure_style();
213 if(this.theme_colors)
215 this.title_color = this.paned.style.text[Gtk.StateType.PRELIGHT].to_string();
216 this.item_color = this.paned.style.text[Gtk.StateType.PRELIGHT].to_string();
218 if(use_backdrop)
220 this.title_color = "#fff";
221 this.item_color = "#fff";
222 this.theme_colors = false;
224 this.update();
227 /* Called by gmpc, telling the plugin to remove itself from the container */
228 public void browser_unselected(Gtk.Container container)
230 this.selected = false;
231 container.remove(this.paned);
235 * If the style changed because f.e. the user switched theme, make sure the correct colouring is kept preserved.
238 private void browser_bg_style_changed(Gtk.Widget bg,Gtk.Style? style)
240 debug("Change style signal");
241 if(this.theme_colors)
243 this.title_color = this.paned.style.text[Gtk.StateType.PRELIGHT].to_string();
244 this.item_color = this.paned.style.text[Gtk.StateType.PRELIGHT].to_string();
246 this.change_color_style(this.container);
249 * Recursively force a style on widget bg and children.
251 private void change_color_style(Gtk.Widget bg)
253 debug("change style");
254 if( bg is Gtk.Notebook || bg is Gtk.CheckButton ||
255 bg is Gtk.Image || bg is Gmpc.DataView || bg is Gtk.Container)
257 /* Do nothing */
259 else if (bg is Gtk.Separator)
261 bg.modify_fg(Gtk.StateType.NORMAL,this.foreground);
263 else
265 if(theme_colors)
267 bg.modify_bg(Gtk.StateType.NORMAL,this.paned.style.base[Gtk.StateType.NORMAL]);
268 /*bg.modify_base(Gtk.StateType.NORMAL,this.paned.style.mid[Gtk.StateType.NORMAL]);/*
269 // bg.modify_text(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
270 bg.modify_fg(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
271 bg.modify_text(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);
272 bg.modify_fg(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);*/
274 else
276 if(!( bg is Gtk.Label)) {
277 bg.modify_bg(Gtk.StateType.NORMAL,this.background);
278 bg.modify_base(Gtk.StateType.NORMAL,this.background);
280 bg.modify_text(Gtk.StateType.NORMAL,this.foreground);
281 bg.modify_fg(Gtk.StateType.NORMAL,this.foreground);
282 bg.modify_text(Gtk.StateType.ACTIVE,this.foreground);
283 bg.modify_fg(Gtk.StateType.ACTIVE,this.foreground);
286 /* Recurse into children, if the widget can hold children (so is a container */
287 if(bg is Gtk.Container)
289 foreach(Gtk.Widget child in ((Gtk.Container)bg).get_children())
291 change_color_style(child);
295 /* Create the basic gui. on initializing */
296 private void browser_init()
298 if(this.paned == null)
301 this.paned = new Gtk.ScrolledWindow(null,null);
302 this.paned.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
303 this.paned.set_shadow_type(Gtk.ShadowType.ETCHED_IN);
304 if(use_backdrop)
306 this.container = new Gmpc.MetaData.Widgets.Backdrop(Gmpc.MetaData.Type.BACKDROP_ART);
308 else
310 this.container = new Gtk.EventBox();
312 // Keybindings.
313 this.container.key_press_event.connect((source, event)=>{
314 if(event.keyval == Gdk.Key_j &&
315 !((event.state&Gdk.ModifierType.CONTROL_MASK) ==
316 Gdk.ModifierType.CONTROL_MASK ))
318 var va = this.paned.get_vadjustment();
319 va.set_value(va.get_value()+va.get_step_increment());
321 else if(event.keyval == Gdk.Key_k &&
322 !((event.state&Gdk.ModifierType.CONTROL_MASK) ==
323 Gdk.ModifierType.CONTROL_MASK ))
325 var va = this.paned.get_vadjustment();
326 va.set_value(va.get_value()-va.get_step_increment());
328 return false;
331 this.container.set_focus_hadjustment(this.paned.get_hadjustment());
332 this.container.set_focus_vadjustment(this.paned.get_vadjustment());
334 this.paned.style_set.connect(browser_bg_style_changed);
335 this.paned.add_with_viewport(this.container);
336 this.paned.get_vadjustment().set("step-increment", 20.0);
337 this.paned.show_all();
342 /* Clear the view inside the scrolled window*/
343 private void clear()
345 /* Clear */
346 var list = this.container.get_children();
347 foreach(Gtk.Widget child in list)
349 child.destroy();
351 bitrate_label = null;
355 private string get_extension(string path)
357 long length = path.length;
358 long i=length;
359 string retv = null;
360 for(; i>0 && (length-i) <8; i--)
362 if(path[i] == '.')
364 retv = path.substring(i+1);
365 return retv;
368 return retv;
371 * Show the page when playing
373 private string song_checksum = null;
374 private void update_playing()
376 unowned MPD.Song? song = server.playlist_get_current_song();
377 if(song == null)
379 debug("GMPC Is playing, cannot get this");
380 if(use_backdrop)
381 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(null);
382 update_not_playing();
383 return;
385 /* Force it so we won't update when not needed */
386 var checksum = Gmpc.Misc.song_checksum(song);
387 if(checksum == this.song_checksum)
389 /* No need to update. */
390 return;
392 GLib.Timer t = new GLib.Timer();
393 this.clear();
394 if(use_backdrop)
395 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(song);
396 this.song_checksum = checksum;
398 var vbox = new Gtk.VBox (false,6);
399 vbox.border_width = 8;
400 /* Start building the gui */
401 /* Artist image */
402 var hbox = new Gtk.HBox(false, 6);
403 Gtk.Alignment ali = null;
405 int meta_size = (int)(this.container.get_allocated_width()*0.20);
406 /* get size based on alloc */
407 meta_size = int.min(int.max(100, meta_size), 250);
408 if(config.get_int_with_default("Interface", "hide-album-art", 0) == 0)
410 /* Album image */
411 ali = new Gtk.Alignment(0f,0f,0f,0f);
412 //ali.set_size_request(meta_size,meta_size);
413 var album_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, meta_size);
414 album_image.set_scale_up(true);
415 album_image.set_squared(false);
416 ali.add(album_image);
417 album_image.update_from_song(song);
418 hbox.pack_start(ali, false, false, 0);
421 /* Artist image */
422 if(config.get_int_with_default("Interface", "hide-album-art", 0) == 0 && !use_backdrop)
424 ali = new Gtk.Alignment(1f,0f,0f,0f);
425 var artist_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ARTIST_ART, meta_size);
426 artist_image.set_scale_up(true);
427 artist_image.set_squared(false);
428 artist_image.update_from_song(song);
429 ali.add(artist_image);
430 hbox.pack_end(ali, false, false, 0);
433 /* Information box */
434 var info_vbox = new Gtk.VBox(false, 6);
435 /* Title */
436 if(song.title != null)
438 var box = new Gtk.HBox(false, 6);
439 /* Favored button */
441 if(config.get_int_with_default("Interface", "hide-favorites-icon",0) == 0)
443 var fav_button = new Gmpc.Favorites.Button();
444 fav_button.set_song(song);
445 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
446 ali.add(fav_button);
447 box.pack_start(ali, false, false, 0);
449 var label = new Gtk.Label(song.title);
450 label.selectable = true;
451 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",
452 this.title_color,Pango.SCALE*20 ,song.title));
453 label.set_ellipsize(Pango.EllipsizeMode.END);
454 label.set_alignment(0.0f, 0.5f);
455 box.pack_start(label, true, true, 0);
456 info_vbox.pack_start(box, false, false, 0);
458 if(MPD.Sticker.supported(server))
460 /* Favored button */
461 var rating_button = new Gmpc.Rating(server, song);
462 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
463 ali.add(rating_button);
464 info_vbox.pack_start(ali, false, false, 0);
467 else if (song.name!= null)
469 var label = new Gtk.Label(song.name);
470 label.selectable = true;
471 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this.
472 title_color, Pango.SCALE*20, song.name));
473 label.set_ellipsize(Pango.EllipsizeMode.END);
474 label.set_alignment(0.0f, 0.5f);
475 info_vbox.pack_start(label, false, false, 0);
477 else if (song.file != null)
479 var filename = GLib.Path.get_basename(song.file);
480 var label = new Gtk.Label(song.name);
481 label.selectable = true;
484 var regex_a = new GLib.Regex ("\\.[0-9a-zA-Z]*$");
485 filename = regex_a.replace_literal (filename, -1, 0, "");
487 catch (GLib.RegexError e)
489 GLib.error("%s", e.message);
493 var regex_b = new GLib.Regex ("_");
494 filename = regex_b.replace_literal (filename, -1, 0, " ");
496 catch (GLib.RegexError e)
498 GLib.error("%s", e.message);
500 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this.
501 title_color, Pango.SCALE*20, filename));
502 label.set_ellipsize(Pango.EllipsizeMode.END);
503 label.set_alignment(0.0f, 0.5f);
504 info_vbox.pack_start(label, false, false, 0);
507 /* Artist */
508 if(song.artist != null)
510 var event = new Gtk.EventBox();
511 var box = new Gtk.HBox(false, 6);
512 var label = new Gtk.Label(song.artist);
513 event.set_visible_window(false);
514 label.selectable = true;
515 var image = new Gtk.Image.from_icon_name("media-artist", Gtk.IconSize.MENU);
516 event.add(image);
517 box.pack_start(event, false, false, 0);
518 label.set_markup(GLib.Markup.printf_escaped("<span size='xx-large' weight='bold'>%s</span>", song.artist));
519 label.set_ellipsize(Pango.EllipsizeMode.END);
520 label.set_alignment(0.0f, 0.5f);
521 box.pack_start(label, true, true, 0);
522 info_vbox.pack_start(box, false, false, 0);
524 event.set_data("artist",song.artist);
525 event.button_press_event.connect((widget, event) =>
527 string artist = (string)widget.get_data<string>("artist");
528 Gmpc.Browser.Metadata.show_artist(artist);
529 return false;
532 /* Album */
533 if(song.album != null)
535 var event = new Gtk.EventBox();
536 var box = new Gtk.HBox(false, 6);
537 var label = new Gtk.Label(song.album);
538 event.set_visible_window(false);
539 label.selectable = true;
540 var image = new Gtk.Image.from_icon_name("media-album", Gtk.IconSize.MENU);
541 event.add(image);
542 box.pack_start(event, false, false, 0);
543 label.set_markup(GLib.Markup.printf_escaped("<span size='x-large' weight='bold'>%s %s</span>", song.album,
544 (song.date != null)? "(%s)".printf(song.date):""));
545 label.set_ellipsize(Pango.EllipsizeMode.END);
546 label.set_alignment(0.0f, 0.5f);
547 box.pack_start(label, true, true, 0);
548 info_vbox.pack_start(box, false, false, 0);
552 event.set_data("artist",song.artist);
553 event.set_data("album",song.album);
554 event.button_press_event.connect((widget, event) =>
556 string artist = (string)widget.get_data<string>("artist");
557 string album = (string)widget.get_data<string>("album");
558 if(artist != null && album != null)
560 Gmpc.Browser.Metadata.show_album(artist,album);
561 return true;
563 return false;
566 /* Genre */
567 if(song.genre != null)
569 var box = new Gtk.HBox(false, 6);
570 var label = new Gtk.Label(song.title);
571 label.selectable = true;
572 var image = new Gtk.Image.from_icon_name("media-genre", Gtk.IconSize.MENU);
573 box.pack_start(image, false, false, 0);
574 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
575 this.item_color,_("Genre"), song.genre));
576 label.set_ellipsize(Pango.EllipsizeMode.END);
577 label.set_alignment(0.0f, 0.5f);
578 box.pack_start(label, true, true, 0);
579 info_vbox.pack_start(box, false, false, 0);
582 /* Format */
584 var box = new Gtk.HBox(false, 6);
585 var image = new Gtk.Image.from_icon_name("media-format", Gtk.IconSize.MENU);
586 box.pack_start(image, false, false, 0);
588 bitrate_label = new Gtk.Label(song.title);
589 bitrate_label.selectable = true;
590 bitrate_label.set_ellipsize(Pango.EllipsizeMode.END);
591 bitrate_label.set_alignment(0.0f, 0.5f);
593 box.pack_start(bitrate_label, true, true, 0);
595 var bitrate = MPD.Status.get_bitrate(Gmpc.server);
596 var channels = MPD.Status.get_channels(Gmpc.server);
597 bitrate_label.set_markup(GLib.Markup.printf_escaped(
598 "<span color='%s' weight='bold'>%s:</span> %i %s, %.1f %s, %i %s",
599 this.item_color, _("Format"),
600 channels , GLib.ngettext(N_("Channel"),N_("Channels"), channels),
601 MPD.Status.get_samplerate(Gmpc.server)/1000.0, "kHz",
602 bitrate, "kbps"
605 info_vbox.pack_start(box, false, false, 0);
607 if(song.file != null)
610 string extension = null;
611 extension = get_extension(song.file);
612 if(extension != null)
614 var box = new Gtk.HBox(false, 6);
615 var image = new Gtk.Image.from_icon_name("media-codec", Gtk.IconSize.MENU);
616 box.pack_start(image, false, false, 0);
618 var label = new Gtk.Label(song.title);
619 label.selectable = true;
620 label.set_ellipsize(Pango.EllipsizeMode.END);
621 label.set_alignment(0.0f, 0.5f);
622 box.pack_start(label, true, true, 0);
623 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
624 this.item_color, _("Codec"),
625 extension));
626 info_vbox.pack_start(box, false, false, 0);
629 /* Time*/
630 if(song.time > 0)
632 var box = new Gtk.HBox(false, 6);
633 var image = new Gtk.Image.from_icon_name("media-track-length", Gtk.IconSize.MENU);
634 box.pack_start(image, false, false, 0);
635 var label = new Gtk.Label("");
636 label.selectable = true;
637 label.set_ellipsize(Pango.EllipsizeMode.END);
638 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
639 this.item_color,_("Length"),
640 Gmpc.Misc.format_time((ulong) song.time, "")));
641 label.set_alignment(0.0f, 0.5f);
642 box.pack_start(label, true, true, 0);
643 info_vbox.pack_start(box, false, false, 0);
646 if(song.track != null)
648 var box = new Gtk.HBox(false, 6);
649 var image = new Gtk.Image.from_icon_name("media-num-tracks", Gtk.IconSize.MENU);
650 box.pack_start(image, false, false, 0);
651 var label = new Gtk.Label("");
652 label.selectable = true;
653 label.set_ellipsize(Pango.EllipsizeMode.END);
654 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s %s",
655 this.item_color, _("Track number"),
656 song.track,
657 (song.disc != null)? "[%s]".printf(song.disc):""
659 label.set_alignment(0.0f, 0.5f);
660 box.pack_start(label, true, true, 0);
661 info_vbox.pack_start(box, false, false, 0);
665 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "heading took: %.6f seconds.", t.elapsed());
666 hbox.pack_start(info_vbox, true, true, 0);
667 vbox.pack_start(hbox, false, false, 0);
669 /* Separator */
670 var sep = new Gtk.HSeparator();
671 sep.set_size_request(-1, 4);
672 vbox.pack_start(sep, false, false, 0);
674 var hboxje = new Gtk.HBox(false, 6);
676 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
677 var notebook = new Gtk.Notebook();
678 notebook.set_show_border(false);
679 notebook.set_show_tabs(false);
681 /* Lyrics */
682 var i = 0;
683 unowned SList<unowned Gtk.RadioButton> group = null;
684 if(config.get_int_with_default("MetaData", "show-lyrics",1) == 1)
686 var alib = new Gtk.Alignment(0f,0f,1f,0f);
687 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_TXT);
688 alib.add(text_view);
689 notebook.append_page(alib, new Gtk.Label("Lyrics"));
690 var button = new Gtk.RadioButton.with_label(group,("Lyrics"));
691 ((button as Gtk.Bin).get_child() as
692 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
694 if(group != null)
695 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
696 group = button.get_group();
697 hboxje.pack_start(button, false, false, 0);
698 var j = i;
699 button.clicked.connect((source) =>
701 if((source as Gtk.CheckButton).get_active())
703 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics notebook page %i clicked", j);
704 notebook.set_current_page(j);
707 i++;
709 alib.show();
711 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics took: %.6f seconds.", t.elapsed());
713 /* Album information */
714 if(config.get_int_with_default("MetaData", "show-album-information",1) == 1)
716 var alib = new Gtk.Alignment(0f,0f,1f,0f);
717 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.ALBUM_TXT);
718 alib.add(text_view);
719 notebook.append_page(alib, new Gtk.Label("Album information"));
720 var button = new Gtk.RadioButton.with_label(group,_("Album information"));
721 ((button as Gtk.Bin).get_child() as
722 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
724 if(group != null)
725 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
726 group = button.get_group();
727 hboxje.pack_start(button, false, false, 0);
728 var j = i;
729 button.clicked.connect((source) =>
731 if((source as Gtk.CheckButton).get_active())
733 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics notebook page %i clicked", j);
734 notebook.set_current_page(j);
737 i++;
739 alib.show();
742 /* Guitar Tabs */
743 if(config.get_int_with_default("MetaData", "show-guitar-tabs",1) == 1)
745 var alib = new Gtk.Alignment(0f,0f,1f,0f);
746 var text_view_queried = false;
747 notebook.append_page(alib, new Gtk.Label(_("Guitar Tabs")));
748 var button = new Gtk.RadioButton.with_label(group,_("Guitar Tabs"));
749 ((button as Gtk.Bin).get_child() as
750 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
752 //button.add(label);
753 if(group != null)
754 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
755 group = button.get_group();
756 hboxje.pack_start(button, false, false, 0);
757 var j = i;
758 /* Only query the guitar-tab when opened or first notebook page*/
759 button.clicked.connect((source) =>
761 if((source as Gtk.CheckButton).get_active())
763 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "guitar tab notebook page %i clicked", j);
764 notebook.set_current_page(j);
765 if(!text_view_queried)
767 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_GUITAR_TAB);
768 alib.add(text_view);
769 text_view_queried = true;
770 this.change_color_style(text_view);
771 text_view.show();
775 if(i == 0)
777 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_GUITAR_TAB);
778 alib.add(text_view);
779 text_view_queried = true;
781 alib.show_all();
782 i++;
784 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "guitar tabs took: %.6f seconds.", t.elapsed());
786 /* Similar songs */
788 if(config.get_int_with_default("MetaData", "show-similar-songs",1) == 1)
790 var similar_songs_queried = false;
791 var similar_songs_box = new Gtk.Alignment(0f,0f,1f,0f);
793 notebook.append_page(similar_songs_box, new Gtk.Label(_("Similar Songs")));
795 var button = new Gtk.RadioButton.with_label(group,_("Similar Songs"));
796 ((button as Gtk.Bin).get_child() as
797 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
798 if(group != null)
799 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
800 group = button.get_group();
801 hboxje.pack_start(button, false, false, 0);
803 var j = i;
804 /* Only query when opened or first notebook page*/
805 button.clicked.connect((source) =>
807 if((source as Gtk.CheckButton).get_active())
809 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "similar song notebook page %i clicked", j);
810 notebook.set_current_page(j);
811 if(!similar_songs_queried)
813 var similar_songs = new Gmpc.MetaData.Widgets.SimilarSongs(song);
814 similar_songs.update();
815 similar_songs_queried = true;
816 similar_songs_box.add(similar_songs);
817 this.change_color_style(similar_songs_box);
818 similar_songs_box.show_all();
822 if(i == 0)
824 var similar_songs = new Gmpc.MetaData.Widgets.SimilarSongs(song);
825 similar_songs.update();
826 similar_songs_queried = true;
827 similar_songs_box.add(similar_songs);
828 similar_songs_box.show_all();
830 similar_songs_box.show();
831 i++;
834 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "similar songs took: %.6f seconds.", t.elapsed());
835 if(config.get_int_with_default("MetaData", "show-similar-artist",1) == 1 && song.artist != null)
837 var similar_artist = new Gmpc.MetaData.Widgets.SimilarArtists(Gmpc.server,song);
839 notebook.append_page(similar_artist, new Gtk.Label(_("Similar Artists")));
841 var button = new Gtk.RadioButton.with_label(group,_("Similar Artists"));
842 ((button as Gtk.Bin).get_child() as
843 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
844 if(group != null)
845 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
846 group = button.get_group();
847 hboxje.pack_start(button, false, false, 0);
849 var j = i;
850 button.clicked.connect((source) =>
852 if((source as Gtk.CheckButton).get_active())
854 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "similar artist notebook page %i clicked", j);
855 similar_artist.first_show();
856 notebook.set_current_page(j);
859 similar_artist.show();
860 i++;
862 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "similar Artist took: %.6f seconds.", t.elapsed());
863 if(config.get_int_with_default("MetaData", "show-artist-information",1) == 1)
865 var alib = new Gtk.Alignment(0f,0f,1f,0f);
866 var text_view_queried = false;
868 notebook.append_page(alib, new Gtk.Label(_("Artist information")));
869 var button = new Gtk.RadioButton.with_label(group,_("Artist information"));
870 ((button as Gtk.Bin).get_child() as
871 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
872 if(group != null)
873 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
874 group = button.get_group();
875 hboxje.pack_start(button, false, false, 0);
876 var j = i;
877 /* Only query the guitar-tab when opened or first notebook page*/
878 button.clicked.connect((source) =>
880 if((source as Gtk.CheckButton).get_active())
882 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "artist info notebook page %i clicked", j);
883 notebook.set_current_page(j);
884 if(!text_view_queried)
886 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song,Gmpc.MetaData.Type.ARTIST_TXT);
887 alib.add(text_view);
888 text_view_queried = true;
889 text_view.show();
890 this.change_color_style(text_view);
894 if(i == 0)
896 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song,Gmpc.MetaData.Type.ARTIST_TXT);
897 alib.add(text_view);
898 text_view_queried = true;
900 alib.show_all();
901 i++;
904 if(config.get_int_with_default("MetaData", "show-songs-from-album",1) == 1)
906 var alib = new Gtk.Alignment(0f,0f,1f,0f);
907 var text_view_queried = false;
909 notebook.append_page(alib, new Gtk.Label(_("Songs from album")));
910 var button = new Gtk.RadioButton.with_label(group,_("Songs from album"));
911 ((button as Gtk.Bin).get_child() as
912 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
913 if(group != null)
914 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
915 group = button.get_group();
916 hboxje.pack_start(button, false, false, 0);
917 var j = i;
918 var sl = new Gmpc.DataView("now-playing-song-from-album");
919 sl.set_opacity(0.6);
920 var sl_model = new Gmpc.MpdData.Model();
921 sl.set_model(sl_model);
923 alib.add(sl);
924 button.clicked.connect((source) =>
926 if((source as Gtk.CheckButton).get_active())
928 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "artist info notebook page %i clicked", j);
929 notebook.set_current_page(j);
930 if(!text_view_queried)
932 if(song.artist != null && song.album != null)
934 MPD.Database.search_start(server,true);
935 if(song.albumartist != null)
937 MPD.Database.search_add_constraint(server,
938 MPD.Tag.Type.ALBUM_ARTIST, song.albumartist);
940 else
942 MPD.Database.search_add_constraint(server,
943 MPD.Tag.Type.ARTIST, song.artist);
945 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, song.album);
946 var data = MPD.Database.search_commit(server);
947 data.sort_album_disc_track();
948 sl_model.set_mpd_data((owned)data);
949 // sl.set_from_data((owned)data, true);
950 // this.change_color_style(sl);
952 else
954 sl.destroy();
955 alib.add(new Gtk.Label(_("Not available")));
957 text_view_queried = true;
961 if(i == 0)
963 if(song.artist != null && song.album != null)
965 MPD.Database.search_start(server,true);
966 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
967 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, song.album);
968 var data = MPD.Database.search_commit(server);
969 data.sort_album_disc_track();
970 sl_model.set_mpd_data((owned)data);
971 //sl.set_from_data((owned)data, true);
973 else
975 sl.destroy();
976 alib.add(new Gtk.Label(_("Not available")));
978 text_view_queried = true;
980 alib.show_all();
981 i++;
984 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Artist info took: %.6f seconds.", t.elapsed());
985 /* Track changed pages */
986 notebook.notify["page"].connect((source,spec) =>
988 var page = notebook.get_current_page();
989 config.set_int("NowPlaying", "last-page", (int)page);
992 /* Restore right page */
993 if(i > 0)
995 var page = config.get_int_with_default("NowPlaying", "last-page", 0);
996 if(page > i)
998 notebook.set_current_page(0);
1000 else
1002 /* The list is in reversed order, compensate for that. */
1003 var w = group.nth_data(i-page-1);
1004 w.set_active(true);
1005 notebook.set_current_page(page);
1009 ali = new Gtk.Alignment(0.0f, 0.5f,1f,0f);
1010 ali.add(hboxje);
1012 /* Create pane in 2. */
1013 var bottom_hbox = new Gtk.HBox(false, 6);
1014 /* left pane */
1015 var metadata_vbox = new Gtk.VBox(false, 0);
1016 metadata_vbox.pack_start(ali, false, false, 0);
1017 sep = new Gtk.HSeparator();
1018 sep.set_size_request(-1, 1);
1019 metadata_vbox.pack_start(sep, false, false, 0);
1020 metadata_vbox.pack_start(notebook, false, false, 0);
1022 bottom_hbox.pack_start(metadata_vbox, true, true, 0);
1024 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Building now playing took: %.6f seconds.", t.elapsed());
1025 /* Create album list */
1026 if(song.album != null && song.artist != null)
1028 var sep2 = new Gtk.VSeparator();
1029 sep2.set_size_request(-1, 4);
1030 bottom_hbox.pack_start(sep2, false, false, 0);
1031 int albums =0;
1032 /* Create album list */
1033 ali = new Gtk.Alignment(0.0f, 0.0f, 0.0f, 0.0f);
1034 var album_hbox = new Gtk.VBox(false, 6);
1035 album_hbox.set_size_request(250, -1);
1036 ali.add(album_hbox);
1037 bottom_hbox.pack_start(ali, false, false, 0);
1039 var label = new Gtk.Label(song.artist);
1040 label.selectable = true;
1041 label.set_size_request(240, -1);
1042 label.set_markup(GLib.Markup.printf_escaped("<span size='x-large' weight='bold' color='%s'>%s</span><span size='x-large' weight='bold'> %s</span>",this.item_color,_("Other albums by"), song.artist));
1043 label.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR);
1044 label.set_line_wrap(true);
1045 label.set_alignment(0.0f, 0.5f);
1046 album_hbox.pack_start(label, false, false,0);
1048 MPD.Database.search_field_start(server, MPD.Tag.Type.ALBUM);
1049 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
1050 MPD.Data.Item list = null;
1051 var data = MPD.Database.search_commit(server);
1052 if(data != null)
1054 unowned MPD.Data.Item iter = data.get_first();
1057 if(iter.tag == song.album)
1059 iter.next(false);
1060 continue;
1062 list.append_new();
1063 list.type = MPD.Data.Type.SONG;
1064 list.song = new MPD.Song();
1065 list.song.artist = song.artist;
1066 list.song.album = iter.tag;
1068 MPD.Database.search_field_start(server,MPD.Tag.Type.DATE);
1069 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
1070 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, iter.tag);
1071 var ydata = MPD.Database.search_commit(server);
1072 if(ydata != null) {
1073 list.song.date = ydata.tag;
1076 iter.next(false);
1078 while(iter != null);
1081 list.sort_album_disc_track();
1082 int count = 0;
1083 if(list != null)
1085 unowned MPD.Data.Item iter = list.get_first();
1088 if(count > this.max_albums)
1090 var l = new Gtk.Label(_("More..."));
1091 l.set_markup("<a
1092 href=\"artist\">%s</a>".printf(_("More...")));
1093 l.set_alignment(0, 0.5f);
1094 album_hbox.pack_start(l, false,false, 0);
1095 l.activate_link.connect((source)=>{
1096 Gmpc.Browser.Metadata.show_artist(song.artist);
1097 return false;
1099 // jump out.
1100 iter = null;
1101 continue;
1103 count++;
1104 var button = new Gtk.Button();
1105 button.set_relief(Gtk.ReliefStyle.NONE);
1106 var but_hbox = new Gtk.HBox(false, 6);
1107 button.add(but_hbox);
1108 var image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, 48);
1109 unowned MPD.Song but_song = iter.song;
1110 image.set_squared(true);
1111 image.update_from_song_delayed(but_song);
1113 but_hbox.pack_start(image, false, false, 0);
1115 var but_label = new Gtk.Label(iter.song.album);
1116 but_label.selectable = true;
1117 but_label.set_alignment(0.0f, 0.5f);
1118 var strlabel = "";
1119 if(iter.song.date != null && iter.song.date.length > 0) strlabel += "%s\n".printf(iter.song.date);
1120 if(iter.song.album != null) strlabel+= iter.song.album;
1121 else strlabel += _("No Album");
1122 but_label.set_markup(GLib.Markup.printf_escaped("<b>%s</b>",strlabel));
1123 but_label.set_ellipsize(Pango.EllipsizeMode.END);
1124 but_hbox.pack_start(but_label, true, true, 0);
1126 album_hbox.pack_start(button, false, false,0);
1127 button.set_data("artist",
1128 but_song.artist.dup());
1129 button.set_data("album",
1130 but_song.album.dup());
1131 stdout.printf("open: %s %s\n", but_song.artist, but_song.album);
1132 button.clicked.connect((source) =>
1134 unowned string artist = (string)source.get_data<string>("artist");
1135 unowned string album = (string)source.get_data<string>("album");
1136 stdout.printf("open: %s %s\n", artist, album);
1137 Gmpc.Browser.Metadata.show_album(artist, album);
1139 albums++;
1141 iter.next(false);
1143 while(iter!= null);
1146 if(albums == 0)
1148 album_hbox.destroy();
1149 sep2.destroy();
1152 vbox.pack_start(bottom_hbox, true, true, 0);
1154 /* show it */
1155 this.container.add(vbox);
1156 this.change_color_style(this.container);
1157 this.container.show_all();
1159 t.stop();
1160 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Building now playing took: %.6f seconds.", t.elapsed());
1163 * This shows the page when mpd is not playing, for now it is the gmpc logo + Gnome Music Player Client
1165 private void update_not_playing()
1167 this.clear();
1168 song_checksum = null;
1169 if(use_backdrop)
1170 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(null);
1172 var it = Gtk.IconTheme.get_default();
1173 Gtk.IconInfo info = it.lookup_icon("gmpc", 150, 0);
1174 var path = info.get_filename();
1175 Gtk.Image image = null;
1176 if(path != null)
1180 var pb = new Gdk.Pixbuf.from_file_at_scale(path, 150, 150, true);
1181 image = new Gtk.Image.from_pixbuf(pb);
1183 catch (Error e)
1185 warning("Failed to load the gmpc logo: %s", e.message);
1186 return;
1189 if(image == null)
1191 image = new Gtk.Image.from_icon_name("gmpc", Gtk.IconSize.DIALOG);
1194 var hbox = new Gtk.HBox(false, 6);
1195 var label = new Gtk.Label(_("Gnome Music Player Client"));
1196 label.set_selectable(true);
1197 label.set_markup("<span size='%i' weight='bold'>%s</span>".printf(28*Pango.SCALE,_("Gnome Music Player Client")));
1198 hbox.pack_start(image, false, false, 0);
1199 hbox.pack_start(label, false, false, 0);
1201 var ali = new Gtk.Alignment(0.5f,0.5f,0.0f, 0.0f);
1202 ali.add(hbox);
1203 this.container.add(ali);
1205 this.change_color_style(this.container);
1206 this.container.show_all();
1210 * Update the view according to state. If playing/paused show song info, other wise the not playing page
1212 private void update()
1214 switch(MPD.Player.get_state(Gmpc.server))
1216 case MPD.Player.State.PLAY:
1217 case MPD.Player.State.PAUSE:
1218 debug("Update playing");
1219 update_playing();
1220 break;
1221 default:
1222 debug("update not playing");
1223 update_not_playing();
1224 break;
1229 * Makes gmpc jump to the now playing browser
1231 public void select_now_playing_browser()
1233 unowned Gtk.TreeView tree = Gmpc.Playlist3.get_category_tree_view();
1234 var sel = tree.get_selection();
1235 var path = np_ref.get_path();
1236 if(path != null)
1238 sel.select_path(path);
1243 * Gmpc.Plugin.BrowserIface.add_go_menu
1245 private int browser_add_go_menu(Gtk.Menu menu)
1247 if(this.get_enabled())
1249 var item = new Gtk.ImageMenuItem.with_mnemonic(_("Now Playing"));
1250 item.set_image(new Gtk.Image.from_icon_name("media-audiofile", Gtk.IconSize.MENU));
1251 item.activate.connect(select_now_playing_browser);
1252 item.add_accelerator("activate", menu.get_accel_group(),0x069, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);
1253 menu.append(item);
1254 return 1;
1256 return 0;