now-playing: jk does scrolling.
[gmpc.git] / src / browsers / gmpc-nowplaying2.vala
blob14eb7da9526ba2b4222c954089b7a8d2054be62e
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.Separator || bg is Gtk.Notebook || bg is Gtk.CheckButton ||
255 bg is Gtk.Image || bg is Gmpc.DataView)
257 /* Do nothing */
259 else
261 if(theme_colors)
263 bg.modify_bg(Gtk.StateType.NORMAL,this.paned.style.base[Gtk.StateType.NORMAL]);
264 /*bg.modify_base(Gtk.StateType.NORMAL,this.paned.style.mid[Gtk.StateType.NORMAL]);/*
265 // bg.modify_text(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
266 bg.modify_fg(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
267 bg.modify_text(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);
268 bg.modify_fg(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);*/
270 else
272 if(!( bg is Gtk.Label)) {
273 bg.modify_bg(Gtk.StateType.NORMAL,this.background);
274 bg.modify_base(Gtk.StateType.NORMAL,this.background);
276 bg.modify_text(Gtk.StateType.NORMAL,this.foreground);
277 bg.modify_fg(Gtk.StateType.NORMAL,this.foreground);
278 bg.modify_text(Gtk.StateType.ACTIVE,this.foreground);
279 bg.modify_fg(Gtk.StateType.ACTIVE,this.foreground);
282 /* Recurse into children, if the widget can hold children (so is a container */
283 if(bg is Gtk.Container)
285 foreach(Gtk.Widget child in ((Gtk.Container)bg).get_children())
287 change_color_style(child);
291 /* Create the basic gui. on initializing */
292 private void browser_init()
294 if(this.paned == null)
297 this.paned = new Gtk.ScrolledWindow(null,null);
298 this.paned.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
299 this.paned.set_shadow_type(Gtk.ShadowType.ETCHED_IN);
300 if(use_backdrop)
302 this.container = new Gmpc.MetaData.Widgets.Backdrop(Gmpc.MetaData.Type.BACKDROP_ART);
304 else
306 this.container = new Gtk.EventBox();
308 // Keybindings.
309 this.container.key_press_event.connect((source, event)=>{
310 if(event.keyval == Gdk.Key_j &&
311 !((event.state&Gdk.ModifierType.CONTROL_MASK) ==
312 Gdk.ModifierType.CONTROL_MASK ))
314 var va = this.paned.get_vadjustment();
315 va.set_value(va.get_value()+va.get_step_increment());
317 else if(event.keyval == Gdk.Key_k &&
318 !((event.state&Gdk.ModifierType.CONTROL_MASK) ==
319 Gdk.ModifierType.CONTROL_MASK ))
321 var va = this.paned.get_vadjustment();
322 va.set_value(va.get_value()-va.get_step_increment());
324 return false;
327 this.container.set_focus_hadjustment(this.paned.get_hadjustment());
328 this.container.set_focus_vadjustment(this.paned.get_vadjustment());
330 this.paned.style_set.connect(browser_bg_style_changed);
331 this.paned.add_with_viewport(this.container);
332 this.paned.get_vadjustment().set("step-increment", 20.0);
333 this.paned.show_all();
338 /* Clear the view inside the scrolled window*/
339 private void clear()
341 /* Clear */
342 var list = this.container.get_children();
343 foreach(Gtk.Widget child in list)
345 child.destroy();
347 bitrate_label = null;
351 private string get_extension(string path)
353 long length = path.length;
354 long i=length;
355 string retv = null;
356 for(; i>0 && (length-i) <8; i--)
358 if(path[i] == '.')
360 retv = path.substring(i+1);
361 return retv;
364 return retv;
367 * Show the page when playing
369 private string song_checksum = null;
370 private void update_playing()
372 unowned MPD.Song? song = server.playlist_get_current_song();
373 if(song == null)
375 debug("GMPC Is playing, cannot get this");
376 if(use_backdrop)
377 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(null);
378 update_not_playing();
379 return;
381 /* Force it so we won't update when not needed */
382 var checksum = Gmpc.Misc.song_checksum(song);
383 if(checksum == this.song_checksum)
385 /* No need to update. */
386 return;
388 GLib.Timer t = new GLib.Timer();
389 this.clear();
390 if(use_backdrop)
391 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(song);
392 this.song_checksum = checksum;
394 var vbox = new Gtk.VBox (false,6);
395 vbox.border_width = 8;
396 /* Start building the gui */
397 /* Artist image */
398 var hbox = new Gtk.HBox(false, 6);
399 Gtk.Alignment ali = null;
401 int meta_size = (int)(this.container.get_allocated_width()*0.20);
402 /* get size based on alloc */
403 meta_size = int.min(int.max(100, meta_size), 250);
404 if(config.get_int_with_default("Interface", "hide-album-art", 0) == 0)
406 /* Album image */
407 ali = new Gtk.Alignment(0f,0f,0f,0f);
408 //ali.set_size_request(meta_size,meta_size);
409 var album_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, meta_size);
410 album_image.set_scale_up(true);
411 album_image.set_squared(false);
412 ali.add(album_image);
413 album_image.update_from_song(song);
414 hbox.pack_start(ali, false, false, 0);
417 /* Artist image */
418 if(config.get_int_with_default("Interface", "hide-album-art", 0) == 0 && !use_backdrop)
420 ali = new Gtk.Alignment(1f,0f,0f,0f);
421 var artist_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ARTIST_ART, meta_size);
422 artist_image.set_scale_up(true);
423 artist_image.set_squared(false);
424 artist_image.update_from_song(song);
425 ali.add(artist_image);
426 hbox.pack_end(ali, false, false, 0);
429 /* Information box */
430 var info_vbox = new Gtk.VBox(false, 6);
431 /* Title */
432 if(song.title != null)
434 var box = new Gtk.HBox(false, 6);
435 /* Favored button */
437 if(config.get_int_with_default("Interface", "hide-favorites-icon",0) == 0)
439 var fav_button = new Gmpc.Favorites.Button();
440 fav_button.set_song(song);
441 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
442 ali.add(fav_button);
443 box.pack_start(ali, false, false, 0);
445 var label = new Gtk.Label(song.title);
446 label.selectable = true;
447 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",
448 this.title_color,Pango.SCALE*20 ,song.title));
449 label.set_ellipsize(Pango.EllipsizeMode.END);
450 label.set_alignment(0.0f, 0.5f);
451 box.pack_start(label, true, true, 0);
452 info_vbox.pack_start(box, false, false, 0);
455 else if (song.name!= null)
457 var label = new Gtk.Label(song.name);
458 label.selectable = true;
459 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this.
460 title_color, Pango.SCALE*20, song.name));
461 label.set_ellipsize(Pango.EllipsizeMode.END);
462 label.set_alignment(0.0f, 0.5f);
463 info_vbox.pack_start(label, false, false, 0);
465 else if (song.file != null)
467 var filename = GLib.Path.get_basename(song.file);
468 var label = new Gtk.Label(song.name);
469 label.selectable = true;
472 var regex_a = new GLib.Regex ("\\.[0-9a-zA-Z]*$");
473 filename = regex_a.replace_literal (filename, -1, 0, "");
475 catch (GLib.RegexError e)
477 GLib.error("%s", e.message);
481 var regex_b = new GLib.Regex ("_");
482 filename = regex_b.replace_literal (filename, -1, 0, " ");
484 catch (GLib.RegexError e)
486 GLib.error("%s", e.message);
488 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this.
489 title_color, Pango.SCALE*20, filename));
490 label.set_ellipsize(Pango.EllipsizeMode.END);
491 label.set_alignment(0.0f, 0.5f);
492 info_vbox.pack_start(label, false, false, 0);
495 /* Artist */
496 if(song.artist != null)
498 var event = new Gtk.EventBox();
499 var box = new Gtk.HBox(false, 6);
500 var label = new Gtk.Label(song.artist);
501 event.set_visible_window(false);
502 label.selectable = true;
503 var image = new Gtk.Image.from_icon_name("media-artist", Gtk.IconSize.MENU);
504 event.add(image);
505 box.pack_start(event, false, false, 0);
506 label.set_markup(GLib.Markup.printf_escaped("<span size='xx-large' weight='bold'>%s</span>", song.artist));
507 label.set_ellipsize(Pango.EllipsizeMode.END);
508 label.set_alignment(0.0f, 0.5f);
509 box.pack_start(label, true, true, 0);
510 info_vbox.pack_start(box, false, false, 0);
512 event.set_data("artist",song.artist);
513 event.button_press_event.connect((widget, event) =>
515 string artist = (string)widget.get_data<string>("artist");
516 Gmpc.Browser.Metadata.show_artist(artist);
517 return false;
520 /* Album */
521 if(song.album != null)
523 var event = new Gtk.EventBox();
524 var box = new Gtk.HBox(false, 6);
525 var label = new Gtk.Label(song.album);
526 event.set_visible_window(false);
527 label.selectable = true;
528 var image = new Gtk.Image.from_icon_name("media-album", Gtk.IconSize.MENU);
529 event.add(image);
530 box.pack_start(event, false, false, 0);
531 label.set_markup(GLib.Markup.printf_escaped("<span size='x-large' weight='bold'>%s %s</span>", song.album,
532 (song.date != null)? "(%s)".printf(song.date):""));
533 label.set_ellipsize(Pango.EllipsizeMode.END);
534 label.set_alignment(0.0f, 0.5f);
535 box.pack_start(label, true, true, 0);
536 info_vbox.pack_start(box, false, false, 0);
540 event.set_data("artist",song.artist);
541 event.set_data("album",song.album);
542 event.button_press_event.connect((widget, event) =>
544 string artist = (string)widget.get_data<string>("artist");
545 string album = (string)widget.get_data<string>("album");
546 if(artist != null && album != null)
548 Gmpc.Browser.Metadata.show_album(artist,album);
549 return true;
551 return false;
554 /* Genre */
555 if(song.genre != null)
557 var box = new Gtk.HBox(false, 6);
558 var label = new Gtk.Label(song.title);
559 label.selectable = true;
560 var image = new Gtk.Image.from_icon_name("media-genre", Gtk.IconSize.MENU);
561 box.pack_start(image, false, false, 0);
562 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
563 this.item_color,_("Genre"), song.genre));
564 label.set_ellipsize(Pango.EllipsizeMode.END);
565 label.set_alignment(0.0f, 0.5f);
566 box.pack_start(label, true, true, 0);
567 info_vbox.pack_start(box, false, false, 0);
570 /* Format */
572 var box = new Gtk.HBox(false, 6);
573 var image = new Gtk.Image.from_icon_name("media-format", Gtk.IconSize.MENU);
574 box.pack_start(image, false, false, 0);
576 bitrate_label = new Gtk.Label(song.title);
577 bitrate_label.selectable = true;
578 bitrate_label.set_ellipsize(Pango.EllipsizeMode.END);
579 bitrate_label.set_alignment(0.0f, 0.5f);
581 box.pack_start(bitrate_label, true, true, 0);
583 var bitrate = MPD.Status.get_bitrate(Gmpc.server);
584 var channels = MPD.Status.get_channels(Gmpc.server);
585 bitrate_label.set_markup(GLib.Markup.printf_escaped(
586 "<span color='%s' weight='bold'>%s:</span> %i %s, %.1f %s, %i %s",
587 this.item_color, _("Format"),
588 channels , GLib.ngettext(N_("Channel"),N_("Channels"), channels),
589 MPD.Status.get_samplerate(Gmpc.server)/1000.0, "kHz",
590 bitrate, "kbps"
593 info_vbox.pack_start(box, false, false, 0);
595 if(song.file != null)
598 string extension = null;
599 extension = get_extension(song.file);
600 if(extension != null)
602 var box = new Gtk.HBox(false, 6);
603 var image = new Gtk.Image.from_icon_name("media-codec", Gtk.IconSize.MENU);
604 box.pack_start(image, false, false, 0);
606 var label = new Gtk.Label(song.title);
607 label.selectable = true;
608 label.set_ellipsize(Pango.EllipsizeMode.END);
609 label.set_alignment(0.0f, 0.5f);
610 box.pack_start(label, true, true, 0);
611 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
612 this.item_color, _("Codec"),
613 extension));
614 info_vbox.pack_start(box, false, false, 0);
617 /* Time*/
618 if(song.time > 0)
620 var box = new Gtk.HBox(false, 6);
621 var image = new Gtk.Image.from_icon_name("media-track-length", Gtk.IconSize.MENU);
622 box.pack_start(image, false, false, 0);
623 var label = new Gtk.Label("");
624 label.selectable = true;
625 label.set_ellipsize(Pango.EllipsizeMode.END);
626 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
627 this.item_color,_("Length"),
628 Gmpc.Misc.format_time((ulong) song.time, "")));
629 label.set_alignment(0.0f, 0.5f);
630 box.pack_start(label, true, true, 0);
631 info_vbox.pack_start(box, false, false, 0);
634 if(song.track != null)
636 var box = new Gtk.HBox(false, 6);
637 var image = new Gtk.Image.from_icon_name("media-num-tracks", Gtk.IconSize.MENU);
638 box.pack_start(image, false, false, 0);
639 var label = new Gtk.Label("");
640 label.selectable = true;
641 label.set_ellipsize(Pango.EllipsizeMode.END);
642 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s %s",
643 this.item_color, _("Track number"),
644 song.track,
645 (song.disc != null)? "[%s]".printf(song.disc):""
647 label.set_alignment(0.0f, 0.5f);
648 box.pack_start(label, true, true, 0);
649 info_vbox.pack_start(box, false, false, 0);
653 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "heading took: %.6f seconds.", t.elapsed());
654 hbox.pack_start(info_vbox, true, true, 0);
655 vbox.pack_start(hbox, false, false, 0);
657 /* Separator */
658 var sep = new Gtk.HSeparator();
659 sep.set_size_request(-1, 4);
660 vbox.pack_start(sep, false, false, 0);
662 var hboxje = new Gtk.HBox(false, 6);
664 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
665 var notebook = new Gtk.Notebook();
666 notebook.set_show_border(false);
667 notebook.set_show_tabs(false);
669 /* Lyrics */
670 var i = 0;
671 unowned SList<unowned Gtk.RadioButton> group = null;
672 if(config.get_int_with_default("MetaData", "show-lyrics",1) == 1)
674 var alib = new Gtk.Alignment(0f,0f,1f,0f);
675 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_TXT);
676 alib.add(text_view);
677 notebook.append_page(alib, new Gtk.Label("Lyrics"));
678 var button = new Gtk.RadioButton.with_label(group,("Lyrics"));
679 ((button as Gtk.Bin).get_child() as
680 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
682 if(group != null)
683 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
684 group = button.get_group();
685 hboxje.pack_start(button, false, false, 0);
686 var j = i;
687 button.clicked.connect((source) =>
689 if((source as Gtk.CheckButton).get_active())
691 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics notebook page %i clicked", j);
692 notebook.set_current_page(j);
695 i++;
697 alib.show();
699 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics took: %.6f seconds.", t.elapsed());
701 /* Album information */
702 if(config.get_int_with_default("MetaData", "show-album-information",1) == 1)
704 var alib = new Gtk.Alignment(0f,0f,1f,0f);
705 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.ALBUM_TXT);
706 alib.add(text_view);
707 notebook.append_page(alib, new Gtk.Label("Album information"));
708 var button = new Gtk.RadioButton.with_label(group,_("Album information"));
709 ((button as Gtk.Bin).get_child() as
710 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
712 if(group != null)
713 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
714 group = button.get_group();
715 hboxje.pack_start(button, false, false, 0);
716 var j = i;
717 button.clicked.connect((source) =>
719 if((source as Gtk.CheckButton).get_active())
721 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics notebook page %i clicked", j);
722 notebook.set_current_page(j);
725 i++;
727 alib.show();
730 /* Guitar Tabs */
731 if(config.get_int_with_default("MetaData", "show-guitar-tabs",1) == 1)
733 var alib = new Gtk.Alignment(0f,0f,1f,0f);
734 var text_view_queried = false;
735 notebook.append_page(alib, new Gtk.Label(_("Guitar Tabs")));
736 var button = new Gtk.RadioButton.with_label(group,_("Guitar Tabs"));
737 ((button as Gtk.Bin).get_child() as
738 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
740 //button.add(label);
741 if(group != null)
742 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
743 group = button.get_group();
744 hboxje.pack_start(button, false, false, 0);
745 var j = i;
746 /* Only query the guitar-tab when opened or first notebook page*/
747 button.clicked.connect((source) =>
749 if((source as Gtk.CheckButton).get_active())
751 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "guitar tab notebook page %i clicked", j);
752 notebook.set_current_page(j);
753 if(!text_view_queried)
755 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_GUITAR_TAB);
756 alib.add(text_view);
757 text_view_queried = true;
758 this.change_color_style(text_view);
759 text_view.show();
763 if(i == 0)
765 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_GUITAR_TAB);
766 alib.add(text_view);
767 text_view_queried = true;
769 alib.show_all();
770 i++;
772 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "guitar tabs took: %.6f seconds.", t.elapsed());
774 /* Similar songs */
776 if(config.get_int_with_default("MetaData", "show-similar-songs",1) == 1)
778 var similar_songs_queried = false;
779 var similar_songs_box = new Gtk.Alignment(0f,0f,1f,0f);
781 notebook.append_page(similar_songs_box, new Gtk.Label(_("Similar Songs")));
783 var button = new Gtk.RadioButton.with_label(group,_("Similar Songs"));
784 ((button as Gtk.Bin).get_child() as
785 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
786 if(group != null)
787 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
788 group = button.get_group();
789 hboxje.pack_start(button, false, false, 0);
791 var j = i;
792 /* Only query when opened or first notebook page*/
793 button.clicked.connect((source) =>
795 if((source as Gtk.CheckButton).get_active())
797 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "similar song notebook page %i clicked", j);
798 notebook.set_current_page(j);
799 if(!similar_songs_queried)
801 var similar_songs = new Gmpc.MetaData.Widgets.SimilarSongs(song);
802 similar_songs.update();
803 similar_songs_queried = true;
804 similar_songs_box.add(similar_songs);
805 this.change_color_style(similar_songs_box);
806 similar_songs_box.show_all();
810 if(i == 0)
812 var similar_songs = new Gmpc.MetaData.Widgets.SimilarSongs(song);
813 similar_songs.update();
814 similar_songs_queried = true;
815 similar_songs_box.add(similar_songs);
816 similar_songs_box.show_all();
818 similar_songs_box.show();
819 i++;
822 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "similar songs took: %.6f seconds.", t.elapsed());
823 if(config.get_int_with_default("MetaData", "show-similar-artist",1) == 1 && song.artist != null)
825 var similar_artist = new Gmpc.MetaData.Widgets.SimilarArtists(Gmpc.server,song);
827 notebook.append_page(similar_artist, new Gtk.Label(_("Similar Artists")));
829 var button = new Gtk.RadioButton.with_label(group,_("Similar Artists"));
830 ((button as Gtk.Bin).get_child() as
831 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
832 if(group != null)
833 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
834 group = button.get_group();
835 hboxje.pack_start(button, false, false, 0);
837 var j = i;
838 button.clicked.connect((source) =>
840 if((source as Gtk.CheckButton).get_active())
842 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "similar artist notebook page %i clicked", j);
843 similar_artist.first_show();
844 notebook.set_current_page(j);
847 similar_artist.show();
848 i++;
850 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "similar Artist took: %.6f seconds.", t.elapsed());
851 if(config.get_int_with_default("MetaData", "show-artist-information",1) == 1)
853 var alib = new Gtk.Alignment(0f,0f,1f,0f);
854 var text_view_queried = false;
856 notebook.append_page(alib, new Gtk.Label(_("Artist information")));
857 var button = new Gtk.RadioButton.with_label(group,_("Artist information"));
858 ((button as Gtk.Bin).get_child() as
859 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
860 if(group != null)
861 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
862 group = button.get_group();
863 hboxje.pack_start(button, false, false, 0);
864 var j = i;
865 /* Only query the guitar-tab when opened or first notebook page*/
866 button.clicked.connect((source) =>
868 if((source as Gtk.CheckButton).get_active())
870 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "artist info notebook page %i clicked", j);
871 notebook.set_current_page(j);
872 if(!text_view_queried)
874 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song,Gmpc.MetaData.Type.ARTIST_TXT);
875 alib.add(text_view);
876 text_view_queried = true;
877 text_view.show();
878 this.change_color_style(text_view);
882 if(i == 0)
884 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song,Gmpc.MetaData.Type.ARTIST_TXT);
885 alib.add(text_view);
886 text_view_queried = true;
888 alib.show_all();
889 i++;
892 if(config.get_int_with_default("MetaData", "show-songs-from-album",1) == 1)
894 var alib = new Gtk.Alignment(0f,0f,1f,0f);
895 var text_view_queried = false;
897 notebook.append_page(alib, new Gtk.Label(_("Songs from album")));
898 var button = new Gtk.RadioButton.with_label(group,_("Songs from album"));
899 ((button as Gtk.Bin).get_child() as
900 Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END);
901 if(group != null)
902 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
903 group = button.get_group();
904 hboxje.pack_start(button, false, false, 0);
905 var j = i;
906 var sl = new Gmpc.DataView("now-playing-song-from-album");
907 var sl_model = new Gmpc.MpdData.Model();
908 sl.set_model(sl_model);
910 alib.add(sl);
911 button.clicked.connect((source) =>
913 if((source as Gtk.CheckButton).get_active())
915 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "artist info notebook page %i clicked", j);
916 notebook.set_current_page(j);
917 if(!text_view_queried)
919 if(song.artist != null && song.album != null)
921 MPD.Database.search_start(server,true);
922 if(song.albumartist != null)
924 MPD.Database.search_add_constraint(server,
925 MPD.Tag.Type.ALBUM_ARTIST, song.albumartist);
927 else
929 MPD.Database.search_add_constraint(server,
930 MPD.Tag.Type.ARTIST, song.artist);
932 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, song.album);
933 var data = MPD.Database.search_commit(server);
934 data.sort_album_disc_track();
935 sl_model.set_mpd_data((owned)data);
936 // sl.set_from_data((owned)data, true);
937 // this.change_color_style(sl);
939 else
941 sl.destroy();
942 alib.add(new Gtk.Label(_("Not available")));
944 text_view_queried = true;
948 if(i == 0)
950 if(song.artist != null && song.album != null)
952 MPD.Database.search_start(server,true);
953 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
954 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, song.album);
955 var data = MPD.Database.search_commit(server);
956 data.sort_album_disc_track();
957 sl_model.set_mpd_data((owned)data);
958 //sl.set_from_data((owned)data, true);
960 else
962 sl.destroy();
963 alib.add(new Gtk.Label(_("Not available")));
965 text_view_queried = true;
967 alib.show_all();
968 i++;
971 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Artist info took: %.6f seconds.", t.elapsed());
972 /* Track changed pages */
973 notebook.notify["page"].connect((source,spec) =>
975 var page = notebook.get_current_page();
976 config.set_int("NowPlaying", "last-page", (int)page);
979 /* Restore right page */
980 if(i > 0)
982 var page = config.get_int_with_default("NowPlaying", "last-page", 0);
983 if(page > i)
985 notebook.set_current_page(0);
987 else
989 /* The list is in reversed order, compensate for that. */
990 var w = group.nth_data(i-page-1);
991 w.set_active(true);
992 notebook.set_current_page(page);
996 ali = new Gtk.Alignment(0.0f, 0.5f,1f,0f);
997 ali.add(hboxje);
999 /* Create pane in 2. */
1000 var bottom_hbox = new Gtk.HBox(false, 6);
1001 /* left pane */
1002 var metadata_vbox = new Gtk.VBox(false, 0);
1003 metadata_vbox.pack_start(ali, false, false, 0);
1004 sep = new Gtk.HSeparator();
1005 sep.set_size_request(-1, 1);
1006 metadata_vbox.pack_start(sep, false, false, 0);
1007 metadata_vbox.pack_start(notebook, false, false, 0);
1009 bottom_hbox.pack_start(metadata_vbox, true, true, 0);
1011 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Building now playing took: %.6f seconds.", t.elapsed());
1012 /* Create album list */
1013 if(song.album != null && song.artist != null)
1015 var sep2 = new Gtk.VSeparator();
1016 sep2.set_size_request(-1, 4);
1017 bottom_hbox.pack_start(sep2, false, false, 0);
1018 int albums =0;
1019 /* Create album list */
1020 ali = new Gtk.Alignment(0.0f, 0.0f, 0.0f, 0.0f);
1021 var album_hbox = new Gtk.VBox(false, 6);
1022 album_hbox.set_size_request(250, -1);
1023 ali.add(album_hbox);
1024 bottom_hbox.pack_start(ali, false, false, 0);
1026 var label = new Gtk.Label(song.artist);
1027 label.selectable = true;
1028 label.set_size_request(240, -1);
1029 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));
1030 label.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR);
1031 label.set_line_wrap(true);
1032 label.set_alignment(0.0f, 0.5f);
1033 album_hbox.pack_start(label, false, false,0);
1035 MPD.Database.search_field_start(server, MPD.Tag.Type.ALBUM);
1036 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
1037 MPD.Data.Item list = null;
1038 var data = MPD.Database.search_commit(server);
1039 if(data != null)
1041 unowned MPD.Data.Item iter = data.get_first();
1044 if(iter.tag == song.album)
1046 iter.next(false);
1047 continue;
1049 list.append_new();
1050 list.type = MPD.Data.Type.SONG;
1051 list.song = new MPD.Song();
1052 list.song.artist = song.artist;
1053 list.song.album = iter.tag;
1055 MPD.Database.search_field_start(server,MPD.Tag.Type.DATE);
1056 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
1057 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, iter.tag);
1058 var ydata = MPD.Database.search_commit(server);
1059 if(ydata != null) {
1060 list.song.date = ydata.tag;
1063 iter.next(false);
1065 while(iter != null);
1068 list.sort_album_disc_track();
1069 int count = 0;
1070 if(list != null)
1072 unowned MPD.Data.Item iter = list.get_first();
1075 if(count > this.max_albums)
1077 var l = new Gtk.Label(_("More..."));
1078 l.set_alignment(0, 0.5f);
1079 album_hbox.pack_start(l, false,false, 0);
1080 // jump out.
1081 iter = null;
1082 continue;
1084 count++;
1085 var button = new Gtk.Button();
1086 button.set_relief(Gtk.ReliefStyle.NONE);
1087 var but_hbox = new Gtk.HBox(false, 6);
1088 button.add(but_hbox);
1089 var image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, 48);
1090 unowned MPD.Song but_song = iter.song;
1091 image.set_squared(true);
1092 image.update_from_song_delayed(but_song);
1094 but_hbox.pack_start(image, false, false, 0);
1096 var but_label = new Gtk.Label(iter.song.album);
1097 but_label.selectable = true;
1098 but_label.set_alignment(0.0f, 0.5f);
1099 var strlabel = "";
1100 if(iter.song.date != null && iter.song.date.length > 0) strlabel += "%s\n".printf(iter.song.date);
1101 if(iter.song.album != null) strlabel+= iter.song.album;
1102 else strlabel += _("No Album");
1103 but_label.set_markup(GLib.Markup.printf_escaped("<b>%s</b>",strlabel));
1104 but_label.set_ellipsize(Pango.EllipsizeMode.END);
1105 but_hbox.pack_start(but_label, true, true, 0);
1107 album_hbox.pack_start(button, false, false,0);
1108 button.set_data("artist",
1109 but_song.artist.dup());
1110 button.set_data("album",
1111 but_song.album.dup());
1112 stdout.printf("open: %s %s\n", but_song.artist, but_song.album);
1113 button.clicked.connect((source) =>
1115 unowned string artist = (string)source.get_data<string>("artist");
1116 unowned string album = (string)source.get_data<string>("album");
1117 stdout.printf("open: %s %s\n", artist, album);
1118 Gmpc.Browser.Metadata.show_album(artist, album);
1120 albums++;
1122 iter.next(false);
1124 while(iter!= null);
1127 if(albums == 0)
1129 album_hbox.destroy();
1130 sep2.destroy();
1133 vbox.pack_start(bottom_hbox, true, true, 0);
1135 /* show it */
1136 this.container.add(vbox);
1137 this.change_color_style(this.container);
1138 this.container.show_all();
1140 t.stop();
1141 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Building now playing took: %.6f seconds.", t.elapsed());
1144 * This shows the page when mpd is not playing, for now it is the gmpc logo + Gnome Music Player Client
1146 private void update_not_playing()
1148 this.clear();
1149 song_checksum = null;
1150 if(use_backdrop)
1151 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(null);
1153 var it = Gtk.IconTheme.get_default();
1154 Gtk.IconInfo info = it.lookup_icon("gmpc", 150, 0);
1155 var path = info.get_filename();
1156 Gtk.Image image = null;
1157 if(path != null)
1161 var pb = new Gdk.Pixbuf.from_file_at_scale(path, 150, 150, true);
1162 image = new Gtk.Image.from_pixbuf(pb);
1164 catch (Error e)
1166 warning("Failed to load the gmpc logo: %s", e.message);
1167 return;
1170 if(image == null)
1172 image = new Gtk.Image.from_icon_name("gmpc", Gtk.IconSize.DIALOG);
1175 var hbox = new Gtk.HBox(false, 6);
1176 var label = new Gtk.Label(_("Gnome Music Player Client"));
1177 label.set_selectable(true);
1178 label.set_markup("<span size='%i' weight='bold'>%s</span>".printf(28*Pango.SCALE,_("Gnome Music Player Client")));
1179 hbox.pack_start(image, false, false, 0);
1180 hbox.pack_start(label, false, false, 0);
1182 var ali = new Gtk.Alignment(0.5f,0.5f,0.0f, 0.0f);
1183 ali.add(hbox);
1184 this.container.add(ali);
1186 this.change_color_style(this.container);
1187 this.container.show_all();
1191 * Update the view according to state. If playing/paused show song info, other wise the not playing page
1193 private void update()
1195 switch(MPD.Player.get_state(Gmpc.server))
1197 case MPD.Player.State.PLAY:
1198 case MPD.Player.State.PAUSE:
1199 debug("Update playing");
1200 update_playing();
1201 break;
1202 default:
1203 debug("update not playing");
1204 update_not_playing();
1205 break;
1210 * Makes gmpc jump to the now playing browser
1212 public void select_now_playing_browser()
1214 unowned Gtk.TreeView tree = Gmpc.Playlist3.get_category_tree_view();
1215 var sel = tree.get_selection();
1216 var path = np_ref.get_path();
1217 if(path != null)
1219 sel.select_path(path);
1224 * Gmpc.Plugin.BrowserIface.add_go_menu
1226 private int browser_add_go_menu(Gtk.Menu menu)
1228 if(this.get_enabled())
1230 var item = new Gtk.ImageMenuItem.with_mnemonic(_("Now Playing"));
1231 item.set_image(new Gtk.Image.from_icon_name("media-audiofile", Gtk.IconSize.MENU));
1232 item.activate.connect(select_now_playing_browser);
1233 item.add_accelerator("activate", menu.get_accel_group(),0x069, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);
1234 menu.append(item);
1235 return 1;
1237 return 0;