Remove weblinks.
[gmpc.git] / src / browsers / gmpc-nowplaying2.vala
blob30963f3d1672c3da28a92aad033f7d5195867f5e
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 {
36 namespace Browsers {
37 public class Nowplaying : Gmpc.Plugin.Base, Gmpc.Plugin.BrowserIface {
38 private bool theme_colors = (bool) config.get_int_with_default("Now Playing", "use-theme-color",1);
39 private string title_color = config.get_string_with_default("Now Playing", "title-color", "#4d90dd");
40 private string item_color = config.get_string_with_default("Now Playing", "item-color", "#304ab8");
41 private Gdk.Color background;
42 private Gdk.Color foreground;
44 private Gtk.Label bitrate_label = null;
45 private Gtk.TreeRowReference np_ref = null;
47 private bool use_backdrop = (bool) config.get_int_with_default("Now Playing", "use-backdrop",0);
50 construct {
51 /* Set the plugin as Browser type*/
52 this.plugin_type = 2|8;
53 /* Track changed status */
54 gmpcconn.status_changed.connect(status_changed);
55 /* Track connect/disconnect */
56 gmpcconn.connection_changed.connect((source, connect) => {
57 /* If disconnect update the page */
58 if(connect == 0 && this.paned != null)
59 this.update_not_playing();
60 });
62 var background = config.get_string_with_default("Now Playing",
63 "background-color", "#000");
64 var foreground = config.get_string_with_default("Now Playing",
65 "foreground-color", "#FFF");
66 Gdk.Color.parse(background,out this.background);
67 Gdk.Color.parse(foreground,out this.foreground);
69 /* Register easycommand to switch to this browser */
70 easy_command.add_entry(
71 _("switch now playing"),
72 "",
73 _("Switch to Now Playing"),
74 (Gmpc.Easy.Command.Callback *)select_now_playing_browser,
75 this);
77 /* Version of the plugin*/
78 private const int[] version = {0,0,0};
79 public override unowned int[] get_version() {
80 return version;
82 /* Name */
83 public override unowned string get_name() {
84 return N_("Now Playing");
87 public override void set_enabled(bool state) {
88 if(state) {
89 if(paned == null) {
90 browser_add( Gmpc.Playlist3.get_category_tree_view());
91 browser_init();
93 }else {
94 if(this.np_ref != null) {
95 var path = np_ref.get_path();
96 if(path != null) {
97 unowned int[] indices = path.get_indices();
98 config.set_int(this.get_name(), "position", indices[0]);
99 Gtk.ListStore model = (Gtk.ListStore) np_ref.get_model();
100 Gtk.TreeIter iter;
101 if(model.get_iter(out iter, path))
103 model.remove(iter);
107 if(this.paned != null) {
108 this.paned.destroy();
109 this.paned = null;
110 this.song_checksum = null;
114 if(this.get_name() != null)
115 Gmpc.config.set_int(this.get_name(), "enabled", (int)state);
117 /* Save our position in the side-bar */
118 public override void save_yourself() {
119 if(this.np_ref != null) {
120 var path = np_ref.get_path();
121 if(path != null) {
122 unowned int[] indices = path.get_indices();
123 config.set_int(this.get_name(), "position", indices[0]);
128 /* React MPD's status changed */
129 private
130 void
131 status_changed(Gmpc.Connection conn, MPD.Server server, MPD.Status.Changed what)
133 if(!this.get_enabled())return;
134 if(!this.selected) return;
135 /* If the state changes, update. */
136 if((what&MPD.Status.Changed.STATE) == MPD.Status.Changed.STATE)
138 this.update();
140 /* If the playlist changed, this might mean that the metadata of the currently playing song changed, update. */
141 else if ((what&(MPD.Status.Changed.SONGID|MPD.Status.Changed.PLAYLIST)) > 0)
143 this.update();
145 /* If the bitrate changed, update the bitrate label. */
146 if((what&(MPD.Status.Changed.BITRATE|MPD.Status.Changed.AUDIOFORMAT)) > 0)
148 if(bitrate_label != null)
150 var channels = MPD.Status.get_channels(Gmpc.server);
151 debug("bitrate changed");
152 var bitrate = MPD.Status.get_bitrate(Gmpc.server);
153 bitrate_label.set_markup(GLib.Markup.printf_escaped(
154 "<span color='%s' weight='bold'>%s:</span> %i %s, %.1f %s, %i %s",
155 this.item_color, _("Format"),
156 channels , GLib.ngettext(N_("Channel"),N_("Channels"), channels),
157 MPD.Status.get_samplerate(Gmpc.server)/1000.0, "kHz",
158 bitrate, "kbps"
165 /* Browser */
166 private Gtk.ScrolledWindow paned = null;
167 private Gtk.EventBox container = null;
168 private bool selected = false;
170 * Browser Interface bindings
172 public void browser_add (Gtk.Widget category_tree)
174 Gtk.TreeView tree = (Gtk.TreeView)category_tree;
175 Gtk.ListStore store = (Gtk.ListStore)tree.get_model();
176 Gtk.TreeModel model = tree.get_model();
177 Gtk.TreeIter iter;
178 Gmpc.Browser.insert(out iter, Gmpc.Playlist.BrowserType.TOP);
179 store.set(iter, 0, this.id, 1, this.get_name(), 3, "media-audiofile");
180 /* Create a row reference */
181 this.np_ref = new Gtk.TreeRowReference(model, model.get_path(iter));
183 /* Called by gmpc, telling the plugin to embed itself in container */
184 public void browser_selected (Gtk.Container container)
189 this.selected = true;
190 this.browser_init();
191 container.add(this.paned);
193 container.show_all();
194 container.ensure_style();
195 if(this.theme_colors) {
196 this.title_color = this.paned.style.text[Gtk.StateType.PRELIGHT].to_string();
197 this.item_color = this.paned.style.text[Gtk.StateType.PRELIGHT].to_string();
199 if(use_backdrop) {
200 this.title_color = "#fff";
201 this.item_color = "#fff";
202 this.theme_colors = false;
204 this.update();
207 /* Called by gmpc, telling the plugin to remove itself from the container */
208 public void browser_unselected(Gtk.Container container)
210 this.selected = false;
211 container.remove(this.paned);
215 * If the style changed because f.e. the user switched theme, make sure the correct colouring is kept preserved.
218 private void browser_bg_style_changed(Gtk.Widget bg,Gtk.Style? style)
220 debug("Change style signal");
221 if(this.theme_colors) {
222 this.title_color = this.paned.style.text[Gtk.StateType.PRELIGHT].to_string();
223 this.item_color = this.paned.style.text[Gtk.StateType.PRELIGHT].to_string();
225 this.change_color_style(this.container);
228 * Recursively force a style on widget bg and children.
230 private void change_color_style(Gtk.Widget bg)
232 debug("change style");
233 if(bg is Gtk.Separator || bg is Gtk.Notebook || bg is Gtk.CheckButton){
234 /* Do nothing */
235 }else{
236 if(theme_colors)
238 bg.modify_bg(Gtk.StateType.NORMAL,this.paned.style.base[Gtk.StateType.NORMAL]);
239 /*bg.modify_base(Gtk.StateType.NORMAL,this.paned.style.mid[Gtk.StateType.NORMAL]);/*
240 // bg.modify_text(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
241 bg.modify_fg(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
242 bg.modify_text(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);
243 bg.modify_fg(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);*/
244 }else{
245 bg.modify_bg(Gtk.StateType.NORMAL,this.background);
246 bg.modify_base(Gtk.StateType.NORMAL,this.background);
247 bg.modify_text(Gtk.StateType.NORMAL,this.foreground);
248 bg.modify_fg(Gtk.StateType.NORMAL,this.foreground);
249 bg.modify_text(Gtk.StateType.ACTIVE,this.foreground);
250 bg.modify_fg(Gtk.StateType.ACTIVE,this.foreground);
253 /* Recurse into children, if the widget can hold children (so is a container */
254 if(bg is Gtk.Container){
255 foreach(Gtk.Widget child in ((Gtk.Container)bg).get_children())
257 change_color_style(child);
261 /* Create the basic gui. on initializing */
262 private void browser_init() {
263 if(this.paned == null)
266 this.paned = new Gtk.ScrolledWindow(null,null);
267 this.paned.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
268 this.paned.set_shadow_type(Gtk.ShadowType.NONE);
269 if(use_backdrop) {
270 this.container = new Gmpc.MetaData.Widgets.Backdrop(Gmpc.MetaData.Type.BACKDROP_ART);
271 }else{
272 this.container = new Gtk.EventBox();
275 this.container.set_focus_hadjustment(this.paned.get_hadjustment());
276 this.container.set_focus_vadjustment(this.paned.get_vadjustment());
278 this.paned.style_set.connect(browser_bg_style_changed);
279 this.paned.add_with_viewport(this.container);
280 this.paned.get_vadjustment().set("step-increment", 20.0);
281 this.paned.show_all();
286 /* Clear the view inside the scrolled window*/
287 private void clear()
289 /* Clear */
290 var list = this.container.get_children();
291 foreach(Gtk.Widget child in list){
292 child.destroy();
294 bitrate_label = null;
298 private string get_extension(string path)
300 long length = path.length;
301 long i=length;
302 string retv = null;
303 for(;i>0 && (length-i) <8;i--){
304 if(path[i] == '.') {
305 retv = path.substring(i+1);
306 return retv;
309 return retv;
312 * Show the page when playing
314 private string song_checksum = null;
315 private void update_playing()
317 unowned MPD.Song? song = server.playlist_get_current_song();
318 if(song == null) {
319 debug("GMPC Is playing, cannot get this");
320 if(use_backdrop)
321 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(null);
322 update_not_playing();
323 return;
325 /* Force it so we won't update when not needed */
326 var checksum = Gmpc.Misc.song_checksum(song);
327 if(checksum == this.song_checksum)
329 /* No need to update. */
330 return;
332 GLib.Timer t = new GLib.Timer();
333 this.clear();
334 if(use_backdrop)
335 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(song);
336 this.song_checksum = checksum;
338 var vbox = new Gtk.VBox (false,6);
339 vbox.border_width = 8;
340 /* Start building the gui */
341 /* Artist image */
342 var hbox = new Gtk.HBox(false, 6);
343 Gtk.Alignment ali = null;
345 int meta_size = (int)(this.container.allocation.width*0.20);
346 /* get size based on alloc */
347 meta_size = int.min(int.max(100, meta_size), 250);
348 if(config.get_int_with_default("Interface", "hide-album-art", 0) == 0)
350 /* Album image */
351 ali = new Gtk.Alignment(0f,0f,0f,0f);
352 //ali.set_size_request(meta_size,meta_size);
353 var album_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, meta_size);
354 album_image.set_scale_up(true);
355 album_image.set_squared(false);
356 ali.add(album_image);
357 album_image.update_from_song(song);
358 hbox.pack_start(ali, false, false, 0);
361 /* Artist image */
362 if(config.get_int_with_default("Interface", "hide-album-art", 0) == 0 && !use_backdrop)
364 ali = new Gtk.Alignment(1f,0f,0f,0f);
365 var artist_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ARTIST_ART, meta_size);
366 artist_image.set_scale_up(true);
367 artist_image.set_squared(false);
368 artist_image.update_from_song(song);
369 ali.add(artist_image);
370 hbox.pack_end(ali, false, false, 0);
373 /* Information box */
374 var info_vbox = new Gtk.VBox(false, 6);
375 /* Title */
376 if(song.title != null) {
377 var box = new Gtk.HBox(false, 6);
378 /* Favored button */
380 if(config.get_int_with_default("Interface", "hide-favorites-icon",0) == 0){
381 var fav_button = new Gmpc.Favorites.Button();
382 fav_button.set_song(song);
383 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
384 ali.add(fav_button);
385 box.pack_start(ali, false, false, 0);
387 var label = new Gtk.Label(song.title);
388 label.selectable = true;
389 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",
390 this.title_color,Pango.SCALE*20 ,song.title));
391 label.set_ellipsize(Pango.EllipsizeMode.END);
392 label.set_alignment(0.0f, 0.5f);
393 box.pack_start(label, true, true, 0);
394 info_vbox.pack_start(box, false, false, 0);
396 }else if (song.name!= null) {
397 var label = new Gtk.Label(song.name);
398 label.selectable = true;
399 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this.
400 title_color, Pango.SCALE*20, song.name));
401 label.set_ellipsize(Pango.EllipsizeMode.END);
402 label.set_alignment(0.0f, 0.5f);
403 info_vbox.pack_start(label, false, false, 0);
405 else if (song.file != null){
406 var filename = GLib.Path.get_basename(song.file);
407 var label = new Gtk.Label(song.name);
408 label.selectable = true;
409 try {
410 var regex_a = new GLib.Regex ("\\.[0-9a-zA-Z]*$");
411 filename = regex_a.replace_literal (filename, -1, 0, "");
412 } catch (GLib.RegexError e) {
413 GLib.error("%s", e.message);
415 try {
416 var regex_b = new GLib.Regex ("_");
417 filename = regex_b.replace_literal (filename, -1, 0, " ");
418 } catch (GLib.RegexError e) {
419 GLib.error("%s", e.message);
421 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this.
422 title_color, Pango.SCALE*20, filename));
423 label.set_ellipsize(Pango.EllipsizeMode.END);
424 label.set_alignment(0.0f, 0.5f);
425 info_vbox.pack_start(label, false, false, 0);
428 /* Artist */
429 if(song.artist != null) {
430 var event = new Gtk.EventBox();
431 var box = new Gtk.HBox(false, 6);
432 var label = new Gtk.Label(song.artist);
433 event.set_visible_window(false);
434 label.selectable = true;
435 var image = new Gtk.Image.from_icon_name("media-artist", Gtk.IconSize.MENU);
436 event.add(image);
437 box.pack_start(event, false, false, 0);
438 label.set_markup(GLib.Markup.printf_escaped("<span size='xx-large' weight='bold'>%s</span>", song.artist));
439 label.set_ellipsize(Pango.EllipsizeMode.END);
440 label.set_alignment(0.0f, 0.5f);
441 box.pack_start(label, true, true, 0);
442 info_vbox.pack_start(box, false, false, 0);
444 event.set_data("artist",song.artist);
445 event.button_press_event.connect((widget, event) => {
446 string artist = (string)widget.get_data<string>("artist");
447 Gmpc.Browser.Metadata.show_artist(artist);
448 return false;
451 /* Album */
452 if(song.album != null) {
453 var event = new Gtk.EventBox();
454 var box = new Gtk.HBox(false, 6);
455 var label = new Gtk.Label(song.album);
456 event.set_visible_window(false);
457 label.selectable = true;
458 var image = new Gtk.Image.from_icon_name("media-album", Gtk.IconSize.MENU);
459 event.add(image);
460 box.pack_start(event, false, false, 0);
461 label.set_markup(GLib.Markup.printf_escaped("<span size='x-large' weight='bold'>%s %s</span>", song.album,
462 (song.date != null)? "(%s)".printf(song.date):""));
463 label.set_ellipsize(Pango.EllipsizeMode.END);
464 label.set_alignment(0.0f, 0.5f);
465 box.pack_start(label, true, true, 0);
466 info_vbox.pack_start(box, false, false, 0);
470 event.set_data("artist",song.artist);
471 event.set_data("album",song.album);
472 event.button_press_event.connect((widget, event) => {
473 string artist = (string)widget.get_data<string>("artist");
474 string album = (string)widget.get_data<string>("album");
475 if(artist != null && album != null) {
476 Gmpc.Browser.Metadata.show_album(artist,album);
477 return true;
479 return false;
482 /* Genre */
483 if(song.genre != null) {
484 var box = new Gtk.HBox(false, 6);
485 var label = new Gtk.Label(song.title);
486 label.selectable = true;
487 var image = new Gtk.Image.from_icon_name("media-genre", Gtk.IconSize.MENU);
488 box.pack_start(image, false, false, 0);
489 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
490 this.item_color,_("Genre"), song.genre));
491 label.set_ellipsize(Pango.EllipsizeMode.END);
492 label.set_alignment(0.0f, 0.5f);
493 box.pack_start(label, true, true, 0);
494 info_vbox.pack_start(box, false, false, 0);
497 /* Format */
499 var box = new Gtk.HBox(false, 6);
500 var image = new Gtk.Image.from_icon_name("media-format", Gtk.IconSize.MENU);
501 box.pack_start(image, false, false, 0);
503 bitrate_label = new Gtk.Label(song.title);
504 bitrate_label.selectable = true;
505 bitrate_label.set_ellipsize(Pango.EllipsizeMode.END);
506 bitrate_label.set_alignment(0.0f, 0.5f);
508 box.pack_start(bitrate_label, true, true, 0);
510 var bitrate = MPD.Status.get_bitrate(Gmpc.server);
511 var channels = MPD.Status.get_channels(Gmpc.server);
512 bitrate_label.set_markup(GLib.Markup.printf_escaped(
513 "<span color='%s' weight='bold'>%s:</span> %i %s, %.1f %s, %i %s",
514 this.item_color, _("Format"),
515 channels , GLib.ngettext(N_("Channel"),N_("Channels"), channels),
516 MPD.Status.get_samplerate(Gmpc.server)/1000.0, "kHz",
517 bitrate, "kbps"
520 info_vbox.pack_start(box, false, false, 0);
522 if(song.file != null)
525 string extension = null;
526 extension = get_extension(song.file);
527 if(extension != null)
529 var box = new Gtk.HBox(false, 6);
530 var image = new Gtk.Image.from_icon_name("media-codec", Gtk.IconSize.MENU);
531 box.pack_start(image, false, false, 0);
533 var label = new Gtk.Label(song.title);
534 label.selectable = true;
535 label.set_ellipsize(Pango.EllipsizeMode.END);
536 label.set_alignment(0.0f, 0.5f);
537 box.pack_start(label, true, true, 0);
538 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
539 this.item_color, _("Codec"),
540 extension));
541 info_vbox.pack_start(box, false, false, 0);
544 /* Time*/
545 if(song.time > 0) {
546 var box = new Gtk.HBox(false, 6);
547 var image = new Gtk.Image.from_icon_name("media-track-length", Gtk.IconSize.MENU);
548 box.pack_start(image, false, false, 0);
549 var label = new Gtk.Label("");
550 label.selectable = true;
551 label.set_ellipsize(Pango.EllipsizeMode.END);
552 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
553 this.item_color,_("Length"),
554 Gmpc.Misc.format_time((ulong) song.time, "")));
555 label.set_alignment(0.0f, 0.5f);
556 box.pack_start(label, true, true, 0);
557 info_vbox.pack_start(box, false, false, 0);
560 if(song.track != null) {
561 var box = new Gtk.HBox(false, 6);
562 var image = new Gtk.Image.from_icon_name("media-num-tracks", Gtk.IconSize.MENU);
563 box.pack_start(image, false, false, 0);
564 var label = new Gtk.Label("");
565 label.selectable = true;
566 label.set_ellipsize(Pango.EllipsizeMode.END);
567 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s %s",
568 this.item_color, _("Track number"),
569 song.track,
570 (song.disc != null)? "[%s]".printf(song.disc):""
572 label.set_alignment(0.0f, 0.5f);
573 box.pack_start(label, true, true, 0);
574 info_vbox.pack_start(box, false, false, 0);
578 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "heading took: %.6f seconds.", t.elapsed());
579 hbox.pack_start(info_vbox, true, true, 0);
580 vbox.pack_start(hbox, false, false, 0);
582 /* Separator */
583 var sep = new Gtk.HSeparator();
584 sep.set_size_request(-1, 4);
585 vbox.pack_start(sep, false, false, 0);
587 var hboxje = new Gtk.HBox(false, 6);
589 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
590 var notebook = new Gtk.Notebook();
591 notebook.set_show_border(false);
592 notebook.set_show_tabs(false);
594 /* Lyrics */
595 var i = 0;
596 unowned SList<unowned Gtk.RadioButton> group = null;
597 if(config.get_int_with_default("MetaData", "show-lyrics",1) == 1)
599 var alib = new Gtk.Alignment(0f,0f,1f,0f);
600 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_TXT);
601 alib.add(text_view);
602 notebook.append_page(alib, new Gtk.Label("Lyrics"));
603 var button = new Gtk.RadioButton(group);//.with_label(group,("Lyrics"));
604 var label = new Gtk.Label(_("Lyrics"));
605 label.ellipsize = Pango.EllipsizeMode.END;
606 label.set_alignment(0.0f, 0.5f);
607 // button.add(label);
609 if(group != null)
610 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
611 group = button.get_group();
612 hboxje.pack_start(button, false, false, 0);
613 hboxje.pack_start(label, true, true, 0);
614 var j = i;
615 button.clicked.connect((source) => {
616 if((source as Gtk.CheckButton).get_active()) {
617 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics notebook page %i clicked", j);
618 notebook.set_current_page(j);
621 i++;
623 alib.show();
625 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "lyrics took: %.6f seconds.", t.elapsed());
627 /* Guitar Tabs */
628 if(config.get_int_with_default("MetaData", "show-guitar-tabs",1) == 1)
630 var alib = new Gtk.Alignment(0f,0f,1f,0f);
631 var text_view_queried = false;
632 notebook.append_page(alib, new Gtk.Label(_("Guitar Tabs")));
633 var button = new Gtk.RadioButton(group);//.with_label(group,_("Guitar Tabs"));
634 var label = new Gtk.Label(_("Guitar Tabs"));
635 label.ellipsize = Pango.EllipsizeMode.END;
636 label.set_alignment(0.0f, 0.5f);
637 //button.add(label);
638 if(group != null)
639 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
640 group = button.get_group();
641 hboxje.pack_start(button, false, false, 0);
642 hboxje.pack_start(label, true, true, 0);
643 var j = i;
644 /* Only query the guitar-tab when opened or first notebook page*/
645 button.clicked.connect((source) => {
646 if((source as Gtk.CheckButton).get_active()) {
647 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "guitar tab notebook page %i clicked", j);
648 notebook.set_current_page(j);
649 if(!text_view_queried){
650 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_GUITAR_TAB);
651 alib.add(text_view);
652 text_view_queried = true;
653 this.change_color_style(text_view);
654 text_view.show();
658 if(i == 0){
659 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song, Gmpc.MetaData.Type.SONG_GUITAR_TAB);
660 alib.add(text_view);
661 text_view_queried = true;
663 alib.show_all();
664 i++;
666 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "guitar tabs took: %.6f seconds.", t.elapsed());
668 /* Similar songs */
670 if(config.get_int_with_default("MetaData", "show-similar-songs",1) == 1)
672 var similar_songs_queried = false;
673 var similar_songs_box = new Gtk.Alignment(0f,0f,0f,0f);
675 notebook.append_page(similar_songs_box, new Gtk.Label(_("Similar Songs")));
677 var button = new Gtk.RadioButton(group);//.with_label(group,_("Similar Songs"));
678 var label = new Gtk.Label(_("Similar Songs"));
679 label.ellipsize = Pango.EllipsizeMode.END;
680 label.set_alignment(0.0f, 0.5f);
681 //button.add(label);
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 hboxje.pack_start(label, true, true, 0);
688 var j = i;
689 /* Only query when opened or first notebook page*/
690 button.clicked.connect((source) => {
691 if((source as Gtk.CheckButton).get_active()) {
692 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "similar song notebook page %i clicked", j);
693 notebook.set_current_page(j);
694 if(!similar_songs_queried){
695 var similar_songs = new Gmpc.MetaData.Widgets.SimilarSongs(song);
696 similar_songs.update();
697 similar_songs_queried = true;
698 similar_songs_box.add(similar_songs);
699 this.change_color_style(similar_songs_box);
700 similar_songs_box.show_all();
704 if(i == 0){
705 var similar_songs = new Gmpc.MetaData.Widgets.SimilarSongs(song);
706 similar_songs.update();
707 similar_songs_queried = true;
708 similar_songs_box.add(similar_songs);
709 similar_songs_box.show_all();
711 similar_songs_box.show();
712 i++;
715 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "similar songs took: %.6f seconds.", t.elapsed());
716 if(config.get_int_with_default("MetaData", "show-similar-artist",1) == 1 && song.artist != null)
718 var similar_artist = new Gmpc.MetaData.Widgets.SimilarArtists(Gmpc.server,song);
720 notebook.append_page(similar_artist, new Gtk.Label(_("Similar Artist")));
722 var button = new Gtk.RadioButton(group);//.with_label(group,_("Similar Artist"));
723 var label = new Gtk.Label(_("Similar Artist"));
724 label.ellipsize = Pango.EllipsizeMode.END;
725 label.set_alignment(0.0f, 0.5f);
726 //button.add(label);
727 if(group != null)
728 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
729 group = button.get_group();
730 hboxje.pack_start(button, false, false, 0);
731 hboxje.pack_start(label, true, true, 0);
733 var j = i;
734 button.clicked.connect((source) => {
735 if((source as Gtk.CheckButton).get_active()) {
736 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "similar artist notebook page %i clicked", j);
737 similar_artist.first_show();
738 notebook.set_current_page(j);
741 similar_artist.show();
742 i++;
744 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "similar Artist took: %.6f seconds.", t.elapsed());
745 if(config.get_int_with_default("MetaData", "show-artist-information",1) == 1)
747 var alib = new Gtk.Alignment(0f,0f,1f,0f);
748 var text_view_queried = false;
750 notebook.append_page(alib, new Gtk.Label(_("Artist information")));
751 var button = new Gtk.RadioButton(group);//.with_label(group,_("Artist information"));
752 var label = new Gtk.Label(_("Artist information"));
753 label.ellipsize = Pango.EllipsizeMode.END;
754 label.set_alignment(0.0f, 0.5f);
755 //button.add(label);
756 if(group != null)
757 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
758 group = button.get_group();
759 hboxje.pack_start(button, false, false, 0);
760 hboxje.pack_start(label, true, true, 0);
761 var j = i;
762 /* Only query the guitar-tab when opened or first notebook page*/
763 button.clicked.connect((source) => {
764 if((source as Gtk.CheckButton).get_active()) {
765 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "artist info notebook page %i clicked", j);
766 notebook.set_current_page(j);
767 if(!text_view_queried){
768 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song,Gmpc.MetaData.Type.ARTIST_TXT);
769 alib.add(text_view);
770 text_view_queried = true;
771 text_view.show();
772 this.change_color_style(text_view);
776 if(i == 0){
777 var text_view = new Gmpc.MetaData.Widgets.TextLabel(song,Gmpc.MetaData.Type.ARTIST_TXT);
778 alib.add(text_view);
779 text_view_queried = true;
781 alib.show_all();
782 i++;
785 if(config.get_int_with_default("MetaData", "show-songs-from-album",1) == 1)
787 var alib = new Gtk.Alignment(0f,0f,1f,0f);
788 var text_view_queried = false;
790 notebook.append_page(alib, new Gtk.Label(_("Songs from album")));
791 var button = new Gtk.RadioButton(group);//.with_label(group,_("Songs from album"));
792 var label = new Gtk.Label(_("Songs from album"));
793 label.ellipsize = Pango.EllipsizeMode.END;
794 label.set_alignment(0.0f, 0.5f);
795 //button.add(label);
796 if(group != null)
797 hboxje.pack_start(new Gtk.VSeparator(), false, false, 0);
798 group = button.get_group();
799 hboxje.pack_start(button, false, false, 0);
800 hboxje.pack_start(label, true, true, 0);
801 var j = i;
802 var sl = new Gmpc.Widgets.Songlist();
804 sl.song_clicked.connect((source, song) => {
805 if(song.file != null) {
806 Gmpc.MpdInteraction.play_path(song.file);
809 sl.play_song_clicked.connect((source, song) => {
810 if(song.file != null) {
811 Gmpc.MpdInteraction.play_path(song.file);
814 alib.add(sl);
815 button.clicked.connect((source) => {
816 if((source as Gtk.CheckButton).get_active()) {
817 GLib.log(np2_LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG, "artist info notebook page %i clicked", j);
818 notebook.set_current_page(j);
819 if(!text_view_queried){
820 if(song.artist != null && song.album != null)
822 MPD.Database.search_start(server,true);
823 if(song.albumartist != null) {
824 MPD.Database.search_add_constraint(server,
825 MPD.Tag.Type.ALBUM_ARTIST, song.albumartist);
826 }else{
827 MPD.Database.search_add_constraint(server,
828 MPD.Tag.Type.ARTIST, song.artist);
830 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, song.album);
831 var data = MPD.Database.search_commit(server);
832 data.sort_album_disc_track();
833 sl.set_from_data((owned)data, true);
834 this.change_color_style(sl);
835 }else{
836 sl.destroy();
837 alib.add(new Gtk.Label(_("Not available")));
839 text_view_queried = true;
843 if(i == 0){
844 if(song.artist != null && song.album != null)
846 MPD.Database.search_start(server,true);
847 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
848 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, song.album);
849 var data = MPD.Database.search_commit(server);
850 data.sort_album_disc_track();
851 sl.set_from_data((owned)data, true);
852 }else{
853 sl.destroy();
854 alib.add(new Gtk.Label(_("Not available")));
856 text_view_queried = true;
858 alib.show_all();
859 i++;
862 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Artist info took: %.6f seconds.", t.elapsed());
863 /* Track changed pages */
864 notebook.notify["page"].connect((source,spec) => {
865 var page = notebook.get_current_page();
866 config.set_int("NowPlaying", "last-page", (int)page);
869 /* Restore right page */
870 if(i > 0){
871 var page = config.get_int_with_default("NowPlaying", "last-page", 0);
872 if(page > i)
874 notebook.set_current_page(0);
875 }else{
876 /* The list is in reversed order, compensate for that. */
877 var w = group.nth_data(i-page-1);
878 w.set_active(true);
879 notebook.set_current_page(page);
883 ali = new Gtk.Alignment(0.0f, 0.5f,1f,0f);
884 ali.add(hboxje);
886 /* Create pane in 2. */
887 var bottom_hbox = new Gtk.HBox(false, 6);
888 /* left pane */
889 var metadata_vbox = new Gtk.VBox(false, 0);
890 metadata_vbox.pack_start(ali, false, false, 0);
891 sep = new Gtk.HSeparator();
892 sep.set_size_request(-1, 1);
893 metadata_vbox.pack_start(sep, false, false, 0);
894 metadata_vbox.pack_start(notebook, false, false, 0);
896 bottom_hbox.pack_start(metadata_vbox, true, true, 0);
898 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Building now playing took: %.6f seconds.", t.elapsed());
899 /* Create album list */
900 if(song.album != null && song.artist != null)
902 var sep2 = new Gtk.VSeparator();
903 sep2.set_size_request(-1, 4);
904 bottom_hbox.pack_start(sep2, false, false, 0);
905 int albums =0;
906 /* Create album list */
907 ali = new Gtk.Alignment(0.0f, 0.0f, 0.0f, 0.0f);
908 var album_hbox = new Gtk.VBox(false, 6);
909 album_hbox.set_size_request(250, -1);
910 ali.add(album_hbox);
911 bottom_hbox.pack_start(ali, false, false, 0);
913 var label = new Gtk.Label(song.artist);
914 label.selectable = true;
915 label.set_size_request(240, -1);
916 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));
917 label.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR);
918 label.set_line_wrap(true);
919 label.set_alignment(0.0f, 0.5f);
920 album_hbox.pack_start(label, false, false,0);
922 MPD.Database.search_field_start(server, MPD.Tag.Type.ALBUM);
923 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
924 MPD.Data.Item list = null;
925 var data = MPD.Database.search_commit(server);
926 if(data != null){
927 unowned MPD.Data.Item iter = data.get_first();
929 if(iter.tag == song.album){
930 iter.next(false);
931 continue;
933 list.append_new();
934 list.type = MPD.Data.Type.SONG;
935 list.song = new MPD.Song();
936 list.song.artist = song.artist;
937 list.song.album = iter.tag;
939 MPD.Database.search_field_start(server,MPD.Tag.Type.DATE);
940 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
941 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, iter.tag);
942 var ydata = MPD.Database.search_commit(server);
943 if(ydata != null) {
944 list.song.date = ydata.tag;
947 iter.next(false);
948 }while(iter != null);
951 list.sort_album_disc_track();
952 if(list != null) {
953 unowned MPD.Data.Item iter = list.get_first();
955 var button = new Gtk.Button();
956 button.set_relief(Gtk.ReliefStyle.NONE);
957 var but_hbox = new Gtk.HBox(false, 6);
958 button.add(but_hbox);
959 var image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, 48);
960 unowned MPD.Song but_song = iter.song;
961 image.set_squared(true);
962 image.update_from_song_delayed(but_song);
964 but_hbox.pack_start(image, false, false, 0);
966 var but_label = new Gtk.Label(iter.song.album);
967 but_label.selectable = true;
968 but_label.set_alignment(0.0f, 0.5f);
969 var strlabel = "";
970 if(iter.song.date != null && iter.song.date.length > 0) strlabel += "%s\n".printf(iter.song.date);
971 if(iter.song.album != null) strlabel+= iter.song.album;
972 else strlabel += _("No Album");
973 but_label.set_markup(GLib.Markup.printf_escaped("<b>%s</b>",strlabel));
974 but_label.set_ellipsize(Pango.EllipsizeMode.END);
975 but_hbox.pack_start(but_label, true, true, 0);
977 album_hbox.pack_start(button, false, false,0);
978 button.set_data("artist",
979 but_song.artist.dup());
980 button.set_data("album",
981 but_song.album.dup());
982 stdout.printf("open: %s %s\n", but_song.artist, but_song.album);
983 button.clicked.connect((source) => {
984 unowned string artist = (string)source.get_data<string>("artist");
985 unowned string album = (string)source.get_data<string>("album");
986 stdout.printf("open: %s %s\n", artist, album);
987 Gmpc.Browser.Metadata.show_album(artist, album);
989 albums++;
991 iter.next(false);
992 }while(iter!= null);
995 if(albums == 0) {
996 album_hbox.destroy();
997 sep2.destroy();
1000 vbox.pack_start(bottom_hbox, true, true, 0);
1002 /* show it */
1003 this.container.add(vbox);
1004 this.change_color_style(this.container);
1005 this.container.show_all();
1007 t.stop();
1008 GLib.log(np2_LOG_DOMAIN, GLib.LogLevelFlags.LEVEL_DEBUG, "Building now playing took: %.6f seconds.", t.elapsed());
1011 * This shows the page when mpd is not playing, for now it is the gmpc logo + Gnome Music Player Client
1013 private void update_not_playing()
1015 this.clear();
1016 song_checksum = null;
1017 if(use_backdrop)
1018 (this.container as Gmpc.MetaData.Widgets.Backdrop).set_song(null);
1020 var it = Gtk.IconTheme.get_default();
1021 Gtk.IconInfo info = it.lookup_icon("gmpc", 150, 0);
1022 var path = info.get_filename();
1023 Gtk.Image image = null;
1024 if(path != null)
1026 try {
1027 var pb = new Gdk.Pixbuf.from_file_at_scale(path, 150, 150, true);
1028 image = new Gtk.Image.from_pixbuf(pb);
1029 } catch (Error e)
1031 warning("Failed to load the gmpc logo: %s", e.message);
1032 return;
1035 if(image == null){
1036 image = new Gtk.Image.from_icon_name("gmpc", Gtk.IconSize.DIALOG);
1039 var hbox = new Gtk.HBox(false, 6);
1040 var label = new Gtk.Label(_("Gnome Music Player Client"));
1041 label.set_selectable(true);
1042 label.set_markup("<span size='%i' weight='bold'>%s</span>".printf(28*Pango.SCALE,_("Gnome Music Player Client")));
1043 hbox.pack_start(image, false, false, 0);
1044 hbox.pack_start(label, false, false, 0);
1046 var ali = new Gtk.Alignment(0.5f,0.5f,0.0f, 0.0f);
1047 ali.add(hbox);
1048 this.container.add(ali);
1050 this.change_color_style(this.container);
1051 this.container.show_all();
1055 * Update the view according to state. If playing/paused show song info, other wise the not playing page
1057 private void update()
1059 switch(MPD.Player.get_state(Gmpc.server))
1061 case MPD.Player.State.PLAY:
1062 case MPD.Player.State.PAUSE:
1063 debug("Update playing");
1064 update_playing();
1065 break;
1066 default:
1067 debug("update not playing");
1068 update_not_playing();
1069 break;
1074 * Makes gmpc jump to the now playing browser
1076 public void select_now_playing_browser()
1078 unowned Gtk.TreeView tree = Gmpc.Playlist3.get_category_tree_view();
1079 var sel = tree.get_selection();
1080 var path = np_ref.get_path();
1081 if(path != null)
1083 sel.select_path(path);
1088 * Gmpc.Plugin.BrowserIface.add_go_menu
1090 private int browser_add_go_menu(Gtk.Menu menu)
1092 if(this.get_enabled())
1094 var item = new Gtk.ImageMenuItem.with_mnemonic(_("Now Playing"));
1095 item.set_image(new Gtk.Image.from_icon_name("media-audiofile", Gtk.IconSize.MENU));
1096 item.activate.connect(select_now_playing_browser);
1097 item.add_accelerator("activate", menu.get_accel_group(),0x069, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);
1098 menu.append(item);
1099 return 1;
1101 return 0;