small tweak
[gmpc.git] / src / browsers / gmpc-nowplaying2.vala
blobfe9013dcbb025752cc3341885e99850cdb0cfd47
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 bool theme_colors = (bool) config.get_int_with_default("Now Playing", "use-theme-color",1);
42 private string title_color = config.get_string_with_default("Now Playing", "title-color", "#4d90dd");
43 private string item_color = config.get_string_with_default("Now Playing", "item-color", "#304ab8");
44 private Gdk.Color background;
45 private Gdk.Color foreground;
47 private Gtk.Label bitrate_label = null;
48 private Gtk.TreeRowReference np_ref = null;
50 private bool use_backdrop = (bool) config.get_int_with_default("Now Playing", "use-backdrop",0);
53 construct
55 /* Set the plugin as Browser type*/
56 this.plugin_type = 2|8;
57 /* Track changed status */
58 gmpcconn.status_changed.connect(status_changed);
59 /* Track connect/disconnect */
60 gmpcconn.connection_changed.connect((source, connect) => {
61 /* If disconnect update the page */
62 if(connect == 0 && this.paned != null)
63 this.update_not_playing();
64 });
66 var background = config.get_string_with_default("Now Playing",
67 "background-color", "#000");
68 var foreground = config.get_string_with_default("Now Playing",
69 "foreground-color", "#FFF");
70 Gdk.Color.parse(background,out this.background);
71 Gdk.Color.parse(foreground,out this.foreground);
73 /* Register easycommand to switch to this browser */
74 easy_command.add_entry(
75 _("switch now playing"),
76 "",
77 _("Switch to Now Playing"),
78 (Gmpc.Easy.Command.Callback *)select_now_playing_browser,
79 this);
81 /* Version of the plugin*/
82 private const int[] version = {0,0,0};
83 public override unowned int[] get_version()
85 return version;
87 /* Name */
88 public override unowned string get_name()
90 return N_("Now Playing");
93 public override void set_enabled(bool state)
95 if(state)
97 if(paned == null)
99 browser_add( Gmpc.Playlist3.get_category_tree_view());
100 browser_init();
103 else
105 if(this.np_ref != null)
107 var path = np_ref.get_path();
108 if(path != null)
110 unowned int[] indices = path.get_indices();
111 config.set_int(this.get_name(), "position", indices[0]);
112 Gtk.ListStore model = (Gtk.ListStore) np_ref.get_model();
113 Gtk.TreeIter iter;
114 if(model.get_iter(out iter, path))
116 model.remove(iter);
120 if(this.paned != null)
122 this.paned.destroy();
123 this.paned = null;
124 this.song_checksum = null;
128 if(this.get_name() != null)
129 Gmpc.config.set_int(this.get_name(), "enabled", (int)state);
131 /* Save our position in the side-bar */
132 public override void save_yourself()
134 if(this.np_ref != null)
136 var path = np_ref.get_path();
137 if(path != null)
139 unowned int[] indices = path.get_indices();
140 config.set_int(this.get_name(), "position", indices[0]);
145 /* React MPD's status changed */
146 private
147 void
148 status_changed(Gmpc.Connection conn, MPD.Server server, MPD.Status.Changed what)
150 if(!this.get_enabled())return;
151 if(!this.selected) return;
152 /* If the state changes, update. */
153 if((what&MPD.Status.Changed.STATE) == MPD.Status.Changed.STATE)
155 this.update();
157 /* If the playlist changed, this might mean that the metadata of the currently playing song changed, update. */
158 else if ((what&(MPD.Status.Changed.SONGID|MPD.Status.Changed.PLAYLIST)) > 0)
160 this.update();
162 /* If the bitrate changed, update the bitrate label. */
163 if((what&(MPD.Status.Changed.BITRATE|MPD.Status.Changed.AUDIOFORMAT)) > 0)
165 if(bitrate_label != null)
167 var channels = MPD.Status.get_channels(Gmpc.server);
168 debug("bitrate changed");
169 var bitrate = MPD.Status.get_bitrate(Gmpc.server);
170 bitrate_label.set_markup(GLib.Markup.printf_escaped(
171 "<span color='%s' weight='bold'>%s:</span> %i %s, %.1f %s, %i %s",
172 this.item_color, _("Format"),
173 channels , GLib.ngettext(N_("Channel"),N_("Channels"), channels),
174 MPD.Status.get_samplerate(Gmpc.server)/1000.0, "kHz",
175 bitrate, "kbps"
182 /* Browser */
183 private Gtk.ScrolledWindow paned = null;
184 private Gtk.EventBox container = null;
185 private bool selected = false;
187 * Browser Interface bindings
189 public void browser_add (Gtk.Widget category_tree)
191 Gtk.TreeView tree = (Gtk.TreeView)category_tree;
192 Gtk.ListStore store = (Gtk.ListStore)tree.get_model();
193 Gtk.TreeModel model = tree.get_model();
194 Gtk.TreeIter iter;
195 Gmpc.Browser.insert(out iter, Gmpc.Playlist.BrowserType.TOP);
196 store.set(iter, 0, this.id, 1, this.get_name(), 3, "media-audiofile");
197 /* Create a row reference */
198 this.np_ref = new Gtk.TreeRowReference(model, model.get_path(iter));
200 /* Called by gmpc, telling the plugin to embed itself in container */
201 public void browser_selected (Gtk.Container container)
206 this.selected = true;
207 this.browser_init();
208 container.add(this.paned);
210 container.show_all();
211 container.ensure_style();
212 if(this.theme_colors)
214 this.title_color = this.paned.style.text[Gtk.StateType.PRELIGHT].to_string();
215 this.item_color = this.paned.style.text[Gtk.StateType.PRELIGHT].to_string();
217 if(use_backdrop)
219 this.title_color = "#fff";
220 this.item_color = "#fff";
221 this.theme_colors = false;
223 this.update();
226 /* Called by gmpc, telling the plugin to remove itself from the container */
227 public void browser_unselected(Gtk.Container container)
229 this.selected = false;
230 container.remove(this.paned);
234 * If the style changed because f.e. the user switched theme, make sure the correct colouring is kept preserved.
237 private void browser_bg_style_changed(Gtk.Widget bg,Gtk.Style? style)
239 debug("Change style signal");
240 if(this.theme_colors)
242 this.title_color = this.paned.style.text[Gtk.StateType.PRELIGHT].to_string();
243 this.item_color = this.paned.style.text[Gtk.StateType.PRELIGHT].to_string();
245 this.change_color_style(this.container);
248 * Recursively force a style on widget bg and children.
250 private void change_color_style(Gtk.Widget bg)
252 debug("change style");
253 if(bg is Gtk.Separator || bg is Gtk.Notebook || bg is Gtk.CheckButton)
255 /* Do nothing */
257 else
259 if(theme_colors)
261 bg.modify_bg(Gtk.StateType.NORMAL,this.paned.style.base[Gtk.StateType.NORMAL]);
262 /*bg.modify_base(Gtk.StateType.NORMAL,this.paned.style.mid[Gtk.StateType.NORMAL]);/*
263 // bg.modify_text(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
264 bg.modify_fg(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
265 bg.modify_text(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);
266 bg.modify_fg(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);*/
268 else
270 bg.modify_bg(Gtk.StateType.NORMAL,this.background);
271 bg.modify_base(Gtk.StateType.NORMAL,this.background);
272 bg.modify_text(Gtk.StateType.NORMAL,this.foreground);
273 bg.modify_fg(Gtk.StateType.NORMAL,this.foreground);
274 bg.modify_text(Gtk.StateType.ACTIVE,this.foreground);
275 bg.modify_fg(Gtk.StateType.ACTIVE,this.foreground);
278 /* Recurse into children, if the widget can hold children (so is a container */
279 if(bg is Gtk.Container)
281 foreach(Gtk.Widget child in ((Gtk.Container)bg).get_children())
283 change_color_style(child);
287 /* Create the basic gui. on initializing */
288 private void browser_init()
290 if(this.paned == null)
293 this.paned = new Gtk.ScrolledWindow(null,null);
294 this.paned.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
295 this.paned.set_shadow_type(Gtk.ShadowType.ETCHED_IN);
296 if(use_backdrop)
298 this.container = new Gmpc.MetaData.Widgets.Backdrop(Gmpc.MetaData.Type.BACKDROP_ART);
300 else
302 this.container = new Gtk.EventBox();
305 this.container.set_focus_hadjustment(this.paned.get_hadjustment());
306 this.container.set_focus_vadjustment(this.paned.get_vadjustment());
308 this.paned.style_set.connect(browser_bg_style_changed);
309 this.paned.add_with_viewport(this.container);
310 this.paned.get_vadjustment().set("step-increment", 20.0);
311 this.paned.show_all();
316 /* Clear the view inside the scrolled window*/
317 private void clear()
319 /* Clear */
320 var list = this.container.get_children();
321 foreach(Gtk.Widget child in list)
323 child.destroy();
325 bitrate_label = null;
329 private string get_extension(string path)
331 long length = path.length;
332 long i=length;
333 string retv = null;
334 for(; i>0 && (length-i) <8; i--)
336 if(path[i] == '.')
338 retv = path.substring(i+1);
339 return retv;
342 return retv;
345 * Show the page when playing
347 private string song_checksum = null;
348 private void update_playing()
350 unowned MPD.Song? song = server.playlist_get_current_song();
351 if(song == null)
353 debug("GMPC Is playing, cannot get this");
354 if(use_backdrop)
355 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(null);
356 update_not_playing();
357 return;
359 /* Force it so we won't update when not needed */
360 var checksum = Gmpc.Misc.song_checksum(song);
361 if(checksum == this.song_checksum)
363 /* No need to update. */
364 return;
366 GLib.Timer t = new GLib.Timer();
367 this.clear();
368 if(use_backdrop)
369 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(song);
370 this.song_checksum = checksum;
372 var vbox = new Gtk.VBox (false,6);
373 vbox.border_width = 8;
374 /* Start building the gui */
375 /* Artist image */
376 var hbox = new Gtk.HBox(false, 6);
377 Gtk.Alignment ali = null;
379 int meta_size = (int)(this.container.get_allocated_width()*0.20);
380 /* get size based on alloc */
381 meta_size = int.min(int.max(100, meta_size), 250);
382 if(config.get_int_with_default("Interface", "hide-album-art", 0) == 0)
384 /* Album image */
385 ali = new Gtk.Alignment(0f,0f,0f,0f);
386 //ali.set_size_request(meta_size,meta_size);
387 var album_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, meta_size);
388 album_image.set_scale_up(true);
389 album_image.set_squared(false);
390 ali.add(album_image);
391 album_image.update_from_song(song);
392 hbox.pack_start(ali, false, false, 0);
395 /* Artist image */
396 if(config.get_int_with_default("Interface", "hide-album-art", 0) == 0 && !use_backdrop)
398 ali = new Gtk.Alignment(1f,0f,0f,0f);
399 var artist_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ARTIST_ART, meta_size);
400 artist_image.set_scale_up(true);
401 artist_image.set_squared(false);
402 artist_image.update_from_song(song);
403 ali.add(artist_image);
404 hbox.pack_end(ali, false, false, 0);
407 /* Information box */
408 var info_vbox = new Gtk.VBox(false, 6);
409 /* Title */
410 if(song.title != null)
412 var box = new Gtk.HBox(false, 6);
413 /* Favored button */
415 if(config.get_int_with_default("Interface", "hide-favorites-icon",0) == 0)
417 var fav_button = new Gmpc.Favorites.Button();
418 fav_button.set_song(song);
419 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
420 ali.add(fav_button);
421 box.pack_start(ali, false, false, 0);
423 var label = new Gtk.Label(song.title);
424 label.selectable = true;
425 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",
426 this.title_color,Pango.SCALE*20 ,song.title));
427 label.set_ellipsize(Pango.EllipsizeMode.END);
428 label.set_alignment(0.0f, 0.5f);
429 box.pack_start(label, true, true, 0);
430 info_vbox.pack_start(box, false, false, 0);
433 else if (song.name!= null)
435 var label = new Gtk.Label(song.name);
436 label.selectable = true;
437 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this.
438 title_color, Pango.SCALE*20, song.name));
439 label.set_ellipsize(Pango.EllipsizeMode.END);
440 label.set_alignment(0.0f, 0.5f);
441 info_vbox.pack_start(label, false, false, 0);
443 else if (song.file != null)
445 var filename = GLib.Path.get_basename(song.file);
446 var label = new Gtk.Label(song.name);
447 label.selectable = true;
450 var regex_a = new GLib.Regex ("\\.[0-9a-zA-Z]*$");
451 filename = regex_a.replace_literal (filename, -1, 0, "");
453 catch (GLib.RegexError e)
455 GLib.error("%s", e.message);
459 var regex_b = new GLib.Regex ("_");
460 filename = regex_b.replace_literal (filename, -1, 0, " ");
462 catch (GLib.RegexError e)
464 GLib.error("%s", e.message);
466 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this.
467 title_color, Pango.SCALE*20, filename));
468 label.set_ellipsize(Pango.EllipsizeMode.END);
469 label.set_alignment(0.0f, 0.5f);
470 info_vbox.pack_start(label, false, false, 0);
473 /* Artist */
474 if(song.artist != null)
476 var event = new Gtk.EventBox();
477 var box = new Gtk.HBox(false, 6);
478 var label = new Gtk.Label(song.artist);
479 event.set_visible_window(false);
480 label.selectable = true;
481 var image = new Gtk.Image.from_icon_name("media-artist", Gtk.IconSize.MENU);
482 event.add(image);
483 box.pack_start(event, false, false, 0);
484 label.set_markup(GLib.Markup.printf_escaped("<span size='xx-large' weight='bold'>%s</span>", song.artist));
485 label.set_ellipsize(Pango.EllipsizeMode.END);
486 label.set_alignment(0.0f, 0.5f);
487 box.pack_start(label, true, true, 0);
488 info_vbox.pack_start(box, false, false, 0);
490 event.set_data("artist",song.artist);
491 event.button_press_event.connect((widget, event) =>
493 string artist = (string)widget.get_data<string>("artist");
494 Gmpc.Browser.Metadata.show_artist(artist);
495 return false;
498 /* Album */
499 if(song.album != null)
501 var event = new Gtk.EventBox();
502 var box = new Gtk.HBox(false, 6);
503 var label = new Gtk.Label(song.album);
504 event.set_visible_window(false);
505 label.selectable = true;
506 var image = new Gtk.Image.from_icon_name("media-album", Gtk.IconSize.MENU);
507 event.add(image);
508 box.pack_start(event, false, false, 0);
509 label.set_markup(GLib.Markup.printf_escaped("<span size='x-large' weight='bold'>%s %s</span>", song.album,
510 (song.date != null)? "(%s)".printf(song.date):""));
511 label.set_ellipsize(Pango.EllipsizeMode.END);
512 label.set_alignment(0.0f, 0.5f);
513 box.pack_start(label, true, true, 0);
514 info_vbox.pack_start(box, false, false, 0);
518 event.set_data("artist",song.artist);
519 event.set_data("album",song.album);
520 event.button_press_event.connect((widget, event) =>
522 string artist = (string)widget.get_data<string>("artist");
523 string album = (string)widget.get_data<string>("album");
524 if(artist != null && album != null)
526 Gmpc.Browser.Metadata.show_album(artist,album);
527 return true;
529 return false;
532 /* Genre */
533 if(song.genre != null)
535 var box = new Gtk.HBox(false, 6);
536 var label = new Gtk.Label(song.title);
537 label.selectable = true;
538 var image = new Gtk.Image.from_icon_name("media-genre", Gtk.IconSize.MENU);
539 box.pack_start(image, false, false, 0);
540 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
541 this.item_color,_("Genre"), song.genre));
542 label.set_ellipsize(Pango.EllipsizeMode.END);
543 label.set_alignment(0.0f, 0.5f);
544 box.pack_start(label, true, true, 0);
545 info_vbox.pack_start(box, false, false, 0);
548 /* Format */
550 var box = new Gtk.HBox(false, 6);
551 var image = new Gtk.Image.from_icon_name("media-format", Gtk.IconSize.MENU);
552 box.pack_start(image, false, false, 0);
554 bitrate_label = new Gtk.Label(song.title);
555 bitrate_label.selectable = true;
556 bitrate_label.set_ellipsize(Pango.EllipsizeMode.END);
557 bitrate_label.set_alignment(0.0f, 0.5f);
559 box.pack_start(bitrate_label, true, true, 0);
561 var bitrate = MPD.Status.get_bitrate(Gmpc.server);
562 var channels = MPD.Status.get_channels(Gmpc.server);
563 bitrate_label.set_markup(GLib.Markup.printf_escaped(
564 "<span color='%s' weight='bold'>%s:</span> %i %s, %.1f %s, %i %s",
565 this.item_color, _("Format"),
566 channels , GLib.ngettext(N_("Channel"),N_("Channels"), channels),
567 MPD.Status.get_samplerate(Gmpc.server)/1000.0, "kHz",
568 bitrate, "kbps"
571 info_vbox.pack_start(box, false, false, 0);
573 if(song.file != null)
576 string extension = null;
577 extension = get_extension(song.file);
578 if(extension != null)
580 var box = new Gtk.HBox(false, 6);
581 var image = new Gtk.Image.from_icon_name("media-codec", Gtk.IconSize.MENU);
582 box.pack_start(image, false, false, 0);
584 var label = new Gtk.Label(song.title);
585 label.selectable = true;
586 label.set_ellipsize(Pango.EllipsizeMode.END);
587 label.set_alignment(0.0f, 0.5f);
588 box.pack_start(label, true, true, 0);
589 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
590 this.item_color, _("Codec"),
591 extension));
592 info_vbox.pack_start(box, false, false, 0);
595 /* Time*/
596 if(song.time > 0)
598 var box = new Gtk.HBox(false, 6);
599 var image = new Gtk.Image.from_icon_name("media-track-length", Gtk.IconSize.MENU);
600 box.pack_start(image, false, false, 0);
601 var label = new Gtk.Label("");
602 label.selectable = true;
603 label.set_ellipsize(Pango.EllipsizeMode.END);
604 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
605 this.item_color,_("Length"),
606 Gmpc.Misc.format_time((ulong) song.time, "")));
607 label.set_alignment(0.0f, 0.5f);
608 box.pack_start(label, true, true, 0);
609 info_vbox.pack_start(box, false, false, 0);
612 if(song.track != null)
614 var box = new Gtk.HBox(false, 6);
615 var image = new Gtk.Image.from_icon_name("media-num-tracks", Gtk.IconSize.MENU);
616 box.pack_start(image, false, false, 0);
617 var label = new Gtk.Label("");
618 label.selectable = true;
619 label.set_ellipsize(Pango.EllipsizeMode.END);
620 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s %s",
621 this.item_color, _("Track number"),
622 song.track,
623 (song.disc != null)? "[%s]".printf(song.disc):""
625 label.set_alignment(0.0f, 0.5f);
626 box.pack_start(label, true, true, 0);
627 info_vbox.pack_start(box, false, false, 0);
631 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "heading took: %.6f seconds.", t.elapsed());
632 hbox.pack_start(info_vbox, true, true, 0);
633 vbox.pack_start(hbox, false, false, 0);
635 /* Separator */
636 var sep = new Gtk.HSeparator();
637 sep.set_size_request(-1, 4);
638 vbox.pack_start(sep, false, false, 0);
640 var hboxje = new Gtk.HBox(false, 6);
642 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
643 var notebook = new Gtk.Notebook();
644 notebook.set_show_border(false);
645 notebook.set_show_tabs(false);
647 /* Lyrics */
648 var i = 0;
649 unowned SList<unowned Gtk.RadioButton> group = null;
650 if(config.get_int_with_default("MetaData", "show-lyrics",1) == 1)
652 var alib = new Gtk.Alignment(0f,0f,1f,0f);
653 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_TXT);
654 alib.add(text_view);
655 notebook.append_page(alib, new Gtk.Label("Lyrics"));
656 var button = new Gtk.RadioButton(group);//.with_label(group,("Lyrics"));
657 var label = new Gtk.Label(_("Lyrics"));
658 label.ellipsize = Pango.EllipsizeMode.END;
659 label.set_alignment(0.0f, 0.5f);
660 // button.add(label);
662 if(group != null)
663 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
664 group = button.get_group();
665 hboxje.pack_start(button, false, false, 0);
666 hboxje.pack_start(label, true, true, 0);
667 var j = i;
668 button.clicked.connect((source) =>
670 if((source as Gtk.CheckButton).get_active())
672 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics notebook page %i clicked", j);
673 notebook.set_current_page(j);
676 i++;
678 alib.show();
680 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics took: %.6f seconds.", t.elapsed());
682 /* Album information */
683 if(config.get_int_with_default("MetaData", "show-album-information",1) == 1)
685 var alib = new Gtk.Alignment(0f,0f,1f,0f);
686 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.ALBUM_TXT);
687 alib.add(text_view);
688 notebook.append_page(alib, new Gtk.Label("Album information"));
689 var button = new Gtk.RadioButton(group);
690 var label = new Gtk.Label(_("Album information"));
691 label.ellipsize = Pango.EllipsizeMode.END;
692 label.set_alignment(0.0f, 0.5f);
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 hboxje.pack_start(label, true, true, 0);
699 var j = i;
700 button.clicked.connect((source) =>
702 if((source as Gtk.CheckButton).get_active())
704 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics notebook page %i clicked", j);
705 notebook.set_current_page(j);
708 i++;
710 alib.show();
713 /* Guitar Tabs */
714 if(config.get_int_with_default("MetaData", "show-guitar-tabs",1) == 1)
716 var alib = new Gtk.Alignment(0f,0f,1f,0f);
717 var text_view_queried = false;
718 notebook.append_page(alib, new Gtk.Label(_("Guitar Tabs")));
719 var button = new Gtk.RadioButton(group);//.with_label(group,_("Guitar Tabs"));
720 var label = new Gtk.Label(_("Guitar Tabs"));
721 label.ellipsize = Pango.EllipsizeMode.END;
722 label.set_alignment(0.0f, 0.5f);
723 //button.add(label);
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 hboxje.pack_start(label, true, true, 0);
729 var j = i;
730 /* Only query the guitar-tab when opened or first notebook page*/
731 button.clicked.connect((source) =>
733 if((source as Gtk.CheckButton).get_active())
735 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "guitar tab notebook page %i clicked", j);
736 notebook.set_current_page(j);
737 if(!text_view_queried)
739 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_GUITAR_TAB);
740 alib.add(text_view);
741 text_view_queried = true;
742 this.change_color_style(text_view);
743 text_view.show();
747 if(i == 0)
749 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_GUITAR_TAB);
750 alib.add(text_view);
751 text_view_queried = true;
753 alib.show_all();
754 i++;
756 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "guitar tabs took: %.6f seconds.", t.elapsed());
758 /* Similar songs */
760 if(config.get_int_with_default("MetaData", "show-similar-songs",1) == 1)
762 var similar_songs_queried = false;
763 var similar_songs_box = new Gtk.Alignment(0f,0f,0f,0f);
765 notebook.append_page(similar_songs_box, new Gtk.Label(_("Similar Songs")));
767 var button = new Gtk.RadioButton(group);//.with_label(group,_("Similar Songs"));
768 var label = new Gtk.Label(_("Similar Songs"));
769 label.ellipsize = Pango.EllipsizeMode.END;
770 label.set_alignment(0.0f, 0.5f);
771 //button.add(label);
772 if(group != null)
773 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
774 group = button.get_group();
775 hboxje.pack_start(button, false, false, 0);
776 hboxje.pack_start(label, true, true, 0);
778 var j = i;
779 /* Only query when opened or first notebook page*/
780 button.clicked.connect((source) =>
782 if((source as Gtk.CheckButton).get_active())
784 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "similar song notebook page %i clicked", j);
785 notebook.set_current_page(j);
786 if(!similar_songs_queried)
788 var similar_songs = new Gmpc.MetaData.Widgets.SimilarSongs(song);
789 similar_songs.update();
790 similar_songs_queried = true;
791 similar_songs_box.add(similar_songs);
792 this.change_color_style(similar_songs_box);
793 similar_songs_box.show_all();
797 if(i == 0)
799 var similar_songs = new Gmpc.MetaData.Widgets.SimilarSongs(song);
800 similar_songs.update();
801 similar_songs_queried = true;
802 similar_songs_box.add(similar_songs);
803 similar_songs_box.show_all();
805 similar_songs_box.show();
806 i++;
809 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "similar songs took: %.6f seconds.", t.elapsed());
810 if(config.get_int_with_default("MetaData", "show-similar-artist",1) == 1 && song.artist != null)
812 var similar_artist = new Gmpc.MetaData.Widgets.SimilarArtists(Gmpc.server,song);
814 notebook.append_page(similar_artist, new Gtk.Label(_("Similar Artist")));
816 var button = new Gtk.RadioButton(group);//.with_label(group,_("Similar Artist"));
817 var label = new Gtk.Label(_("Similar Artist"));
818 label.ellipsize = Pango.EllipsizeMode.END;
819 label.set_alignment(0.0f, 0.5f);
820 //button.add(label);
821 if(group != null)
822 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
823 group = button.get_group();
824 hboxje.pack_start(button, false, false, 0);
825 hboxje.pack_start(label, true, true, 0);
827 var j = i;
828 button.clicked.connect((source) =>
830 if((source as Gtk.CheckButton).get_active())
832 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "similar artist notebook page %i clicked", j);
833 similar_artist.first_show();
834 notebook.set_current_page(j);
837 similar_artist.show();
838 i++;
840 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "similar Artist took: %.6f seconds.", t.elapsed());
841 if(config.get_int_with_default("MetaData", "show-artist-information",1) == 1)
843 var alib = new Gtk.Alignment(0f,0f,1f,0f);
844 var text_view_queried = false;
846 notebook.append_page(alib, new Gtk.Label(_("Artist information")));
847 var button = new Gtk.RadioButton(group);//.with_label(group,_("Artist information"));
848 var label = new Gtk.Label(_("Artist information"));
849 label.ellipsize = Pango.EllipsizeMode.END;
850 label.set_alignment(0.0f, 0.5f);
851 //button.add(label);
852 if(group != null)
853 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
854 group = button.get_group();
855 hboxje.pack_start(button, false, false, 0);
856 hboxje.pack_start(label, true, true, 0);
857 var j = i;
858 /* Only query the guitar-tab when opened or first notebook page*/
859 button.clicked.connect((source) =>
861 if((source as Gtk.CheckButton).get_active())
863 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "artist info notebook page %i clicked", j);
864 notebook.set_current_page(j);
865 if(!text_view_queried)
867 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song,Gmpc.MetaData.Type.ARTIST_TXT);
868 alib.add(text_view);
869 text_view_queried = true;
870 text_view.show();
871 this.change_color_style(text_view);
875 if(i == 0)
877 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song,Gmpc.MetaData.Type.ARTIST_TXT);
878 alib.add(text_view);
879 text_view_queried = true;
881 alib.show_all();
882 i++;
885 if(config.get_int_with_default("MetaData", "show-songs-from-album",1) == 1)
887 var alib = new Gtk.Alignment(0f,0f,1f,0f);
888 var text_view_queried = false;
890 notebook.append_page(alib, new Gtk.Label(_("Songs from album")));
891 var button = new Gtk.RadioButton(group);//.with_label(group,_("Songs from album"));
892 var label = new Gtk.Label(_("Songs from album"));
893 label.ellipsize = Pango.EllipsizeMode.END;
894 label.set_alignment(0.0f, 0.5f);
895 //button.add(label);
896 if(group != null)
897 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
898 group = button.get_group();
899 hboxje.pack_start(button, false, false, 0);
900 hboxje.pack_start(label, true, true, 0);
901 var j = i;
902 var sl = new Gmpc.Widgets.Songlist();
904 sl.song_clicked.connect((source, song) =>
906 if(song.file != null)
908 Gmpc.MpdInteraction.play_path(song.file);
911 sl.play_song_clicked.connect((source, song) =>
913 if(song.file != null)
915 Gmpc.MpdInteraction.play_path(song.file);
918 alib.add(sl);
919 button.clicked.connect((source) =>
921 if((source as Gtk.CheckButton).get_active())
923 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "artist info notebook page %i clicked", j);
924 notebook.set_current_page(j);
925 if(!text_view_queried)
927 if(song.artist != null && song.album != null)
929 MPD.Database.search_start(server,true);
930 if(song.albumartist != null)
932 MPD.Database.search_add_constraint(server,
933 MPD.Tag.Type.ALBUM_ARTIST, song.albumartist);
935 else
937 MPD.Database.search_add_constraint(server,
938 MPD.Tag.Type.ARTIST, song.artist);
940 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, song.album);
941 var data = MPD.Database.search_commit(server);
942 data.sort_album_disc_track();
943 sl.set_from_data((owned)data, true);
944 this.change_color_style(sl);
946 else
948 sl.destroy();
949 alib.add(new Gtk.Label(_("Not available")));
951 text_view_queried = true;
955 if(i == 0)
957 if(song.artist != null && song.album != null)
959 MPD.Database.search_start(server,true);
960 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
961 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, song.album);
962 var data = MPD.Database.search_commit(server);
963 data.sort_album_disc_track();
964 sl.set_from_data((owned)data, true);
966 else
968 sl.destroy();
969 alib.add(new Gtk.Label(_("Not available")));
971 text_view_queried = true;
973 alib.show_all();
974 i++;
977 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Artist info took: %.6f seconds.", t.elapsed());
978 /* Track changed pages */
979 notebook.notify["page"].connect((source,spec) =>
981 var page = notebook.get_current_page();
982 config.set_int("NowPlaying", "last-page", (int)page);
985 /* Restore right page */
986 if(i > 0)
988 var page = config.get_int_with_default("NowPlaying", "last-page", 0);
989 if(page > i)
991 notebook.set_current_page(0);
993 else
995 /* The list is in reversed order, compensate for that. */
996 var w = group.nth_data(i-page-1);
997 w.set_active(true);
998 notebook.set_current_page(page);
1002 ali = new Gtk.Alignment(0.0f, 0.5f,1f,0f);
1003 ali.add(hboxje);
1005 /* Create pane in 2. */
1006 var bottom_hbox = new Gtk.HBox(false, 6);
1007 /* left pane */
1008 var metadata_vbox = new Gtk.VBox(false, 0);
1009 metadata_vbox.pack_start(ali, false, false, 0);
1010 sep = new Gtk.HSeparator();
1011 sep.set_size_request(-1, 1);
1012 metadata_vbox.pack_start(sep, false, false, 0);
1013 metadata_vbox.pack_start(notebook, false, false, 0);
1015 bottom_hbox.pack_start(metadata_vbox, true, true, 0);
1017 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Building now playing took: %.6f seconds.", t.elapsed());
1018 /* Create album list */
1019 if(song.album != null && song.artist != null)
1021 var sep2 = new Gtk.VSeparator();
1022 sep2.set_size_request(-1, 4);
1023 bottom_hbox.pack_start(sep2, false, false, 0);
1024 int albums =0;
1025 /* Create album list */
1026 ali = new Gtk.Alignment(0.0f, 0.0f, 0.0f, 0.0f);
1027 var album_hbox = new Gtk.VBox(false, 6);
1028 album_hbox.set_size_request(250, -1);
1029 ali.add(album_hbox);
1030 bottom_hbox.pack_start(ali, false, false, 0);
1032 var label = new Gtk.Label(song.artist);
1033 label.selectable = true;
1034 label.set_size_request(240, -1);
1035 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));
1036 label.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR);
1037 label.set_line_wrap(true);
1038 label.set_alignment(0.0f, 0.5f);
1039 album_hbox.pack_start(label, false, false,0);
1041 MPD.Database.search_field_start(server, MPD.Tag.Type.ALBUM);
1042 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
1043 MPD.Data.Item list = null;
1044 var data = MPD.Database.search_commit(server);
1045 if(data != null)
1047 unowned MPD.Data.Item iter = data.get_first();
1050 if(iter.tag == song.album)
1052 iter.next(false);
1053 continue;
1055 list.append_new();
1056 list.type = MPD.Data.Type.SONG;
1057 list.song = new MPD.Song();
1058 list.song.artist = song.artist;
1059 list.song.album = iter.tag;
1061 MPD.Database.search_field_start(server,MPD.Tag.Type.DATE);
1062 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
1063 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, iter.tag);
1064 var ydata = MPD.Database.search_commit(server);
1065 if(ydata != null) {
1066 list.song.date = ydata.tag;
1069 iter.next(false);
1071 while(iter != null);
1074 list.sort_album_disc_track();
1075 if(list != null)
1077 unowned MPD.Data.Item iter = list.get_first();
1080 var button = new Gtk.Button();
1081 button.set_relief(Gtk.ReliefStyle.NONE);
1082 var but_hbox = new Gtk.HBox(false, 6);
1083 button.add(but_hbox);
1084 var image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, 48);
1085 unowned MPD.Song but_song = iter.song;
1086 image.set_squared(true);
1087 image.update_from_song_delayed(but_song);
1089 but_hbox.pack_start(image, false, false, 0);
1091 var but_label = new Gtk.Label(iter.song.album);
1092 but_label.selectable = true;
1093 but_label.set_alignment(0.0f, 0.5f);
1094 var strlabel = "";
1095 if(iter.song.date != null && iter.song.date.length > 0) strlabel += "%s\n".printf(iter.song.date);
1096 if(iter.song.album != null) strlabel+= iter.song.album;
1097 else strlabel += _("No Album");
1098 but_label.set_markup(GLib.Markup.printf_escaped("<b>%s</b>",strlabel));
1099 but_label.set_ellipsize(Pango.EllipsizeMode.END);
1100 but_hbox.pack_start(but_label, true, true, 0);
1102 album_hbox.pack_start(button, false, false,0);
1103 button.set_data("artist",
1104 but_song.artist.dup());
1105 button.set_data("album",
1106 but_song.album.dup());
1107 stdout.printf("open: %s %s\n", but_song.artist, but_song.album);
1108 button.clicked.connect((source) =>
1110 unowned string artist = (string)source.get_data<string>("artist");
1111 unowned string album = (string)source.get_data<string>("album");
1112 stdout.printf("open: %s %s\n", artist, album);
1113 Gmpc.Browser.Metadata.show_album(artist, album);
1115 albums++;
1117 iter.next(false);
1119 while(iter!= null);
1122 if(albums == 0)
1124 album_hbox.destroy();
1125 sep2.destroy();
1128 vbox.pack_start(bottom_hbox, true, true, 0);
1130 /* show it */
1131 this.container.add(vbox);
1132 this.change_color_style(this.container);
1133 this.container.show_all();
1135 t.stop();
1136 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Building now playing took: %.6f seconds.", t.elapsed());
1139 * This shows the page when mpd is not playing, for now it is the gmpc logo + Gnome Music Player Client
1141 private void update_not_playing()
1143 this.clear();
1144 song_checksum = null;
1145 if(use_backdrop)
1146 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(null);
1148 var it = Gtk.IconTheme.get_default();
1149 Gtk.IconInfo info = it.lookup_icon("gmpc", 150, 0);
1150 var path = info.get_filename();
1151 Gtk.Image image = null;
1152 if(path != null)
1156 var pb = new Gdk.Pixbuf.from_file_at_scale(path, 150, 150, true);
1157 image = new Gtk.Image.from_pixbuf(pb);
1159 catch (Error e)
1161 warning("Failed to load the gmpc logo: %s", e.message);
1162 return;
1165 if(image == null)
1167 image = new Gtk.Image.from_icon_name("gmpc", Gtk.IconSize.DIALOG);
1170 var hbox = new Gtk.HBox(false, 6);
1171 var label = new Gtk.Label(_("Gnome Music Player Client"));
1172 label.set_selectable(true);
1173 label.set_markup("<span size='%i' weight='bold'>%s</span>".printf(28*Pango.SCALE,_("Gnome Music Player Client")));
1174 hbox.pack_start(image, false, false, 0);
1175 hbox.pack_start(label, false, false, 0);
1177 var ali = new Gtk.Alignment(0.5f,0.5f,0.0f, 0.0f);
1178 ali.add(hbox);
1179 this.container.add(ali);
1181 this.change_color_style(this.container);
1182 this.container.show_all();
1186 * Update the view according to state. If playing/paused show song info, other wise the not playing page
1188 private void update()
1190 switch(MPD.Player.get_state(Gmpc.server))
1192 case MPD.Player.State.PLAY:
1193 case MPD.Player.State.PAUSE:
1194 debug("Update playing");
1195 update_playing();
1196 break;
1197 default:
1198 debug("update not playing");
1199 update_not_playing();
1200 break;
1205 * Makes gmpc jump to the now playing browser
1207 public void select_now_playing_browser()
1209 unowned Gtk.TreeView tree = Gmpc.Playlist3.get_category_tree_view();
1210 var sel = tree.get_selection();
1211 var path = np_ref.get_path();
1212 if(path != null)
1214 sel.select_path(path);
1219 * Gmpc.Plugin.BrowserIface.add_go_menu
1221 private int browser_add_go_menu(Gtk.Menu menu)
1223 if(this.get_enabled())
1225 var item = new Gtk.ImageMenuItem.with_mnemonic(_("Now Playing"));
1226 item.set_image(new Gtk.Image.from_icon_name("media-audiofile", Gtk.IconSize.MENU));
1227 item.activate.connect(select_now_playing_browser);
1228 item.add_accelerator("activate", menu.get_accel_group(),0x069, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);
1229 menu.append(item);
1230 return 1;
1232 return 0;