add support for adding random artists/albums to playlist
[ncmpcpp.git] / src / ncmpcpp.cpp
blob9c780d50e49b5fffa7f3dd27525f724f2d154aa2
1 /***************************************************************************
2 * Copyright (C) 2008-2009 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
4 * *
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. *
9 * *
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. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #include <cerrno>
22 #include <clocale>
23 #include <csignal>
24 #include <cstring>
25 #include <sys/time.h>
27 #include <iostream>
28 #include <fstream>
29 #include <stdexcept>
31 #include "mpdpp.h"
32 #include "ncmpcpp.h"
34 #include "browser.h"
35 #include "charset.h"
36 #include "clock.h"
37 #include "display.h"
38 #include "global.h"
39 #include "help.h"
40 #include "helpers.h"
41 #include "media_library.h"
42 #include "misc.h"
43 #include "server_info.h"
44 #include "lyrics.h"
45 #include "playlist.h"
46 #include "playlist_editor.h"
47 #include "search_engine.h"
48 #include "settings.h"
49 #include "song.h"
50 #include "info.h"
51 #include "outputs.h"
52 #include "status.h"
53 #include "tag_editor.h"
54 #include "tiny_tag_editor.h"
55 #include "visualizer.h"
57 #define CHECK_PLAYLIST_FOR_FILTERING \
58 if (myPlaylist->Items->isFiltered()) \
59 { \
60 ShowMessage("%s", MPD::Message::FunctionDisabledFilteringEnabled); \
61 continue; \
64 #define CHECK_MPD_MUSIC_DIR \
65 if (Config.mpd_music_dir.empty()) \
66 { \
67 ShowMessage("configuration variable mpd_music_dir is not set!"); \
68 continue; \
71 using namespace Global;
72 using namespace MPD;
74 BasicScreen *Global::myScreen;
75 BasicScreen *Global::myOldScreen;
76 BasicScreen *Global::myPrevScreen;
78 Window *Global::wHeader;
79 Window *Global::wFooter;
81 size_t Global::MainStartY;
82 size_t Global::MainHeight;
84 bool Global::BlockItemListUpdate = 0;
86 bool Global::MessagesAllowed = 0;
87 bool Global::SeekingInProgress = 0;
88 bool Global::RedrawHeader = 1;
90 namespace
92 std::ofstream errorlog;
93 std::streambuf *cerr_buffer;
95 bool design_changed = 0;
96 bool order_resize = 0;
97 size_t header_height, footer_start_y, footer_height;
99 void resize_screen()
101 order_resize = 0;
103 # if defined(USE_PDCURSES)
104 resize_term(0, 0);
105 # else
106 // update internal screen dimensions
107 if (!design_changed)
109 endwin();
110 refresh();
111 // get rid of KEY_RESIZE as it sometimes
112 // corrupts our new cool ReadKey() function
113 // because KEY_RESIZE doesn't come from stdin
114 // and thus select cannot detect it
115 timeout(10);
116 getch();
117 timeout(-1);
119 # endif
121 RedrawHeader = 1;
122 MainHeight = LINES-(Config.new_design ? 7 : 4);
124 if (COLS < 20 || MainHeight < 3)
126 DestroyScreen();
127 std::cout << "Screen is too small!\n";
128 exit(1);
131 if (!Config.header_visibility)
132 MainHeight += 2;
133 if (!Config.statusbar_visibility)
134 MainHeight++;
136 myHelp->hasToBeResized = 1;
137 myPlaylist->hasToBeResized = 1;
138 myBrowser->hasToBeResized = 1;
139 mySearcher->hasToBeResized = 1;
140 myLibrary->hasToBeResized = 1;
141 myPlaylistEditor->hasToBeResized = 1;
142 myInfo->hasToBeResized = 1;
143 myLyrics->hasToBeResized = 1;
144 mySelectedItemsAdder->hasToBeResized = 1;
146 # ifdef HAVE_TAGLIB_H
147 myTinyTagEditor->hasToBeResized = 1;
148 myTagEditor->hasToBeResized = 1;
149 # endif // HAVE_TAGLIB_H
151 # ifdef ENABLE_VISUALIZER
152 myVisualizer->hasToBeResized = 1;
153 # endif // ENABLE_VISUALIZER
155 # ifdef ENABLE_OUTPUTS
156 myOutputs->hasToBeResized = 1;
157 # endif // ENABLE_OUTPUTS
159 # ifdef ENABLE_CLOCK
160 myClock->hasToBeResized = 1;
161 # endif // ENABLE_CLOCK
163 myScreen->Resize();
165 if (Config.header_visibility || Config.new_design)
166 wHeader->Resize(COLS, header_height);
168 footer_start_y = LINES-(Config.statusbar_visibility ? 2 : 1);
169 wFooter->MoveTo(0, footer_start_y);
170 wFooter->Resize(COLS, Config.statusbar_visibility ? 2 : 1);
172 myScreen->Refresh();
173 RedrawStatusbar = 1;
174 StatusChanges changes;
175 if (!Mpd.isPlaying() || design_changed)
177 changes.PlayerState = 1;
178 if (design_changed)
179 changes.Volume = 1;
181 // Note: routines for drawing separator if alternative user
182 // interface is active and header is hidden are placed in
183 // NcmpcppStatusChanges.StatusFlags
184 changes.StatusFlags = 1; // force status update
185 NcmpcppStatusChanged(&Mpd, changes, 0);
186 if (design_changed)
188 RedrawStatusbar = 1;
189 NcmpcppStatusChanged(&Mpd, StatusChanges(), 0);
190 design_changed = 0;
191 ShowMessage("User interface: %s", Config.new_design ? "Alternative" : "Classic");
193 wFooter->Refresh();
196 # if !defined(WIN32)
197 void sighandler(int signal)
199 if (signal == SIGPIPE)
201 ShowMessage("Broken pipe signal caught!");
203 else if (signal == SIGWINCH)
205 order_resize = 1;
208 # endif // !WIN32
210 void do_at_exit()
212 // restore old cerr buffer
213 std::cerr.rdbuf(cerr_buffer);
214 errorlog.close();
215 Mpd.Disconnect();
216 # ifndef USE_PDCURSES // destroying screen somehow crashes pdcurses
217 DestroyScreen();
218 # endif // USE_PDCURSES
219 WindowTitle("");
223 int main(int argc, char *argv[])
225 setlocale(LC_ALL, "");
227 CreateConfigDir();
228 DefaultConfiguration(Config);
229 DefaultKeys(Key);
230 ReadConfiguration(Config);
231 ReadKeys(Key);
233 if (getenv("MPD_HOST"))
234 Mpd.SetHostname(getenv("MPD_HOST"));
235 if (getenv("MPD_PORT"))
236 Mpd.SetPort(atoi(getenv("MPD_PORT")));
238 if (Config.mpd_host != "localhost")
239 Mpd.SetHostname(Config.mpd_host);
240 if (Config.mpd_port != 6600)
241 Mpd.SetPort(Config.mpd_port);
243 Mpd.SetTimeout(Config.mpd_connection_timeout);
244 Mpd.SetIdleEnabled(Config.enable_idle_notifications);
246 if (argc > 1)
247 ParseArgv(argc, argv);
249 if (!ConnectToMPD())
250 return -1;
252 // always execute these commands, even if ncmpcpp use exit function
253 atexit(do_at_exit);
255 // redirect std::cerr output to ~/.ncmpcpp/error.log file
256 errorlog.open((config_dir + "error.log").c_str(), std::ios::app);
257 cerr_buffer = std::cerr.rdbuf();
258 std::cerr.rdbuf(errorlog.rdbuf());
260 InitScreen("ncmpc++ ver. "VERSION, Config.colors_enabled);
262 bool real_statusbar_visibility = Config.statusbar_visibility;
264 if (Config.new_design)
265 Config.statusbar_visibility = 0;
267 SetWindowsDimensions(header_height, footer_start_y, footer_height);
269 if (Config.header_visibility || Config.new_design)
271 wHeader = new Window(0, 0, COLS, header_height, "", Config.header_color, brNone);
272 wHeader->Display();
275 wFooter = new Window(0, footer_start_y, COLS, footer_height, "", Config.statusbar_color, brNone);
276 wFooter->SetTimeout(ncmpcpp_window_timeout);
277 wFooter->SetGetStringHelper(StatusbarGetStringHelper);
278 wFooter->AddFDCallback(Mpd.GetFD(), StatusbarMPDCallback);
279 wFooter->CreateHistory();
281 // initialize screens to browser as default previous screen
282 myScreen = myBrowser;
283 myPrevScreen = myBrowser;
284 myOldScreen = myBrowser;
286 // go to playlist
287 myPlaylist->SwitchTo();
288 myPlaylist->UpdateTimer();
290 Mpd.SetStatusUpdater(NcmpcppStatusChanged, 0);
291 Mpd.SetErrorHandler(NcmpcppErrorCallback, 0);
293 // local variables
294 int input = 0;
296 bool main_exit = 0;
297 bool title_allowed = !Config.display_screens_numbers_on_start;
299 std::string screen_title;
301 timeval past = { 0, 0 };
302 // local variables end
304 # ifndef WIN32
305 signal(SIGPIPE, sighandler);
306 signal(SIGWINCH, sighandler);
307 # endif // !WIN32
309 MEVENT mouse_event;
310 mouseinterval(0);
311 if (Config.mouse_support)
312 mousemask(ALL_MOUSE_EVENTS, 0);
314 if (Config.jump_to_now_playing_song_at_start)
316 TraceMpdStatus();
317 if (myPlaylist->isPlaying())
318 myPlaylist->Items->Highlight(myPlaylist->NowPlaying);
321 while (!main_exit)
323 if (!Mpd.Connected())
325 if (!wFooter->FDCallbacksListEmpty())
326 wFooter->ClearFDCallbacksList();
327 ShowMessage("Attempting to reconnect...");
328 if (Mpd.Connect())
330 ShowMessage("Connected to %s!", Mpd.GetHostname().c_str());
331 wFooter->AddFDCallback(Mpd.GetFD(), StatusbarMPDCallback);
332 MessagesAllowed = 0;
333 UpdateStatusImmediately = 1;
334 # ifdef ENABLE_VISUALIZER
335 myVisualizer->ResetFD();
336 if (myScreen == myVisualizer)
337 myVisualizer->SetFD();
338 myVisualizer->FindOutputID();
339 # endif // ENABLE_VISUALIZER
343 TraceMpdStatus();
345 MessagesAllowed = 1;
347 if (order_resize)
348 resize_screen();
350 // header stuff
351 if (((Timer.tv_sec == past.tv_sec && Timer.tv_usec >= past.tv_usec+500000) || Timer.tv_sec > past.tv_sec)
352 && (myScreen == myPlaylist || myScreen == myBrowser || myScreen == myLyrics)
355 RedrawHeader = 1;
356 gettimeofday(&past, 0);
358 if (Config.header_visibility && RedrawHeader)
360 if (title_allowed)
362 if (Config.new_design)
364 std::basic_string<my_char_t> title = myScreen->Title();
365 *wHeader << XY(0, 3) << wclrtoeol;
366 *wHeader << fmtBold << Config.alternative_ui_separator_color;
367 mvwhline(wHeader->Raw(), 2, 0, 0, COLS);
368 mvwhline(wHeader->Raw(), 4, 0, 0, COLS);
369 *wHeader << XY((COLS-Window::Length(title))/2, 3);
370 *wHeader << Config.header_color << title << clEnd;
371 *wHeader << clEnd << fmtBoldEnd;
373 else
374 *wHeader << XY(0, 0) << wclrtoeol << fmtBold << myScreen->Title() << fmtBoldEnd;
376 else
378 *wHeader << XY(0, Config.new_design ? 3 : 0)
379 << fmtBold << char(Key.Help[0]) << fmtBoldEnd << ":Help "
380 << fmtBold << char(Key.Playlist[0]) << fmtBoldEnd << ":Playlist "
381 << fmtBold << char(Key.Browser[0]) << fmtBoldEnd << ":Browse "
382 << fmtBold << char(Key.SearchEngine[0]) << fmtBoldEnd << ":Search "
383 << fmtBold << char(Key.MediaLibrary[0]) << fmtBoldEnd << ":Library "
384 << fmtBold << char(Key.PlaylistEditor[0]) << fmtBoldEnd << ":Playlist editor";
385 # ifdef HAVE_TAGLIB_H
386 *wHeader << " " << fmtBold << char(Key.TagEditor[0]) << fmtBoldEnd << ":Tag editor";
387 # endif // HAVE_TAGLIB_H
388 # ifdef ENABLE_VISUALIZER
389 *wHeader << " " << fmtBold << char(Key.Visualizer[0]) << fmtBoldEnd << ":Music visualizer";
390 # endif // ENABLE_VISUALIZER
391 # ifdef ENABLE_CLOCK
392 *wHeader << " " << fmtBold << char(Key.Clock[0]) << fmtBoldEnd << ":Clock";
393 # endif // ENABLE_CLOCK
394 if (Config.new_design)
396 *wHeader << fmtBold << Config.alternative_ui_separator_color;
397 mvwhline(wHeader->Raw(), 2, 0, 0, COLS);
398 mvwhline(wHeader->Raw(), 4, 0, 0, COLS);
399 *wHeader << clEnd << fmtBoldEnd;
402 if (!Config.new_design)
404 *wHeader << Config.volume_color;
405 *wHeader << XY(wHeader->GetWidth()-VolumeState.length(), 0) << VolumeState;
406 *wHeader << clEnd;
408 wHeader->Refresh();
409 RedrawHeader = 0;
411 // header stuff end
413 if (input != ERR)
414 myScreen->RefreshWindow();
415 wFooter->ReadKey(input);
417 if (input == ERR)
418 continue;
420 if (!title_allowed)
421 RedrawHeader = 1;
422 title_allowed = 1;
424 if (myScreen == myPlaylist)
425 myPlaylist->EnableHighlighting();
427 // key mapping beginning
429 if (Keypressed(input, Key.Up))
431 myScreen->Scroll(wUp, Key.Up);
433 else if (Keypressed(input, Key.Down))
435 myScreen->Scroll(wDown, Key.Down);
437 else if (Keypressed(input, Key.PageUp))
439 myScreen->Scroll(wPageUp, Key.PageUp);
441 else if (Keypressed(input, Key.PageDown))
443 myScreen->Scroll(wPageDown, Key.PageDown);
445 else if (Keypressed(input, Key.Home))
447 myScreen->Scroll(wHome);
449 else if (Keypressed(input, Key.End))
451 myScreen->Scroll(wEnd);
453 else if (Config.mouse_support && input == KEY_MOUSE)
455 getmouse(&mouse_event);
456 if (mouse_event.bstate & BUTTON1_PRESSED
457 && mouse_event.y == LINES-(Config.statusbar_visibility ? 2 : 1)
458 ) // progressbar
460 if (!myPlaylist->isPlaying())
461 continue;
462 Mpd.Seek(Mpd.GetTotalTime()*mouse_event.x/double(COLS));
463 UpdateStatusImmediately = 1;
465 else if (mouse_event.bstate & BUTTON1_PRESSED
466 && (Config.statusbar_visibility || Config.new_design)
467 && Mpd.isPlaying()
468 && mouse_event.y == (Config.new_design ? 1 : LINES-1) && mouse_event.x < 9
469 ) // playing/paused
471 Mpd.Toggle();
472 UpdateStatusImmediately = 1;
474 else if ((mouse_event.bstate & BUTTON2_PRESSED || mouse_event.bstate & BUTTON4_PRESSED)
475 && Config.header_visibility
476 && mouse_event.y == 0 && size_t(mouse_event.x) > COLS-VolumeState.length()
477 ) // volume
479 if (mouse_event.bstate & BUTTON2_PRESSED)
480 Mpd.SetVolume(Mpd.GetVolume()-2);
481 else
482 Mpd.SetVolume(Mpd.GetVolume()+2);
484 else if (mouse_event.bstate & (BUTTON1_PRESSED | BUTTON2_PRESSED | BUTTON3_PRESSED | BUTTON4_PRESSED))
485 myScreen->MouseButtonPressed(mouse_event);
487 if (Keypressed(input, Key.ToggleInterface))
489 Config.new_design = !Config.new_design;
490 Config.statusbar_visibility = Config.new_design ? 0 : real_statusbar_visibility;
491 SetWindowsDimensions(header_height, footer_start_y, footer_height);
492 UnlockProgressbar();
493 UnlockStatusbar();
494 design_changed = 1;
495 resize_screen();
497 else if (Keypressed(input, Key.GoToParentDir))
499 if (myScreen == myBrowser && myBrowser->CurrentDir() != "/")
501 myBrowser->Main()->Reset();
502 myBrowser->EnterPressed();
504 # ifdef HAVE_TAGLIB_H
505 else if (myScreen->ActiveWindow() == myTagEditor->Dirs && myTagEditor->CurrentDir() != "/")
507 myTagEditor->Dirs->Reset();
508 myTagEditor->EnterPressed();
510 # endif // HAVE_TAGLIB_H
512 else if (Keypressed(input, Key.Enter))
514 myScreen->EnterPressed();
516 else if (Keypressed(input, Key.Space))
518 myScreen->SpacePressed();
520 else if (Keypressed(input, Key.VolumeUp))
522 if (myScreen == myLibrary && input == Key.VolumeUp[0])
524 myLibrary->NextColumn();
526 else if (myScreen == myPlaylistEditor && input == Key.VolumeUp[0])
528 myPlaylistEditor->NextColumn();
530 # ifdef HAVE_TAGLIB_H
531 else if (myScreen == myTagEditor && input == Key.VolumeUp[0])
533 myTagEditor->NextColumn();
535 # endif // HAVE_TAGLIB_H
536 else
537 Mpd.SetVolume(Mpd.GetVolume()+1);
539 else if (Keypressed(input, Key.VolumeDown))
541 if (myScreen == myLibrary && input == Key.VolumeDown[0])
543 myLibrary->PrevColumn();
545 else if (myScreen == myPlaylistEditor && input == Key.VolumeDown[0])
547 myPlaylistEditor->PrevColumn();
549 # ifdef HAVE_TAGLIB_H
550 else if (myScreen == myTagEditor && input == Key.VolumeDown[0])
552 myTagEditor->PrevColumn();
554 # endif // HAVE_TAGLIB_H
555 else
556 Mpd.SetVolume(Mpd.GetVolume()-1);
558 else if (Keypressed(input, Key.Delete))
560 if (!myPlaylist->Items->Empty() && myScreen == myPlaylist)
562 if (myPlaylist->Items->hasSelected())
564 std::vector<size_t> list;
565 myPlaylist->Items->GetSelected(list);
566 Mpd.StartCommandsList();
567 for (std::vector<size_t>::reverse_iterator it = list.rbegin(); it != list.rend(); ++it)
568 Mpd.DeleteID((*myPlaylist->Items)[*it].GetID());
569 if (Mpd.CommitCommandsList())
571 for (size_t i = 0; i < myPlaylist->Items->Size(); ++i)
572 myPlaylist->Items->Select(i, 0);
573 myPlaylist->FixPositions(list.front());
574 ShowMessage("Selected items deleted!");
577 else
579 Playlist::BlockNowPlayingUpdate = 1;
580 wFooter->SetTimeout(50);
581 int del_counter = 0;
582 while (!myPlaylist->Items->Empty() && Keypressed(input, Key.Delete))
584 size_t id = myPlaylist->Items->Choice();
585 TraceMpdStatus();
586 Playlist::BlockUpdate = 1;
587 myPlaylist->UpdateTimer();
588 // needed for keeping proper position of now playing song.
589 if (myPlaylist->NowPlaying > int(myPlaylist->CurrentSong()->GetPosition())-del_counter)
590 --myPlaylist->NowPlaying;
591 if (Mpd.DeleteID(myPlaylist->CurrentSong()->GetID()))
593 myPlaylist->Items->DeleteOption(id);
594 myPlaylist->Items->Refresh();
595 wFooter->ReadKey(input);
596 ++del_counter;
598 else
599 break;
601 myPlaylist->FixPositions(myPlaylist->Items->Choice());
602 wFooter->SetTimeout(ncmpcpp_window_timeout);
603 Playlist::BlockNowPlayingUpdate = 0;
606 else if (
607 (myScreen == myBrowser && !myBrowser->Main()->Empty() && myBrowser->Main()->Current().type == itPlaylist)
608 || (myScreen->ActiveWindow() == myPlaylistEditor->Playlists)
611 std::string name = myScreen == myBrowser ? myBrowser->Main()->Current().name : myPlaylistEditor->Playlists->Current();
612 LockStatusbar();
613 Statusbar() << "Delete playlist \"" << Shorten(TO_WSTRING(name), COLS-28) << "\" ? [" << fmtBold << 'y' << fmtBoldEnd << '/' << fmtBold << 'n' << fmtBoldEnd << "]";
614 wFooter->Refresh();
615 int answer = 0;
618 TraceMpdStatus();
619 wFooter->ReadKey(answer);
621 while (answer != 'y' && answer != 'n');
622 UnlockStatusbar();
623 if (answer == 'y')
625 if (Mpd.DeletePlaylist(locale_to_utf_cpy(name)))
627 static const char msg[] = "Playlist \"%s\" deleted!";
628 ShowMessage(msg, Shorten(TO_WSTRING(name), COLS-static_strlen(msg)).c_str());
629 if (myBrowser->Main() && !myBrowser->isLocal() && myBrowser->CurrentDir() == "/")
630 myBrowser->GetDirectory("/");
633 else
634 ShowMessage("Aborted!");
635 if (myPlaylistEditor->Main()) // check if initialized
636 myPlaylistEditor->Playlists->Clear(); // make playlists list update itself
638 # ifndef WIN32
639 else if (myScreen == myBrowser && !myBrowser->Main()->Empty() && myBrowser->Main()->Current().type != itPlaylist)
641 if (!myBrowser->isLocal())
642 CHECK_MPD_MUSIC_DIR;
644 MPD::Item &item = myBrowser->Main()->Current();
646 if (item.type == itSong && !Config.allow_physical_files_deletion)
648 ShowMessage("Deleting files is disabled by default, see man page for more details");
649 continue;
651 if (item.type == itDirectory && !Config.allow_physical_directories_deletion)
653 ShowMessage("Deleting directories is disabled by default, see man page for more details");
654 continue;
656 if (item.type == itDirectory && item.song) // parent dir
657 continue;
659 std::string name = item.type == itSong ? item.song->GetName() : item.name;
660 LockStatusbar();
661 Statusbar() << "Delete " << (item.type == itSong ? "file" : "directory") << " \"" << Shorten(TO_WSTRING(name), COLS-30) << "\" ? [" << fmtBold << 'y' << fmtBoldEnd << '/' << fmtBold << 'n' << fmtBoldEnd << "] ";
662 wFooter->Refresh();
663 int answer = 0;
666 TraceMpdStatus();
667 wFooter->ReadKey(answer);
669 while (answer != 'y' && answer != 'n');
670 UnlockStatusbar();
671 if (answer == 'y')
673 std::string path;
674 if (!myBrowser->isLocal())
675 path = Config.mpd_music_dir;
676 path += item.type == itSong ? item.song->GetFile() : item.name;
678 if (item.type == itDirectory)
679 myBrowser->ClearDirectory(path);
681 if (remove(path.c_str()) == 0)
683 static const char msg[] = "\"%s\" deleted!";
684 ShowMessage(msg, Shorten(TO_WSTRING(name), COLS-static_strlen(msg)).c_str());
685 if (!myBrowser->isLocal())
686 Mpd.UpdateDirectory(myBrowser->CurrentDir());
687 else
688 myBrowser->GetDirectory(myBrowser->CurrentDir());
690 else
692 static const char msg[] = "Couldn't remove \"%s\": %s";
693 ShowMessage(msg, Shorten(TO_WSTRING(name), COLS-static_strlen(msg)-25).c_str(), strerror(errno));
696 else
697 ShowMessage("Aborted!");
700 # endif // !WIN32
701 else if (myScreen->ActiveWindow() == myPlaylistEditor->Content && !myPlaylistEditor->Content->Empty())
703 if (myPlaylistEditor->Content->hasSelected())
705 std::vector<size_t> list;
706 myPlaylistEditor->Content->GetSelected(list);
707 std::string playlist = locale_to_utf_cpy(myPlaylistEditor->Playlists->Current());
708 ShowMessage("Deleting selected items...");
709 Mpd.StartCommandsList();
710 for (std::vector<size_t>::reverse_iterator it = list.rbegin(); it != list.rend(); ++it)
712 Mpd.Delete(playlist, *it);
713 myPlaylistEditor->Content->DeleteOption(*it);
715 Mpd.CommitCommandsList();
716 ShowMessage("Selected items deleted from playlist \"%s\"!", myPlaylistEditor->Playlists->Current().c_str());
718 else
720 wFooter->SetTimeout(50);
721 locale_to_utf(myPlaylistEditor->Playlists->Current());
722 while (!myPlaylistEditor->Content->Empty() && Keypressed(input, Key.Delete))
724 TraceMpdStatus();
725 myPlaylist->UpdateTimer();
726 Mpd.Delete(myPlaylistEditor->Playlists->Current(), myPlaylistEditor->Content->Choice());
727 myPlaylistEditor->Content->DeleteOption(myPlaylistEditor->Content->Choice());
728 myPlaylistEditor->Content->Refresh();
729 wFooter->ReadKey(input);
731 utf_to_locale(myPlaylistEditor->Playlists->Current());
732 wFooter->SetTimeout(ncmpcpp_window_timeout);
736 else if (Keypressed(input, Key.Prev))
738 Mpd.Prev();
739 UpdateStatusImmediately = 1;
741 else if (Keypressed(input, Key.Next))
743 Mpd.Next();
744 UpdateStatusImmediately = 1;
746 else if (Keypressed(input, Key.Pause))
748 Mpd.Toggle();
749 UpdateStatusImmediately = 1;
751 else if (Keypressed(input, Key.SavePlaylist))
753 LockStatusbar();
754 Statusbar() << "Save playlist as: ";
755 std::string playlist_name = wFooter->GetString();
756 std::string real_playlist_name = locale_to_utf_cpy(playlist_name);
757 UnlockStatusbar();
758 if (playlist_name.find("/") != std::string::npos)
760 ShowMessage("Playlist name cannot contain slashes!");
761 continue;
763 if (!playlist_name.empty())
765 if (myPlaylist->Items->isFiltered())
767 Mpd.StartCommandsList();
768 for (size_t i = 0; i < myPlaylist->Items->Size(); ++i)
769 Mpd.AddToPlaylist(real_playlist_name, (*myPlaylist->Items)[i]);
770 Mpd.CommitCommandsList();
771 if (Mpd.GetErrorMessage().empty())
772 ShowMessage("Filtered items added to playlist \"%s\"", playlist_name.c_str());
774 else if (Mpd.SavePlaylist(real_playlist_name))
776 ShowMessage("Playlist saved as: %s", playlist_name.c_str());
777 if (myPlaylistEditor->Main()) // check if initialized
778 myPlaylistEditor->Playlists->Clear(); // make playlist's list update itself
780 else
782 LockStatusbar();
783 Statusbar() << "Playlist already exists, overwrite: " << playlist_name << " ? [" << fmtBold << 'y' << fmtBoldEnd << '/' << fmtBold << 'n' << fmtBoldEnd << "] ";
784 wFooter->Refresh();
785 int answer = 0;
786 while (answer != 'y' && answer != 'n')
788 TraceMpdStatus();
789 wFooter->ReadKey(answer);
791 UnlockStatusbar();
793 if (answer == 'y')
795 Mpd.DeletePlaylist(real_playlist_name);
796 if (Mpd.SavePlaylist(real_playlist_name))
797 ShowMessage("Playlist overwritten!");
799 else
800 ShowMessage("Aborted!");
801 if (myPlaylistEditor->Main()) // check if initialized
802 myPlaylistEditor->Playlists->Clear(); // make playlist's list update itself
803 if (myScreen == myPlaylist)
804 myPlaylist->EnableHighlighting();
807 if (myBrowser->Main()
808 && !myBrowser->isLocal()
809 && myBrowser->CurrentDir() == "/"
810 && !myBrowser->Main()->Empty())
811 myBrowser->GetDirectory(myBrowser->CurrentDir());
813 else if (Keypressed(input, Key.Stop))
815 Mpd.Stop();
816 UpdateStatusImmediately = 1;
818 else if (Keypressed(input, Key.MvSongUp))
820 if (myScreen == myPlaylist && myPlaylist->SortingInProgress())
821 myPlaylist->AdjustSortOrder(input);
822 else if (myScreen == myPlaylist && !myPlaylist->Items->Empty())
824 CHECK_PLAYLIST_FOR_FILTERING;
825 wFooter->SetTimeout(50);
826 if (myPlaylist->Items->hasSelected())
828 std::vector<size_t> list;
829 myPlaylist->Items->GetSelected(list);
830 std::vector<size_t> origs(list);
832 // NOTICE: since ncmpcpp only pretends to move the songs until the key is
833 // released, mpd doesn't know about the change while the songs are moved
834 // so wee need to block playlist update for this time and also if one of
835 // the songs being moved is currently playing, now playing update to prevent
836 // mpd from 'updating' and thus showing wrong position
838 bool modify_now_playing = 0;
839 for (std::vector<size_t>::iterator it = list.begin(); it != list.end(); ++it)
841 if (*it == size_t(myPlaylist->NowPlaying) && list.front() > 0)
843 modify_now_playing = 1;
844 Playlist::BlockNowPlayingUpdate = 1;
845 break;
849 while (Keypressed(input, Key.MvSongUp) && list.front() > 0)
851 TraceMpdStatus();
852 Playlist::BlockUpdate = 1;
853 myPlaylist->UpdateTimer();
854 if (modify_now_playing)
855 --myPlaylist->NowPlaying;
856 for (std::vector<size_t>::iterator it = list.begin(); it != list.end(); ++it)
858 --*it;
859 myPlaylist->Items->at((*it)+1).SetPosition(*it);
860 myPlaylist->Items->at(*it).SetPosition((*it)+1);
861 myPlaylist->Items->Swap(*it, (*it)+1);
863 myPlaylist->Items->Highlight(list[(list.size()-1)/2]);
864 myPlaylist->Items->Refresh();
865 wFooter->ReadKey(input);
867 Playlist::BlockNowPlayingUpdate = 0;
868 Mpd.StartCommandsList();
869 for (size_t i = 0; i < list.size(); ++i)
870 Mpd.Move(origs[i], list[i]);
871 Mpd.CommitCommandsList();
873 else
875 size_t from, to;
876 from = to = myPlaylist->Items->Choice();
877 bool modify_now_playing = from == size_t(myPlaylist->NowPlaying);
878 if (modify_now_playing)
879 Playlist::BlockNowPlayingUpdate = 1;
880 while (Keypressed(input, Key.MvSongUp) && to > 0)
882 TraceMpdStatus();
883 Playlist::BlockUpdate = 1;
884 myPlaylist->UpdateTimer();
885 if (modify_now_playing)
886 --myPlaylist->NowPlaying;
887 --to;
888 myPlaylist->Items->at(from).SetPosition(to);
889 myPlaylist->Items->at(to).SetPosition(from);
890 myPlaylist->Items->Swap(to, to+1);
891 myPlaylist->Items->Scroll(wUp);
892 myPlaylist->Items->Refresh();
893 wFooter->ReadKey(input);
895 Mpd.Move(from, to);
896 Playlist::BlockNowPlayingUpdate = 0;
897 UpdateStatusImmediately = 1;
899 wFooter->SetTimeout(ncmpcpp_window_timeout);
901 else if (myScreen->ActiveWindow() == myPlaylistEditor->Content && !myPlaylistEditor->Content->Empty())
903 wFooter->SetTimeout(50);
904 if (myPlaylistEditor->Content->hasSelected())
906 std::vector<size_t> list;
907 myPlaylistEditor->Content->GetSelected(list);
909 std::vector<size_t> origs(list);
911 while (Keypressed(input, Key.MvSongUp) && list.front() > 0)
913 TraceMpdStatus();
914 myPlaylist->UpdateTimer();
915 for (std::vector<size_t>::iterator it = list.begin(); it != list.end(); ++it)
917 --*it;
918 myPlaylistEditor->Content->Swap(*it, (*it)+1);
920 myPlaylistEditor->Content->Highlight(list[(list.size()-1)/2]);
921 myPlaylistEditor->Content->Refresh();
922 wFooter->ReadKey(input);
924 Mpd.StartCommandsList();
925 for (size_t i = 0; i < list.size(); ++i)
926 if (origs[i] != list[i])
927 Mpd.Move(myPlaylistEditor->Playlists->Current(), origs[i], list[i]);
928 Mpd.CommitCommandsList();
930 else
932 size_t from, to;
933 from = to = myPlaylistEditor->Content->Choice();
934 while (Keypressed(input, Key.MvSongUp) && to > 0)
936 TraceMpdStatus();
937 myPlaylist->UpdateTimer();
938 --to;
939 myPlaylistEditor->Content->Swap(to, to+1);
940 myPlaylistEditor->Content->Scroll(wUp);
941 myPlaylistEditor->Content->Refresh();
942 wFooter->ReadKey(input);
944 if (from != to)
945 Mpd.Move(myPlaylistEditor->Playlists->Current(), from, to);
947 wFooter->SetTimeout(ncmpcpp_window_timeout);
950 else if (Keypressed(input, Key.MvSongDown))
952 if (myScreen == myPlaylist && myPlaylist->SortingInProgress())
953 myPlaylist->AdjustSortOrder(input);
954 else if (myScreen == myPlaylist && !myPlaylist->Items->Empty())
956 CHECK_PLAYLIST_FOR_FILTERING;
957 wFooter->SetTimeout(50);
958 if (myPlaylist->Items->hasSelected())
960 std::vector<size_t> list;
961 myPlaylist->Items->GetSelected(list);
962 std::vector<size_t> origs(list);
964 bool modify_now_playing = 0;
965 for (std::vector<size_t>::iterator it = list.begin(); it != list.end(); ++it)
967 if (*it == size_t(myPlaylist->NowPlaying) && list.back() < myPlaylist->Items->Size()-1)
969 modify_now_playing = 1;
970 Playlist::BlockNowPlayingUpdate = 1;
971 break;
975 while (Keypressed(input, Key.MvSongDown) && list.back() < myPlaylist->Items->Size()-1)
977 TraceMpdStatus();
978 Playlist::BlockUpdate = 1;
979 myPlaylist->UpdateTimer();
980 if (modify_now_playing)
981 ++myPlaylist->NowPlaying;
982 for (std::vector<size_t>::reverse_iterator it = list.rbegin(); it != list.rend(); ++it)
984 ++*it;
985 myPlaylist->Items->at((*it)-1).SetPosition(*it);
986 myPlaylist->Items->at(*it).SetPosition((*it)-1);
987 myPlaylist->Items->Swap(*it, (*it)-1);
989 myPlaylist->Items->Highlight(list[(list.size()-1)/2]);
990 myPlaylist->Items->Refresh();
991 wFooter->ReadKey(input);
993 Playlist::BlockNowPlayingUpdate = 0;
994 Mpd.StartCommandsList();
995 for (int i = list.size()-1; i >= 0; --i)
996 Mpd.Move(origs[i], list[i]);
997 Mpd.CommitCommandsList();
999 else
1001 size_t from, to;
1002 from = to = myPlaylist->Items->Choice();
1003 bool modify_now_playing = from == size_t(myPlaylist->NowPlaying);
1004 if (modify_now_playing)
1005 Playlist::BlockNowPlayingUpdate = 1;
1006 while (Keypressed(input, Key.MvSongDown) && to < myPlaylist->Items->Size()-1)
1008 TraceMpdStatus();
1009 Playlist::BlockUpdate = 1;
1010 myPlaylist->UpdateTimer();
1011 if (modify_now_playing)
1012 ++myPlaylist->NowPlaying;
1013 ++to;
1014 myPlaylist->Items->at(from).SetPosition(to);
1015 myPlaylist->Items->at(to).SetPosition(from);
1016 myPlaylist->Items->Swap(to, to-1);
1017 myPlaylist->Items->Scroll(wDown);
1018 myPlaylist->Items->Refresh();
1019 wFooter->ReadKey(input);
1021 Mpd.Move(from, to);
1022 Playlist::BlockNowPlayingUpdate = 0;
1023 UpdateStatusImmediately = 1;
1025 wFooter->SetTimeout(ncmpcpp_window_timeout);
1028 else if (myScreen->ActiveWindow() == myPlaylistEditor->Content && !myPlaylistEditor->Content->Empty())
1030 wFooter->SetTimeout(50);
1031 if (myPlaylistEditor->Content->hasSelected())
1033 std::vector<size_t> list;
1034 myPlaylistEditor->Content->GetSelected(list);
1036 std::vector<size_t> origs(list);
1038 while (Keypressed(input, Key.MvSongDown) && list.back() < myPlaylistEditor->Content->Size()-1)
1040 TraceMpdStatus();
1041 myPlaylist->UpdateTimer();
1042 for (std::vector<size_t>::reverse_iterator it = list.rbegin(); it != list.rend(); ++it)
1044 ++*it;
1045 myPlaylistEditor->Content->Swap(*it, (*it)-1);
1047 myPlaylistEditor->Content->Highlight(list[(list.size()-1)/2]);
1048 myPlaylistEditor->Content->Refresh();
1049 wFooter->ReadKey(input);
1051 Mpd.StartCommandsList();
1052 for (int i = list.size()-1; i >= 0; --i)
1053 if (origs[i] != list[i])
1054 Mpd.Move(myPlaylistEditor->Playlists->Current(), origs[i], list[i]);
1055 Mpd.CommitCommandsList();
1057 else
1059 size_t from, to;
1060 from = to = myPlaylistEditor->Content->Choice();
1061 while (Keypressed(input, Key.MvSongDown) && to < myPlaylistEditor->Content->Size()-1)
1063 TraceMpdStatus();
1064 myPlaylist->UpdateTimer();
1065 ++to;
1066 myPlaylistEditor->Content->Swap(to, to-1);
1067 myPlaylistEditor->Content->Scroll(wDown);
1068 myPlaylistEditor->Content->Refresh();
1069 wFooter->ReadKey(input);
1071 if (from != to)
1072 Mpd.Move(myPlaylistEditor->Playlists->Current(), from, to);
1074 wFooter->SetTimeout(ncmpcpp_window_timeout);
1077 else if (Keypressed(input, Key.MoveTo) && myScreen == myPlaylist)
1079 CHECK_PLAYLIST_FOR_FILTERING;
1080 if (!myPlaylist->Items->hasSelected())
1082 ShowMessage("No selected items to move!");
1083 continue;
1085 Playlist::BlockUpdate = 1;
1086 size_t pos = myPlaylist->Items->Choice();
1087 // if cursor is at the last item, break convention and move at the end of playlist
1088 if (pos == myPlaylist->Items->Size()-1)
1089 pos++;
1090 std::vector<size_t> list;
1091 myPlaylist->Items->GetSelected(list);
1092 if (pos >= list.front() && pos <= list.back())
1093 continue;
1094 int diff = pos-list.front();
1095 Mpd.StartCommandsList();
1096 if (diff > 0)
1098 pos -= list.size();
1099 size_t i = list.size()-1;
1100 for (std::vector<size_t>::reverse_iterator it = list.rbegin(); it != list.rend(); ++it, --i)
1102 Mpd.Move(*it, pos+i);
1103 myPlaylist->Items->Move(*it, pos+i);
1106 else if (diff < 0)
1108 size_t i = 0;
1109 for (std::vector<size_t>::const_iterator it = list.begin(); it != list.end(); ++it, ++i)
1111 Mpd.Move(*it, pos+i);
1112 myPlaylist->Items->Move(*it, pos+i);
1115 Mpd.CommitCommandsList();
1116 myPlaylist->Items->Highlight(pos);
1117 myPlaylist->FixPositions();
1119 else if (Keypressed(input, Key.Add))
1121 if (myScreen == myPlaylistEditor && myPlaylistEditor->Playlists->Empty())
1122 continue;
1123 LockStatusbar();
1124 Statusbar() << (myScreen == myPlaylistEditor ? "Add to playlist: " : "Add: ");
1125 std::string path = wFooter->GetString();
1126 UnlockStatusbar();
1127 if (!path.empty())
1129 if (myScreen == myPlaylistEditor)
1131 Mpd.AddToPlaylist(myPlaylistEditor->Playlists->Current(), path);
1132 myPlaylistEditor->Content->Clear(); // make it refetch content of playlist
1134 else
1135 Mpd.Add(path);
1136 UpdateStatusImmediately = 1;
1139 else if (Keypressed(input, Key.SeekForward) || Keypressed(input, Key.SeekBackward))
1141 if (!Mpd.GetTotalTime())
1143 ShowMessage("Unknown item length!");
1144 continue;
1147 const Song *s = myPlaylist->NowPlayingSong();
1148 if (!s)
1149 continue;
1151 LockProgressbar();
1152 LockStatusbar();
1154 int songpos;
1155 time_t t = time(0);
1157 songpos = Mpd.GetElapsedTime();
1159 int old_timeout = wFooter->GetTimeout();
1160 wFooter->SetTimeout(ncmpcpp_window_timeout);
1162 SeekingInProgress = 1;
1163 *wFooter << fmtBold;
1164 while (Keypressed(input, Key.SeekForward) || Keypressed(input, Key.SeekBackward))
1166 TraceMpdStatus();
1167 myPlaylist->UpdateTimer();
1168 wFooter->ReadKey(input);
1170 int howmuch = Config.incremental_seeking ? (myPlaylist->Timer()-t)/2+Config.seek_time : Config.seek_time;
1172 if (Keypressed(input, Key.SeekForward) && songpos < Mpd.GetTotalTime())
1174 songpos += howmuch;
1175 if (songpos > Mpd.GetTotalTime())
1176 songpos = Mpd.GetTotalTime();
1178 else if (Keypressed(input, Key.SeekBackward) && songpos > 0)
1180 songpos -= howmuch;
1181 if (songpos < 0)
1182 songpos = 0;
1185 std::string tracklength;
1186 if (Config.new_design)
1188 if (Config.display_remaining_time)
1190 tracklength = "-";
1191 tracklength += Song::ShowTime(Mpd.GetTotalTime()-songpos);
1193 else
1194 tracklength = Song::ShowTime(songpos);
1195 tracklength += "/";
1196 tracklength += MPD::Song::ShowTime(Mpd.GetTotalTime());
1197 *wHeader << XY(0, 0) << tracklength << " ";
1198 wHeader->Refresh();
1200 else
1202 tracklength = " [";
1203 if (Config.display_remaining_time)
1205 tracklength += "-";
1206 tracklength += Song::ShowTime(Mpd.GetTotalTime()-songpos);
1208 else
1209 tracklength += Song::ShowTime(songpos);
1210 tracklength += "/";
1211 tracklength += MPD::Song::ShowTime(Mpd.GetTotalTime());
1212 tracklength += "]";
1213 *wFooter << XY(wFooter->GetWidth()-tracklength.length(), 1) << tracklength;
1215 DrawProgressbar(songpos, Mpd.GetTotalTime());
1216 wFooter->Refresh();
1218 *wFooter << fmtBoldEnd;
1219 SeekingInProgress = 0;
1220 Mpd.Seek(songpos);
1221 UpdateStatusImmediately = 1;
1223 wFooter->SetTimeout(old_timeout);
1225 UnlockProgressbar();
1226 UnlockStatusbar();
1228 else if (Keypressed(input, Key.ToggleDisplayMode))
1230 if (myScreen == myPlaylist)
1232 Config.columns_in_playlist = !Config.columns_in_playlist;
1233 ShowMessage("Playlist display mode: %s", Config.columns_in_playlist ? "Columns" : "Classic");
1235 if (Config.columns_in_playlist)
1237 myPlaylist->Items->SetItemDisplayer(Display::SongsInColumns);
1238 myPlaylist->Items->SetTitle(Display::Columns());
1239 myPlaylist->Items->SetGetStringFunction(Playlist::SongInColumnsToString);
1241 else
1243 myPlaylist->Items->SetItemDisplayer(Display::Songs);
1244 myPlaylist->Items->SetTitle("");
1245 myPlaylist->Items->SetGetStringFunction(Playlist::SongToString);
1248 else if (myScreen == myBrowser)
1250 Config.columns_in_browser = !Config.columns_in_browser;
1251 ShowMessage("Browser display mode: %s", Config.columns_in_browser ? "Columns" : "Classic");
1252 myBrowser->Main()->SetTitle(Config.columns_in_browser ? Display::Columns() : "");
1255 else if (myScreen == mySearcher)
1257 Config.columns_in_search_engine = !Config.columns_in_search_engine;
1258 ShowMessage("Search engine display mode: %s", Config.columns_in_search_engine ? "Columns" : "Classic");
1259 if (mySearcher->Main()->Size() > SearchEngine::StaticOptions)
1260 mySearcher->Main()->SetTitle(Config.columns_in_search_engine ? Display::Columns() : "");
1263 # ifdef HAVE_CURL_CURL_H
1264 else if (Keypressed(input, Key.ToggleLyricsDB))
1266 const char *current_lyrics_plugin = Lyrics::GetPluginName(++Config.lyrics_db);
1267 if (!current_lyrics_plugin)
1269 current_lyrics_plugin = Lyrics::GetPluginName(Config.lyrics_db = 0);
1271 ShowMessage("Using lyrics database: %s", current_lyrics_plugin);
1273 # endif // HAVE_CURL_CURL_H
1274 else if (Keypressed(input, Key.ToggleAutoCenter))
1276 Config.autocenter_mode = !Config.autocenter_mode;
1277 ShowMessage("Auto center mode: %s", Config.autocenter_mode ? "On" : "Off");
1278 if (Config.autocenter_mode && myPlaylist->isPlaying() && !myPlaylist->Items->isFiltered())
1279 myPlaylist->Items->Highlight(myPlaylist->NowPlaying);
1281 else if (Keypressed(input, Key.UpdateDB))
1283 if (myScreen == myBrowser)
1284 Mpd.UpdateDirectory(locale_to_utf_cpy(myBrowser->CurrentDir()));
1285 # ifdef HAVE_TAGLIB_H
1286 else if (myScreen == myTagEditor && !Config.albums_in_tag_editor)
1287 Mpd.UpdateDirectory(myTagEditor->CurrentDir());
1288 # endif // HAVE_TAGLIB_H
1289 else
1290 Mpd.UpdateDirectory("/");
1292 else if (Keypressed(input, Key.GoToNowPlaying))
1294 if (myScreen == myPlaylist && myPlaylist->isPlaying())
1296 CHECK_PLAYLIST_FOR_FILTERING;
1297 myPlaylist->Items->Highlight(myPlaylist->NowPlaying);
1299 else if (myScreen == myBrowser)
1301 if (const Song *s = myPlaylist->NowPlayingSong())
1303 myBrowser->LocateSong(*s);
1304 RedrawHeader = 1;
1308 else if (Keypressed(input, Key.ToggleRepeat))
1310 Mpd.SetRepeat(!Mpd.GetRepeat());
1311 UpdateStatusImmediately = 1;
1313 else if (Keypressed(input, Key.Shuffle))
1315 Mpd.Shuffle();
1316 UpdateStatusImmediately = 1;
1318 else if (Keypressed(input, Key.ToggleRandom))
1320 Mpd.SetRandom(!Mpd.GetRandom());
1321 UpdateStatusImmediately = 1;
1323 else if (Keypressed(input, Key.ToggleSingle))
1325 if (myScreen == mySearcher && !mySearcher->Main()->isStatic(0))
1327 mySearcher->Main()->Highlight(SearchEngine::SearchButton);
1328 mySearcher->Main()->Highlighting(0);
1329 mySearcher->Main()->Refresh();
1330 mySearcher->Main()->Highlighting(1);
1331 mySearcher->EnterPressed();
1333 # ifdef HAVE_TAGLIB_H
1334 else if (myScreen == myTinyTagEditor)
1336 myTinyTagEditor->Main()->Highlight(myTinyTagEditor->Main()->Size()-2); // Save
1337 myTinyTagEditor->EnterPressed();
1339 # endif // HAVE_TAGLIB_H
1340 else
1342 Mpd.SetSingle(!Mpd.GetSingle());
1343 UpdateStatusImmediately = 1;
1346 else if (Keypressed(input, Key.ToggleConsume))
1348 Mpd.SetConsume(!Mpd.GetConsume());
1349 UpdateStatusImmediately = 1;
1351 else if (Keypressed(input, Key.ToggleCrossfade))
1353 Mpd.SetCrossfade(Mpd.GetCrossfade() ? 0 : Config.crossfade_time);
1354 UpdateStatusImmediately = 1;
1356 else if (Keypressed(input, Key.SetCrossfade))
1358 LockStatusbar();
1359 Statusbar() << "Set crossfade to: ";
1360 std::string crossfade = wFooter->GetString(3);
1361 UnlockStatusbar();
1362 int cf = StrToInt(crossfade);
1363 if (cf > 0)
1365 Config.crossfade_time = cf;
1366 Mpd.SetCrossfade(cf);
1367 UpdateStatusImmediately = 1;
1370 else if (Keypressed(input, Key.EditTags))
1372 if ((myScreen != myBrowser || !myBrowser->isLocal())
1373 && myScreen != myLyrics)
1374 CHECK_MPD_MUSIC_DIR;
1375 # ifdef HAVE_TAGLIB_H
1376 if (myTinyTagEditor->SetEdited(myScreen->CurrentSong()))
1378 myTinyTagEditor->SwitchTo();
1380 else if (myScreen->ActiveWindow() == myLibrary->Artists)
1382 LockStatusbar();
1383 Statusbar() << fmtBold << IntoStr(Config.media_lib_primary_tag) << fmtBoldEnd << ": ";
1384 std::string new_tag = wFooter->GetString(myLibrary->Artists->Current());
1385 UnlockStatusbar();
1386 if (!new_tag.empty() && new_tag != myLibrary->Artists->Current())
1388 bool success = 1;
1389 SongList list;
1390 ShowMessage("Updating tags...");
1391 Mpd.StartSearch(1);
1392 Mpd.AddSearch(Config.media_lib_primary_tag, locale_to_utf_cpy(myLibrary->Artists->Current()));
1393 Mpd.CommitSearch(list);
1394 Song::SetFunction set = IntoSetFunction(Config.media_lib_primary_tag);
1395 if (!set)
1396 continue;
1397 for (SongList::iterator it = list.begin(); it != list.end(); ++it)
1399 (*it)->Localize();
1400 (*it)->SetTags(set, new_tag);
1401 ShowMessage("Updating tags in \"%s\"...", (*it)->GetName().c_str());
1402 std::string path = Config.mpd_music_dir + (*it)->GetFile();
1403 if (!TagEditor::WriteTags(**it))
1405 static const char msg[] = "Error while updating tags in \"%s\"!";
1406 ShowMessage(msg, Shorten(TO_WSTRING((*it)->GetFile()), COLS-static_strlen(msg)).c_str());
1407 success = 0;
1408 break;
1411 if (success)
1413 Mpd.UpdateDirectory(locale_to_utf_cpy(FindSharedDir(list)));
1414 ShowMessage("Tags updated succesfully!");
1416 FreeSongList(list);
1419 else if (myScreen->ActiveWindow() == myLibrary->Albums)
1421 LockStatusbar();
1422 Statusbar() << fmtBold << "Album: " << fmtBoldEnd;
1423 std::string new_album = wFooter->GetString(myLibrary->Albums->Current().Album);
1424 UnlockStatusbar();
1425 if (!new_album.empty() && new_album != myLibrary->Albums->Current().Album)
1427 bool success = 1;
1428 ShowMessage("Updating tags...");
1429 for (size_t i = 0; i < myLibrary->Songs->Size(); ++i)
1431 (*myLibrary->Songs)[i].Localize();
1432 ShowMessage("Updating tags in \"%s\"...", (*myLibrary->Songs)[i].GetName().c_str());
1433 std::string path = Config.mpd_music_dir + (*myLibrary->Songs)[i].GetFile();
1434 TagLib::FileRef f(locale_to_utf_cpy(path).c_str());
1435 if (f.isNull())
1437 static const char msg[] = "Error while opening file \"%s\"!";
1438 ShowMessage(msg, Shorten(TO_WSTRING((*myLibrary->Songs)[i].GetFile()), COLS-static_strlen(msg)).c_str());
1439 success = 0;
1440 break;
1442 f.tag()->setAlbum(ToWString(new_album));
1443 if (!f.save())
1445 static const char msg[] = "Error while writing tags in \"%s\"!";
1446 ShowMessage(msg, Shorten(TO_WSTRING((*myLibrary->Songs)[i].GetFile()), COLS-static_strlen(msg)).c_str());
1447 success = 0;
1448 break;
1451 if (success)
1453 Mpd.UpdateDirectory(locale_to_utf_cpy(FindSharedDir(myLibrary->Songs)));
1454 ShowMessage("Tags updated succesfully!");
1458 else if (myScreen->ActiveWindow() == myTagEditor->Dirs)
1460 std::string old_dir = myTagEditor->Dirs->Current().first;
1461 LockStatusbar();
1462 Statusbar() << fmtBold << "Directory: " << fmtBoldEnd;
1463 std::string new_dir = wFooter->GetString(old_dir);
1464 UnlockStatusbar();
1465 if (!new_dir.empty() && new_dir != old_dir)
1467 std::string full_old_dir = Config.mpd_music_dir + myTagEditor->CurrentDir() + "/" + locale_to_utf_cpy(old_dir);
1468 std::string full_new_dir = Config.mpd_music_dir + myTagEditor->CurrentDir() + "/" + locale_to_utf_cpy(new_dir);
1469 if (rename(full_old_dir.c_str(), full_new_dir.c_str()) == 0)
1471 static const char msg[] = "Directory renamed to \"%s\"";
1472 ShowMessage(msg, Shorten(TO_WSTRING(new_dir), COLS-static_strlen(msg)).c_str());
1473 Mpd.UpdateDirectory(myTagEditor->CurrentDir());
1475 else
1477 static const char msg[] = "Couldn't rename \"%s\": %s";
1478 ShowMessage(msg, Shorten(TO_WSTRING(old_dir), COLS-static_strlen(msg)-25).c_str(), strerror(errno));
1482 else
1483 # endif // HAVE_TAGLIB_H
1484 if (myScreen == myLyrics)
1486 myLyrics->Edit();
1488 if (myScreen == myBrowser && myBrowser->Main()->Current().type == itDirectory)
1490 std::string old_dir = myBrowser->Main()->Current().name;
1491 LockStatusbar();
1492 Statusbar() << fmtBold << "Directory: " << fmtBoldEnd;
1493 std::string new_dir = wFooter->GetString(old_dir);
1494 UnlockStatusbar();
1495 if (!new_dir.empty() && new_dir != old_dir)
1497 std::string full_old_dir;
1498 if (!myBrowser->isLocal())
1499 full_old_dir += Config.mpd_music_dir;
1500 full_old_dir += locale_to_utf_cpy(old_dir);
1501 std::string full_new_dir;
1502 if (!myBrowser->isLocal())
1503 full_new_dir += Config.mpd_music_dir;
1504 full_new_dir += locale_to_utf_cpy(new_dir);
1505 int rename_result = rename(full_old_dir.c_str(), full_new_dir.c_str());
1506 if (rename_result == 0)
1508 static const char msg[] = "Directory renamed to \"%s\"";
1509 ShowMessage(msg, Shorten(TO_WSTRING(new_dir), COLS-static_strlen(msg)).c_str());
1510 if (!myBrowser->isLocal())
1511 Mpd.UpdateDirectory(locale_to_utf_cpy(FindSharedDir(old_dir, new_dir)));
1512 myBrowser->GetDirectory(myBrowser->CurrentDir());
1514 else
1516 static const char msg[] = "Couldn't rename \"%s\": %s";
1517 ShowMessage(msg, Shorten(TO_WSTRING(old_dir), COLS-static_strlen(msg)-25).c_str(), strerror(errno));
1521 else if (myScreen->ActiveWindow() == myPlaylistEditor->Playlists || (myScreen == myBrowser && myBrowser->Main()->Current().type == itPlaylist))
1523 std::string old_name = myScreen->ActiveWindow() == myPlaylistEditor->Playlists ? myPlaylistEditor->Playlists->Current() : myBrowser->Main()->Current().name;
1524 LockStatusbar();
1525 Statusbar() << fmtBold << "Playlist: " << fmtBoldEnd;
1526 std::string new_name = wFooter->GetString(old_name);
1527 UnlockStatusbar();
1528 if (!new_name.empty() && new_name != old_name)
1530 if (Mpd.Rename(locale_to_utf_cpy(old_name), locale_to_utf_cpy(new_name)))
1532 static const char msg[] = "Playlist renamed to \"%s\"";
1533 ShowMessage(msg, Shorten(TO_WSTRING(new_name), COLS-static_strlen(msg)).c_str());
1534 if (myBrowser->Main() && !myBrowser->isLocal())
1535 myBrowser->GetDirectory("/");
1536 if (myPlaylistEditor->Main())
1537 myPlaylistEditor->Playlists->Clear();
1542 else if (Keypressed(input, Key.GoToContainingDir))
1544 Song *s = myScreen->CurrentSong();
1545 if (s)
1546 myBrowser->LocateSong(*s);
1548 else if (Keypressed(input, Key.GoToMediaLibrary))
1550 Song *s = myScreen->CurrentSong();
1551 if (s)
1552 myLibrary->LocateSong(*s);
1554 else if (Keypressed(input, Key.GoToPosition))
1556 if (!Mpd.GetTotalTime())
1558 ShowMessage("Unknown item length!");
1559 continue;
1562 const Song *s = myPlaylist->NowPlayingSong();
1563 if (!s)
1564 continue;
1566 LockStatusbar();
1567 Statusbar() << "Position to go (in %/mm:ss/seconds(s)): ";
1568 std::string position = wFooter->GetString();
1569 UnlockStatusbar();
1571 if (position.empty())
1572 continue;
1574 int newpos = 0;
1575 if (position.find(':') != std::string::npos) // probably time in mm:ss
1577 newpos = StrToInt(position)*60 + StrToInt(position.substr(position.find(':')+1));
1578 if (newpos >= 0 && newpos <= Mpd.GetTotalTime())
1579 Mpd.Seek(newpos);
1580 else
1581 ShowMessage("Out of bounds, 0:00-%s possible for mm:ss, %s given.", s->GetLength().c_str(), MPD::Song::ShowTime(newpos).c_str());
1583 else if (position.find('s') != std::string::npos) // probably position in seconds
1585 newpos = StrToInt(position);
1586 if (newpos >= 0 && newpos <= Mpd.GetTotalTime())
1587 Mpd.Seek(newpos);
1588 else
1589 ShowMessage("Out of bounds, 0-%d possible for seconds, %d given.", s->GetTotalLength(), newpos);
1591 else
1593 newpos = StrToInt(position);
1594 if (newpos >= 0 && newpos <= 100)
1595 Mpd.Seek(Mpd.GetTotalTime()*newpos/100.0);
1596 else
1597 ShowMessage("Out of bounds, 0-100 possible for %%, %d given.", newpos);
1599 UpdateStatusImmediately = 1;
1601 else if (Keypressed(input, Key.ReverseSelection))
1603 if (myScreen->allowsSelection())
1605 myScreen->ReverseSelection();
1606 ShowMessage("Selection reversed!");
1609 else if (Keypressed(input, Key.DeselectAll))
1611 if (myScreen->allowsSelection())
1613 List *mList = myScreen->GetList();
1614 if (!mList->hasSelected())
1615 continue;
1616 for (size_t i = 0; i < mList->Size(); ++i)
1617 mList->Select(i, 0);
1618 ShowMessage("Items deselected!");
1621 else if (Keypressed(input, Key.AddSelected))
1623 mySelectedItemsAdder->SwitchTo();
1625 else if (Keypressed(input, Key.Crop))
1627 CHECK_PLAYLIST_FOR_FILTERING;
1628 if (myPlaylist->Items->hasSelected())
1630 Mpd.StartCommandsList();
1631 for (int i = myPlaylist->Items->Size()-1; i >= 0; --i)
1633 if (!myPlaylist->Items->isSelected(i) && i != myPlaylist->NowPlaying)
1634 Mpd.Delete(i);
1636 // if mpd deletes now playing song deletion will be sluggishly slow
1637 // then so we have to assure it will be deleted at the very end.
1638 if (myPlaylist->isPlaying() && !myPlaylist->Items->isSelected(myPlaylist->NowPlaying))
1639 Mpd.DeleteID(myPlaylist->NowPlayingSong()->GetID());
1641 ShowMessage("Deleting all items but selected...");
1642 Mpd.CommitCommandsList();
1643 ShowMessage("Items deleted!");
1645 else
1647 if (!myPlaylist->isPlaying())
1649 ShowMessage("Nothing is playing now!");
1650 continue;
1652 Mpd.StartCommandsList();
1653 for (int i = myPlaylist->Items->Size()-1; i >= 0; --i)
1654 if (i != myPlaylist->NowPlaying)
1655 Mpd.Delete(i);
1656 ShowMessage("Deleting all items except now playing one...");
1657 Mpd.CommitCommandsList();
1658 ShowMessage("Items deleted!");
1661 else if (Keypressed(input, Key.Clear))
1663 if (myScreen == myPlaylistEditor && myPlaylistEditor->Playlists->Empty())
1664 continue;
1666 if (myScreen->ActiveWindow() == myPlaylistEditor->Content
1667 || Config.ask_before_clearing_main_playlist)
1669 LockStatusbar();
1670 Statusbar() << "Do you really want to clear playlist";
1671 if (myScreen->ActiveWindow() == myPlaylistEditor->Content)
1672 *wFooter << " \"" << myPlaylistEditor->Playlists->Current() << "\"";
1673 *wFooter << " ? [" << fmtBold << 'y' << fmtBoldEnd << '/' << fmtBold << 'n' << fmtBoldEnd << "] ";
1674 wFooter->Refresh();
1675 int answer = 0;
1678 TraceMpdStatus();
1679 wFooter->ReadKey(answer);
1681 while (answer != 'y' && answer != 'n');
1682 UnlockStatusbar();
1683 if (answer != 'y')
1685 ShowMessage("Aborted!");
1686 continue;
1690 if (myPlaylist->Items->isFiltered())
1692 ShowMessage("Deleting filtered items...");
1693 Mpd.StartCommandsList();
1694 for (int i = myPlaylist->Items->Size()-1; i >= 0; --i)
1695 Mpd.Delete((*myPlaylist->Items)[i].GetPosition());
1696 Mpd.CommitCommandsList();
1697 ShowMessage("Filtered items deleted!");
1699 else
1701 if (myScreen->ActiveWindow() == myPlaylistEditor->Content)
1703 Mpd.ClearPlaylist(locale_to_utf_cpy(myPlaylistEditor->Playlists->Current()));
1704 myPlaylistEditor->Content->Clear();
1706 else
1708 ShowMessage("Clearing playlist...");
1709 Mpd.ClearPlaylist();
1712 // if playlist is cleared, items list have to be updated, but this
1713 // can be blocked if new song was added to playlist less than one
1714 // second ago, so we need to assume it's unlocked.
1715 BlockItemListUpdate = 0;
1716 UpdateStatusImmediately = 1;
1718 else if (Keypressed(input, Key.SortPlaylist) && myScreen == myPlaylist)
1720 CHECK_PLAYLIST_FOR_FILTERING;
1721 myPlaylist->Sort();
1723 else if (Keypressed(input, Key.ApplyFilter))
1725 List *mList = myScreen->GetList();
1727 if (!mList)
1728 continue;
1730 LockStatusbar();
1731 Statusbar() << fmtBold << "Apply filter: " << fmtBoldEnd;
1732 wFooter->SetGetStringHelper(StatusbarApplyFilterImmediately);
1733 wFooter->GetString(mList->GetFilter());
1734 wFooter->SetGetStringHelper(StatusbarGetStringHelper);
1735 UnlockStatusbar();
1737 if (mList->isFiltered())
1738 ShowMessage("Using filter \"%s\"", mList->GetFilter().c_str());
1739 else
1740 ShowMessage("Filtering disabled");
1742 if (myScreen == myPlaylist)
1744 myPlaylist->EnableHighlighting();
1745 Playlist::ReloadTotalLength = 1;
1746 RedrawHeader = 1;
1749 else if (Keypressed(input, Key.FindForward) || Keypressed(input, Key.FindBackward))
1751 List *mList = myScreen->GetList();
1753 if (mList)
1755 LockStatusbar();
1756 Statusbar() << "Find " << (Keypressed(input, Key.FindForward) ? "forward" : "backward") << ": ";
1757 std::string findme = wFooter->GetString();
1758 UnlockStatusbar();
1759 myPlaylist->UpdateTimer();
1761 if (!findme.empty())
1762 ShowMessage("Searching...");
1764 bool success = mList->Search(findme, myScreen == mySearcher ? SearchEngine::StaticOptions : 0, REG_ICASE | Config.regex_type);
1766 if (findme.empty())
1767 continue;
1769 success ? ShowMessage("Searching finished!") : ShowMessage("Unable to find \"%s\"", findme.c_str());
1771 if (Keypressed(input, Key.FindForward))
1772 mList->NextFound(Config.wrapped_search);
1773 else
1774 mList->PrevFound(Config.wrapped_search);
1776 if (myScreen == myPlaylist)
1777 myPlaylist->EnableHighlighting();
1779 else if (myScreen == myHelp || myScreen == myLyrics || myScreen == myInfo)
1781 LockStatusbar();
1782 Statusbar() << "Find: ";
1783 std::string findme = wFooter->GetString();
1784 UnlockStatusbar();
1786 ShowMessage("Searching...");
1787 Screen<Scrollpad> *s = static_cast<Screen<Scrollpad> *>(myScreen);
1788 s->Main()->RemoveFormatting();
1789 ShowMessage("%s", findme.empty() || s->Main()->SetFormatting(fmtReverse, TO_WSTRING(findme), fmtReverseEnd, 0) ? "Done!" : "No matching patterns found");
1790 s->Main()->Flush();
1793 else if (Keypressed(input, Key.NextFoundPosition) || Keypressed(input, Key.PrevFoundPosition))
1795 List *mList = myScreen->GetList();
1797 if (!mList)
1798 continue;
1800 if (Keypressed(input, Key.NextFoundPosition))
1801 mList->NextFound(Config.wrapped_search);
1802 else
1803 mList->PrevFound(Config.wrapped_search);
1805 else if (Keypressed(input, Key.ToggleFindMode))
1807 Config.wrapped_search = !Config.wrapped_search;
1808 ShowMessage("Search mode: %s", Config.wrapped_search ? "Wrapped" : "Normal");
1810 else if (Keypressed(input, Key.ToggleReplayGainMode) && Mpd.Version() >= 16)
1812 LockStatusbar();
1813 Statusbar() << "Replay gain mode ? [" << fmtBold << 'o' << fmtBoldEnd << "ff/" << fmtBold << 't' << fmtBoldEnd << "rack/" << fmtBold << 'a' << fmtBoldEnd << "lbum]";
1814 wFooter->Refresh();
1815 int answer = 0;
1818 TraceMpdStatus();
1819 wFooter->ReadKey(answer);
1821 while (answer != 'o' && answer != 't' && answer != 'a');
1822 UnlockStatusbar();
1823 Mpd.SetReplayGainMode(answer == 't' ? rgmTrack : (answer == 'a' ? rgmAlbum : rgmOff));
1824 ShowMessage("Replay gain mode: %s", Mpd.GetReplayGainMode().c_str());
1826 else if (Keypressed(input, Key.ToggleSpaceMode))
1828 Config.space_selects = !Config.space_selects;
1829 ShowMessage("Space mode: %s item", Config.space_selects ? "Select/deselect" : "Add");
1831 else if (Keypressed(input, Key.ToggleAddMode))
1833 Config.ncmpc_like_songs_adding = !Config.ncmpc_like_songs_adding;
1834 ShowMessage("Add mode: %s", Config.ncmpc_like_songs_adding ? "Add item to playlist, remove if already added" : "Always add item to playlist");
1836 else if (Keypressed(input, Key.ToggleMouse))
1838 Config.mouse_support = !Config.mouse_support;
1839 mousemask(Config.mouse_support ? ALL_MOUSE_EVENTS : 0, 0);
1840 ShowMessage("Mouse support %s", Config.mouse_support ? "enabled" : "disabled");
1842 else if (Keypressed(input, Key.SwitchTagTypeList))
1844 if (myScreen == myPlaylist)
1846 LockStatusbar();
1847 Statusbar() << "Add random ? [" << fmtBold << 's' << fmtBoldEnd << "ongs/" << fmtBold << 'a' << fmtBoldEnd << "rtists/al" << fmtBold << 'b' << fmtBoldEnd << "ums] ";
1848 wFooter->Refresh();
1849 int answer = 0;
1852 TraceMpdStatus();
1853 wFooter->ReadKey(answer);
1855 while (answer != 's' && answer != 'a' && answer != 'b');
1856 UnlockStatusbar();
1858 mpd_tag_type tag_type = IntoTagItem(answer);
1859 std::string tag_type_str = answer == 's' ? "song" : IntoStr(tag_type);
1860 ToLower(tag_type_str);
1862 LockStatusbar();
1863 Statusbar() << "Number of random " << tag_type_str << "s: ";
1864 size_t number = StrToLong(wFooter->GetString());
1865 UnlockStatusbar();
1866 if (number && (answer == 's' ? Mpd.AddRandomSongs(number) : Mpd.AddRandomTag(tag_type, number)))
1867 ShowMessage("%zu random %s%s added to playlist!", number, tag_type_str.c_str(), number == 1 ? "" : "s");
1869 else if (myScreen == myBrowser && !myBrowser->isLocal())
1871 Config.browser_sort_by_mtime = !Config.browser_sort_by_mtime;
1872 myBrowser->Main()->Sort<CaseInsensitiveSorting>(myBrowser->CurrentDir() != "/");
1873 ShowMessage("Sort songs by: %s", Config.browser_sort_by_mtime ? "Modification time" : "Name");
1875 else if (myScreen->ActiveWindow() == myLibrary->Artists
1876 || (myLibrary->Columns() == 2 && myScreen->ActiveWindow() == myLibrary->Albums))
1878 LockStatusbar();
1879 Statusbar() << "Tag type ? [" << fmtBold << 'a' << fmtBoldEnd << "rtist/" << fmtBold << 'y' << fmtBoldEnd << "ear/" << fmtBold << 'g' << fmtBoldEnd << "enre/" << fmtBold << 'c' << fmtBoldEnd << "omposer/" << fmtBold << 'p' << fmtBoldEnd << "erformer] ";
1880 wFooter->Refresh();
1881 int answer = 0;
1884 TraceMpdStatus();
1885 wFooter->ReadKey(answer);
1887 while (answer != 'a' && answer != 'y' && answer != 'g' && answer != 'c' && answer != 'p');
1888 UnlockStatusbar();
1889 mpd_tag_type new_tagitem = IntoTagItem(answer);
1890 if (new_tagitem != Config.media_lib_primary_tag)
1892 Config.media_lib_primary_tag = new_tagitem;
1893 std::string item_type = IntoStr(Config.media_lib_primary_tag);
1894 myLibrary->Artists->SetTitle(item_type + "s");
1895 myLibrary->Artists->Reset();
1896 ToLower(item_type);
1897 if (myLibrary->Columns() == 2)
1899 myLibrary->Songs->Clear();
1900 myLibrary->Albums->Reset();
1901 myLibrary->Albums->Clear();
1902 myLibrary->Albums->SetTitle("Albums (sorted by " + item_type + ")");
1903 myLibrary->Albums->Display();
1905 else
1907 myLibrary->Artists->Clear();
1908 myLibrary->Artists->Display();
1910 ShowMessage("Switched to list of %s tag", item_type.c_str());
1913 else if (myScreen == myLyrics)
1915 myLyrics->FetchAgain();
1918 else if (Keypressed(input, Key.SongInfo))
1920 myInfo->GetSong();
1922 # ifdef HAVE_CURL_CURL_H
1923 else if (Keypressed(input, Key.ArtistInfo))
1925 myInfo->GetArtist();
1927 # endif // HAVE_CURL_CURL_H
1928 else if (Keypressed(input, Key.Lyrics))
1930 myLyrics->SwitchTo();
1932 else if (Keypressed(input, Key.Quit))
1934 main_exit = 1;
1936 # ifdef HAVE_TAGLIB_H
1937 else if (myScreen == myTinyTagEditor)
1939 continue;
1941 # endif // HAVE_TAGLIB_H
1942 else if (Keypressed(input, Key.Help))
1944 myHelp->SwitchTo();
1946 else if (Keypressed(input, Key.ScreenSwitcher))
1948 if (Config.screen_switcher_browser_only)
1950 if (myScreen == myPlaylist)
1951 myBrowser->SwitchTo();
1952 else
1953 myPlaylist->SwitchTo();
1955 else
1957 if (myScreen->isTabbable())
1958 myPrevScreen->SwitchTo();
1959 else
1960 myOldScreen->SwitchTo();
1963 else if (Keypressed(input, Key.Playlist))
1965 myPlaylist->SwitchTo();
1967 else if (Keypressed(input, Key.Browser))
1969 myBrowser->SwitchTo();
1971 else if (Keypressed(input, Key.SearchEngine))
1973 mySearcher->SwitchTo();
1975 else if (Keypressed(input, Key.MediaLibrary))
1977 myLibrary->SwitchTo();
1979 else if (Keypressed(input, Key.PlaylistEditor))
1981 myPlaylistEditor->SwitchTo();
1983 # ifdef HAVE_TAGLIB_H
1984 else if (Keypressed(input, Key.TagEditor))
1986 CHECK_MPD_MUSIC_DIR;
1987 myTagEditor->SwitchTo();
1989 # endif // HAVE_TAGLIB_H
1990 # ifdef ENABLE_OUTPUTS
1991 else if (Keypressed(input, Key.Outputs))
1993 myOutputs->SwitchTo();
1995 # endif // ENABLE_OUTPUTS
1996 # ifdef ENABLE_VISUALIZER
1997 else if (Keypressed(input, Key.Visualizer))
1999 myVisualizer->SwitchTo();
2001 # endif // ENABLE_VISUALIZER
2002 # ifdef ENABLE_CLOCK
2003 else if (Keypressed(input, Key.Clock))
2005 myClock->SwitchTo();
2007 # endif // ENABLE_CLOCK
2008 else if (Keypressed(input, Key.ServerInfo))
2010 myServerInfo->SwitchTo();
2012 // key mapping end
2014 if (myScreen == myLibrary
2015 || myScreen == myPlaylistEditor
2016 # ifdef HAVE_TAGLIB_H
2017 || myScreen == myTagEditor
2018 # endif // HAVE_TAGLIB_H
2021 if (Keypressed(input, Key.Up)
2022 || Keypressed(input, Key.Down)
2023 || Keypressed(input, Key.PageUp)
2024 || Keypressed(input, Key.PageDown)
2025 || Keypressed(input, Key.Home)
2026 || Keypressed(input, Key.End)
2027 || Keypressed(input, Key.ApplyFilter)
2028 || Keypressed(input, Key.FindForward)
2029 || Keypressed(input, Key.FindBackward)
2030 || Keypressed(input, Key.NextFoundPosition)
2031 || Keypressed(input, Key.PrevFoundPosition))
2033 if (myScreen->ActiveWindow() == myLibrary->Artists)
2035 myLibrary->Albums->Clear();
2037 else if (myScreen->ActiveWindow() == myLibrary->Albums)
2039 myLibrary->Songs->Clear();
2041 else if (myScreen->ActiveWindow() == myPlaylistEditor->Playlists)
2043 myPlaylistEditor->Content->Clear();
2045 # ifdef HAVE_TAGLIB_H
2046 else if (myScreen->ActiveWindow() == myTagEditor->LeftColumn)
2048 myTagEditor->Tags->Clear();
2050 # endif // HAVE_TAGLIB_H
2054 # ifdef ENABLE_VISUALIZER
2055 // visualizer sets timmeout to 40ms, but since only it needs such small
2056 // value, we should restore defalt one after switching to another screen.
2057 if (wFooter->GetTimeout() < ncmpcpp_window_timeout && myScreen != myVisualizer)
2058 wFooter->SetTimeout(ncmpcpp_window_timeout);
2059 # endif // ENABLE_VISUALIZER
2061 return 0;