|
|
|
|
@ -18,12 +18,8 @@ |
|
|
|
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * |
|
|
|
|
***************************************************************************/ |
|
|
|
|
|
|
|
|
|
#include <cstring> |
|
|
|
|
#include <sys/time.h> |
|
|
|
|
|
|
|
|
|
#include <iostream> |
|
|
|
|
#include <stdexcept> |
|
|
|
|
|
|
|
|
|
#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) |
|
|
|
|
namespace {//
|
|
|
|
|
|
|
|
|
|
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 (strcmp(getenv("TERM"), "linux") && Config.set_window_title) |
|
|
|
|
std::cout << "\033]0;" << status << "\7"; |
|
|
|
|
assert(!np.empty()); |
|
|
|
|
windowTitle(np.toString(Config.song_window_title_format)); |
|
|
|
|
} |
|
|
|
|
#endif // !USE_PDCURSES
|
|
|
|
|
|
|
|
|
|
void DrawNowPlayingTitle(MPD::Song &np) |
|
|
|
|
{ |
|
|
|
|
if (np.empty()) |
|
|
|
|
np = myPlaylist->nowPlayingSong(); |
|
|
|
|
if (!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; |
|
|
|
|
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()); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
MPD::Song np; |
|
|
|
|
if (Mpd.isPlaying()) |
|
|
|
|
drawTitle(myPlaylist->nowPlayingSong()); |
|
|
|
|
|
|
|
|
|
int sx = wFooter->getX(); |
|
|
|
|
int sy = wFooter->getY(); |
|
|
|
|
Playlist::ReloadTotalLength = true; |
|
|
|
|
Playlist::ReloadRemaining = true; |
|
|
|
|
|
|
|
|
|
if (changed.Playlist) |
|
|
|
|
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 Status::Changes::storedPlaylists() |
|
|
|
|
{ |
|
|
|
|
if (myPlaylistEditor->Main()) |
|
|
|
|
{ |
|
|
|
|
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()); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
DrawNowPlayingTitle(np); |
|
|
|
|
|
|
|
|
|
Playlist::ReloadTotalLength = true; |
|
|
|
|
Playlist::ReloadRemaining = true; |
|
|
|
|
|
|
|
|
|
myPlaylistEditor->requestPlaylistsUpdate(); |
|
|
|
|
myPlaylistEditor->requestContentsUpdate(); |
|
|
|
|
} |
|
|
|
|
if (myBrowser->Main() && myBrowser->CurrentDir() == "/") |
|
|
|
|
{ |
|
|
|
|
myBrowser->GetDirectory("/"); |
|
|
|
|
if (isVisible(myBrowser)) |
|
|
|
|
markSongsInPlaylist(myBrowser->getProxySongList()); |
|
|
|
|
if (isVisible(mySearcher)) |
|
|
|
|
markSongsInPlaylist(mySearcher->getProxySongList()); |
|
|
|
|
if (isVisible(myLibrary)) |
|
|
|
|
markSongsInPlaylist(myLibrary->songsProxyList()); |
|
|
|
|
if (isVisible(myPlaylistEditor)) |
|
|
|
|
markSongsInPlaylist(myPlaylistEditor->contentProxyList()); |
|
|
|
|
myBrowser->Refresh(); |
|
|
|
|
} |
|
|
|
|
if (changed.StoredPlaylists) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Status::Changes::database() |
|
|
|
|
{ |
|
|
|
|
if (myBrowser->Main()) |
|
|
|
|
{ |
|
|
|
|
if (myPlaylistEditor->Main()) |
|
|
|
|
{ |
|
|
|
|
myPlaylistEditor->requestPlaylistsUpdate(); |
|
|
|
|
myPlaylistEditor->requestContentsUpdate(); |
|
|
|
|
} |
|
|
|
|
if (myBrowser->Main() && myBrowser->CurrentDir() == "/") |
|
|
|
|
{ |
|
|
|
|
myBrowser->GetDirectory("/"); |
|
|
|
|
if (isVisible(myBrowser)) |
|
|
|
|
myBrowser->Refresh(); |
|
|
|
|
} |
|
|
|
|
if (isVisible(myBrowser)) |
|
|
|
|
myBrowser->GetDirectory(myBrowser->CurrentDir()); |
|
|
|
|
else |
|
|
|
|
myBrowser->Main()->clear(); |
|
|
|
|
} |
|
|
|
|
if (changed.Database) |
|
|
|
|
# ifdef HAVE_TAGLIB_H |
|
|
|
|
if (myTagEditor->Main()) |
|
|
|
|
{ |
|
|
|
|
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; |
|
|
|
|
myTagEditor->Dirs->clear(); |
|
|
|
|
} |
|
|
|
|
if (changed.PlayerState) |
|
|
|
|
# endif // HAVE_TAGLIB_H
|
|
|
|
|
if (myLibrary->Main()) |
|
|
|
|
{ |
|
|
|
|
MPD::PlayerState state = Mpd.GetState(); |
|
|
|
|
switch (state) |
|
|
|
|
{ |
|
|
|
|
case MPD::psUnknown: |
|
|
|
|
{ |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
# ifdef ENABLE_VISUALIZER |
|
|
|
|
if (myScreen == myVisualizer) |
|
|
|
|
wFooter->setTimeout(state == MPD::psPlay ? Visualizer::WindowTimeout : 500); |
|
|
|
|
# endif // ENABLE_VISUALIZER
|
|
|
|
|
if (Config.new_design) |
|
|
|
|
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: |
|
|
|
|
{ |
|
|
|
|
*wHeader << NC::XY(0, 1) << NC::fmtBold << player_state << NC::fmtBoldEnd; |
|
|
|
|
wHeader->refresh(); |
|
|
|
|
player_state = "[unknown]"; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
else if (Statusbar::isUnlocked() && Config.statusbar_visibility) |
|
|
|
|
case MPD::psPlay: |
|
|
|
|
{ |
|
|
|
|
*wFooter << NC::XY(0, 1); |
|
|
|
|
if (player_state.empty()) |
|
|
|
|
*wFooter << wclrtoeol; |
|
|
|
|
else |
|
|
|
|
*wFooter << NC::fmtBold << player_state << NC::fmtBoldEnd; |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (changed.SongID) |
|
|
|
|
{ |
|
|
|
|
if (Mpd.isPlaying()) |
|
|
|
|
case MPD::psPause: |
|
|
|
|
{ |
|
|
|
|
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; |
|
|
|
|
player_state = Config.new_design ? "[paused] " : "[Paused] "; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
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()) |
|
|
|
|
case MPD::psStop: |
|
|
|
|
{ |
|
|
|
|
DrawNowPlayingTitle(np); |
|
|
|
|
|
|
|
|
|
std::string tracklength; |
|
|
|
|
windowTitle("ncmpcpp " VERSION); |
|
|
|
|
if (Progressbar::isUnlocked()) |
|
|
|
|
Progressbar::draw(0, 0); |
|
|
|
|
Playlist::ReloadRemaining = true; |
|
|
|
|
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<std::string>::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; |
|
|
|
|
*wHeader << NC::XY(0, 0) << wclrtoeol << NC::XY(0, 1) << wclrtoeol; |
|
|
|
|
player_state = "[stopped]"; |
|
|
|
|
mixer(); |
|
|
|
|
flags(); |
|
|
|
|
} |
|
|
|
|
else if (Statusbar::isUnlocked() && Config.statusbar_visibility) |
|
|
|
|
{ |
|
|
|
|
if (Config.display_bitrate && Mpd.GetBitrate()) |
|
|
|
|
{ |
|
|
|
|
tracklength += " ["; |
|
|
|
|
tracklength += intTo<std::string>::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; |
|
|
|
|
else |
|
|
|
|
player_state.clear(); |
|
|
|
|
# ifdef ENABLE_VISUALIZER |
|
|
|
|
if (isVisible(myVisualizer)) |
|
|
|
|
myVisualizer->Main()->clear(); |
|
|
|
|
# endif // ENABLE_VISUALIZER
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
# ifdef ENABLE_VISUALIZER |
|
|
|
|
if (myScreen == myVisualizer) |
|
|
|
|
wFooter->setTimeout(state == MPD::psPlay ? Visualizer::WindowTimeout : 500); |
|
|
|
|
# endif // ENABLE_VISUALIZER
|
|
|
|
|
|
|
|
|
|
if (changed.Repeat) |
|
|
|
|
{ |
|
|
|
|
mpd_repeat = Mpd.GetRepeat() ? 'r' : 0; |
|
|
|
|
Statusbar::msg("Repeat mode is %s", !mpd_repeat ? "off" : "on"); |
|
|
|
|
} |
|
|
|
|
if (changed.Random) |
|
|
|
|
if (Config.new_design) |
|
|
|
|
{ |
|
|
|
|
mpd_random = Mpd.GetRandom() ? 'z' : 0; |
|
|
|
|
Statusbar::msg("Random mode is %s", !mpd_random ? "off" : "on"); |
|
|
|
|
*wHeader << NC::XY(0, 1) << NC::fmtBold << player_state << NC::fmtBoldEnd; |
|
|
|
|
wHeader->refresh(); |
|
|
|
|
} |
|
|
|
|
if (changed.Single) |
|
|
|
|
else if (Statusbar::isUnlocked() && Config.statusbar_visibility) |
|
|
|
|
{ |
|
|
|
|
mpd_single = Mpd.GetSingle() ? 's' : 0; |
|
|
|
|
Statusbar::msg("Single mode is %s", !mpd_single ? "off" : "on"); |
|
|
|
|
*wFooter << NC::XY(0, 1); |
|
|
|
|
if (player_state.empty()) |
|
|
|
|
*wFooter << wclrtoeol; |
|
|
|
|
else |
|
|
|
|
*wFooter << NC::fmtBold << player_state << NC::fmtBoldEnd; |
|
|
|
|
} |
|
|
|
|
if (changed.Consume) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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()) |
|
|
|
|
{ |
|
|
|
|
mpd_consume = Mpd.GetConsume() ? 'c' : 0; |
|
|
|
|
Statusbar::msg("Consume mode is %s", !mpd_consume ? "off" : "on"); |
|
|
|
|
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(); |
|
|
|
|
} |
|
|
|
|
if (changed.Crossfade) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Status::Changes::elapsedTime() |
|
|
|
|
{ |
|
|
|
|
if (!Mpd.isPlaying()) |
|
|
|
|
{ |
|
|
|
|
int crossfade = Mpd.GetCrossfade(); |
|
|
|
|
mpd_crossfade = crossfade ? 'x' : 0; |
|
|
|
|
Statusbar::msg("Crossfade set to %d seconds", crossfade); |
|
|
|
|
if (Statusbar::isUnlocked() && Config.statusbar_visibility) |
|
|
|
|
*wFooter << NC::XY(0, 1) << wclrtoeol; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (changed.DBUpdating) |
|
|
|
|
|
|
|
|
|
MPD::Song np = myPlaylist->nowPlayingSong(); |
|
|
|
|
drawTitle(np); |
|
|
|
|
|
|
|
|
|
std::string tracklength; |
|
|
|
|
if (Config.new_design) |
|
|
|
|
{ |
|
|
|
|
// 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) |
|
|
|
|
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()) |
|
|
|
|
{ |
|
|
|
|
myScreen->SwitchTo(); // switch to previous screen
|
|
|
|
|
Statusbar::msg("Database has changed, you need to select your item(s) once again"); |
|
|
|
|
tracklength += " "; |
|
|
|
|
tracklength += intTo<std::string>::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(); |
|
|
|
|
} |
|
|
|
|
if (changed.StatusFlags && (Config.header_visibility || Config.new_design)) |
|
|
|
|
else if (Statusbar::isUnlocked() && Config.statusbar_visibility) |
|
|
|
|
{ |
|
|
|
|
std::string switch_state; |
|
|
|
|
|
|
|
|
|
if (Config.new_design) |
|
|
|
|
if (Config.display_bitrate && Mpd.GetBitrate()) |
|
|
|
|
{ |
|
|
|
|
tracklength += " ["; |
|
|
|
|
tracklength += intTo<std::string>::apply(Mpd.GetBitrate()); |
|
|
|
|
tracklength += " kbps]"; |
|
|
|
|
} |
|
|
|
|
tracklength += " ["; |
|
|
|
|
if (Mpd.GetTotalTime()) |
|
|
|
|
{ |
|
|
|
|
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
|
|
|
|
|
if (Config.display_remaining_time) |
|
|
|
|
{ |
|
|
|
|
*wHeader << NC::fmtBold << NC::clBlack; |
|
|
|
|
mvwhline(wHeader->raw(), 2, 0, 0, COLS); |
|
|
|
|
*wHeader << NC::clEnd << NC::fmtBoldEnd; |
|
|
|
|
tracklength += "-"; |
|
|
|
|
tracklength += MPD::Song::ShowTime(Mpd.GetTotalTime()-Mpd.GetElapsedTime()); |
|
|
|
|
} |
|
|
|
|
wHeader->refresh(); |
|
|
|
|
else |
|
|
|
|
tracklength += MPD::Song::ShowTime(Mpd.GetElapsedTime()); |
|
|
|
|
tracklength += "/"; |
|
|
|
|
tracklength += MPD::Song::ShowTime(Mpd.GetTotalTime()); |
|
|
|
|
tracklength += "]"; |
|
|
|
|
} |
|
|
|
|
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(); |
|
|
|
|
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 (changed.Volume && Config.display_volume_level && (Config.header_visibility || Config.new_design)) |
|
|
|
|
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) |
|
|
|
|
{ |
|
|
|
|
VolumeState = Config.new_design ? " Vol: " : " Volume: "; |
|
|
|
|
int volume = Mpd.GetVolume(); |
|
|
|
|
if (volume < 0) |
|
|
|
|
VolumeState += "n/a"; |
|
|
|
|
else |
|
|
|
|
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
|
|
|
|
|
{ |
|
|
|
|
VolumeState += intTo<std::string>::apply(volume); |
|
|
|
|
VolumeState += "%"; |
|
|
|
|
*wHeader << NC::fmtBold << NC::clBlack; |
|
|
|
|
mvwhline(wHeader->raw(), 2, 0, 0, COLS); |
|
|
|
|
*wHeader << NC::clEnd << NC::fmtBoldEnd; |
|
|
|
|
} |
|
|
|
|
*wHeader << Config.volume_color; |
|
|
|
|
*wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << VolumeState; |
|
|
|
|
*wHeader << NC::clEnd; |
|
|
|
|
wHeader->refresh(); |
|
|
|
|
} |
|
|
|
|
if (changed.Outputs) |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
# ifdef ENABLE_OUTPUTS |
|
|
|
|
myOutputs->FetchList(); |
|
|
|
|
# endif // ENABLE_OUTPUTS
|
|
|
|
|
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(); |
|
|
|
|
} |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void DrawHeader() |
|
|
|
|
void Status::Changes::mixer() |
|
|
|
|
{ |
|
|
|
|
if (!Config.header_visibility) |
|
|
|
|
if (!Config.display_volume_level || (!Config.header_visibility && !Config.new_design)) |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
VolumeState = Config.new_design ? " Vol: " : " Volume: "; |
|
|
|
|
int volume = Mpd.GetVolume(); |
|
|
|
|
if (volume < 0) |
|
|
|
|
VolumeState += "n/a"; |
|
|
|
|
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; |
|
|
|
|
VolumeState += intTo<std::string>::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); |
|
|
|
|
} |
|
|
|
|
|