diff --git a/configure.in b/configure.in index 9aae4ae2..0219f0a3 100644 --- a/configure.in +++ b/configure.in @@ -10,7 +10,7 @@ AC_PROG_CXX AM_PROG_LIBTOOL AC_ARG_ENABLE(unicode, AS_HELP_STRING([--enable-unicode], [Enable utf8 support]), [unicode=$enableval], [unicode=yes]) -AC_ARG_WITH(taglib, AS_HELP_STRING([--with-taglib], [Enable tag editor]), [taglib=$withval], [taglib=yes]) +AC_ARG_WITH(taglib, AS_HELP_STRING([--with-taglib], [Enable tag editor]), [taglib=$withval], [taglib=no]) dnl ======================== dnl = checking for ncurses = @@ -47,6 +47,11 @@ CPPFLAGS="$CPPFLAGS $libmpd_CFLAGS" LDFLAGS="$LDFLAGS $libmpd_LIBS" AC_CHECK_HEADERS([libmpd/libmpd.h], , AC_MSG_ERROR([missing libmpd.h header])) +dnl ======================== +dnl = checking for pthread = +dnl ======================== +AC_CHECK_LIB(pthread, pthread_create, LDFLAGS="$LDFLAGS -pthread", AC_MSG_ERROR([missing pthread library])) +AC_CHECK_HEADERS([pthread.h], , AC_MSG_ERROR([missing pthread.h header])) dnl ======================= dnl = checking for taglib = diff --git a/examples/ncmpcpprc b/examples/ncmpcpprc index 45d1b32f..164b996d 100644 --- a/examples/ncmpcpprc +++ b/examples/ncmpcpprc @@ -63,6 +63,8 @@ # #song_window_title_format = "{%a - }{%t}|{%f}" # +#song_library_format = "{%n - }{%t}|{%f}" +# ##### interface settings ##### # #header_visibility = "yes" @@ -89,3 +91,5 @@ # #statusbar_color = "default" # +#library_active_column_color = "red" +# diff --git a/src/helpers.cpp b/src/helpers.cpp index d89b47d4..6f1ba737 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -38,6 +38,8 @@ extern vector vPlaylist; extern vector vFileType; extern vector vNameList; +extern CurrScreen current_screen; + extern Song edited_song; extern Song searched_song; @@ -61,6 +63,45 @@ extern string UNKNOWN_ARTIST; extern string UNKNOWN_TITLE; extern string UNKNOWN_ALBUM; +void * BoldSongsFromPlaylist(void *t) +{ + if (!vNameList.empty()) + { + bool bold = 0; + for (int i = 0; i < vFileType.size(); i++) + { + if (vFileType[i] == MPD_DATA_TYPE_SONG) + { + for (vector::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++) + { + if (it->GetFile() == vNameList[i]) + { + bold = 1; + break; + } + } + mBrowser->BoldOption(i+1, bold); + bold = 0; + } + } + } + if (current_screen == csBrowser) + mBrowser->Refresh(); + pthread_exit(NULL); +} + +bool SortSongsByTrack(const Song &a, const Song &b) +{ + return StrToInt(a.GetTrack()) < StrToInt(b.GetTrack()); +} + +bool CaseInsensitiveComparison(string a, string b) +{ + transform(a.begin(), a.end(), a.begin(), tolower); + transform(b.begin(), b.end(), b.begin(), tolower); + return a < b; +} + void WindowTitle(const string &status) { if (TERMINAL_TYPE != "linux" && Config.set_window_title) @@ -491,13 +532,14 @@ bool GetSongInfo(Song &s) void GetDirectory(string dir) { + pthread_t bolder; browsed_dir_scroll_begin = 0; if (browsed_dir != dir) mBrowser->Reset(); browsed_dir = dir; vFileType.clear(); vNameList.clear(); - mBrowser->Clear(); + mBrowser->Clear(current_screen != csLibrary); if (dir != "/") { mBrowser->AddOption("[..]"); @@ -535,15 +577,14 @@ void GetDirectory(string dir) vFileType.push_back(MPD_DATA_TYPE_SONG); Song s = browser->song; vNameList.push_back(s.GetFile()); - bool bold = 0; - for (vector::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++) - if (it->GetFile() == s.GetFile()) - bold = 1; - bold ? mBrowser->AddBoldOption(DisplaySong(s)) : mBrowser->AddOption(DisplaySong(s)); + mBrowser->AddOption(DisplaySong(s)); break; } } } + + pthread_create(&bolder, NULL, BoldSongsFromPlaylist, NULL); + mpd_data_free(browser); browsed_subdir.clear(); } diff --git a/src/helpers.h b/src/helpers.h index b2048131..be337624 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -23,12 +23,17 @@ #include +#include + #include "ncmpcpp.h" #include "settings.h" #include "song.h" extern ncmpcpp_config Config; +void * BoldSongsFromPlaylist(void *); +bool SortSongsByTrack(const Song &, const Song &); +bool CaseInsensitiveComparison(string, string); void WindowTitle(const string &); string DisplaySong(const Song &, const string & = Config.song_list_format); void ShowMessage(const string &, int = Config.message_delay_time); diff --git a/src/menu.cpp b/src/menu.cpp index a7108213..5dd553a1 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -140,6 +140,30 @@ void Menu::MakeStatic(int index, IS_STATIC stat) } } +string Menu::GetCurrentOption() const +{ + try + { + return itsOptions.at(itsHighlight); + } + catch (std::out_of_range) + { + return ""; + } +} + +string Menu::GetOption(int i) const +{ + try + { + return itsOptions.at(i-1); + } + catch (std::out_of_range) + { + return ""; + } +} + void Menu::DeleteOption(int no) { try @@ -211,7 +235,10 @@ void Menu::Refresh() for (int i = itsBeginning; i < last; i++) { if (i == itsHighlight && itsHighlightEnabled) + { Reverse(1); + SetColor(itsHighlightColor); + } if (itsBold[i]) Bold(1); @@ -260,7 +287,10 @@ void Menu::Refresh() line++; if (i == itsHighlight && itsHighlightEnabled) + { Reverse(0); + SetColor(itsBaseColor); + } if (itsBold[i]) Bold(0); } diff --git a/src/menu.h b/src/menu.h index 06438a3b..e523bf4c 100644 --- a/src/menu.h +++ b/src/menu.h @@ -34,7 +34,7 @@ enum LOCATION { lLeft, lCenter, lRight }; class Menu : public Window { public: - Menu(int startx, int starty, int width, int height, string title, COLOR color, BORDER border) : Window(startx, starty, width, height, title, color, border), itsStaticsNumber(0), itsChoice(0), itsBeginning(0), itsHighlight(0), itsHighlightEnabled(1) { SetColor(color); } + Menu(int startx, int starty, int width, int height, string title, COLOR color, BORDER border) : Window(startx, starty, width, height, title, color, border), itsStaticsNumber(0), itsChoice(0), itsBeginning(0), itsHighlight(0), itsHighlightColor(itsBaseColor), itsHighlightEnabled(1) { SetColor(color); } virtual ~Menu() {} virtual void Add(string str) { AddOption(str); } @@ -47,8 +47,8 @@ class Menu : public Window void BoldOption(int, IS_BOLD); void MakeStatic(int, IS_STATIC); void DeleteOption(int); - string GetCurrentOption() { return itsOptions[itsHighlight]; } - string GetOption(int i) { return itsOptions[i-1]; } + string GetCurrentOption() const; + string GetOption(int i) const; virtual void Display(); virtual void Refresh(); @@ -57,7 +57,8 @@ class Menu : public Window virtual void Reset(); virtual void Clear(bool clear_screen = 1); - void Highlighting(bool hl) { itsHighlightEnabled = hl; } + void HighlightColor(COLOR col) { itsHighlightColor = col; } + void Highlighting(bool hl) { itsHighlightEnabled = hl; Refresh(); } int GetRealChoice() const; virtual int GetChoice() const { return itsHighlight+1; } @@ -84,6 +85,8 @@ class Menu : public Window int itsBeginning; int itsHighlight; + COLOR itsHighlightColor; + bool itsHighlightEnabled; }; diff --git a/src/ncmpcpp.cpp b/src/ncmpcpp.cpp index acae70c3..89b0907e 100644 --- a/src/ncmpcpp.cpp +++ b/src/ncmpcpp.cpp @@ -60,12 +60,18 @@ vector vSearched; vector vFileType; vector vNameList; +vector vArtists; +vector vSongs; + Window *wCurrent = 0; Window *wPrev = 0; Menu *mPlaylist; Menu *mBrowser; Menu *mTagEditor; Menu *mSearcher; +Menu *mLibArtists; +Menu *mLibAlbums; +Menu *mLibSongs; Scrollpad *sHelp; Window *wHeader; @@ -112,6 +118,7 @@ bool block_progressbar_update = 0; bool block_statusbar_update = 0; bool allow_statusbar_unblock = 1; bool block_playlist_update = 0; +bool block_library_update = 0; bool search_case_sensitive = 1; bool search_mode_match = 1; @@ -161,6 +168,16 @@ int main(int argc, char *argv[]) mTagEditor = new Menu(mPlaylist->EmptyClone()); mSearcher = new Menu(mPlaylist->EmptyClone()); + int lib_artist_width = COLS/3-1; + int lib_albums_width = COLS/3; + int lib_albums_start_x = lib_artist_width+1; + int lib_songs_width = COLS-COLS/3*2-1; + int lib_songs_start_x = lib_artist_width+lib_albums_width+2; + + mLibArtists = new Menu(0, main_start_y, lib_artist_width, main_height, "Artists", Config.main_color, brNone); + mLibAlbums = new Menu(lib_albums_start_x, main_start_y, lib_albums_width, main_height, "Albums", Config.main_color, brNone); + mLibSongs = new Menu(lib_songs_start_x, main_start_y, lib_songs_width, main_height, "Songs", Config.main_color, brNone); + sHelp = new Scrollpad(0, main_start_y, COLS, main_height, "", Config.main_color, brNone); sHelp->Add(" [b]Keys - Movement\n -----------------------------------------[/b]\n"); @@ -192,6 +209,7 @@ int main(int argc, char *argv[]) sHelp->Add("\tZ : Shuffle playlist\n"); sHelp->Add("\tU u : Start a music database update\n\n"); + sHelp->Add(tag_screen_keydesc); sHelp->Add("\tg : Go to chosen position in current song\n\n"); sHelp->Add("\tQ q : Quit\n\n\n"); @@ -203,19 +221,22 @@ int main(int argc, char *argv[]) sHelp->Add("\tm : Move song up\n"); sHelp->Add("\tn : Move song down\n"); sHelp->Add("\tS : Save playlist\n"); - sHelp->Add(tag_screen_keydesc); sHelp->Add("\to : Go to currently playing position\n\n\n"); sHelp->Add(" [b]Keys - Browse screen\n -----------------------------------------[/b]\n"); sHelp->Add("\tEnter : Enter directory/Select and play song\n"); sHelp->Add("\tSpace : Add song to playlist\n"); - sHelp->Add("\tDelete : Delete playlist\n"); - sHelp->Add(tag_screen_keydesc + "\n\n"); + sHelp->Add("\tDelete : Delete playlist\n\n"); sHelp->Add(" [b]Keys - Search engine\n -----------------------------------------[/b]\n"); sHelp->Add("\tEnter : Change option/Select and play song\n"); - sHelp->Add("\tSpace : Add song to playlist\n"); - sHelp->Add(tag_screen_keydesc + "\n\n"); + sHelp->Add("\tSpace : Add song to playlist\n\n\n"); + + sHelp->Add(" [b]Keys - Media library\n -----------------------------------------[/b]\n"); + sHelp->Add("\tLeft : Previous column\n"); + sHelp->Add("\tRight : Next column\n"); + sHelp->Add("\tEnter : Select and play song/album/artist's songs\n"); + sHelp->Add("\tSpace : Select song/album/artist's songs\n\n\n"); sHelp->Add(" [b]Keys - Tag Editor\n -----------------------------------------[/b]\n"); sHelp->Add("\tEnter : Change option\n"); @@ -248,6 +269,9 @@ int main(int argc, char *argv[]) mBrowser->Timeout(ncmpcpp_window_timeout); mTagEditor->Timeout(ncmpcpp_window_timeout); mSearcher->Timeout(ncmpcpp_window_timeout); + mLibArtists->Timeout(ncmpcpp_window_timeout); + mLibAlbums->Timeout(ncmpcpp_window_timeout); + mLibSongs->Timeout(ncmpcpp_window_timeout); wFooter->Timeout(ncmpcpp_window_timeout); while (!main_exit) @@ -273,14 +297,18 @@ int main(int argc, char *argv[]) title = "Browse: "; break; case csTagEditor: -# ifdef HAVE_TAGLIB_H +# ifdef HAVE_TAGLIB_H title = "Tag editor"; -# else +# else title = "Tag info"; -# endif +# endif break; case csSearcher: title = "Search engine"; + break; + case csLibrary: + title = "Media library"; + break; } if (title_allowed) @@ -290,7 +318,7 @@ int main(int argc, char *argv[]) wHeader->Bold(0); } else - wHeader->WriteXY(0, 0, "[b]1:[/b]Help [b]2:[/b]Playlist [b]3:[/b]Browse [b]4:[/b]Search", 1); + wHeader->WriteXY(0, 0, "[b]1:[/b]Help [b]2:[/b]Playlist [b]3:[/b]Browse [b]4:[/b]Search [b]5:[/b]Library", 1); wHeader->SetColor(Config.volume_color); wHeader->WriteXY(max_allowed_title_length, 0, volume_state); @@ -322,22 +350,105 @@ int main(int argc, char *argv[]) } } + if (current_screen == csLibrary && !block_library_update) + { + MpdData *data; + + if (wCurrent == mLibAlbums && mLibAlbums->Empty()) + wCurrent = mLibArtists; + + if (wCurrent == mLibArtists) + { + mLibAlbums->Clear(); + data = mpd_database_get_albums(conn, (char *) mLibArtists->GetCurrentOption().c_str()); + FOR_EACH_MPD_DATA(data) + mLibAlbums->AddOption(data->tag); + mpd_data_free(data); + + if (mLibAlbums->Empty()) + { + mLibAlbums->WriteXY(0, 0, "No albums found."); + vSongs.clear(); + mLibSongs->Clear(); + mpd_database_search_start(conn, 1); + mpd_database_search_add_constraint(conn, MPD_TAG_ITEM_ARTIST, mLibArtists->GetCurrentOption().c_str()); + mpd_database_search_add_constraint(conn, MPD_TAG_ITEM_ALBUM, mLibAlbums->GetCurrentOption().c_str()); + data = mpd_database_search_commit(conn); + FOR_EACH_MPD_DATA(data) + vSongs.push_back(data->song); + mpd_data_free(data); + } + } + + vSongs.clear(); + mLibSongs->Clear(0); + mpd_database_search_start(conn, 1); + mpd_database_search_add_constraint(conn, MPD_TAG_ITEM_ARTIST, mLibArtists->GetCurrentOption().c_str()); + mpd_database_search_add_constraint(conn, MPD_TAG_ITEM_ALBUM, mLibAlbums->GetCurrentOption().c_str()); + data = mpd_database_search_commit(conn); + FOR_EACH_MPD_DATA(data) + vSongs.push_back(data->song); + mpd_data_free(data); + + sort(vSongs.begin(), vSongs.end(), SortSongsByTrack); + + bool bold = 0; + for (vector::const_iterator it = vSongs.begin(); it != vSongs.end(); it++) + { + for (vector::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++) + { + if (it->GetFile() == j->GetFile()) + { + bold = 1; + break; + } + } + bold ? mLibSongs->AddBoldOption(DisplaySong(*it, Config.song_library_format)) : mLibSongs->AddOption(DisplaySong(*it, Config.song_library_format)); + bold = 0; + } + mLibAlbums->Refresh(); + mLibSongs->Hide(); + mLibSongs->Display(); + + block_library_update = 1; + } + wCurrent->Refresh(); wCurrent->ReadKey(input); if (input == ERR) continue; + if (current_screen == csLibrary) + block_library_update = 0; + title_allowed = 1; timer = time(NULL); - if (current_screen == csPlaylist) + switch (current_screen) { - mPlaylist->Highlighting(1); - mPlaylist->Refresh(); + case csPlaylist: + mPlaylist->Highlighting(1); + mPlaylist->Refresh(); + break; + + case csBrowser: + browsed_dir_scroll_begin--; + break; + case csLibrary: + { + if (input == KEY_UP || input == KEY_DOWN || input == KEY_PPAGE || input == KEY_NPAGE || input == KEY_HOME || input == KEY_END) + { + if (wCurrent == mLibArtists) + { mLibAlbums->Reset(); + mLibSongs->Reset(); + } + if (wCurrent == mLibAlbums) + mLibSongs->Reset(); + } + break; + } } - if (current_screen == csBrowser) - browsed_dir_scroll_begin--; switch (input) { @@ -381,6 +492,19 @@ int main(int argc, char *argv[]) mTagEditor->Resize(COLS, main_height); mSearcher->Resize(COLS, main_height); + lib_artist_width = COLS/3-1; + lib_albums_start_x = lib_artist_width+1; + lib_albums_width = COLS/3; + lib_songs_start_x = lib_artist_width+lib_albums_width+2; + lib_songs_width = COLS-COLS/3*2-1; + + mLibArtists->Resize(lib_artist_width, main_height); + mLibAlbums->Resize(lib_albums_width, main_height); + mLibSongs->Resize(lib_songs_width, main_height); + + mLibAlbums->MoveTo(lib_albums_start_x, main_start_y); + mLibSongs->MoveTo(lib_songs_start_x, main_start_y); + if (Config.header_visibility) wHeader->Resize(COLS, wHeader->GetHeight()); @@ -391,6 +515,17 @@ int main(int argc, char *argv[]) if (wCurrent != sHelp) wCurrent->Hide(); wCurrent->Display(); + if (current_screen == csLibrary) + { + mLibArtists->Hide(); + mLibArtists->Display(); + mvvline(main_start_y, lib_albums_start_x-1, 0, main_height); + mLibAlbums->Hide(); + mLibAlbums->Display(); + mvvline(main_start_y, lib_songs_start_x-1, 0, main_height); + mLibSongs->Hide(); + mLibSongs->Display(); + } header_update_status = 1; int mpd_state = mpd_player_get_state(conn); @@ -592,17 +727,26 @@ int main(int argc, char *argv[]) } case 9: { +# endif // HAVE_TAGLIB_H wCurrent->Clear(); wCurrent = wPrev; current_screen = prev_screen; + if (current_screen == csLibrary) + { + mLibSongs->HighlightColor(Config.main_color); + mLibArtists->HighlightColor(Config.library_active_column_color); + wCurrent = mLibArtists; + mLibArtists->Display(); + mvvline(main_start_y, lib_albums_start_x-1, 0, main_height); + mLibAlbums->Display(); + mvvline(main_start_y, lib_songs_start_x-1, 0, main_height); + mLibSongs->Display(); + } +# ifdef HAVE_TAGLIB_H break; } } UNBLOCK_STATUSBAR_UPDATE; -# else - wCurrent->Clear(); - wCurrent = wPrev; - current_screen = prev_screen; # endif // HAVE_TAGLIB_H break; } @@ -766,6 +910,80 @@ int main(int argc, char *argv[]) UNBLOCK_STATUSBAR_UPDATE; break; } + case csLibrary: + { + Start_Point_For_KEY_SPACE: // same code for KEY_SPACE, but without playing. + + MpdData *data; + + if (wCurrent == mLibArtists) + { + const string &artist = mLibArtists->GetCurrentOption(); + ShowMessage("Adding all songs artist's: " + artist); + mpd_database_search_start(conn, 1); + mpd_database_search_add_constraint(conn, MPD_TAG_ITEM_ARTIST, (char *) artist.c_str()); + data = mpd_database_search_commit(conn); + int howmany = 0; + FOR_EACH_MPD_DATA(data) + { + howmany++; + mpd_playlist_queue_add(conn, data->song->file); + } + mpd_data_free(data); + mpd_playlist_queue_commit(conn); + if (input == ENTER) + { + int new_id; + try + { + new_id = vPlaylist.at(mPlaylist->MaxChoice()-howmany).GetID(); + } + catch (std::out_of_range) + { + new_id = -1; + } + if (new_id >= 0) + mpd_player_play_id(conn, new_id); + } + } + + if (wCurrent == mLibAlbums) + { + int howmany = 0; + ShowMessage("Adding songs from album: " + mLibAlbums->GetCurrentOption()); + for (vector::const_iterator it = vSongs.begin(); it != vSongs.end(); it++, howmany++) + mpd_playlist_queue_add(conn, (char *) it->GetFile().c_str()); + mpd_playlist_queue_commit(conn); + if (input == ENTER) + { + int new_id; + try + { + new_id = vPlaylist.at(mPlaylist->MaxChoice()-howmany).GetID(); + } + catch (std::out_of_range) + { + new_id = -1; + } + if (new_id >= 0) + mpd_player_play_id(conn, new_id); + } + } + + if (wCurrent == mLibSongs) + { + Song &s = vSongs[mLibSongs->GetChoice()-1]; + ShowMessage("Added to playlist: " + OmitBBCodes(DisplaySong(s))); + mpd_playlist_add(conn, (char *) s.GetFile().c_str()); + if (input == ENTER) + mpd_player_play_id(conn, vPlaylist.back().GetID()); + } + + if (input == KEY_SPACE) + wCurrent->Go(DOWN); + + break; + } } break; } @@ -830,14 +1048,64 @@ int main(int argc, char *argv[]) ShowMessage("Error adding file!"); } } + if (current_screen == csLibrary) + goto Start_Point_For_KEY_SPACE; // sorry, but that's stupid to copy the same code here. break; } - case KEY_RIGHT: case '+': // volume up + case KEY_RIGHT: + { + if (current_screen == csLibrary) + { + if (wCurrent == mLibArtists) + { + mLibArtists->HighlightColor(Config.main_color); + wCurrent->Refresh(); + wCurrent = mLibAlbums; + mLibAlbums->HighlightColor(Config.library_active_column_color); + if (!mLibAlbums->Empty()) + break; + } + if (wCurrent == mLibAlbums) + { + mLibAlbums->HighlightColor(Config.main_color); + wCurrent->Refresh(); + wCurrent = mLibSongs; + mLibSongs->HighlightColor(Config.library_active_column_color); + break; + } + break; + } + } + case '+': // volume up { mpd_status_set_volume(conn, mpd_status_get_volume(conn)+1); break; } - case KEY_LEFT: case '-': //volume down + case KEY_LEFT: + { + if (current_screen == csLibrary) + { + if (wCurrent == mLibSongs) + { + mLibSongs->HighlightColor(Config.main_color); + wCurrent->Refresh(); + wCurrent = mLibAlbums; + mLibAlbums->HighlightColor(Config.library_active_column_color); + if (!mLibAlbums->Empty()) + break; + } + if (wCurrent == mLibAlbums) + { + mLibAlbums->HighlightColor(Config.main_color); + wCurrent->Refresh(); + wCurrent = mLibArtists; + mLibArtists->HighlightColor(Config.library_active_column_color); + break; + } + break; + } + } + case '-': //volume down { mpd_status_set_volume(conn, mpd_status_get_volume(conn)-1); break; @@ -860,10 +1128,6 @@ int main(int argc, char *argv[]) id = mPlaylist->GetChoice()-1; mpd_playlist_queue_delete_pos(conn, id); - for (vector::iterator it = vPlaylist.begin()+id; it != vPlaylist.end(); it++) - it->SetPosition(it->GetPosition()-1); - if (now_playing > id) - now_playing--; vPlaylist.erase(vPlaylist.begin()+id); mPlaylist->DeleteOption(id+1); mPlaylist->Refresh(); @@ -1108,6 +1372,19 @@ int main(int argc, char *argv[]) } break; } + case csLibrary: + { + if (!vSongs.empty() && wCurrent == mLibSongs) + { + if (GetSongInfo(vSongs[id])) + { + wPrev = wCurrent; + wCurrent = mTagEditor; + current_screen = csTagEditor; + prev_screen = csLibrary; + } + } + } default: break; } @@ -1138,8 +1415,8 @@ int main(int argc, char *argv[]) { if (wCurrent != sHelp) { - wCurrent->Hide(); wCurrent = sHelp; + wCurrent->Hide(); current_screen = csHelp; } break; @@ -1148,8 +1425,8 @@ int main(int argc, char *argv[]) { if (wCurrent != mPlaylist && current_screen != csTagEditor) { - wCurrent->Hide(); wCurrent = mPlaylist; + wCurrent->Hide(); current_screen = csPlaylist; } break; @@ -1161,8 +1438,8 @@ int main(int argc, char *argv[]) if (wCurrent != mBrowser && current_screen != csTagEditor) { - wCurrent->Hide(); wCurrent = mBrowser; + wCurrent->Hide(); current_screen = csBrowser; } if (mBrowser->Empty()) @@ -1173,14 +1450,49 @@ int main(int argc, char *argv[]) { if (current_screen != csTagEditor && current_screen != csSearcher) { - wCurrent->Hide(); if (vSearched.empty()) PrepareSearchEngine(searched_song); wCurrent = mSearcher; + wCurrent->Hide(); current_screen = csSearcher; } break; } + case '5': // artist library + { + if (current_screen != csLibrary) + { + if (mLibArtists->Empty()) + { + MpdData *data = mpd_database_get_artists(conn); + + FOR_EACH_MPD_DATA(data) + vArtists.push_back(data->tag); + mpd_data_free(data); + + sort(vArtists.begin(), vArtists.end(), CaseInsensitiveComparison); + + for (vector::const_iterator it = vArtists.begin(); it != vArtists.end(); it++) + mLibArtists->AddOption(*it); + } + + mLibArtists->HighlightColor(Config.library_active_column_color); + mLibAlbums->HighlightColor(Config.main_color); + mLibSongs->HighlightColor(Config.main_color); + + wCurrent->Hide(); + + mLibArtists->Display(); + mvvline(main_start_y, lib_albums_start_x-1, 0, main_height); + mLibAlbums->Display(); + mvvline(main_start_y, lib_songs_start_x-1, 0, main_height); + mLibSongs->Display(); + + wCurrent = mLibArtists; + current_screen = csLibrary; + } + break; + } case 'q': case 'Q': main_exit = 1; default: continue; diff --git a/src/ncmpcpp.h b/src/ncmpcpp.h index ff0f66b3..d92a7033 100644 --- a/src/ncmpcpp.h +++ b/src/ncmpcpp.h @@ -55,7 +55,7 @@ const bool UNICODE = 0; #include "scrollpad.h" #include "misc.h" -enum CurrScreen { csHelp, csPlaylist, csBrowser, csTagEditor, csSearcher }; +enum CurrScreen { csHelp, csPlaylist, csBrowser, csTagEditor, csSearcher, csLibrary }; const int ncmpcpp_window_timeout = 500; const int search_engine_static_option = 17; diff --git a/src/settings.cpp b/src/settings.cpp index 05668c01..b688250f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -30,6 +30,7 @@ void DefaultConfiguration(ncmpcpp_config &conf) conf.song_list_format = "[green](%l)[/green] {%a - }{%t}|{[white]%f[/white]}"; conf.song_status_format = "(%l) {%a - }{%t}|{%f}"; conf.song_window_title_format = "{%a - }{%t}|{%f}"; + conf.song_library_format = "{%n - }{%t}|{%f}"; conf.empty_tags_color = clCyan; conf.header_color = clDefault; conf.volume_color = clDefault; @@ -38,10 +39,11 @@ void DefaultConfiguration(ncmpcpp_config &conf) conf.main_color = clYellow; conf.progressbar_color = clDefault; conf.statusbar_color = clDefault; + conf.library_active_column_color = clRed; conf.header_visibility = true; conf.statusbar_visibility = true; conf.set_window_title = true; - conf.mpd_connection_timeout = 5; + conf.mpd_connection_timeout = 60; conf.crossfade_time = 5; conf.playlist_disable_highlight_delay = 5; conf.message_delay_time = 4; @@ -163,6 +165,10 @@ void ReadConfiguration(ncmpcpp_config &conf) if (!v.empty()) conf.song_status_format = v; + if (it->find("song_library_format") != string::npos) + if (!v.empty()) + conf.song_library_format = v; + if (it->find("header_visibility") != string::npos) conf.header_visibility = v == "yes"; @@ -204,6 +210,10 @@ void ReadConfiguration(ncmpcpp_config &conf) if (it->find("statusbar_color") != string::npos) if (!v.empty()) conf.statusbar_color = IntoColor(v); + + if (it->find("library_active_column_color") != string::npos) + if (!v.empty()) + conf.library_active_column_color = IntoColor(v); } f.close(); } diff --git a/src/settings.h b/src/settings.h index af2638e7..cd06237d 100644 --- a/src/settings.h +++ b/src/settings.h @@ -33,6 +33,7 @@ struct ncmpcpp_config string song_list_format; string song_status_format; string song_window_title_format; + string song_library_format; COLOR empty_tags_color; COLOR header_color; @@ -42,6 +43,7 @@ struct ncmpcpp_config COLOR main_color; COLOR progressbar_color; COLOR statusbar_color; + COLOR library_active_column_color; bool set_window_title; bool header_visibility; diff --git a/src/song.cpp b/src/song.cpp index 206feb7d..fc25d82d 100644 --- a/src/song.cpp +++ b/src/song.cpp @@ -145,7 +145,7 @@ string Song::GetAlbum() const string Song::GetTrack() const { - return itsGetEmptyFields ? (itsTrack.empty() ? "" : itsTrack) : (itsTrack.empty() ? EMPTY_TAG : itsTrack); + return itsGetEmptyFields ? (itsTrack.empty() ? "" : (StrToInt(itsTrack) < 10 && itsTrack[0] != '0' ? "0"+itsTrack : itsTrack)) : (itsTrack.empty() ? EMPTY_TAG : (StrToInt(itsTrack) < 10 && itsTrack[0] != '0' ? "0"+itsTrack : itsTrack)); } string Song::GetYear() const diff --git a/src/status_checker.cpp b/src/status_checker.cpp index 5f485e41..01faab05 100644 --- a/src/status_checker.cpp +++ b/src/status_checker.cpp @@ -33,7 +33,9 @@ extern Menu *mPlaylist; extern Menu *mBrowser; extern Menu *wCurrent; extern Menu *mSearcher; - +extern Menu *mLibArtists; +extern Menu *mLibAlbums; +extern Menu *mLibSongs; extern Window *wHeader; extern Window *wFooter; @@ -70,6 +72,7 @@ extern bool allow_statusbar_unblock; extern bool block_progressbar_update; extern bool block_statusbar_update; extern bool block_playlist_update; +extern bool block_library_update; int old_playing; @@ -141,7 +144,7 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what) { if (playlist_length < vPlaylist.size()) { - mPlaylist->Clear(!playlist_length); + mPlaylist->Clear(!playlist_length && current_screen != csLibrary); vPlaylist.clear(); } @@ -206,8 +209,13 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what) if (vFileType[i] == MPD_DATA_TYPE_SONG) { for (vector::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++) + { if (it->GetFile() == vNameList[i]) + { bold = 1; + break; + } + } mBrowser->BoldOption(i+1, bold); bold = 0; } @@ -220,15 +228,24 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what) for (vector::const_iterator it = vSearched.begin(); it != vSearched.end(); it++, i++) { for (vector::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++) - if (j->GetFile() == it->GetFile()) - bold = 1; - mSearcher->BoldOption(i+1, bold); - bold = 0; + { + if (j->GetFile() == it->GetFile()) + { + bold = 1; + break; + } + } + mSearcher->BoldOption(i+1, bold); + bold = 0; } } + block_library_update = 0; } if(what & MPD_CST_DATABASE) + { GetDirectory(browsed_dir); + block_library_update = 0; + } if (what & MPD_CST_STATE) { int mpd_state = mpd_player_get_state(conn); diff --git a/src/window.cpp b/src/window.cpp index 501283ea..72169929 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -169,7 +169,7 @@ void Window::Resize(int width, int height) height -= 2; } if (!itsTitle.empty()) - width -= 2; + height -= 2; if (height > 0 && width > 0 && wresize(itsWindow, height, width) == OK) { @@ -188,12 +188,10 @@ void Window::show_border() const if (!itsTitle.empty()) { if (itsBorder != brNone) - { attron(COLOR_PAIR(itsBorder)); - mvhline(itsStartY-1, itsStartX, 0, itsWidth); - } else attron(COLOR_PAIR(itsBaseColor)); + mvhline(itsStartY-1, itsStartX, 0, itsWidth); attron(A_BOLD); mvaddstr(itsStartY-2, itsStartX, itsTitle.c_str()); attroff(COLOR_PAIR(itsBorder) | A_BOLD); @@ -263,7 +261,7 @@ void Window::ReadKey() const void Window::Write(const string &str, CLEAR_TO_EOL clrtoeol) { - if (BBEnabled) + if (BBEnabled && !str.empty()) { bool collect = false; string color, tmp;