Use new DataView in now-playing for testing.
[gmpc.git] / src / browsers / gmpc-nowplaying2.vala
blob62cafe09a70eb8df9fb71be554287e30163223e5
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 || bg is Gtk.Image)
256 /* Do nothing */
258 else
260 if(theme_colors)
262 bg.modify_bg(Gtk.StateType.NORMAL,this.paned.style.base[Gtk.StateType.NORMAL]);
263 /*bg.modify_base(Gtk.StateType.NORMAL,this.paned.style.mid[Gtk.StateType.NORMAL]);/*
264 // bg.modify_text(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
265 bg.modify_fg(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
266 bg.modify_text(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);
267 bg.modify_fg(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);*/
269 else
271 bg.modify_bg(Gtk.StateType.NORMAL,this.background);
272 bg.modify_base(Gtk.StateType.NORMAL,this.background);
273 bg.modify_text(Gtk.StateType.NORMAL,this.foreground);
274 bg.modify_fg(Gtk.StateType.NORMAL,this.foreground);
275 bg.modify_text(Gtk.StateType.ACTIVE,this.foreground);
276 bg.modify_fg(Gtk.StateType.ACTIVE,this.foreground);
279 /* Recurse into children, if the widget can hold children (so is a container */
280 if(bg is Gtk.Container)
282 foreach(Gtk.Widget child in ((Gtk.Container)bg).get_children())
284 change_color_style(child);
288 /* Create the basic gui. on initializing */
289 private void browser_init()
291 if(this.paned == null)
294 this.paned = new Gtk.ScrolledWindow(null,null);
295 this.paned.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
296 this.paned.set_shadow_type(Gtk.ShadowType.ETCHED_IN);
297 if(use_backdrop)
299 this.container = new Gmpc.MetaData.Widgets.Backdrop(Gmpc.MetaData.Type.BACKDROP_ART);
301 else
303 this.container = new Gtk.EventBox();
306 this.container.set_focus_hadjustment(this.paned.get_hadjustment());
307 this.container.set_focus_vadjustment(this.paned.get_vadjustment());
309 this.paned.style_set.connect(browser_bg_style_changed);
310 this.paned.add_with_viewport(this.container);
311 this.paned.get_vadjustment().set("step-increment", 20.0);
312 this.paned.show_all();
317 /* Clear the view inside the scrolled window*/
318 private void clear()
320 /* Clear */
321 var list = this.container.get_children();
322 foreach(Gtk.Widget child in list)
324 child.destroy();
326 bitrate_label = null;
330 private string get_extension(string path)
332 long length = path.length;
333 long i=length;
334 string retv = null;
335 for(; i>0 && (length-i) <8; i--)
337 if(path[i] == '.')
339 retv = path.substring(i+1);
340 return retv;
343 return retv;
346 * Show the page when playing
348 private string song_checksum = null;
349 private void update_playing()
351 unowned MPD.Song? song = server.playlist_get_current_song();
352 if(song == null)
354 debug("GMPC Is playing, cannot get this");
355 if(use_backdrop)
356 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(null);
357 update_not_playing();
358 return;
360 /* Force it so we won't update when not needed */
361 var checksum = Gmpc.Misc.song_checksum(song);
362 if(checksum == this.song_checksum)
364 /* No need to update. */
365 return;
367 GLib.Timer t = new GLib.Timer();
368 this.clear();
369 if(use_backdrop)
370 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(song);
371 this.song_checksum = checksum;
373 var vbox = new Gtk.VBox (false,6);
374 vbox.border_width = 8;
375 /* Start building the gui */
376 /* Artist image */
377 var hbox = new Gtk.HBox(false, 6);
378 Gtk.Alignment ali = null;
380 int meta_size = (int)(this.container.get_allocated_width()*0.20);
381 /* get size based on alloc */
382 meta_size = int.min(int.max(100, meta_size), 250);
383 if(config.get_int_with_default("Interface", "hide-album-art", 0) == 0)
385 /* Album image */
386 ali = new Gtk.Alignment(0f,0f,0f,0f);
387 //ali.set_size_request(meta_size,meta_size);
388 var album_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, meta_size);
389 album_image.set_scale_up(true);
390 album_image.set_squared(false);
391 ali.add(album_image);
392 album_image.update_from_song(song);
393 hbox.pack_start(ali, false, false, 0);
396 /* Artist image */
397 if(config.get_int_with_default("Interface", "hide-album-art", 0) == 0 && !use_backdrop)
399 ali = new Gtk.Alignment(1f,0f,0f,0f);
400 var artist_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ARTIST_ART, meta_size);
401 artist_image.set_scale_up(true);
402 artist_image.set_squared(false);
403 artist_image.update_from_song(song);
404 ali.add(artist_image);
405 hbox.pack_end(ali, false, false, 0);
408 /* Information box */
409 var info_vbox = new Gtk.VBox(false, 6);
410 /* Title */
411 if(song.title != null)
413 var box = new Gtk.HBox(false, 6);
414 /* Favored button */
416 if(config.get_int_with_default("Interface", "hide-favorites-icon",0) == 0)
418 var fav_button = new Gmpc.Favorites.Button();
419 fav_button.set_song(song);
420 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
421 ali.add(fav_button);
422 box.pack_start(ali, false, false, 0);
424 var label = new Gtk.Label(song.title);
425 label.selectable = true;
426 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",
427 this.title_color,Pango.SCALE*20 ,song.title));
428 label.set_ellipsize(Pango.EllipsizeMode.END);
429 label.set_alignment(0.0f, 0.5f);
430 box.pack_start(label, true, true, 0);
431 info_vbox.pack_start(box, false, false, 0);
434 else if (song.name!= null)
436 var label = new Gtk.Label(song.name);
437 label.selectable = true;
438 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this.
439 title_color, Pango.SCALE*20, song.name));
440 label.set_ellipsize(Pango.EllipsizeMode.END);
441 label.set_alignment(0.0f, 0.5f);
442 info_vbox.pack_start(label, false, false, 0);
444 else if (song.file != null)
446 var filename = GLib.Path.get_basename(song.file);
447 var label = new Gtk.Label(song.name);
448 label.selectable = true;
451 var regex_a = new GLib.Regex ("\\.[0-9a-zA-Z]*$");
452 filename = regex_a.replace_literal (filename, -1, 0, "");
454 catch (GLib.RegexError e)
456 GLib.error("%s", e.message);
460 var regex_b = new GLib.Regex ("_");
461 filename = regex_b.replace_literal (filename, -1, 0, " ");
463 catch (GLib.RegexError e)
465 GLib.error("%s", e.message);
467 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this.
468 title_color, Pango.SCALE*20, filename));
469 label.set_ellipsize(Pango.EllipsizeMode.END);
470 label.set_alignment(0.0f, 0.5f);
471 info_vbox.pack_start(label, false, false, 0);
474 /* Artist */
475 if(song.artist != null)
477 var event = new Gtk.EventBox();
478 var box = new Gtk.HBox(false, 6);
479 var label = new Gtk.Label(song.artist);
480 event.set_visible_window(false);
481 label.selectable = true;
482 var image = new Gtk.Image.from_icon_name("media-artist", Gtk.IconSize.MENU);
483 event.add(image);
484 box.pack_start(event, false, false, 0);
485 label.set_markup(GLib.Markup.printf_escaped("<span size='xx-large' weight='bold'>%s</span>", song.artist));
486 label.set_ellipsize(Pango.EllipsizeMode.END);
487 label.set_alignment(0.0f, 0.5f);
488 box.pack_start(label, true, true, 0);
489 info_vbox.pack_start(box, false, false, 0);
491 event.set_data("artist",song.artist);
492 event.button_press_event.connect((widget, event) =>
494 string artist = (string)widget.get_data<string>("artist");
495 Gmpc.Browser.Metadata.show_artist(artist);
496 return false;
499 /* Album */
500 if(song.album != null)
502 var event = new Gtk.EventBox();
503 var box = new Gtk.HBox(false, 6);
504 var label = new Gtk.Label(song.album);
505 event.set_visible_window(false);
506 label.selectable = true;
507 var image = new Gtk.Image.from_icon_name("media-album", Gtk.IconSize.MENU);
508 event.add(image);
509 box.pack_start(event, false, false, 0);
510 label.set_markup(GLib.Markup.printf_escaped("<span size='x-large' weight='bold'>%s %s</span>", song.album,
511 (song.date != null)? "(%s)".printf(song.date):""));
512 label.set_ellipsize(Pango.EllipsizeMode.END);
513 label.set_alignment(0.0f, 0.5f);
514 box.pack_start(label, true, true, 0);
515 info_vbox.pack_start(box, false, false, 0);
519 event.set_data("artist",song.artist);
520 event.set_data("album",song.album);
521 event.button_press_event.connect((widget, event) =>
523 string artist = (string)widget.get_data<string>("artist");
524 string album = (string)widget.get_data<string>("album");
525 if(artist != null && album != null)
527 Gmpc.Browser.Metadata.show_album(artist,album);
528 return true;
530 return false;
533 /* Genre */
534 if(song.genre != null)
536 var box = new Gtk.HBox(false, 6);
537 var label = new Gtk.Label(song.title);
538 label.selectable = true;
539 var image = new Gtk.Image.from_icon_name("media-genre", Gtk.IconSize.MENU);
540 box.pack_start(image, false, false, 0);
541 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
542 this.item_color,_("Genre"), song.genre));
543 label.set_ellipsize(Pango.EllipsizeMode.END);
544 label.set_alignment(0.0f, 0.5f);
545 box.pack_start(label, true, true, 0);
546 info_vbox.pack_start(box, false, false, 0);
549 /* Format */
551 var box = new Gtk.HBox(false, 6);
552 var image = new Gtk.Image.from_icon_name("media-format", Gtk.IconSize.MENU);
553 box.pack_start(image, false, false, 0);
555 bitrate_label = new Gtk.Label(song.title);
556 bitrate_label.selectable = true;
557 bitrate_label.set_ellipsize(Pango.EllipsizeMode.END);
558 bitrate_label.set_alignment(0.0f, 0.5f);
560 box.pack_start(bitrate_label, true, true, 0);
562 var bitrate = MPD.Status.get_bitrate(Gmpc.server);
563 var channels = MPD.Status.get_channels(Gmpc.server);
564 bitrate_label.set_markup(GLib.Markup.printf_escaped(
565 "<span color='%s' weight='bold'>%s:</span> %i %s, %.1f %s, %i %s",
566 this.item_color, _("Format"),
567 channels , GLib.ngettext(N_("Channel"),N_("Channels"), channels),
568 MPD.Status.get_samplerate(Gmpc.server)/1000.0, "kHz",
569 bitrate, "kbps"
572 info_vbox.pack_start(box, false, false, 0);
574 if(song.file != null)
577 string extension = null;
578 extension = get_extension(song.file);
579 if(extension != null)
581 var box = new Gtk.HBox(false, 6);
582 var image = new Gtk.Image.from_icon_name("media-codec", Gtk.IconSize.MENU);
583 box.pack_start(image, false, false, 0);
585 var label = new Gtk.Label(song.title);
586 label.selectable = true;
587 label.set_ellipsize(Pango.EllipsizeMode.END);
588 label.set_alignment(0.0f, 0.5f);
589 box.pack_start(label, true, true, 0);
590 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
591 this.item_color, _("Codec"),
592 extension));
593 info_vbox.pack_start(box, false, false, 0);
596 /* Time*/
597 if(song.time > 0)
599 var box = new Gtk.HBox(false, 6);
600 var image = new Gtk.Image.from_icon_name("media-track-length", Gtk.IconSize.MENU);
601 box.pack_start(image, false, false, 0);
602 var label = new Gtk.Label("");
603 label.selectable = true;
604 label.set_ellipsize(Pango.EllipsizeMode.END);
605 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
606 this.item_color,_("Length"),
607 Gmpc.Misc.format_time((ulong) song.time, "")));
608 label.set_alignment(0.0f, 0.5f);
609 box.pack_start(label, true, true, 0);
610 info_vbox.pack_start(box, false, false, 0);
613 if(song.track != null)
615 var box = new Gtk.HBox(false, 6);
616 var image = new Gtk.Image.from_icon_name("media-num-tracks", Gtk.IconSize.MENU);
617 box.pack_start(image, false, false, 0);
618 var label = new Gtk.Label("");
619 label.selectable = true;
620 label.set_ellipsize(Pango.EllipsizeMode.END);
621 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s %s",
622 this.item_color, _("Track number"),
623 song.track,
624 (song.disc != null)? "[%s]".printf(song.disc):""
626 label.set_alignment(0.0f, 0.5f);
627 box.pack_start(label, true, true, 0);
628 info_vbox.pack_start(box, false, false, 0);
632 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "heading took: %.6f seconds.", t.elapsed());
633 hbox.pack_start(info_vbox, true, true, 0);
634 vbox.pack_start(hbox, false, false, 0);
636 /* Separator */
637 var sep = new Gtk.HSeparator();
638 sep.set_size_request(-1, 4);
639 vbox.pack_start(sep, false, false, 0);
641 var hboxje = new Gtk.HBox(false, 6);
643 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
644 var notebook = new Gtk.Notebook();
645 notebook.set_show_border(false);
646 notebook.set_show_tabs(false);
648 /* Lyrics */
649 var i = 0;
650 unowned SList<unowned Gtk.RadioButton> group = null;
651 if(config.get_int_with_default("MetaData", "show-lyrics",1) == 1)
653 var alib = new Gtk.Alignment(0f,0f,1f,0f);
654 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_TXT);
655 alib.add(text_view);
656 notebook.append_page(alib, new Gtk.Label("Lyrics"));
657 var button = new Gtk.RadioButton(group);//.with_label(group,("Lyrics"));
658 var label = new Gtk.Label(_("Lyrics"));
659 label.ellipsize = Pango.EllipsizeMode.END;
660 label.set_alignment(0.0f, 0.5f);
661 // button.add(label);
663 if(group != null)
664 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
665 group = button.get_group();
666 hboxje.pack_start(button, false, false, 0);
667 hboxje.pack_start(label, true, true, 0);
668 var j = i;
669 button.clicked.connect((source) =>
671 if((source as Gtk.CheckButton).get_active())
673 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics notebook page %i clicked", j);
674 notebook.set_current_page(j);
677 i++;
679 alib.show();
681 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics took: %.6f seconds.", t.elapsed());
683 /* Album information */
684 if(config.get_int_with_default("MetaData", "show-album-information",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.ALBUM_TXT);
688 alib.add(text_view);
689 notebook.append_page(alib, new Gtk.Label("Album information"));
690 var button = new Gtk.RadioButton(group);
691 var label = new Gtk.Label(_("Album information"));
692 label.ellipsize = Pango.EllipsizeMode.END;
693 label.set_alignment(0.0f, 0.5f);
695 if(group != null)
696 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
697 group = button.get_group();
698 hboxje.pack_start(button, false, false, 0);
699 hboxje.pack_start(label, true, true, 0);
700 var j = i;
701 button.clicked.connect((source) =>
703 if((source as Gtk.CheckButton).get_active())
705 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics notebook page %i clicked", j);
706 notebook.set_current_page(j);
709 i++;
711 alib.show();
714 /* Guitar Tabs */
715 if(config.get_int_with_default("MetaData", "show-guitar-tabs",1) == 1)
717 var alib = new Gtk.Alignment(0f,0f,1f,0f);
718 var text_view_queried = false;
719 notebook.append_page(alib, new Gtk.Label(_("Guitar Tabs")));
720 var button = new Gtk.RadioButton(group);//.with_label(group,_("Guitar Tabs"));
721 var label = new Gtk.Label(_("Guitar Tabs"));
722 label.ellipsize = Pango.EllipsizeMode.END;
723 label.set_alignment(0.0f, 0.5f);
724 //button.add(label);
725 if(group != null)
726 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
727 group = button.get_group();
728 hboxje.pack_start(button, false, false, 0);
729 hboxje.pack_start(label, true, true, 0);
730 var j = i;
731 /* Only query the guitar-tab when opened or first notebook page*/
732 button.clicked.connect((source) =>
734 if((source as Gtk.CheckButton).get_active())
736 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "guitar tab notebook page %i clicked", j);
737 notebook.set_current_page(j);
738 if(!text_view_queried)
740 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_GUITAR_TAB);
741 alib.add(text_view);
742 text_view_queried = true;
743 this.change_color_style(text_view);
744 text_view.show();
748 if(i == 0)
750 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_GUITAR_TAB);
751 alib.add(text_view);
752 text_view_queried = true;
754 alib.show_all();
755 i++;
757 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "guitar tabs took: %.6f seconds.", t.elapsed());
759 /* Similar songs */
761 if(config.get_int_with_default("MetaData", "show-similar-songs",1) == 1)
763 var similar_songs_queried = false;
764 var similar_songs_box = new Gtk.Alignment(0f,0f,0f,0f);
766 notebook.append_page(similar_songs_box, new Gtk.Label(_("Similar Songs")));
768 var button = new Gtk.RadioButton(group);//.with_label(group,_("Similar Songs"));
769 var label = new Gtk.Label(_("Similar Songs"));
770 label.ellipsize = Pango.EllipsizeMode.END;
771 label.set_alignment(0.0f, 0.5f);
772 //button.add(label);
773 if(group != null)
774 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
775 group = button.get_group();
776 hboxje.pack_start(button, false, false, 0);
777 hboxje.pack_start(label, true, true, 0);
779 var j = i;
780 /* Only query when opened or first notebook page*/
781 button.clicked.connect((source) =>
783 if((source as Gtk.CheckButton).get_active())
785 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "similar song notebook page %i clicked", j);
786 notebook.set_current_page(j);
787 if(!similar_songs_queried)
789 var similar_songs = new Gmpc.MetaData.Widgets.SimilarSongs(song);
790 similar_songs.update();
791 similar_songs_queried = true;
792 similar_songs_box.add(similar_songs);
793 this.change_color_style(similar_songs_box);
794 similar_songs_box.show_all();
798 if(i == 0)
800 var similar_songs = new Gmpc.MetaData.Widgets.SimilarSongs(song);
801 similar_songs.update();
802 similar_songs_queried = true;
803 similar_songs_box.add(similar_songs);
804 similar_songs_box.show_all();
806 similar_songs_box.show();
807 i++;
810 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "similar songs took: %.6f seconds.", t.elapsed());
811 if(config.get_int_with_default("MetaData", "show-similar-artist",1) == 1 && song.artist != null)
813 var similar_artist = new Gmpc.MetaData.Widgets.SimilarArtists(Gmpc.server,song);
815 notebook.append_page(similar_artist, new Gtk.Label(_("Similar Artist")));
817 var button = new Gtk.RadioButton(group);//.with_label(group,_("Similar Artist"));
818 var label = new Gtk.Label(_("Similar Artist"));
819 label.ellipsize = Pango.EllipsizeMode.END;
820 label.set_alignment(0.0f, 0.5f);
821 //button.add(label);
822 if(group != null)
823 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
824 group = button.get_group();
825 hboxje.pack_start(button, false, false, 0);
826 hboxje.pack_start(label, true, true, 0);
828 var j = i;
829 button.clicked.connect((source) =>
831 if((source as Gtk.CheckButton).get_active())
833 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "similar artist notebook page %i clicked", j);
834 similar_artist.first_show();
835 notebook.set_current_page(j);
838 similar_artist.show();
839 i++;
841 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "similar Artist took: %.6f seconds.", t.elapsed());
842 if(config.get_int_with_default("MetaData", "show-artist-information",1) == 1)
844 var alib = new Gtk.Alignment(0f,0f,1f,0f);
845 var text_view_queried = false;
847 notebook.append_page(alib, new Gtk.Label(_("Artist information")));
848 var button = new Gtk.RadioButton(group);//.with_label(group,_("Artist information"));
849 var label = new Gtk.Label(_("Artist information"));
850 label.ellipsize = Pango.EllipsizeMode.END;
851 label.set_alignment(0.0f, 0.5f);
852 //button.add(label);
853 if(group != null)
854 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
855 group = button.get_group();
856 hboxje.pack_start(button, false, false, 0);
857 hboxje.pack_start(label, true, true, 0);
858 var j = i;
859 /* Only query the guitar-tab when opened or first notebook page*/
860 button.clicked.connect((source) =>
862 if((source as Gtk.CheckButton).get_active())
864 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "artist info notebook page %i clicked", j);
865 notebook.set_current_page(j);
866 if(!text_view_queried)
868 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song,Gmpc.MetaData.Type.ARTIST_TXT);
869 alib.add(text_view);
870 text_view_queried = true;
871 text_view.show();
872 this.change_color_style(text_view);
876 if(i == 0)
878 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song,Gmpc.MetaData.Type.ARTIST_TXT);
879 alib.add(text_view);
880 text_view_queried = true;
882 alib.show_all();
883 i++;
886 if(config.get_int_with_default("MetaData", "show-songs-from-album",1) == 1)
888 var alib = new Gtk.Alignment(0f,0f,1f,0f);
889 var text_view_queried = false;
891 notebook.append_page(alib, new Gtk.Label(_("Songs from album")));
892 var button = new Gtk.RadioButton(group);//.with_label(group,_("Songs from album"));
893 var label = new Gtk.Label(_("Songs from album"));
894 label.ellipsize = Pango.EllipsizeMode.END;
895 label.set_alignment(0.0f, 0.5f);
896 //button.add(label);
897 if(group != null)
898 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
899 group = button.get_group();
900 hboxje.pack_start(button, false, false, 0);
901 hboxje.pack_start(label, true, true, 0);
902 var j = i;
903 var sl = new Gmpc.DataView("now-playing-song-from-album");
904 var sl_model = new Gmpc.MpdData.Model();
905 sl.set_model(sl_model);
907 alib.add(sl);
908 button.clicked.connect((source) =>
910 if((source as Gtk.CheckButton).get_active())
912 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "artist info notebook page %i clicked", j);
913 notebook.set_current_page(j);
914 if(!text_view_queried)
916 if(song.artist != null && song.album != null)
918 MPD.Database.search_start(server,true);
919 if(song.albumartist != null)
921 MPD.Database.search_add_constraint(server,
922 MPD.Tag.Type.ALBUM_ARTIST, song.albumartist);
924 else
926 MPD.Database.search_add_constraint(server,
927 MPD.Tag.Type.ARTIST, song.artist);
929 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, song.album);
930 var data = MPD.Database.search_commit(server);
931 data.sort_album_disc_track();
932 sl_model.set_mpd_data((owned)data);
933 // sl.set_from_data((owned)data, true);
934 // this.change_color_style(sl);
936 else
938 sl.destroy();
939 alib.add(new Gtk.Label(_("Not available")));
941 text_view_queried = true;
945 if(i == 0)
947 if(song.artist != null && song.album != null)
949 MPD.Database.search_start(server,true);
950 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
951 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, song.album);
952 var data = MPD.Database.search_commit(server);
953 data.sort_album_disc_track();
954 sl_model.set_mpd_data((owned)data);
955 //sl.set_from_data((owned)data, true);
957 else
959 sl.destroy();
960 alib.add(new Gtk.Label(_("Not available")));
962 text_view_queried = true;
964 alib.show_all();
965 i++;
968 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Artist info took: %.6f seconds.", t.elapsed());
969 /* Track changed pages */
970 notebook.notify["page"].connect((source,spec) =>
972 var page = notebook.get_current_page();
973 config.set_int("NowPlaying", "last-page", (int)page);
976 /* Restore right page */
977 if(i > 0)
979 var page = config.get_int_with_default("NowPlaying", "last-page", 0);
980 if(page > i)
982 notebook.set_current_page(0);
984 else
986 /* The list is in reversed order, compensate for that. */
987 var w = group.nth_data(i-page-1);
988 w.set_active(true);
989 notebook.set_current_page(page);
993 ali = new Gtk.Alignment(0.0f, 0.5f,1f,0f);
994 ali.add(hboxje);
996 /* Create pane in 2. */
997 var bottom_hbox = new Gtk.HBox(false, 6);
998 /* left pane */
999 var metadata_vbox = new Gtk.VBox(false, 0);
1000 metadata_vbox.pack_start(ali, false, false, 0);
1001 sep = new Gtk.HSeparator();
1002 sep.set_size_request(-1, 1);
1003 metadata_vbox.pack_start(sep, false, false, 0);
1004 metadata_vbox.pack_start(notebook, false, false, 0);
1006 bottom_hbox.pack_start(metadata_vbox, true, true, 0);
1008 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Building now playing took: %.6f seconds.", t.elapsed());
1009 /* Create album list */
1010 if(song.album != null && song.artist != null)
1012 var sep2 = new Gtk.VSeparator();
1013 sep2.set_size_request(-1, 4);
1014 bottom_hbox.pack_start(sep2, false, false, 0);
1015 int albums =0;
1016 /* Create album list */
1017 ali = new Gtk.Alignment(0.0f, 0.0f, 0.0f, 0.0f);
1018 var album_hbox = new Gtk.VBox(false, 6);
1019 album_hbox.set_size_request(250, -1);
1020 ali.add(album_hbox);
1021 bottom_hbox.pack_start(ali, false, false, 0);
1023 var label = new Gtk.Label(song.artist);
1024 label.selectable = true;
1025 label.set_size_request(240, -1);
1026 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));
1027 label.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR);
1028 label.set_line_wrap(true);
1029 label.set_alignment(0.0f, 0.5f);
1030 album_hbox.pack_start(label, false, false,0);
1032 MPD.Database.search_field_start(server, MPD.Tag.Type.ALBUM);
1033 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
1034 MPD.Data.Item list = null;
1035 var data = MPD.Database.search_commit(server);
1036 if(data != null)
1038 unowned MPD.Data.Item iter = data.get_first();
1041 if(iter.tag == song.album)
1043 iter.next(false);
1044 continue;
1046 list.append_new();
1047 list.type = MPD.Data.Type.SONG;
1048 list.song = new MPD.Song();
1049 list.song.artist = song.artist;
1050 list.song.album = iter.tag;
1052 MPD.Database.search_field_start(server,MPD.Tag.Type.DATE);
1053 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
1054 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, iter.tag);
1055 var ydata = MPD.Database.search_commit(server);
1056 if(ydata != null) {
1057 list.song.date = ydata.tag;
1060 iter.next(false);
1062 while(iter != null);
1065 list.sort_album_disc_track();
1066 int count = 0;
1067 if(list != null)
1069 unowned MPD.Data.Item iter = list.get_first();
1072 if(count > this.max_albums)
1074 var l = new Gtk.Label(_("More..."));
1075 l.set_alignment(0, 0.5f);
1076 album_hbox.pack_start(l, false,false, 0);
1077 // jump out.
1078 iter = null;
1079 continue;
1081 count++;
1082 var button = new Gtk.Button();
1083 button.set_relief(Gtk.ReliefStyle.NONE);
1084 var but_hbox = new Gtk.HBox(false, 6);
1085 button.add(but_hbox);
1086 var image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, 48);
1087 unowned MPD.Song but_song = iter.song;
1088 image.set_squared(true);
1089 image.update_from_song_delayed(but_song);
1091 but_hbox.pack_start(image, false, false, 0);
1093 var but_label = new Gtk.Label(iter.song.album);
1094 but_label.selectable = true;
1095 but_label.set_alignment(0.0f, 0.5f);
1096 var strlabel = "";
1097 if(iter.song.date != null && iter.song.date.length > 0) strlabel += "%s\n".printf(iter.song.date);
1098 if(iter.song.album != null) strlabel+= iter.song.album;
1099 else strlabel += _("No Album");
1100 but_label.set_markup(GLib.Markup.printf_escaped("<b>%s</b>",strlabel));
1101 but_label.set_ellipsize(Pango.EllipsizeMode.END);
1102 but_hbox.pack_start(but_label, true, true, 0);
1104 album_hbox.pack_start(button, false, false,0);
1105 button.set_data("artist",
1106 but_song.artist.dup());
1107 button.set_data("album",
1108 but_song.album.dup());
1109 stdout.printf("open: %s %s\n", but_song.artist, but_song.album);
1110 button.clicked.connect((source) =>
1112 unowned string artist = (string)source.get_data<string>("artist");
1113 unowned string album = (string)source.get_data<string>("album");
1114 stdout.printf("open: %s %s\n", artist, album);
1115 Gmpc.Browser.Metadata.show_album(artist, album);
1117 albums++;
1119 iter.next(false);
1121 while(iter!= null);
1124 if(albums == 0)
1126 album_hbox.destroy();
1127 sep2.destroy();
1130 vbox.pack_start(bottom_hbox, true, true, 0);
1132 /* show it */
1133 this.container.add(vbox);
1134 this.change_color_style(this.container);
1135 this.container.show_all();
1137 t.stop();
1138 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Building now playing took: %.6f seconds.", t.elapsed());
1141 * This shows the page when mpd is not playing, for now it is the gmpc logo + Gnome Music Player Client
1143 private void update_not_playing()
1145 this.clear();
1146 song_checksum = null;
1147 if(use_backdrop)
1148 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(null);
1150 var it = Gtk.IconTheme.get_default();
1151 Gtk.IconInfo info = it.lookup_icon("gmpc", 150, 0);
1152 var path = info.get_filename();
1153 Gtk.Image image = null;
1154 if(path != null)
1158 var pb = new Gdk.Pixbuf.from_file_at_scale(path, 150, 150, true);
1159 image = new Gtk.Image.from_pixbuf(pb);
1161 catch (Error e)
1163 warning("Failed to load the gmpc logo: %s", e.message);
1164 return;
1167 if(image == null)
1169 image = new Gtk.Image.from_icon_name("gmpc", Gtk.IconSize.DIALOG);
1172 var hbox = new Gtk.HBox(false, 6);
1173 var label = new Gtk.Label(_("Gnome Music Player Client"));
1174 label.set_selectable(true);
1175 label.set_markup("<span size='%i' weight='bold'>%s</span>".printf(28*Pango.SCALE,_("Gnome Music Player Client")));
1176 hbox.pack_start(image, false, false, 0);
1177 hbox.pack_start(label, false, false, 0);
1179 var ali = new Gtk.Alignment(0.5f,0.5f,0.0f, 0.0f);
1180 ali.add(hbox);
1181 this.container.add(ali);
1183 this.change_color_style(this.container);
1184 this.container.show_all();
1188 * Update the view according to state. If playing/paused show song info, other wise the not playing page
1190 private void update()
1192 switch(MPD.Player.get_state(Gmpc.server))
1194 case MPD.Player.State.PLAY:
1195 case MPD.Player.State.PAUSE:
1196 debug("Update playing");
1197 update_playing();
1198 break;
1199 default:
1200 debug("update not playing");
1201 update_not_playing();
1202 break;
1207 * Makes gmpc jump to the now playing browser
1209 public void select_now_playing_browser()
1211 unowned Gtk.TreeView tree = Gmpc.Playlist3.get_category_tree_view();
1212 var sel = tree.get_selection();
1213 var path = np_ref.get_path();
1214 if(path != null)
1216 sel.select_path(path);
1221 * Gmpc.Plugin.BrowserIface.add_go_menu
1223 private int browser_add_go_menu(Gtk.Menu menu)
1225 if(this.get_enabled())
1227 var item = new Gtk.ImageMenuItem.with_mnemonic(_("Now Playing"));
1228 item.set_image(new Gtk.Image.from_icon_name("media-audiofile", Gtk.IconSize.MENU));
1229 item.activate.connect(select_now_playing_browser);
1230 item.add_accelerator("activate", menu.get_accel_group(),0x069, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);
1231 menu.append(item);
1232 return 1;
1234 return 0;