From 8f065e2da35d152466be23a49054c4389b181ddf Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Wed, 12 Sep 2012 02:41:21 +0200 Subject: [PATCH] status: split NcmpcppStatusChanged into smaller pieces --- src/Makefile.am | 2 + src/actions.cpp | 49 ++- src/browser.cpp | 11 +- src/clock.cpp | 3 +- src/global.cpp | 2 - src/global.h | 3 - src/help.cpp | 3 +- src/lastfm.cpp | 3 +- src/lyrics.cpp | 5 +- src/media_library.cpp | 3 +- src/ncmpcpp.cpp | 13 +- src/outputs.cpp | 3 +- src/playlist.cpp | 3 +- src/playlist_editor.cpp | 3 +- src/search_engine.cpp | 3 +- src/song_info.cpp | 3 +- src/status.cpp | 885 ++++++++++++++++++++-------------------- src/status.h | 36 +- src/statusbar.cpp | 4 +- src/tag_editor.cpp | 5 +- src/tiny_tag_editor.cpp | 3 +- src/title.cpp | 65 +++ src/title.h | 30 ++ src/visualizer.cpp | 3 +- 24 files changed, 633 insertions(+), 510 deletions(-) create mode 100644 src/title.cpp create mode 100644 src/title.h diff --git a/src/Makefile.am b/src/Makefile.am index bfeb0479..1e5754f6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,6 +41,7 @@ ncmpcpp_SOURCES = \ statusbar.cpp \ tag_editor.cpp \ tiny_tag_editor.cpp \ + title.cpp \ visualizer.cpp \ window.cpp @@ -94,5 +95,6 @@ noinst_HEADERS = \ statusbar.h \ tag_editor.h \ tiny_tag_editor.h \ + title.h \ visualizer.h \ window.h diff --git a/src/actions.cpp b/src/actions.cpp index 03c778b7..24d6f567 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -53,6 +53,7 @@ #include "tag_editor.h" #include "tiny_tag_editor.h" #include "visualizer.h" +#include "title.h" #ifdef HAVE_TAGLIB_H # include "fileref.h" @@ -129,7 +130,6 @@ void Action::SetResizeFlags() void Action::ResizeScreen() { using Global::MainHeight; - using Global::RedrawStatusbar; using Global::wHeader; using Global::wFooter; @@ -174,27 +174,24 @@ void Action::ResizeScreen() wFooter->resize(COLS, Config.statusbar_visibility ? 2 : 1); ApplyToVisibleWindows(&BasicScreen::Refresh); - RedrawStatusbar = true; - MPD::StatusChanges changes; + + Status::Changes::elapsedTime(); if (!Mpd.isPlaying() || DesignChanged) { - changes.PlayerState = 1; + Status::Changes::playerState(); if (DesignChanged) - changes.Volume = 1; + Status::Changes::mixer(); } // Note: routines for drawing separator if alternative user // interface is active and header is hidden are placed in // NcmpcppStatusChanges.StatusFlags - changes.StatusFlags = 1; // force status update - NcmpcppStatusChanged(&Mpd, changes, 0); + Status::Changes::flags(); if (DesignChanged) { - RedrawStatusbar = true; - NcmpcppStatusChanged(&Mpd, MPD::StatusChanges(), 0); - DesignChanged = 0; + DesignChanged = false; Statusbar::msg("User interface: %s", Config.new_design ? "Alternative" : "Classic"); } - DrawHeader(); + drawHeader(); wFooter->refresh(); refresh(); } @@ -245,7 +242,7 @@ void Action::Seek() SeekingInProgress = true; while (true) { - TraceMpdStatus(); + Status::trace(); myPlaylist->UpdateTimer(); int howmuch = Config.incremental_seeking ? (Timer.tv_sec-t.tv_sec)/2+Config.seek_time : Config.seek_time; @@ -742,7 +739,7 @@ void MasterScreen::Run() myInactiveScreen = myScreen; myScreen = myLockedScreen; - DrawHeader(); + drawHeader(); } bool SlaveScreen::canBeRun() const @@ -763,7 +760,7 @@ void SlaveScreen::Run() myScreen = myInactiveScreen; myInactiveScreen = myLockedScreen; - DrawHeader(); + drawHeader(); } void VolumeUp::Run() @@ -804,7 +801,7 @@ void Delete::Run() question += ToString(wideShorten(ToWString(name), COLS-question.size()-10)); question += "\"?"; } - bool yes = AskYesNoQuestion(question, TraceMpdStatus); + bool yes = AskYesNoQuestion(question, Status::trace); if (yes) { bool success = true; @@ -849,7 +846,7 @@ void Delete::Run() question += ToString(wideShorten(ToWString(myPlaylistEditor->Playlists->current().value()), COLS-question.size()-10)); question += "\"?"; } - bool yes = AskYesNoQuestion(question, TraceMpdStatus); + bool yes = AskYesNoQuestion(question, Status::trace); if (yes) { auto list = getSelectedOrCurrent(myPlaylistEditor->Playlists->begin(), myPlaylistEditor->Playlists->end(), myPlaylistEditor->Playlists->currentI()); @@ -929,7 +926,7 @@ void SavePlaylist::Run() } else if (result == MPD_SERVER_ERROR_EXIST) { - bool yes = AskYesNoQuestion("Playlist \"" + playlist_name + "\" already exists, overwrite?", TraceMpdStatus); + bool yes = AskYesNoQuestion("Playlist \"" + playlist_name + "\" already exists, overwrite?", Status::trace); if (yes) { Mpd.DeletePlaylist(playlist_name); @@ -1232,7 +1229,7 @@ void JumpToPlayingSong::Run() else if (myScreen == myBrowser) { myBrowser->LocateSong(myPlaylist->nowPlayingSong()); - DrawHeader(); + drawHeader(); } else if (myScreen == myLibrary) { @@ -1782,7 +1779,7 @@ void CropMainPlaylist::Run() { bool yes = true; if (Config.ask_before_clearing_main_playlist) - yes = AskYesNoQuestion("Do you really want to crop main playlist?", TraceMpdStatus); + yes = AskYesNoQuestion("Do you really want to crop main playlist?", Status::trace); if (yes) { Statusbar::msg("Cropping playlist..."); @@ -1802,7 +1799,7 @@ void CropPlaylist::Run() std::string playlist = myPlaylistEditor->Playlists->current().value(); bool yes = true; if (Config.ask_before_clearing_main_playlist) - yes = AskYesNoQuestion("Do you really want to crop playlist \"" + playlist + "\"?", TraceMpdStatus); + yes = AskYesNoQuestion("Do you really want to crop playlist \"" + playlist + "\"?", Status::trace); if (yes) { auto delete_fun = std::bind(&MPD::Connection::PlaylistDelete, _1, playlist, _2); @@ -1816,7 +1813,7 @@ void ClearMainPlaylist::Run() { bool yes = true; if (Config.ask_before_clearing_main_playlist) - yes = AskYesNoQuestion("Do you really want to clear main playlist?", TraceMpdStatus); + yes = AskYesNoQuestion("Do you really want to clear main playlist?", Status::trace); if (yes) { auto delete_fun = std::bind(&MPD::Connection::Delete, _1, _2); @@ -1838,7 +1835,7 @@ void ClearPlaylist::Run() std::string playlist = myPlaylistEditor->Playlists->current().value(); bool yes = true; if (Config.ask_before_clearing_main_playlist) - yes = AskYesNoQuestion("Do you really want to clear playlist \"" + playlist + "\"?", TraceMpdStatus); + yes = AskYesNoQuestion("Do you really want to clear playlist \"" + playlist + "\"?", Status::trace); if (yes) { auto delete_fun = std::bind(&MPD::Connection::PlaylistDelete, _1, playlist, _2); @@ -1902,7 +1899,7 @@ void ApplyFilter::Run() { myPlaylist->EnableHighlighting(); Playlist::ReloadTotalLength = true; - DrawHeader(); + drawHeader(); } ListsChangeFinisher(); } @@ -2007,7 +2004,7 @@ void ToggleReplayGainMode::Run() int answer = 0; do { - TraceMpdStatus(); + Status::trace(); answer = wFooter->readKey(); } while (answer != 'o' && answer != 't' && answer != 'a'); @@ -2051,7 +2048,7 @@ void AddRandomItems::Run() int answer = 0; do { - TraceMpdStatus(); + Status::trace(); answer = wFooter->readKey(); } while (answer != 's' && answer != 'a' && answer != 'b'); @@ -2121,7 +2118,7 @@ void ToggleLibraryTagType::Run() int answer = 0; do { - TraceMpdStatus(); + Status::trace(); answer = wFooter->readKey(); } while (answer != 'a' && answer != 'A' && answer != 'y' && answer != 'g' && answer != 'c' && answer != 'p'); diff --git a/src/browser.cpp b/src/browser.cpp index cacc30d8..8d3fa390 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -36,6 +36,7 @@ #include "statusbar.h" #include "tag_editor.h" #include "utility/comparators.h" +#include "title.h" using namespace std::placeholders; @@ -117,7 +118,7 @@ void Browser::SwitchTo() if (myScreen != this && myScreen->isTabbable()) Global::myPrevScreen = myScreen; myScreen = this; - DrawHeader(); + drawHeader(); } std::wstring Browser::Title() @@ -141,7 +142,7 @@ void Browser::EnterPressed() GetDirectory(getParentDirectory(itsBrowsedDir), itsBrowsedDir); else GetDirectory(item.name, itsBrowsedDir); - DrawHeader(); + drawHeader(); break; } case itSong: @@ -231,7 +232,7 @@ void Browser::MouseButtonPressed(MEVENT me) if (me.bstate & BUTTON1_PRESSED) { GetDirectory(w->current().value().name); - DrawHeader(); + drawHeader(); } else { @@ -383,7 +384,7 @@ void Browser::LocateSong(const MPD::Song &s) break; } } - DrawHeader(); + drawHeader(); } void Browser::GetDirectory(std::string dir, std::string subdir) @@ -568,7 +569,7 @@ void Browser::ChangeBrowseMode() itsBrowsedDir.resize(itsBrowsedDir.length()-1); w->reset(); GetDirectory(itsBrowsedDir); - DrawHeader(); + drawHeader(); } bool Browser::deleteItem(const MPD::Item &item) diff --git a/src/clock.cpp b/src/clock.cpp index 38490e54..73dd32c9 100644 --- a/src/clock.cpp +++ b/src/clock.cpp @@ -32,6 +32,7 @@ #include "settings.h" #include "status.h" #include "statusbar.h" +#include "title.h" using Global::MainHeight; using Global::MainStartY; @@ -103,7 +104,7 @@ void Clock::SwitchTo() if (myScreen != this && myScreen->isTabbable()) Global::myPrevScreen = myScreen; myScreen = this; - DrawHeader(); + drawHeader(); Prepare(); itsPane->refresh(); // clearing screen apparently fixes the problem with last digits being misrendered diff --git a/src/global.cpp b/src/global.cpp index ef2481a4..cbeff616 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -35,7 +35,5 @@ size_t Global::MainHeight; bool Global::ShowMessages = false; bool Global::SeekingInProgress = false; -bool Global::RedrawStatusbar = true; - std::string Global::VolumeState; timeval Global::Timer; diff --git a/src/global.h b/src/global.h index 493d3373..faf5551d 100644 --- a/src/global.h +++ b/src/global.h @@ -61,9 +61,6 @@ namespace Global // indicates whether seeking action in currently in progress extern bool SeekingInProgress; - // indicates whether statusbar should be immediately repainted - extern bool RedrawStatusbar; - // string that represents volume in right top corner. being global // to be used for calculating width offsets in various files. extern std::string VolumeState; diff --git a/src/help.cpp b/src/help.cpp index 2fc520d4..078034c8 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -26,6 +26,7 @@ #include "settings.h" #include "status.h" #include "utility/wide_string.h" +#include "title.h" using Global::MainHeight; using Global::MainStartY; @@ -131,7 +132,7 @@ void Help::SwitchTo() if (myScreen != this && myScreen->isTabbable()) Global::myPrevScreen = myScreen; myScreen = this; - DrawHeader(); + drawHeader(); } std::wstring Help::Title() diff --git a/src/lastfm.cpp b/src/lastfm.cpp index 08790827..5d2437c3 100644 --- a/src/lastfm.cpp +++ b/src/lastfm.cpp @@ -38,6 +38,7 @@ #include "charset.h" #include "global.h" #include "statusbar.h" +#include "title.h" using Global::MainHeight; using Global::MainStartY; @@ -106,7 +107,7 @@ void Lastfm::SwitchTo() myOldScreen = myScreen; myScreen = this; - DrawHeader(); + drawHeader(); } void Lastfm::Load() diff --git a/src/lyrics.cpp b/src/lyrics.cpp index 5eee0bcd..e71282b9 100644 --- a/src/lyrics.cpp +++ b/src/lyrics.cpp @@ -34,6 +34,7 @@ #include "settings.h" #include "song.h" #include "statusbar.h" +#include "title.h" using Global::MainHeight; using Global::MainStartY; @@ -81,7 +82,7 @@ void Lyrics::Update() const MPD::Song s = myPlaylist->nowPlayingSong(); if (!s.empty() && !s.getArtist().empty() && !s.getTitle().empty()) { - DrawHeader(); + drawHeader(); itsScrollBegin = 0; itsSong = s; Load(); @@ -130,7 +131,7 @@ void Lyrics::SwitchTo() itsSong = *s; Load(); - DrawHeader(); + drawHeader(); } else { diff --git a/src/media_library.cpp b/src/media_library.cpp index c2e21593..3a664d2c 100644 --- a/src/media_library.cpp +++ b/src/media_library.cpp @@ -34,6 +34,7 @@ #include "statusbar.h" #include "utility/comparators.h" #include "utility/type_conversions.h" +#include "title.h" using namespace std::placeholders; @@ -238,7 +239,7 @@ void MediaLibrary::SwitchTo() if (myScreen != this && myScreen->isTabbable()) Global::myPrevScreen = myScreen; myScreen = this; - DrawHeader(); + drawHeader(); markSongsInPlaylist(songsProxyList()); Refresh(); } diff --git a/src/ncmpcpp.cpp b/src/ncmpcpp.cpp index 5c672698..1fb18145 100644 --- a/src/ncmpcpp.cpp +++ b/src/ncmpcpp.cpp @@ -42,6 +42,7 @@ #include "status.h" #include "statusbar.h" #include "visualizer.h" +#include "title.h" namespace { @@ -71,7 +72,7 @@ namespace # ifndef USE_PDCURSES // destroying screen somehow crashes pdcurses NC::destroyScreen(); # endif // USE_PDCURSES - WindowTitle(""); + windowTitle(""); } } @@ -179,8 +180,8 @@ int main(int argc, char **argv) if (Config.startup_screen != myScreen) Config.startup_screen->SwitchTo(); - Mpd.SetStatusUpdater(NcmpcppStatusChanged, 0); - Mpd.SetErrorHandler(NcmpcppErrorCallback, 0); + Mpd.SetStatusUpdater(Status::update, 0); + Mpd.SetErrorHandler(Status::handleError, 0); // local variables Key input(0, Key::Standard); @@ -199,7 +200,7 @@ int main(int argc, char **argv) Mpd.OrderDataFetching(); if (Config.jump_to_now_playing_song_at_start) { - TraceMpdStatus(); + Status::trace(); int curr_pos = Mpd.GetCurrentSongPos(); if (curr_pos >= 0) myPlaylist->Items->highlight(curr_pos); @@ -230,7 +231,7 @@ int main(int argc, char **argv) } } - TraceMpdStatus(); + Status::trace(); ShowMessages = true; @@ -242,7 +243,7 @@ int main(int argc, char **argv) && (myScreen == myPlaylist || myScreen == myBrowser || myScreen == myLyrics) ) { - DrawHeader(); + drawHeader(); past = Timer; } diff --git a/src/outputs.cpp b/src/outputs.cpp index 2b0c7942..98a7bd0e 100644 --- a/src/outputs.cpp +++ b/src/outputs.cpp @@ -27,6 +27,7 @@ #include "settings.h" #include "status.h" #include "statusbar.h" +#include "title.h" using Global::MainHeight; using Global::MainStartY; @@ -66,7 +67,7 @@ void Outputs::SwitchTo() Global::myPrevScreen = myScreen; myScreen = this; w->Window::clear(); - DrawHeader(); + drawHeader(); } void Outputs::Resize() diff --git a/src/playlist.cpp b/src/playlist.cpp index e3eb2253..71f72d71 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -31,6 +31,7 @@ #include "status.h" #include "statusbar.h" #include "utility/comparators.h" +#include "title.h" using namespace std::placeholders; @@ -122,7 +123,7 @@ void Playlist::SwitchTo() EnableHighlighting(); if (w != Items) // even if sorting window is active, background has to be refreshed anyway Items->display(); - DrawHeader(); + drawHeader(); } void Playlist::Resize() diff --git a/src/playlist_editor.cpp b/src/playlist_editor.cpp index 66204406..0ab0ae06 100644 --- a/src/playlist_editor.cpp +++ b/src/playlist_editor.cpp @@ -33,6 +33,7 @@ #include "statusbar.h" #include "tag_editor.h" #include "utility/comparators.h" +#include "title.h" using namespace std::placeholders; @@ -134,7 +135,7 @@ void PlaylistEditor::SwitchTo() if (myScreen != this && myScreen->isTabbable()) Global::myPrevScreen = myScreen; myScreen = this; - DrawHeader(); + drawHeader(); markSongsInPlaylist(contentProxyList()); Refresh(); } diff --git a/src/search_engine.cpp b/src/search_engine.cpp index a0f9b99f..1a254078 100644 --- a/src/search_engine.cpp +++ b/src/search_engine.cpp @@ -31,6 +31,7 @@ #include "status.h" #include "statusbar.h" #include "utility/comparators.h" +#include "title.h" using namespace std::placeholders; @@ -149,7 +150,7 @@ void SearchEngine::SwitchTo() if (myScreen != this && myScreen->isTabbable()) Global::myPrevScreen = myScreen; myScreen = this; - DrawHeader(); + drawHeader(); markSongsInPlaylist(getProxySongList()); } diff --git a/src/song_info.cpp b/src/song_info.cpp index d4d2411c..0978972f 100644 --- a/src/song_info.cpp +++ b/src/song_info.cpp @@ -22,6 +22,7 @@ #include "helpers.h" #include "song_info.h" #include "tag_editor.h" +#include "title.h" #ifdef HAVE_TAGLIB_H # include "fileref.h" @@ -102,7 +103,7 @@ void SongInfo::SwitchTo() // redraw header after we're done with the file, since reading it from disk // takes a bit of time and having header updated before content of a window // is displayed doesn't look nice. - DrawHeader(); + drawHeader(); } void SongInfo::PrepareSong(MPD::Song &s) diff --git a/src/status.cpp b/src/status.cpp index f9624399..5b68a268 100644 --- a/src/status.cpp +++ b/src/status.cpp @@ -18,12 +18,8 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#include #include -#include -#include - #include "browser.h" #include "charset.h" #include "global.h" @@ -40,10 +36,9 @@ #include "statusbar.h" #include "tag_editor.h" #include "visualizer.h" +#include "title.h" using Global::myScreen; -using Global::myLockedScreen; -using Global::myInactiveScreen; using Global::wFooter; using Global::wHeader; @@ -51,26 +46,32 @@ using Global::wHeader; using Global::Timer; using Global::VolumeState; -#ifndef USE_PDCURSES -void WindowTitle(const std::string &status) -{ - if (strcmp(getenv("TERM"), "linux") && Config.set_window_title) - std::cout << "\033]0;" << status << "\7"; -} -#endif // !USE_PDCURSES +namespace {// -void DrawNowPlayingTitle(MPD::Song &np) +timeval past = { 0, 0 }; + +size_t playing_song_scroll_begin = 0; +size_t first_line_scroll_begin = 0; +size_t second_line_scroll_begin = 0; +std::string player_state; + +char mpd_repeat; +char mpd_random; +char mpd_single; +char mpd_consume; +char mpd_crossfade; +char mpd_db_updating; + +void drawTitle(const MPD::Song &np) { - if (np.empty()) - np = myPlaylist->nowPlayingSong(); - if (!np.empty()) - WindowTitle(np.toString(Config.song_window_title_format)); + assert(!np.empty()); + windowTitle(np.toString(Config.song_window_title_format)); } -void TraceMpdStatus() +} + +void Status::trace() { - static timeval past = { 0, 0 }; - gettimeofday(&Timer, 0); if (Mpd.Connected() && (Mpd.SupportsIdle() || Timer.tv_sec > past.tv_sec)) { @@ -103,7 +104,7 @@ void TraceMpdStatus() Statusbar::tryRedraw(); } -void NcmpcppErrorCallback(MPD::Connection *, int errorid, const char *msg, void *) +void Status::handleError(MPD::Connection * , int errorid, const char *msg, void *) { // for errorid: // - 0-7 bits define MPD_ERROR_* codes, compare them with (0xff & errorid) @@ -126,441 +127,443 @@ void NcmpcppErrorCallback(MPD::Connection *, int errorid, const char *msg, void Statusbar::msg("MPD: %s", msg); } -void NcmpcppStatusChanged(MPD::Connection *, MPD::StatusChanges changed, void *) +void Status::Changes::playlist() { - static size_t playing_song_scroll_begin = 0; - static size_t first_line_scroll_begin = 0; - static size_t second_line_scroll_begin = 0; - static std::string player_state; - - MPD::Song np; - - int sx = wFooter->getX(); - int sy = wFooter->getY(); - - if (changed.Playlist) - { - myPlaylist->Items->clearSearchResults(); - withUnfilteredMenuReapplyFilter(*myPlaylist->Items, []() { - size_t playlist_length = Mpd.GetPlaylistLength(); - if (playlist_length < myPlaylist->Items->size()) - { - auto it = myPlaylist->Items->begin()+playlist_length; - auto end = myPlaylist->Items->end(); - for (; it != end; ++it) - myPlaylist->unregisterHash(it->value().getHash()); - myPlaylist->Items->resizeList(playlist_length); - } - - auto songs = Mpd.GetPlaylistChanges(Mpd.GetOldPlaylistID()); - for (auto s = songs.begin(); s != songs.end(); ++s) - { - size_t pos = s->getPosition(); - if (pos < myPlaylist->Items->size()) - { - // if song's already in playlist, replace it with a new one - MPD::Song &old_s = (*myPlaylist->Items)[pos].value(); - myPlaylist->unregisterHash(old_s.getHash()); - old_s = *s; - } - else // otherwise just add it to playlist - myPlaylist->Items->addItem(*s); - myPlaylist->registerHash(s->getHash()); - } - }); + myPlaylist->Items->clearSearchResults(); + withUnfilteredMenuReapplyFilter(*myPlaylist->Items, []() { + size_t playlist_length = Mpd.GetPlaylistLength(); + if (playlist_length < myPlaylist->Items->size()) + { + auto it = myPlaylist->Items->begin()+playlist_length; + auto end = myPlaylist->Items->end(); + for (; it != end; ++it) + myPlaylist->unregisterHash(it->value().getHash()); + myPlaylist->Items->resizeList(playlist_length); + } - DrawNowPlayingTitle(np); - - Playlist::ReloadTotalLength = true; - Playlist::ReloadRemaining = true; - - if (isVisible(myBrowser)) - markSongsInPlaylist(myBrowser->getProxySongList()); - if (isVisible(mySearcher)) - markSongsInPlaylist(mySearcher->getProxySongList()); - if (isVisible(myLibrary)) - markSongsInPlaylist(myLibrary->songsProxyList()); - if (isVisible(myPlaylistEditor)) - markSongsInPlaylist(myPlaylistEditor->contentProxyList()); - } - if (changed.StoredPlaylists) - { - if (myPlaylistEditor->Main()) + auto songs = Mpd.GetPlaylistChanges(Mpd.GetOldPlaylistID()); + for (auto s = songs.begin(); s != songs.end(); ++s) { - myPlaylistEditor->requestPlaylistsUpdate(); - myPlaylistEditor->requestContentsUpdate(); - } - if (myBrowser->Main() && myBrowser->CurrentDir() == "/") - { - myBrowser->GetDirectory("/"); - if (isVisible(myBrowser)) - myBrowser->Refresh(); - } - } - if (changed.Database) - { - if (myBrowser->Main()) - { - if (isVisible(myBrowser)) - myBrowser->GetDirectory(myBrowser->CurrentDir()); - else - myBrowser->Main()->clear(); - } -# ifdef HAVE_TAGLIB_H - if (myTagEditor->Main()) - { - myTagEditor->Dirs->clear(); - } -# endif // HAVE_TAGLIB_H - if (myLibrary->Main()) - { - if (myLibrary->Columns() == 2) - myLibrary->Albums->clear(); - else - myLibrary->Tags->clear(); - } - changed.DBUpdating = 1; - } - if (changed.PlayerState) - { - MPD::PlayerState state = Mpd.GetState(); - switch (state) - { - case MPD::psUnknown: + size_t pos = s->getPosition(); + if (pos < myPlaylist->Items->size()) { - player_state = "[unknown]"; - break; - } - case MPD::psPlay: - { - DrawNowPlayingTitle(np); - player_state = Config.new_design ? "[playing]" : "Playing: "; - Playlist::ReloadRemaining = true; - if (Mpd.GetOldState() == MPD::psStop) // show track info in status immediately - changed.ElapsedTime = 1; - break; - } - case MPD::psPause: - { - player_state = Config.new_design ? "[paused] " : "[Paused] "; - break; - } - case MPD::psStop: - { - WindowTitle("ncmpcpp " VERSION); - if (Progressbar::isUnlocked()) - Progressbar::draw(0, 0); - Playlist::ReloadRemaining = true; - if (Config.new_design) - { - *wHeader << NC::XY(0, 0) << wclrtoeol << NC::XY(0, 1) << wclrtoeol; - player_state = "[stopped]"; - changed.Volume = 1; - changed.StatusFlags = 1; - } - else - player_state.clear(); -# ifdef ENABLE_VISUALIZER - if (isVisible(myVisualizer)) - myVisualizer->Main()->clear(); -# endif // ENABLE_VISUALIZER - break; + // if song's already in playlist, replace it with a new one + MPD::Song &old_s = (*myPlaylist->Items)[pos].value(); + myPlaylist->unregisterHash(old_s.getHash()); + old_s = *s; } + else // otherwise just add it to playlist + myPlaylist->Items->addItem(*s); + myPlaylist->registerHash(s->getHash()); } -# ifdef ENABLE_VISUALIZER - if (myScreen == myVisualizer) - wFooter->setTimeout(state == MPD::psPlay ? Visualizer::WindowTimeout : 500); -# endif // ENABLE_VISUALIZER - if (Config.new_design) - { - *wHeader << NC::XY(0, 1) << NC::fmtBold << player_state << NC::fmtBoldEnd; - wHeader->refresh(); - } - else if (Statusbar::isUnlocked() && Config.statusbar_visibility) - { - *wFooter << NC::XY(0, 1); - if (player_state.empty()) - *wFooter << wclrtoeol; - else - *wFooter << NC::fmtBold << player_state << NC::fmtBoldEnd; - } - } - if (changed.SongID) - { - if (Mpd.isPlaying()) - { - GNUC_UNUSED int res; - if (!Config.execute_on_song_change.empty()) - res = system(Config.execute_on_song_change.c_str()); - -# ifdef HAVE_CURL_CURL_H - if (Config.fetch_lyrics_in_background) - Lyrics::DownloadInBackground(myPlaylist->nowPlayingSong()); -# endif // HAVE_CURL_CURL_H - - DrawNowPlayingTitle(np); - - if (Config.autocenter_mode && !myPlaylist->Items->isFiltered()) - myPlaylist->Items->highlight(Mpd.GetCurrentlyPlayingSongPos()); - - if (Config.now_playing_lyrics && isVisible(myLyrics) && Global::myOldScreen == myPlaylist) - myLyrics->ReloadNP = 1; - } - Playlist::ReloadRemaining = true; - playing_song_scroll_begin = 0; - first_line_scroll_begin = 0; - second_line_scroll_begin = 0; - } - if (changed.ElapsedTime || changed.SongID || Global::RedrawStatusbar) - { - if (Mpd.isPlaying()) - { - DrawNowPlayingTitle(np); - - std::string tracklength; - if (Config.new_design) - { - if (Config.display_remaining_time) - { - tracklength = "-"; - tracklength += MPD::Song::ShowTime(Mpd.GetTotalTime()-Mpd.GetElapsedTime()); - } - else - tracklength = MPD::Song::ShowTime(Mpd.GetElapsedTime()); - if (Mpd.GetTotalTime()) - { - tracklength += "/"; - tracklength += MPD::Song::ShowTime(Mpd.GetTotalTime()); - } - // bitrate here doesn't look good, but it can be moved somewhere else later - if (Config.display_bitrate && Mpd.GetBitrate()) - { - tracklength += " "; - tracklength += intTo::apply(Mpd.GetBitrate()); - tracklength += " kbps"; - } - - NC::WBuffer first, second; - String2Buffer(ToWString(IConv::utf8ToLocale(np.toString(Config.new_header_first_line, "$"))), first); - String2Buffer(ToWString(IConv::utf8ToLocale(np.toString(Config.new_header_second_line, "$"))), second); - - size_t first_len = wideLength(first.str()); - size_t first_margin = (std::max(tracklength.length()+1, VolumeState.length()))*2; - size_t first_start = first_len < COLS-first_margin ? (COLS-first_len)/2 : tracklength.length()+1; - - size_t second_len = wideLength(second.str()); - size_t second_margin = (std::max(player_state.length(), size_t(8))+1)*2; - size_t second_start = second_len < COLS-second_margin ? (COLS-second_len)/2 : player_state.length()+1; - - if (!Global::SeekingInProgress) - *wHeader << NC::XY(0, 0) << wclrtoeol << tracklength; - *wHeader << NC::XY(first_start, 0); - first.write(*wHeader, first_line_scroll_begin, COLS-tracklength.length()-VolumeState.length()-1, L" ** "); - - *wHeader << NC::XY(0, 1) << wclrtoeol << NC::fmtBold << player_state << NC::fmtBoldEnd; - *wHeader << NC::XY(second_start, 1); - second.write(*wHeader, second_line_scroll_begin, COLS-player_state.length()-8-2, L" ** "); - - *wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << Config.volume_color << VolumeState << NC::clEnd; - - changed.StatusFlags = 1; - } - else if (Statusbar::isUnlocked() && Config.statusbar_visibility) - { - if (Config.display_bitrate && Mpd.GetBitrate()) - { - tracklength += " ["; - tracklength += intTo::apply(Mpd.GetBitrate()); - tracklength += " kbps]"; - } - tracklength += " ["; - if (Mpd.GetTotalTime()) - { - if (Config.display_remaining_time) - { - tracklength += "-"; - tracklength += MPD::Song::ShowTime(Mpd.GetTotalTime()-Mpd.GetElapsedTime()); - } - else - tracklength += MPD::Song::ShowTime(Mpd.GetElapsedTime()); - tracklength += "/"; - tracklength += MPD::Song::ShowTime(Mpd.GetTotalTime()); - tracklength += "]"; - } - else - { - tracklength += MPD::Song::ShowTime(Mpd.GetElapsedTime()); - tracklength += "]"; - } - NC::WBuffer np_song; - String2Buffer(ToWString(IConv::utf8ToLocale(np.toString(Config.song_status_format, "$"))), np_song); - *wFooter << NC::XY(0, 1) << wclrtoeol << NC::fmtBold << player_state << NC::fmtBoldEnd; - np_song.write(*wFooter, playing_song_scroll_begin, wFooter->getWidth()-player_state.length()-tracklength.length(), L" ** "); - *wFooter << NC::fmtBold << NC::XY(wFooter->getWidth()-tracklength.length(), 1) << tracklength << NC::fmtBoldEnd; - } - if (Progressbar::isUnlocked()) - Progressbar::draw(Mpd.GetElapsedTime(), Mpd.GetTotalTime()); - Global::RedrawStatusbar = false; - } - else - { - if (Statusbar::isUnlocked() && Config.statusbar_visibility) - *wFooter << NC::XY(0, 1) << wclrtoeol; - } - } + }); - static char mpd_repeat; - static char mpd_random; - static char mpd_single; - static char mpd_consume; - static char mpd_crossfade; - static char mpd_db_updating; + if (Mpd.isPlaying()) + drawTitle(myPlaylist->nowPlayingSong()); - if (changed.Repeat) - { - mpd_repeat = Mpd.GetRepeat() ? 'r' : 0; - Statusbar::msg("Repeat mode is %s", !mpd_repeat ? "off" : "on"); - } - if (changed.Random) - { - mpd_random = Mpd.GetRandom() ? 'z' : 0; - Statusbar::msg("Random mode is %s", !mpd_random ? "off" : "on"); - } - if (changed.Single) - { - mpd_single = Mpd.GetSingle() ? 's' : 0; - Statusbar::msg("Single mode is %s", !mpd_single ? "off" : "on"); - } - if (changed.Consume) - { - mpd_consume = Mpd.GetConsume() ? 'c' : 0; - Statusbar::msg("Consume mode is %s", !mpd_consume ? "off" : "on"); - } - if (changed.Crossfade) - { - int crossfade = Mpd.GetCrossfade(); - mpd_crossfade = crossfade ? 'x' : 0; - Statusbar::msg("Crossfade set to %d seconds", crossfade); - } - if (changed.DBUpdating) - { - // mpd-0.{14,15} doesn't support idle notification that dbupdate had - // finished and nothing changed, so we need to switch it off for them. - if (!Mpd.SupportsIdle() || Mpd.Version() > 15) - mpd_db_updating = Mpd.GetDBIsUpdating() ? 'U' : 0; - Statusbar::msg(Mpd.GetDBIsUpdating() ? "Database update started" : "Database update finished"); - if (changed.Database && myScreen == mySelectedItemsAdder) - { - myScreen->SwitchTo(); // switch to previous screen - Statusbar::msg("Database has changed, you need to select your item(s) once again"); - } - } - if (changed.StatusFlags && (Config.header_visibility || Config.new_design)) - { - std::string switch_state; - - if (Config.new_design) - { - switch_state += '['; - switch_state += mpd_repeat ? mpd_repeat : '-'; - switch_state += mpd_random ? mpd_random : '-'; - switch_state += mpd_single ? mpd_single : '-'; - switch_state += mpd_consume ? mpd_consume : '-'; - switch_state += mpd_crossfade ? mpd_crossfade : '-'; - switch_state += mpd_db_updating ? mpd_db_updating : '-'; - switch_state += ']'; - *wHeader << NC::XY(COLS-switch_state.length(), 1) << NC::fmtBold << Config.state_flags_color << switch_state << NC::clEnd << NC::fmtBoldEnd; - if (Config.new_design && !Config.header_visibility) // in this case also draw separator - { - *wHeader << NC::fmtBold << NC::clBlack; - mvwhline(wHeader->raw(), 2, 0, 0, COLS); - *wHeader << NC::clEnd << NC::fmtBoldEnd; - } - wHeader->refresh(); - } - else - { - if (mpd_repeat) - switch_state += mpd_repeat; - if (mpd_random) - switch_state += mpd_random; - if (mpd_single) - switch_state += mpd_single; - if (mpd_consume) - switch_state += mpd_consume; - if (mpd_crossfade) - switch_state += mpd_crossfade; - if (mpd_db_updating) - switch_state += mpd_db_updating; - - // this is done by raw ncurses because creating another - // window only for handling this is quite silly - attrset(A_BOLD|COLOR_PAIR(Config.state_line_color)); - mvhline(1, 0, 0, COLS); - if (!switch_state.empty()) - { - mvprintw(1, COLS-switch_state.length()-3, "["); - attroff(COLOR_PAIR(Config.state_line_color)); - attron(COLOR_PAIR(Config.state_flags_color)); - mvprintw(1, COLS-switch_state.length()-2, "%s", switch_state.c_str()); - attroff(COLOR_PAIR(Config.state_flags_color)); - attron(COLOR_PAIR(Config.state_line_color)); - mvprintw(1, COLS-2, "]"); - } - attroff(A_BOLD|COLOR_PAIR(Config.state_line_color)); - refresh(); - } - } - if (changed.Volume && Config.display_volume_level && (Config.header_visibility || Config.new_design)) - { - VolumeState = Config.new_design ? " Vol: " : " Volume: "; - int volume = Mpd.GetVolume(); - if (volume < 0) - VolumeState += "n/a"; - else - { - VolumeState += intTo::apply(volume); - VolumeState += "%"; - } - *wHeader << Config.volume_color; - *wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << VolumeState; - *wHeader << NC::clEnd; - wHeader->refresh(); - } - if (changed.Outputs) - { -# ifdef ENABLE_OUTPUTS - myOutputs->FetchList(); -# endif // ENABLE_OUTPUTS - } - wFooter->goToXY(sx, sy); - if (changed.PlayerState || (changed.ElapsedTime && (!Config.new_design || Mpd.GetState() == MPD::psPlay))) - wFooter->refresh(); - if (changed.Playlist || changed.Database || changed.PlayerState || changed.SongID) - ApplyToVisibleWindows(&BasicScreen::RefreshWindow); + Playlist::ReloadTotalLength = true; + Playlist::ReloadRemaining = true; + + if (isVisible(myBrowser)) + markSongsInPlaylist(myBrowser->getProxySongList()); + if (isVisible(mySearcher)) + markSongsInPlaylist(mySearcher->getProxySongList()); + if (isVisible(myLibrary)) + markSongsInPlaylist(myLibrary->songsProxyList()); + if (isVisible(myPlaylistEditor)) + markSongsInPlaylist(myPlaylistEditor->contentProxyList()); } -void DrawHeader() +void Status::Changes::storedPlaylists() { - if (!Config.header_visibility) - return; + if (myPlaylistEditor->Main()) + { + myPlaylistEditor->requestPlaylistsUpdate(); + myPlaylistEditor->requestContentsUpdate(); + } + if (myBrowser->Main() && myBrowser->CurrentDir() == "/") + { + myBrowser->GetDirectory("/"); + if (isVisible(myBrowser)) + myBrowser->Refresh(); + } +} + +void Status::Changes::database() +{ + if (myBrowser->Main()) + { + if (isVisible(myBrowser)) + myBrowser->GetDirectory(myBrowser->CurrentDir()); + else + myBrowser->Main()->clear(); + } +# ifdef HAVE_TAGLIB_H + if (myTagEditor->Main()) + { + myTagEditor->Dirs->clear(); + } +# endif // HAVE_TAGLIB_H + if (myLibrary->Main()) + { + if (myLibrary->Columns() == 2) + myLibrary->Albums->clear(); + else + myLibrary->Tags->clear(); + } +} + +void Status::Changes::playerState() +{ + MPD::PlayerState state = Mpd.GetState(); + switch (state) + { + case MPD::psUnknown: + { + player_state = "[unknown]"; + break; + } + case MPD::psPlay: + { + drawTitle(myPlaylist->nowPlayingSong()); + player_state = Config.new_design ? "[playing]" : "Playing: "; + Playlist::ReloadRemaining = true; + if (Mpd.GetOldState() == MPD::psStop) // show track info in status immediately + elapsedTime(); + break; + } + case MPD::psPause: + { + player_state = Config.new_design ? "[paused] " : "[Paused] "; + break; + } + case MPD::psStop: + { + windowTitle("ncmpcpp " VERSION); + if (Progressbar::isUnlocked()) + Progressbar::draw(0, 0); + Playlist::ReloadRemaining = true; + if (Config.new_design) + { + *wHeader << NC::XY(0, 0) << wclrtoeol << NC::XY(0, 1) << wclrtoeol; + player_state = "[stopped]"; + mixer(); + flags(); + } + else + player_state.clear(); +# ifdef ENABLE_VISUALIZER + if (isVisible(myVisualizer)) + myVisualizer->Main()->clear(); +# endif // ENABLE_VISUALIZER + break; + } + } + +# ifdef ENABLE_VISUALIZER + if (myScreen == myVisualizer) + wFooter->setTimeout(state == MPD::psPlay ? Visualizer::WindowTimeout : 500); +# endif // ENABLE_VISUALIZER + if (Config.new_design) { - std::wstring title = myScreen->Title(); - *wHeader << NC::XY(0, 3) << wclrtoeol; - *wHeader << NC::fmtBold << Config.alternative_ui_separator_color; - mvwhline(wHeader->raw(), 2, 0, 0, COLS); - mvwhline(wHeader->raw(), 4, 0, 0, COLS); - *wHeader << NC::XY((COLS-wideLength(title))/2, 3); - *wHeader << Config.header_color << title << NC::clEnd; - *wHeader << NC::clEnd << NC::fmtBoldEnd; + *wHeader << NC::XY(0, 1) << NC::fmtBold << player_state << NC::fmtBoldEnd; + wHeader->refresh(); + } + else if (Statusbar::isUnlocked() && Config.statusbar_visibility) + { + *wFooter << NC::XY(0, 1); + if (player_state.empty()) + *wFooter << wclrtoeol; + else + *wFooter << NC::fmtBold << player_state << NC::fmtBoldEnd; + } +} + +void Status::Changes::songID() +{ + Playlist::ReloadRemaining = true; + playing_song_scroll_begin = 0; + first_line_scroll_begin = 0; + second_line_scroll_begin = 0; + if (Mpd.isPlaying()) + { + GNUC_UNUSED int res; + if (!Config.execute_on_song_change.empty()) + res = system(Config.execute_on_song_change.c_str()); + +# ifdef HAVE_CURL_CURL_H + if (Config.fetch_lyrics_in_background) + Lyrics::DownloadInBackground(myPlaylist->nowPlayingSong()); +# endif // HAVE_CURL_CURL_H + + drawTitle(myPlaylist->nowPlayingSong()); + + if (Config.autocenter_mode && !myPlaylist->Items->isFiltered()) + myPlaylist->Items->highlight(Mpd.GetCurrentlyPlayingSongPos()); + + if (Config.now_playing_lyrics && isVisible(myLyrics) && Global::myOldScreen == myPlaylist) + myLyrics->ReloadNP = 1; + + elapsedTime(); + } +} + +void Status::Changes::elapsedTime() +{ + if (!Mpd.isPlaying()) + { + if (Statusbar::isUnlocked() && Config.statusbar_visibility) + *wFooter << NC::XY(0, 1) << wclrtoeol; + return; + } + + MPD::Song np = myPlaylist->nowPlayingSong(); + drawTitle(np); + + std::string tracklength; + if (Config.new_design) + { + if (Config.display_remaining_time) + { + tracklength = "-"; + tracklength += MPD::Song::ShowTime(Mpd.GetTotalTime()-Mpd.GetElapsedTime()); + } + else + tracklength = MPD::Song::ShowTime(Mpd.GetElapsedTime()); + if (Mpd.GetTotalTime()) + { + tracklength += "/"; + tracklength += MPD::Song::ShowTime(Mpd.GetTotalTime()); + } + // bitrate here doesn't look good, but it can be moved somewhere else later + if (Config.display_bitrate && Mpd.GetBitrate()) + { + tracklength += " "; + tracklength += intTo::apply(Mpd.GetBitrate()); + tracklength += " kbps"; + } + + NC::WBuffer first, second; + String2Buffer(ToWString(IConv::utf8ToLocale(np.toString(Config.new_header_first_line, "$"))), first); + String2Buffer(ToWString(IConv::utf8ToLocale(np.toString(Config.new_header_second_line, "$"))), second); + + size_t first_len = wideLength(first.str()); + size_t first_margin = (std::max(tracklength.length()+1, VolumeState.length()))*2; + size_t first_start = first_len < COLS-first_margin ? (COLS-first_len)/2 : tracklength.length()+1; + + size_t second_len = wideLength(second.str()); + size_t second_margin = (std::max(player_state.length(), size_t(8))+1)*2; + size_t second_start = second_len < COLS-second_margin ? (COLS-second_len)/2 : player_state.length()+1; + + if (!Global::SeekingInProgress) + *wHeader << NC::XY(0, 0) << wclrtoeol << tracklength; + *wHeader << NC::XY(first_start, 0); + first.write(*wHeader, first_line_scroll_begin, COLS-tracklength.length()-VolumeState.length()-1, L" ** "); + + *wHeader << NC::XY(0, 1) << wclrtoeol << NC::fmtBold << player_state << NC::fmtBoldEnd; + *wHeader << NC::XY(second_start, 1); + second.write(*wHeader, second_line_scroll_begin, COLS-player_state.length()-8-2, L" ** "); + + *wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << Config.volume_color << VolumeState << NC::clEnd; + + flags(); + } + else if (Statusbar::isUnlocked() && Config.statusbar_visibility) + { + if (Config.display_bitrate && Mpd.GetBitrate()) + { + tracklength += " ["; + tracklength += intTo::apply(Mpd.GetBitrate()); + tracklength += " kbps]"; + } + tracklength += " ["; + if (Mpd.GetTotalTime()) + { + if (Config.display_remaining_time) + { + tracklength += "-"; + tracklength += MPD::Song::ShowTime(Mpd.GetTotalTime()-Mpd.GetElapsedTime()); + } + else + tracklength += MPD::Song::ShowTime(Mpd.GetElapsedTime()); + tracklength += "/"; + tracklength += MPD::Song::ShowTime(Mpd.GetTotalTime()); + tracklength += "]"; + } + else + { + tracklength += MPD::Song::ShowTime(Mpd.GetElapsedTime()); + tracklength += "]"; + } + NC::WBuffer np_song; + String2Buffer(ToWString(IConv::utf8ToLocale(np.toString(Config.song_status_format, "$"))), np_song); + *wFooter << NC::XY(0, 1) << wclrtoeol << NC::fmtBold << player_state << NC::fmtBoldEnd; + np_song.write(*wFooter, playing_song_scroll_begin, wFooter->getWidth()-player_state.length()-tracklength.length(), L" ** "); + *wFooter << NC::fmtBold << NC::XY(wFooter->getWidth()-tracklength.length(), 1) << tracklength << NC::fmtBoldEnd; + } + if (Progressbar::isUnlocked()) + Progressbar::draw(Mpd.GetElapsedTime(), Mpd.GetTotalTime()); +} + +void Status::Changes::repeat() +{ + mpd_repeat = Mpd.GetRepeat() ? 'r' : 0; + Statusbar::msg("Repeat mode is %s", !mpd_repeat ? "off" : "on"); +} + +void Status::Changes::random() +{ + mpd_random = Mpd.GetRandom() ? 'z' : 0; + Statusbar::msg("Random mode is %s", !mpd_random ? "off" : "on"); +} + +void Status::Changes::single() +{ + mpd_single = Mpd.GetSingle() ? 's' : 0; + Statusbar::msg("Single mode is %s", !mpd_single ? "off" : "on"); +} + +void Status::Changes::consume() +{ + mpd_consume = Mpd.GetConsume() ? 'c' : 0; + Statusbar::msg("Consume mode is %s", !mpd_consume ? "off" : "on"); +} + +void Status::Changes::crossfade() +{ + int crossfade = Mpd.GetCrossfade(); + mpd_crossfade = crossfade ? 'x' : 0; + Statusbar::msg("Crossfade set to %d seconds", crossfade); +} + +void Status::Changes::dbUpdateState() +{ + mpd_db_updating = Mpd.GetDBIsUpdating() ? 'U' : 0; + Statusbar::msg(Mpd.GetDBIsUpdating() ? "Database update started" : "Database update finished"); +} + +void Status::Changes::flags() +{ + if (!Config.header_visibility && !Config.new_design) + return; + + std::string switch_state; + if (Config.new_design) + { + switch_state += '['; + switch_state += mpd_repeat ? mpd_repeat : '-'; + switch_state += mpd_random ? mpd_random : '-'; + switch_state += mpd_single ? mpd_single : '-'; + switch_state += mpd_consume ? mpd_consume : '-'; + switch_state += mpd_crossfade ? mpd_crossfade : '-'; + switch_state += mpd_db_updating ? mpd_db_updating : '-'; + switch_state += ']'; + *wHeader << NC::XY(COLS-switch_state.length(), 1) << NC::fmtBold << Config.state_flags_color << switch_state << NC::clEnd << NC::fmtBoldEnd; + if (Config.new_design && !Config.header_visibility) // in this case also draw separator + { + *wHeader << NC::fmtBold << NC::clBlack; + mvwhline(wHeader->raw(), 2, 0, 0, COLS); + *wHeader << NC::clEnd << NC::fmtBoldEnd; + } + wHeader->refresh(); } else { - *wHeader << NC::XY(0, 0) << wclrtoeol << NC::fmtBold << myScreen->Title() << NC::fmtBoldEnd; - *wHeader << Config.volume_color; - *wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << VolumeState; - *wHeader << NC::clEnd; + if (mpd_repeat) + switch_state += mpd_repeat; + if (mpd_random) + switch_state += mpd_random; + if (mpd_single) + switch_state += mpd_single; + if (mpd_consume) + switch_state += mpd_consume; + if (mpd_crossfade) + switch_state += mpd_crossfade; + if (mpd_db_updating) + switch_state += mpd_db_updating; + + // this is done by raw ncurses because creating another + // window only for handling this is quite silly + attrset(A_BOLD|COLOR_PAIR(Config.state_line_color)); + mvhline(1, 0, 0, COLS); + if (!switch_state.empty()) + { + mvprintw(1, COLS-switch_state.length()-3, "["); + attroff(COLOR_PAIR(Config.state_line_color)); + attron(COLOR_PAIR(Config.state_flags_color)); + mvprintw(1, COLS-switch_state.length()-2, "%s", switch_state.c_str()); + attroff(COLOR_PAIR(Config.state_flags_color)); + attron(COLOR_PAIR(Config.state_line_color)); + mvprintw(1, COLS-2, "]"); + } + attroff(A_BOLD|COLOR_PAIR(Config.state_line_color)); + refresh(); } +} + +void Status::Changes::mixer() +{ + if (!Config.display_volume_level || (!Config.header_visibility && !Config.new_design)) + return; + + VolumeState = Config.new_design ? " Vol: " : " Volume: "; + int volume = Mpd.GetVolume(); + if (volume < 0) + VolumeState += "n/a"; + else + { + VolumeState += intTo::apply(volume); + VolumeState += "%"; + } + *wHeader << Config.volume_color; + *wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << VolumeState; + *wHeader << NC::clEnd; wHeader->refresh(); } + +void Status::Changes::outputs() +{ +# ifdef ENABLE_OUTPUTS + myOutputs->FetchList(); +# endif // ENABLE_OUTPUTS +} + +void Status::update(MPD::Connection *, MPD::StatusChanges changes, void *) +{ + if (changes.Playlist) + Changes::playlist(); + if (changes.StoredPlaylists) + Changes::storedPlaylists(); + if (changes.Database) + Changes::database(); + if (changes.PlayerState) + Changes::playerState(); + if (changes.SongID) + Changes::songID(); + if (changes.ElapsedTime) + Changes::elapsedTime(); + if (changes.Repeat) + Changes::repeat(); + if (changes.Random) + Changes::random(); + if (changes.Single) + Changes::single(); + if (changes.Consume) + Changes::consume(); + if (changes.Crossfade) + Changes::crossfade(); + if (changes.DBUpdating) + Changes::dbUpdateState(); + if (changes.StatusFlags) + Changes::flags(); + if (changes.Volume) + Changes::mixer(); + if (changes.Outputs) + Changes::outputs(); + + if (changes.PlayerState || (changes.ElapsedTime && (!Config.new_design || Mpd.GetState() == MPD::psPlay))) + wFooter->refresh(); + if (changes.Playlist || changes.Database || changes.PlayerState || changes.SongID) + ApplyToVisibleWindows(&BasicScreen::RefreshWindow); +} diff --git a/src/status.h b/src/status.h index 2ead6046..303a39ee 100644 --- a/src/status.h +++ b/src/status.h @@ -24,18 +24,34 @@ #include "interfaces.h" #include "mpdpp.h" -#ifndef USE_PDCURSES - void WindowTitle(const std::string &); -#else -# define WindowTitle(x); -#endif // USE_PDCURSES +namespace Status {// -void DrawNowPlayingTitle(); +void trace(); -void TraceMpdStatus(); -void NcmpcppStatusChanged(MPD::Connection *, MPD::StatusChanges, void *); -void NcmpcppErrorCallback(MPD::Connection *, int, const char *, void *); +void handleError(MPD::Connection * , int errorid, const char *msg, void *); -void DrawHeader(); +void update(MPD::Connection *, MPD::StatusChanges changes, void *); + +namespace Changes {// + +void playlist(); +void storedPlaylists(); +void database(); +void playerState(); +void songID(); +void elapsedTime(); +void repeat(); +void random(); +void single(); +void consume(); +void crossfade(); +void dbUpdateState(); +void flags(); +void mixer(); +void outputs(); + +} + +} #endif diff --git a/src/statusbar.cpp b/src/statusbar.cpp index e15545f4..6e4408bf 100644 --- a/src/statusbar.cpp +++ b/src/statusbar.cpp @@ -175,7 +175,7 @@ void Statusbar::Helpers::mpd() void Statusbar::Helpers::getString(const std::wstring &) { - TraceMpdStatus(); + Status::trace(); } void Statusbar::Helpers::ApplyFilterImmediately::operator()(const std::wstring &ws) @@ -194,6 +194,6 @@ void Statusbar::Helpers::ApplyFilterImmediately::operator()(const std::wstring & m_f->applyFilter(ToString(m_ws)); myScreen->RefreshWindow(); } - TraceMpdStatus(); + Status::trace(); } } diff --git a/src/tag_editor.cpp b/src/tag_editor.cpp index 6143a205..d64d3638 100644 --- a/src/tag_editor.cpp +++ b/src/tag_editor.cpp @@ -45,6 +45,7 @@ #include "song_info.h" #include "statusbar.h" #include "utility/comparators.h" +#include "title.h" using namespace std::placeholders; @@ -226,7 +227,7 @@ void TagEditor::SwitchTo() if (myScreen != this && myScreen->isTabbable()) Global::myPrevScreen = myScreen; myScreen = this; - DrawHeader(); + drawHeader(); Refresh(); } @@ -497,7 +498,7 @@ void TagEditor::EnterPressed() if (w == TagTypes && id == 5) { - bool yes = Action::AskYesNoQuestion("Number tracks?", TraceMpdStatus); + bool yes = Action::AskYesNoQuestion("Number tracks?", Status::trace); if (yes) { auto it = EditedSongs.begin(); diff --git a/src/tiny_tag_editor.cpp b/src/tiny_tag_editor.cpp index 8ebb5716..78681fca 100644 --- a/src/tiny_tag_editor.cpp +++ b/src/tiny_tag_editor.cpp @@ -38,6 +38,7 @@ #include "search_engine.h" #include "statusbar.h" #include "tag_editor.h" +#include "title.h" using Global::MainHeight; using Global::MainStartY; @@ -83,7 +84,7 @@ void TinyTagEditor::SwitchTo() myOldScreen = myScreen; myScreen = this; - DrawHeader(); + drawHeader(); } else { diff --git a/src/title.cpp b/src/title.cpp new file mode 100644 index 00000000..e0d0e3ec --- /dev/null +++ b/src/title.cpp @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (C) 2008-2012 by Andrzej Rybczak * + * electricityispower@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include +#include + +#include "global.h" +#include "settings.h" +#include "title.h" + +#ifdef USE_PDCURSES +void windowTitle(const std::string &) { } +#else +void windowTitle(const std::string &status) +{ + if (strcmp(getenv("TERM"), "linux") && Config.set_window_title) + std::cout << "\033]0;" << status << "\7"; +} +#endif // USE_PDCURSES + +void drawHeader() +{ + using Global::myScreen; + using Global::wHeader; + using Global::VolumeState; + + if (!Config.header_visibility) + return; + if (Config.new_design) + { + std::wstring title = myScreen->Title(); + *wHeader << NC::XY(0, 3) << wclrtoeol; + *wHeader << NC::fmtBold << Config.alternative_ui_separator_color; + mvwhline(wHeader->raw(), 2, 0, 0, COLS); + mvwhline(wHeader->raw(), 4, 0, 0, COLS); + *wHeader << NC::XY((COLS-wideLength(title))/2, 3); + *wHeader << Config.header_color << title << NC::clEnd; + *wHeader << NC::clEnd << NC::fmtBoldEnd; + } + else + { + *wHeader << NC::XY(0, 0) << wclrtoeol << NC::fmtBold << myScreen->Title() << NC::fmtBoldEnd; + *wHeader << Config.volume_color; + *wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << VolumeState; + *wHeader << NC::clEnd; + } + wHeader->refresh(); +} diff --git a/src/title.h b/src/title.h new file mode 100644 index 00000000..2f317112 --- /dev/null +++ b/src/title.h @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2008-2012 by Andrzej Rybczak * + * electricityispower@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef _TITLE_H +#define _TITLE_H + +#include "window.h" + +void windowTitle(const std::string &title); + +void drawHeader(); + +#endif diff --git a/src/visualizer.cpp b/src/visualizer.cpp index 0e33702a..6e87159b 100644 --- a/src/visualizer.cpp +++ b/src/visualizer.cpp @@ -35,6 +35,7 @@ #include "settings.h" #include "status.h" #include "statusbar.h" +#include "title.h" using Global::MainStartY; using Global::MainHeight; @@ -82,7 +83,7 @@ void Visualizer::SwitchTo() if (myScreen != this && myScreen->isTabbable()) Global::myPrevScreen = myScreen; myScreen = this; - DrawHeader(); + drawHeader(); w->clear(); SetFD();