From 8ba72bc78ae92d1ed5b4cdfb81e4879680362961 Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Fri, 13 Feb 2009 17:24:06 +0100 Subject: [PATCH] separate some code from ncmpcpp.cpp --- src/Makefile.am | 11 +- src/browser.cpp | 185 ++++ src/browser.h | 10 + src/clock.cpp | 85 +- src/clock.h | 14 +- src/display.h | 11 + src/global.h | 17 +- src/help.cpp | 150 +-- src/help.h | 7 +- src/helpers.cpp | 61 +- src/helpers.h | 7 +- src/info.cpp | 451 +++++++++ src/info.h | 41 + src/lyrics.cpp | 362 +++---- src/lyrics.h | 13 +- src/media_library.cpp | 356 +++++++ src/media_library.h | 44 + src/misc.cpp | 49 + src/misc.h | 4 + src/ncmpcpp.cpp | 1988 ++++----------------------------------- src/ncmpcpp.h | 14 + src/playlist.cpp | 64 ++ src/playlist.h | 32 + src/playlist_editor.cpp | 244 +++++ src/playlist_editor.h | 44 + src/search_engine.cpp | 255 ++++- src/search_engine.h | 14 +- src/tag_editor.cpp | 572 +++++++++++ src/tag_editor.h | 19 + 29 files changed, 2956 insertions(+), 2168 deletions(-) create mode 100644 src/info.cpp create mode 100644 src/info.h create mode 100644 src/media_library.cpp create mode 100644 src/media_library.h create mode 100644 src/playlist.cpp create mode 100644 src/playlist.h create mode 100644 src/playlist_editor.cpp create mode 100644 src/playlist_editor.h diff --git a/src/Makefile.am b/src/Makefile.am index bd461d76..e2d44616 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,8 +1,8 @@ bin_PROGRAMS = ncmpcpp ncmpcpp_SOURCES = browser.cpp charset.cpp clock.cpp display.cpp help.cpp \ - helpers.cpp libmpdclient.c lyrics.cpp misc.cpp mpdpp.cpp ncmpcpp.cpp scrollpad.cpp \ - search_engine.cpp settings.cpp song.cpp status_checker.cpp str_pool.c tag_editor.cpp \ - window.cpp + helpers.cpp info.cpp libmpdclient.c lyrics.cpp media_library.cpp misc.cpp mpdpp.cpp \ + ncmpcpp.cpp playlist.cpp playlist_editor.cpp scrollpad.cpp search_engine.cpp \ + settings.cpp song.cpp status_checker.cpp str_pool.c tag_editor.cpp window.cpp # set the include path found by configure INCLUDES= $(all_includes) @@ -10,5 +10,6 @@ INCLUDES= $(all_includes) # the library search path. ncmpcpp_LDFLAGS = $(all_libraries) noinst_HEADERS = browser.h charset.h clock.h display.h global.h help.h \ - helpers.h lyrics.h menu.h mpdpp.h scrollpad.h search_engine.h settings.h song.h \ - status_checker.h tag_editor.h window.h + helpers.h info.h lyrics.h media_library.h menu.h mpdpp.h playlist_editor.h \ + scrollpad.h search_engine.h settings.h song.h status_checker.h tag_editor.h \ + window.h diff --git a/src/browser.cpp b/src/browser.cpp index 290e8c87..19b3fa1c 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -28,6 +28,7 @@ #include "global.h" #include "helpers.h" #include "settings.h" +#include "status_checker.h" #ifdef HAVE_TAGLIB_H # include "tag_editor.h" #endif // HAVE_TAGLIB_H @@ -36,6 +37,190 @@ using namespace Global; using namespace MPD; using std::string; +Menu *Global::mBrowser; + +void Browser::Init() +{ + mBrowser = new Menu(0, main_start_y, COLS, main_height, "", Config.main_color, brNone); + mBrowser->HighlightColor(Config.main_highlight_color); + mBrowser->SetTimeout(ncmpcpp_window_timeout); + mBrowser->SetSelectPrefix(&Config.selected_item_prefix); + mBrowser->SetSelectSuffix(&Config.selected_item_suffix); + mBrowser->SetItemDisplayer(Display::Items); +} + +void Browser::Resize() +{ + mBrowser->Resize(COLS, main_height); +} + +void Browser::SwitchTo() +{ + if (current_screen != csBrowser +# ifdef HAVE_TAGLIB_H + && current_screen != csTinyTagEditor +# endif // HAVE_TAGLIB_H + ) + { + CLEAR_FIND_HISTORY; + mBrowser->Empty() ? GetDirectory(browsed_dir) : UpdateItemList(mBrowser); + wCurrent = mBrowser; + wCurrent->Hide(); + current_screen = csBrowser; +// redraw_screen = 1; + redraw_header = 1; + } +} + +void Browser::EnterPressed() +{ + if (mBrowser->Empty()) + return; + + const Item &item = mBrowser->Current(); + switch (item.type) + { + case itDirectory: + { + CLEAR_FIND_HISTORY; + GetDirectory(item.name, browsed_dir); + redraw_header = 1; + break; + } + case itSong: + { + block_item_list_update = 1; + if (Config.ncmpc_like_songs_adding && mBrowser->isBold()) + { + bool found = 0; + long long hash = mBrowser->Current().song->GetHash(); + for (size_t i = 0; i < mPlaylist->Size(); i++) + { + if (mPlaylist->at(i).GetHash() == hash) + { + Mpd->Play(i); + found = 1; + break; + } + } + if (found) + break; + } + Song &s = *item.song; + int id = Mpd->AddSong(s); + if (id >= 0) + { + Mpd->PlayID(id); + ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str()); + mBrowser->BoldOption(mBrowser->Choice(), 1); + } + break; + } + case itPlaylist: + { + SongList list; + Mpd->GetPlaylistContent(locale_to_utf_cpy(item.name), list); + for (SongList::const_iterator it = list.begin(); it != list.end(); it++) + Mpd->QueueAddSong(**it); + if (Mpd->CommitQueue()) + { + ShowMessage("Loading and playing playlist %s...", item.name.c_str()); + Song *s = &mPlaylist->at(mPlaylist->Size()-list.size()); + if (s->GetHash() == list[0]->GetHash()) + Mpd->PlayID(s->GetID()); + else + ShowMessage("%s", message_part_of_songs_added); + } + FreeSongList(list); + break; + } + } +} + +void Browser::SpacePressed() +{ + if (mBrowser->Empty()) + return; + + const Item &item = mBrowser->Current(); + switch (item.type) + { + case itDirectory: + { + if (browsed_dir != "/" && !mBrowser->Choice()) + break; // do not let add parent dir. + + if (Config.local_browser) + { + ShowMessage("Adding whole directories from local browser is not supported!"); + break; + } + + SongList list; + Mpd->GetDirectoryRecursive(locale_to_utf_cpy(item.name), list); + + for (SongList::const_iterator it = list.begin(); it != list.end(); it++) + Mpd->QueueAddSong(**it); + if (Mpd->CommitQueue()) + { + ShowMessage("Added folder: %s", item.name.c_str()); + Song &s = mPlaylist->at(mPlaylist->Size()-list.size()); + if (s.GetHash() != list[0]->GetHash()) + ShowMessage("%s", message_part_of_songs_added); + } + FreeSongList(list); + break; + } + case itSong: + { + block_item_list_update = 1; + if (Config.ncmpc_like_songs_adding && mBrowser->isBold()) + { + block_playlist_update = 1; + long long hash = mBrowser->Current().song->GetHash(); + for (size_t i = 0; i < mPlaylist->Size(); i++) + { + if (mPlaylist->at(i).GetHash() == hash) + { + Mpd->QueueDeleteSong(i); + mPlaylist->DeleteOption(i); + i--; + } + } + Mpd->CommitQueue(); + mBrowser->BoldOption(mBrowser->Choice(), 0); + } + else + { + Song &s = *item.song; + if (Mpd->AddSong(s) != -1) + { + ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str()); + mBrowser->BoldOption(mBrowser->Choice(), 1); + } + } + break; + } + case itPlaylist: + { + SongList list; + Mpd->GetPlaylistContent(locale_to_utf_cpy(item.name), list); + for (SongList::const_iterator it = list.begin(); it != list.end(); it++) + Mpd->QueueAddSong(**it); + if (Mpd->CommitQueue()) + { + ShowMessage("Loading playlist %s...", item.name.c_str()); + Song &s = mPlaylist->at(mPlaylist->Size()-list.size()); + if (s.GetHash() != list[0]->GetHash()) + ShowMessage("%s", message_part_of_songs_added); + } + FreeSongList(list); + break; + } + } + mBrowser->Scroll(wDown); +} + namespace { const char *supported_extensions[] = { "wma", "asf", "rm", "mp1", "mp2", "mp3", "mp4", "m4a", "flac", "ogg", "wav", "au", "aiff", "aif", "ac3", "aac", "mpc", "it", "mod", "s3m", "xm", "wv", 0 }; diff --git a/src/browser.h b/src/browser.h index dd3e9142..521f3bb9 100644 --- a/src/browser.h +++ b/src/browser.h @@ -24,6 +24,16 @@ #include "mpdpp.h" #include "ncmpcpp.h" +namespace Browser +{ + void Init(); + void Resize(); + void SwitchTo(); + + void EnterPressed(); + void SpacePressed(); +} + void UpdateItemList(Menu *); void GetDirectory(std::string, std::string = "/"); diff --git a/src/clock.cpp b/src/clock.cpp index 22d7ecff..88f549de 100644 --- a/src/clock.cpp +++ b/src/clock.cpp @@ -21,12 +21,17 @@ /// NOTICE: Major part of this code is ported from ncmpc's clock screen #include "clock.h" -#include "display.h" -#include "global.h" #ifdef ENABLE_CLOCK +#include "display.h" +#include "global.h" #include "settings.h" +#include "status_checker.h" + +using namespace Global; + +Scrollpad *Global::wClock; namespace { @@ -52,14 +57,47 @@ namespace } } -void InitClock() +namespace Clock +{ + const size_t width = Config.clock_display_seconds ? 60 : 40; + const size_t height = 8; +} + +void Clock::Init() +{ + wClock = new Scrollpad((COLS-width)/2, (LINES-height)/2, width, height-1, "", Config.main_color, Border(Config.main_color)); + wClock->SetTimeout(ncmpcpp_window_timeout); +} + +void Clock::Resize() +{ + if (width <= size_t(COLS) && height <= main_height) + { + wClock->MoveTo((COLS-width)/2, (LINES-height)/2); + if (current_screen == csClock) + { + mPlaylist->Hide(); + Prepare(); + wClock->Display(); + } + } +} + +void Clock::Prepare() { for (int i = 0; i < 5; i++) older[i] = newer[i] = next[i] = 0; } -void Display::Clock(Window &w, const tm *time) +void Clock::Update() { + if (width > size_t(COLS) || height > main_height) + return; + + time_t rawtime; + time(&rawtime); + tm *time = localtime(&rawtime); + mask = 0; set(time->tm_sec % 10, 0); set(time->tm_sec / 10, 4); @@ -72,9 +110,9 @@ void Display::Clock(Window &w, const tm *time) char buf[54]; strftime(buf, 64, "%x", time); - attron(COLOR_PAIR(Global::Config.main_color)); - mvprintw(w.GetStartY()+w.GetHeight(), w.GetStartX()+(w.GetWidth()-strlen(buf))/2, "%s", buf); - attroff(COLOR_PAIR(Global::Config.main_color)); + attron(COLOR_PAIR(Config.main_color)); + mvprintw(wCurrent->GetStartY()+wCurrent->GetHeight(), wCurrent->GetStartX()+(wCurrent->GetWidth()-strlen(buf))/2, "%s", buf); + attroff(COLOR_PAIR(Config.main_color)); refresh(); for (int k = 0; k < 6; k++) @@ -83,7 +121,7 @@ void Display::Clock(Window &w, const tm *time) next[k] = 0; for (int s = 1; s >= 0; s--) { - w.Reverse(s); + wCurrent->Reverse(s); for (int i = 0; i < 6; i++) { long a = (newer[i] ^ older[i]) & (s ? newer : older)[i]; @@ -96,10 +134,10 @@ void Display::Clock(Window &w, const tm *time) { if (!(a & (t << 1))) { - w.GotoXY(2*j+2, i); + wCurrent->GotoXY(2*j+2, i); } if (Global::Config.clock_display_seconds || j < 18) - w << " "; + *wCurrent << " "; } } } @@ -108,13 +146,32 @@ void Display::Clock(Window &w, const tm *time) older[i] = newer[i]; } } - if (!s) - { - w.Refresh(); - } } } } +void Clock::SwitchTo() +{ + if (width > size_t(COLS) || height > main_height) + { + ShowMessage("Screen is too small to display clock!"); + } + else if ( + current_screen != csClock +# ifdef HAVE_TAGLIB_H + && current_screen != csTinyTagEditor +# endif // HAVE_TAGLIB_H + ) + { + CLEAR_FIND_HISTORY; + wCurrent = wClock; + mPlaylist->Hide(); + current_screen = csClock; + redraw_header = 1; + Clock::Prepare(); + wCurrent->Display(); + } +} + #endif // ENABLE_CLOCK diff --git a/src/clock.h b/src/clock.h index f62d80a8..b86cd3fe 100644 --- a/src/clock.h +++ b/src/clock.h @@ -27,11 +27,19 @@ #ifdef ENABLE_CLOCK -#include - #include "window.h" -void InitClock(); +namespace Clock +{ + void Init(); + void Resize(); + void SwitchTo(); + + void Update(); + void Prepare(); +} + +#include #endif // ENABLE_CLOCK diff --git a/src/display.h b/src/display.h index 06c2227f..96a51164 100644 --- a/src/display.h +++ b/src/display.h @@ -51,5 +51,16 @@ namespace Display void Clock(Window &, const tm *); } +namespace Refresh +{ + void MediaLibrary(); + + void PlaylistEditor(); + +# ifdef HAVE_TAGLIB_H + void TagEditor(); +# endif +} + #endif diff --git a/src/global.h b/src/global.h index 2c67df31..e9d91bbb 100644 --- a/src/global.h +++ b/src/global.h @@ -49,11 +49,10 @@ namespace Global extern Menu *mTagEditor; extern Menu *mEditorAlbums; extern Menu *mEditorDirs; -# endif // HAVE_TAGLIB_H - // blah, I use below in conditionals. extern Menu *mEditorLeftCol; extern Menu *mEditorTagTypes; extern Menu *mEditorTags; +# endif // HAVE_TAGLIB_H extern Window *wPlaylistEditorActiveCol; extern Menu *mPlaylistList; @@ -75,21 +74,22 @@ namespace Global extern int lock_statusbar_delay; extern size_t browsed_dir_scroll_begin; + extern size_t main_start_y; + extern size_t main_height; + extern size_t lyrics_scroll_begin; extern time_t timer; extern std::string browsed_dir; extern std::string editor_browsed_dir; extern std::string editor_highlighted_dir; + extern std::string info_title; extern NcmpcppScreen current_screen; extern NcmpcppScreen prev_screen; # ifdef HAVE_CURL_CURL_H - extern pthread_t lyrics_downloader; - extern pthread_t artist_info_downloader; - extern bool lyrics_ready; - extern bool artist_info_ready; + extern pthread_mutex_t curl; # endif extern bool dont_change_now_playing; @@ -113,6 +113,11 @@ namespace Global extern const char *search_mode_normal; extern const char *search_mode_strict; + + extern std::vector vFoundPositions; + extern int found_pos; + + extern MPD::Song lyrics_song; } #endif diff --git a/src/help.cpp b/src/help.cpp index 5fe59305..1cc5507d 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -24,71 +24,104 @@ #include "help.h" #include "settings.h" -using Global::Key; -using Global::Mpd; +using namespace Global; using std::string; +Scrollpad *Global::sHelp; + namespace { - string DisplayKeys(int *key, int size = 2) + void GetKeybindings(Scrollpad &help); +} + +void Help::Init() +{ + sHelp = new Scrollpad(0, main_start_y, COLS, main_height, "", Config.main_color, brNone); + sHelp->SetTimeout(ncmpcpp_window_timeout); + GetKeybindings(*sHelp); + sHelp->Flush(); +} + +void Help::Resize() +{ + sHelp->Resize(COLS, main_height); +} + +void Help::SwitchTo() +{ + if (current_screen != csHelp +# ifdef HAVE_TAGLIB_H + && current_screen != csTinyTagEditor +# endif // HAVE_TAGLIB_H + ) { - bool backspace = 1; - string result = "\t"; - for (int i = 0; i < size; i++) - { - if (key[i] == null_key); - else if (key[i] == 259) - result += "Up"; - else if (key[i] == 258) - result += "Down"; - else if (key[i] == 339) - result += "Page Up"; - else if (key[i] == 338) - result += "Page Down"; - else if (key[i] == 262) - result += "Home"; - else if (key[i] == 360) - result += "End"; - else if (key[i] == 32) - result += "Space"; - else if (key[i] == 10) - result += "Enter"; - else if (key[i] == 330) - result += "Delete"; - else if (key[i] == 261) - result += "Right"; - else if (key[i] == 260) - result += "Left"; - else if (key[i] == 9) - result += "Tab"; - else if (key[i] >= 1 && key[i] <= 26) - { - result += "Ctrl-"; - result += key[i]+64; - } - else if (key[i] >= 265 && key[i] <= 276) - { - result += "F"; - result += IntoStr(key[i]-264); - } - else if ((key[i] == 263 || key[i] == 127) && !backspace); - else if ((key[i] == 263 || key[i] == 127) && backspace) - { - result += "Backspace"; - backspace = 0; - } - else - result += key[i]; - result += " "; - } - if (result.length() > 12) - result = result.substr(0, 12); - for (size_t i = result.length(); i <= 12; result += " ", i++) { } - result += ": "; - return result; + wCurrent = sHelp; + wCurrent->Hide(); + current_screen = csHelp; + redraw_header = 1; } } +namespace { + +string DisplayKeys(int *key, int size = 2) +{ + bool backspace = 1; + string result = "\t"; + for (int i = 0; i < size; i++) + { + if (key[i] == null_key); + else if (key[i] == 259) + result += "Up"; + else if (key[i] == 258) + result += "Down"; + else if (key[i] == 339) + result += "Page Up"; + else if (key[i] == 338) + result += "Page Down"; + else if (key[i] == 262) + result += "Home"; + else if (key[i] == 360) + result += "End"; + else if (key[i] == 32) + result += "Space"; + else if (key[i] == 10) + result += "Enter"; + else if (key[i] == 330) + result += "Delete"; + else if (key[i] == 261) + result += "Right"; + else if (key[i] == 260) + result += "Left"; + else if (key[i] == 9) + result += "Tab"; + else if (key[i] >= 1 && key[i] <= 26) + { + result += "Ctrl-"; + result += key[i]+64; + } + else if (key[i] >= 265 && key[i] <= 276) + { + result += "F"; + result += IntoStr(key[i]-264); + } + else if ((key[i] == 263 || key[i] == 127) && !backspace); + else if ((key[i] == 263 || key[i] == 127) && backspace) + { + result += "Backspace"; + backspace = 0; + } + else + result += key[i]; + result += " "; + } + if (result.length() > 12) + result = result.substr(0, 12); + for (size_t i = result.length(); i <= 12; result += " ", i++) { } + result += ": "; + return result; +} + void GetKeybindings(Scrollpad &help) { help << " " << fmtBold << "Keys - Movement\n -----------------------------------------\n" << fmtBoldEnd; @@ -193,7 +226,7 @@ void GetKeybindings(Scrollpad &help) help << DisplayKeys(Key.Space) << "Add to playlist song/album/artist's songs\n"; help << DisplayKeys(Key.SwitchTagTypeList) << "Tag type list switcher (left column)\n\n\n"; - help << " " << fmtBold << "Keys - Playlist Editorz\n -----------------------------------------\n" << fmtBoldEnd; + help << " " << fmtBold << "Keys - Playlist Editor\n -----------------------------------------\n" << fmtBoldEnd; help << DisplayKeys(&Key.VolumeDown[0], 1) << "Previous column\n"; help << DisplayKeys(&Key.VolumeUp[0], 1) << "Next column\n"; help << DisplayKeys(Key.Enter) << "Add item to playlist and play\n"; @@ -218,3 +251,4 @@ void GetKeybindings(Scrollpad &help) # endif // HAVE_TAGLIB_H } +} diff --git a/src/help.h b/src/help.h index 2b5e0972..355e51b0 100644 --- a/src/help.h +++ b/src/help.h @@ -23,7 +23,12 @@ #include "ncmpcpp.h" -void GetKeybindings(Scrollpad &); +namespace Help +{ + void Init(); + void Resize(); + void SwitchTo(); +} #endif diff --git a/src/helpers.cpp b/src/helpers.cpp index b40c3c39..d0658140 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -265,43 +265,6 @@ string FindSharedDir(const string &one, const string &two) return i != string::npos ? result.substr(0, i) : "/"; } -void GetInfo(Song &s, Scrollpad &info) -{ -# ifdef HAVE_TAGLIB_H - string path_to_file; - if (s.IsFromDB()) - path_to_file += Config.mpd_music_dir; - path_to_file += s.GetFile(); - TagLib::FileRef f(path_to_file.c_str()); - if (!f.isNull()) - s.SetComment(f.tag()->comment().to8Bit(1)); -# endif // HAVE_TAGLIB_H - - info << fmtBold << Config.color1 << "Filename: " << fmtBoldEnd << Config.color2 << s.GetName() << "\n" << clEnd; - info << fmtBold << "Directory: " << fmtBoldEnd << Config.color2 << ShowTagInInfoScreen(s.GetDirectory()) << "\n\n" << clEnd; - info << fmtBold << "Length: " << fmtBoldEnd << Config.color2 << s.GetLength() << "\n" << clEnd; -# ifdef HAVE_TAGLIB_H - if (!f.isNull()) - { - info << fmtBold << "Bitrate: " << fmtBoldEnd << Config.color2 << f.audioProperties()->bitrate() << " kbps\n" << clEnd; - info << fmtBold << "Sample rate: " << fmtBoldEnd << Config.color2 << f.audioProperties()->sampleRate() << " Hz\n" << clEnd; - info << fmtBold << "Channels: " << fmtBoldEnd << Config.color2 << (f.audioProperties()->channels() == 1 ? "Mono" : "Stereo") << "\n" << clDefault; - } - else - info << clDefault; -# endif // HAVE_TAGLIB_H - info << fmtBold << "\nTitle: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetTitle()); - info << fmtBold << "\nArtist: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetArtist()); - info << fmtBold << "\nAlbum: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetAlbum()); - info << fmtBold << "\nYear: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetYear()); - info << fmtBold << "\nTrack: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetTrack()); - info << fmtBold << "\nGenre: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetGenre()); - info << fmtBold << "\nComposer: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetComposer()); - info << fmtBold << "\nPerformer: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetPerformer()); - info << fmtBold << "\nDisc: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetDisc()); - info << fmtBold << "\nComment: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetComment()); -} - string GetLineValue(string &line, char a, char b, bool once) { int i = 0; @@ -342,21 +305,6 @@ const Buffer &ShowTag(const string &tag) return result; } -const basic_buffer &ShowTagInInfoScreen(const string &tag) -{ -# ifdef _UTF8 - static WBuffer result; - result.Clear(); - if (tag.empty()) - result << Config.empty_tags_color << ToWString(Config.empty_tag) << clEnd; - else - result << ToWString(tag); - return result; -# else - return ShowTag(tag); -# endif -} - void Scroller(Window &w, const string &string, size_t width, size_t &pos) { std::basic_string s = TO_WSTRING(string); @@ -401,3 +349,12 @@ void Scroller(Window &w, const string &string, size_t width, size_t &pos) w << s; } +#ifdef HAVE_CURL_CURL_H +size_t write_data(char *buffer, size_t size, size_t nmemb, string data) +{ + size_t result = size * nmemb; + data.append(buffer, result); + return result; +} +#endif // HAVE_CURL_CURL_H + diff --git a/src/helpers.h b/src/helpers.h index 5dfe531e..6a1fb87a 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -44,16 +44,17 @@ bool Keypressed(int, const int *); std::string FindSharedDir(const std::string &, const std::string &); -void GetInfo(MPD::Song &, Scrollpad &); - std::string GetLineValue(std::string &, char = '"', char = '"', bool = 0); Window &Statusbar(); const Buffer &ShowTag(const std::string &); -const basic_buffer &ShowTagInInfoScreen(const std::string &); void Scroller(Window &, const std::string &, size_t, size_t &); +#ifdef HAVE_CURL_CURL_H +size_t write_data(char *, size_t, size_t, std::string); +#endif + #endif diff --git a/src/info.cpp b/src/info.cpp new file mode 100644 index 00000000..250b33b0 --- /dev/null +++ b/src/info.cpp @@ -0,0 +1,451 @@ +/*************************************************************************** + * Copyright (C) 2008-2009 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 "info.h" + +#ifdef HAVE_CURL_CURL_H +# include +# include +# include +# include "curl/curl.h" +# include "helpers.h" +#endif + +#include "charset.h" +#include "global.h" +#include "media_library.h" +#include "playlist_editor.h" +#include "status_checker.h" +#include "tag_editor.h" + +using namespace Global; +using std::string; +using std::vector; + +Scrollpad *Global::sInfo; + +const string artists_folder = home_folder + "/.ncmpcpp/artists"; + +namespace +{ + pthread_t artist_info_downloader; + bool artist_info_ready = 0; + +# ifdef HAVE_CURL_CURL_H + void *GetArtistInfo(void *); +# endif + void GetSongInfo(MPD::Song &, Scrollpad &); + const basic_buffer &ShowTagInInfoScreen(const string &); +} + +void Info::Init() +{ + sInfo = new Scrollpad(0, main_start_y, COLS, main_height, "", Config.main_color, brNone); + sInfo->SetTimeout(ncmpcpp_window_timeout); +} + +void Info::Resize() +{ + sInfo->Resize(COLS, main_height); +} + +bool Info::Ready() +{ + if (!artist_info_ready) + return false; + pthread_join(artist_info_downloader, NULL); + sInfo->Flush(); + artist_info_downloader = 0; + artist_info_ready = 0; + return true; +} + +void Info::GetSong() +{ + if (wCurrent == sInfo) + { + wCurrent->Hide(); + current_screen = prev_screen; + wCurrent = wPrev; +// redraw_screen = 1; + redraw_header = 1; + if (current_screen == csLibrary) + { + MediaLibrary::Refresh(); + } + else if (current_screen == csPlaylistEditor) + { + PlaylistEditor::Refresh(); + } +# ifdef HAVE_TAGLIB_H + else if (current_screen == csTagEditor) + { + TagEditor::Refresh(); + } +# endif // HAVE_TAGLIB_H + } + else if ( + (wCurrent == mPlaylist && !mPlaylist->Empty()) + || (wCurrent == mBrowser && mBrowser->Current().type == MPD::itSong) + || (wCurrent == mSearcher && !mSearcher->Current().first) + || (wCurrent == mLibSongs && !mLibSongs->Empty()) + || (wCurrent == mPlaylistEditor && !mPlaylistEditor->Empty()) +# ifdef HAVE_TAGLIB_H + || (wCurrent == mEditorTags && !mEditorTags->Empty()) +# endif // HAVE_TAGLIB_H + ) + { + MPD::Song *s = 0; + size_t id = ((Menu *)wCurrent)->Choice(); + switch (current_screen) + { + case csPlaylist: + s = &mPlaylist->at(id); + break; + case csBrowser: + s = mBrowser->at(id).song; + break; + case csSearcher: + s = mSearcher->at(id).second; + break; + case csLibrary: + s = &mLibSongs->at(id); + break; + case csPlaylistEditor: + s = &mPlaylistEditor->at(id); + break; +# ifdef HAVE_TAGLIB_H + case csTagEditor: + s = &mEditorTags->at(id); + break; +# endif // HAVE_TAGLIB_H + default: + break; + } + wPrev = wCurrent; + wCurrent = sInfo; + prev_screen = current_screen; + current_screen = csInfo; + redraw_header = 1; + info_title = "Song info"; + sInfo->Clear(); + GetSongInfo(*s, *sInfo); + sInfo->Flush(); + sInfo->Hide(); + } +} + +void Info::GetArtist() +{ + if (wCurrent == sInfo) + { + wCurrent->Hide(); + current_screen = prev_screen; + wCurrent = wPrev; +// redraw_screen = 1; + redraw_header = 1; + if (current_screen == csLibrary) + { + MediaLibrary::Refresh(); + } + else if (current_screen == csPlaylistEditor) + { + PlaylistEditor::Refresh(); + } +# ifdef HAVE_TAGLIB_H + else if (current_screen == csTagEditor) + { + TagEditor::Refresh(); + } +# endif // HAVE_TAGLIB_H + } + else if ( + (wCurrent == mPlaylist && !mPlaylist->Empty()) + || (wCurrent == mBrowser && mBrowser->Current().type == MPD::itSong) + || (wCurrent == mSearcher && !mSearcher->Current().first) + || (wCurrent == mLibArtists && !mLibArtists->Empty()) + || (wCurrent == mLibSongs && !mLibSongs->Empty()) + || (wCurrent == mPlaylistEditor && !mPlaylistEditor->Empty()) +# ifdef HAVE_TAGLIB_H + || (wCurrent == mEditorTags && !mEditorTags->Empty()) +# endif // HAVE_TAGLIB_H + ) + { + if (artist_info_downloader) + { + ShowMessage("Artist's info is being downloaded..."); + return; + } + + string *artist = new string(); + int id = ((Menu *)wCurrent)->Choice(); + switch (current_screen) + { + case csPlaylist: + *artist = mPlaylist->at(id).GetArtist(); + break; + case csBrowser: + *artist = mBrowser->at(id).song->GetArtist(); + break; + case csSearcher: + *artist = mSearcher->at(id).second->GetArtist(); + break; + case csLibrary: + *artist = mLibArtists->at(id); + break; + case csPlaylistEditor: + *artist = mPlaylistEditor->at(id).GetArtist(); + break; +# ifdef HAVE_TAGLIB_H + case csTagEditor: + *artist = mEditorTags->at(id).GetArtist(); + break; +# endif // HAVE_TAGLIB_H + default: + break; + } + if (!artist->empty()) + { + wPrev = wCurrent; + wCurrent = sInfo; + prev_screen = current_screen; + current_screen = csInfo; + redraw_header = 1; + info_title = "Artist's info - " + *artist; + sInfo->Clear(); + sInfo->WriteXY(0, 0, 0, "Fetching artist's info..."); + sInfo->Refresh(); + if (!artist_info_downloader) + { + pthread_create(&artist_info_downloader, NULL, GetArtistInfo, artist); + } + } + else + delete artist; + } +} + +namespace { +#ifdef HAVE_CURL_CURL_H +void *GetArtistInfo(void *ptr) +{ + string *strptr = static_cast(ptr); + string artist = *strptr; + delete strptr; + + locale_to_utf(artist); + + string filename = artist + ".txt"; + ToLower(filename); + EscapeUnallowedChars(filename); + + const string fullpath = artists_folder + "/" + filename; + mkdir(artists_folder.c_str(), 0755); + + string result; + std::ifstream input(fullpath.c_str()); + + if (input.is_open()) + { + bool first = 1; + string line; + while (getline(input, line)) + { + if (!first) + *sInfo << "\n"; + utf_to_locale(line); + *sInfo << line; + first = 0; + } + input.close(); + sInfo->SetFormatting(fmtBold, "\n\nSimilar artists:\n", fmtBoldEnd, 0); + sInfo->SetFormatting(Config.color2, "\n * ", clEnd); + artist_info_ready = 1; + pthread_exit(NULL); + } + + CURLcode code; + + char *c_artist = curl_easy_escape(0, artist.c_str(), artist.length()); + + string url = "http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist="; + url += c_artist; + url += "&api_key=d94e5b6e26469a2d1ffae8ef20131b79"; + + pthread_mutex_lock(&curl); + CURL *info = curl_easy_init(); + curl_easy_setopt(info, CURLOPT_URL, url.c_str()); + curl_easy_setopt(info, CURLOPT_WRITEFUNCTION, write_data); + curl_easy_setopt(info, CURLOPT_WRITEDATA, &result); + curl_easy_setopt(info, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(info, CURLOPT_NOSIGNAL, 1); + code = curl_easy_perform(info); + curl_easy_cleanup(info); + pthread_mutex_unlock(&curl); + + curl_free(c_artist); + + if (code != CURLE_OK) + { + *sInfo << "Error while fetching artist's info: " << curl_easy_strerror(code); + artist_info_ready = 1; + pthread_exit(NULL); + } + + size_t a, b; + bool save = 1; + + a = result.find("status=\"failed\""); + + if (a != string::npos) + { + EscapeHtml(result); + *sInfo << "Last.fm returned an error message: " << result; + artist_info_ready = 1; + pthread_exit(NULL); + } + + vector similar; + for (size_t i = result.find(""); i != string::npos; i = result.find("")) + { + result[i] = '.'; + size_t j = result.find(""); + result[j] = '.'; + i += 6; + similar.push_back(result.substr(i, j-i)); + EscapeHtml(similar.back()); + } + vector urls; + for (size_t i = result.find(""); i != string::npos; i = result.find("")) + { + result[i] = '.'; + size_t j = result.find(""); + result[j] = '.'; + i += 5; + urls.push_back(result.substr(i, j-i)); + } + + a = result.find("")+9; + b = result.find(""); + + if (a == b) + { + result = "No description available for this artist."; + save = 0; + } + else + { + a += 9; // for + result = result.substr(a, b-a); + } + + EscapeHtml(result); + Trim(result); + + Buffer filebuffer; + if (save) + filebuffer << result; + utf_to_locale(result); + *sInfo << result; + + if (save) + filebuffer << "\n\nSimilar artists:\n"; + *sInfo << fmtBold << "\n\nSimilar artists:\n" << fmtBoldEnd; + for (size_t i = 1; i < similar.size(); i++) + { + if (save) + filebuffer << "\n * " << similar[i] << " (" << urls[i] << ")"; + utf_to_locale(similar[i]); + utf_to_locale(urls[i]); + *sInfo << "\n" << Config.color2 << " * " << clEnd << similar[i] << " (" << urls[i] << ")"; + } + + if (save) + filebuffer << "\n\n" << urls.front(); + utf_to_locale(urls.front()); + *sInfo << "\n\n" << urls.front(); + + if (save) + { + std::ofstream output(fullpath.c_str()); + if (output.is_open()) + { + output << filebuffer.Str(); + output.close(); + } + } + artist_info_ready = 1; + pthread_exit(NULL); +} +#endif // HVAE_CURL_CURL_H + +void GetSongInfo(MPD::Song &s, Scrollpad &info) +{ +# ifdef HAVE_TAGLIB_H + string path_to_file; + if (s.IsFromDB()) + path_to_file += Config.mpd_music_dir; + path_to_file += s.GetFile(); + TagLib::FileRef f(path_to_file.c_str()); + if (!f.isNull()) + s.SetComment(f.tag()->comment().to8Bit(1)); +# endif // HAVE_TAGLIB_H + + info << fmtBold << Config.color1 << "Filename: " << fmtBoldEnd << Config.color2 << s.GetName() << "\n" << clEnd; + info << fmtBold << "Directory: " << fmtBoldEnd << Config.color2 << ShowTagInInfoScreen(s.GetDirectory()) << "\n\n" << clEnd; + info << fmtBold << "Length: " << fmtBoldEnd << Config.color2 << s.GetLength() << "\n" << clEnd; +# ifdef HAVE_TAGLIB_H + if (!f.isNull()) + { + info << fmtBold << "Bitrate: " << fmtBoldEnd << Config.color2 << f.audioProperties()->bitrate() << " kbps\n" << clEnd; + info << fmtBold << "Sample rate: " << fmtBoldEnd << Config.color2 << f.audioProperties()->sampleRate() << " Hz\n" << clEnd; + info << fmtBold << "Channels: " << fmtBoldEnd << Config.color2 << (f.audioProperties()->channels() == 1 ? "Mono" : "Stereo") << "\n" << clDefault; + } + else + info << clDefault; +# endif // HAVE_TAGLIB_H + info << fmtBold << "\nTitle: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetTitle()); + info << fmtBold << "\nArtist: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetArtist()); + info << fmtBold << "\nAlbum: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetAlbum()); + info << fmtBold << "\nYear: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetYear()); + info << fmtBold << "\nTrack: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetTrack()); + info << fmtBold << "\nGenre: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetGenre()); + info << fmtBold << "\nComposer: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetComposer()); + info << fmtBold << "\nPerformer: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetPerformer()); + info << fmtBold << "\nDisc: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetDisc()); + info << fmtBold << "\nComment: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetComment()); +} + +const basic_buffer &ShowTagInInfoScreen(const string &tag) +{ +# ifdef _UTF8 + static WBuffer result; + result.Clear(); + if (tag.empty()) + result << Config.empty_tags_color << ToWString(Config.empty_tag) << clEnd; + else + result << ToWString(tag); + return result; +# else + return ShowTag(tag); +# endif +} +} diff --git a/src/info.h b/src/info.h new file mode 100644 index 00000000..08fb945f --- /dev/null +++ b/src/info.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2008-2009 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 _H_INFO +#define _H_INFO + +#include "ncmpcpp.h" +#include "mpdpp.h" + +namespace Info +{ + void Init(); + void Resize(); + + bool Ready(); + + void GetSong(); +# ifdef HAVE_CURL_CURL_H + void GetArtist(); +# endif +} + +#endif + diff --git a/src/lyrics.cpp b/src/lyrics.cpp index f45894e6..6471bf4d 100644 --- a/src/lyrics.cpp +++ b/src/lyrics.cpp @@ -25,231 +25,178 @@ #include "global.h" #include "helpers.h" #include "lyrics.h" +#include "media_library.h" +#include "playlist_editor.h" #include "settings.h" #include "song.h" +#include "status_checker.h" +#include "tag_editor.h" using namespace Global; using std::vector; using std::string; -const string artists_folder = home_folder + "/.ncmpcpp/artists"; +Scrollpad *Global::sLyrics; + +MPD::Song Global::lyrics_song; + const string lyrics_folder = home_folder + "/.lyrics"; #ifdef HAVE_CURL_CURL_H +pthread_mutex_t Global::curl = PTHREAD_MUTEX_INITIALIZER; +#endif namespace { - pthread_mutex_t curl = PTHREAD_MUTEX_INITIALIZER; + pthread_t lyrics_downloader; + bool lyrics_ready; - size_t write_data(char *buffer, size_t size, size_t nmemb, string data) - { - size_t result = size * nmemb; - data.append(buffer, result); - return result; - } - - void EscapeHtml(string &s) - { - bool erase = 0; - for (size_t i = s.find("<"); i != string::npos; i = s.find("<")) - { - size_t j = s.find(">")+1; - s.replace(i, j-i, ""); - } - for (size_t i = s.find("'"); i != string::npos; i = s.find("'")) - s.replace(i, 6, "'"); - for (size_t i = s.find("""); i != string::npos; i = s.find(""")) - s.replace(i, 6, "\""); - for (size_t i = s.find("&"); i != string::npos; i = s.find("&")) - s.replace(i, 5, "&"); - for (size_t i = 0; i < s.length(); i++) - { - if (erase) - { - s.erase(s.begin()+i); - erase = 0; - } - if (s[i] == 13) // ascii code for windows line ending, get rid of this shit - { - s[i] = '\n'; - erase = 1; - } - else if (s[i] == '\t') - s[i] = ' '; - } - } - - void Trim(string &s) - { - if (s.empty()) - return; - - size_t b = 0; - size_t e = s.length()-1; - - while (!isprint(s[b])) - b++; - while (!isprint(s[e])) - e--; - e++; - - if (b != 0 || e != s.length()-1) - s = s.substr(b, e-b); - } + void *GetLyrics(void *); } -void *GetArtistInfo(void *ptr) +void Lyrics::Init() { - string *strptr = static_cast(ptr); - string artist = *strptr; - delete strptr; - - locale_to_utf(artist); - - string filename = artist + ".txt"; - ToLower(filename); - EscapeUnallowedChars(filename); - - const string fullpath = artists_folder + "/" + filename; - mkdir(artists_folder.c_str(), 0755); - - string result; - std::ifstream input(fullpath.c_str()); - - if (input.is_open()) - { - bool first = 1; - string line; - while (getline(input, line)) - { - if (!first) - *sInfo << "\n"; - utf_to_locale(line); - *sInfo << line; - first = 0; - } - input.close(); - sInfo->SetFormatting(fmtBold, "\n\nSimilar artists:\n", fmtBoldEnd, 0); - sInfo->SetFormatting(Config.color2, "\n * ", clEnd); - artist_info_ready = 1; - pthread_exit(NULL); - } - - CURLcode code; - - char *c_artist = curl_easy_escape(0, artist.c_str(), artist.length()); - - string url = "http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist="; - url += c_artist; - url += "&api_key=d94e5b6e26469a2d1ffae8ef20131b79"; - - pthread_mutex_lock(&curl); - CURL *info = curl_easy_init(); - curl_easy_setopt(info, CURLOPT_URL, url.c_str()); - curl_easy_setopt(info, CURLOPT_WRITEFUNCTION, write_data); - curl_easy_setopt(info, CURLOPT_WRITEDATA, &result); - curl_easy_setopt(info, CURLOPT_CONNECTTIMEOUT, 10); - curl_easy_setopt(info, CURLOPT_NOSIGNAL, 1); - code = curl_easy_perform(info); - curl_easy_cleanup(info); - pthread_mutex_unlock(&curl); - - curl_free(c_artist); - - if (code != CURLE_OK) - { - *sInfo << "Error while fetching artist's info: " << curl_easy_strerror(code); - artist_info_ready = 1; - pthread_exit(NULL); - } - - size_t a, b; - bool save = 1; - - a = result.find("status=\"failed\""); - - if (a != string::npos) - { - EscapeHtml(result); - *sInfo << "Last.fm returned an error message: " << result; - artist_info_ready = 1; - pthread_exit(NULL); - } - - vector similar; - for (size_t i = result.find(""); i != string::npos; i = result.find("")) - { - result[i] = '.'; - size_t j = result.find(""); - result[j] = '.'; - i += 6; - similar.push_back(result.substr(i, j-i)); - EscapeHtml(similar.back()); - } - vector urls; - for (size_t i = result.find(""); i != string::npos; i = result.find("")) - { - result[i] = '.'; - size_t j = result.find(""); - result[j] = '.'; - i += 5; - urls.push_back(result.substr(i, j-i)); - } - - a = result.find("")+9; - b = result.find(""); - - if (a == b) - { - result = "No description available for this artist."; - save = 0; - } - else - { - a += 9; // for - result = result.substr(a, b-a); - } - - EscapeHtml(result); - Trim(result); - - Buffer filebuffer; - if (save) - filebuffer << result; - utf_to_locale(result); - *sInfo << result; - - if (save) - filebuffer << "\n\nSimilar artists:\n"; - *sInfo << fmtBold << "\n\nSimilar artists:\n" << fmtBoldEnd; - for (size_t i = 1; i < similar.size(); i++) - { - if (save) - filebuffer << "\n * " << similar[i] << " (" << urls[i] << ")"; - utf_to_locale(similar[i]); - utf_to_locale(urls[i]); - *sInfo << "\n" << Config.color2 << " * " << clEnd << similar[i] << " (" << urls[i] << ")"; - } - - if (save) - filebuffer << "\n\n" << urls.front(); - utf_to_locale(urls.front()); - *sInfo << "\n\n" << urls.front(); - - if (save) - { - std::ofstream output(fullpath.c_str()); - if (output.is_open()) - { - output << filebuffer.Str(); - output.close(); - } - } - artist_info_ready = 1; - pthread_exit(NULL); + sLyrics = new Scrollpad(0, main_start_y, COLS, main_height, "", Config.main_color, brNone); + sLyrics->SetTimeout(ncmpcpp_window_timeout); } +void Lyrics::Resize() +{ + sLyrics->Resize(COLS, main_height); +} + +void Lyrics::Update() +{ + if (!reload_lyrics) + return; + + const MPD::Song &s = mPlaylist->at(now_playing); + if (!s.GetArtist().empty() && !s.GetTitle().empty()) + Get(); + else + reload_lyrics = 0; +} + +bool Lyrics::Ready() +{ + if (!lyrics_ready) + return false; + pthread_join(lyrics_downloader, NULL); + sLyrics->Flush(); + lyrics_downloader = 0; + lyrics_ready = 0; + return true; +} + +void Lyrics::Get() +{ + if (wCurrent == sLyrics && !reload_lyrics) + { + wCurrent->Hide(); + current_screen = prev_screen; + wCurrent = wPrev; +// redraw_screen = 1; + redraw_header = 1; + if (current_screen == csLibrary) + { + MediaLibrary::Refresh(); + } + else if (current_screen == csPlaylistEditor) + { + PlaylistEditor::Refresh(); + } +# ifdef HAVE_TAGLIB_H + else if (current_screen == csTagEditor) + { + TagEditor::Refresh(); + } +# endif // HAVE_TAGLIB_H + } + else if ( + reload_lyrics + || (wCurrent == mPlaylist && !mPlaylist->Empty()) + || (wCurrent == mBrowser && mBrowser->Current().type == MPD::itSong) + || (wCurrent == mSearcher && !mSearcher->Current().first) + || (wCurrent == mLibSongs && !mLibSongs->Empty()) + || (wCurrent == mPlaylistEditor && !mPlaylistEditor->Empty()) +# ifdef HAVE_TAGLIB_H + || (wCurrent == mEditorTags && !mEditorTags->Empty()) +# endif // HAVE_TAGLIB_H + ) + { +# ifdef HAVE_CURL_CURL_H + if (lyrics_downloader) + { + ShowMessage("Lyrics are being downloaded..."); + return; + } +# endif + + MPD::Song *s = 0; + int id; + + if (reload_lyrics) + { + current_screen = csPlaylist; + wCurrent = mPlaylist; + reload_lyrics = 0; + id = now_playing; + } + else + id = ((Menu *)wCurrent)->Choice(); + + switch (current_screen) + { + case csPlaylist: + s = &mPlaylist->at(id); + break; + case csBrowser: + s = mBrowser->at(id).song; + break; + case csSearcher: + s = mSearcher->at(id).second; + break; + case csLibrary: + s = &mLibSongs->at(id); + break; + case csPlaylistEditor: + s = &mPlaylistEditor->at(id); + break; +# ifdef HAVE_TAGLIB_H + case csTagEditor: + s = &mEditorTags->at(id); + break; +# endif // HAVE_TAGLIB_H + default: + break; + } + if (!s->GetArtist().empty() && !s->GetTitle().empty()) + { + lyrics_scroll_begin = 0; + lyrics_song = *s; + wPrev = wCurrent; + prev_screen = current_screen; + wCurrent = sLyrics; + current_screen = csLyrics; + redraw_header = 1; + sLyrics->Clear(); + sLyrics->WriteXY(0, 0, 0, "Fetching lyrics..."); + sLyrics->Refresh(); +# ifdef HAVE_CURL_CURL_H + if (!lyrics_downloader) + { + pthread_create(&lyrics_downloader, NULL, GetLyrics, s); + } +# else + GetLyrics(s); + sLyrics->Flush(); +# endif + } + } +} + +#ifdef HAVE_CURL_CURL_H + namespace { bool lyricwiki_not_found(const string &s) @@ -311,6 +258,7 @@ const char *GetLyricsPluginName(int offset) #endif // HAVE_CURL_CURL_H +namespace { void *GetLyrics(void *song) { string artist = static_cast(song)->GetArtist(); @@ -415,4 +363,4 @@ void *GetLyrics(void *song) return NULL; # endif } - +} diff --git a/src/lyrics.h b/src/lyrics.h index c56375c7..703ae2b9 100644 --- a/src/lyrics.h +++ b/src/lyrics.h @@ -26,7 +26,16 @@ #ifdef HAVE_CURL_CURL_H # include # include "curl/curl.h" -void *GetArtistInfo(void *); + +namespace Lyrics +{ + void Init(); + void Resize(); + void Update(); + + bool Ready(); + void Get(); +} struct LyricsPlugin { @@ -40,7 +49,5 @@ const char *GetLyricsPluginName(int); #endif -void *GetLyrics(void *); - #endif diff --git a/src/media_library.cpp b/src/media_library.cpp new file mode 100644 index 00000000..03457947 --- /dev/null +++ b/src/media_library.cpp @@ -0,0 +1,356 @@ +/*************************************************************************** + * Copyright (C) 2008-2009 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 "charset.h" +#include "display.h" +#include "helpers.h" +#include "global.h" +#include "media_library.h" +#include "mpdpp.h" +#include "status_checker.h" + +using namespace MPD; +using namespace Global; +using std::string; + +Window *Global::wLibActiveCol; +Menu *Global::mLibArtists; +Menu *Global::mLibAlbums; +Menu *Global::mLibSongs; + +namespace MediaLibrary +{ + size_t left_col_width; + size_t middle_col_width; + size_t middle_col_startx; + size_t right_col_width; + size_t right_col_startx; +} + +void MediaLibrary::Init() +{ + left_col_width = COLS/3-1; + middle_col_width = COLS/3; + middle_col_startx = left_col_width+1; + right_col_width = COLS-COLS/3*2-1; + right_col_startx = left_col_width+middle_col_width+2; + + mLibArtists = new Menu(0, main_start_y, left_col_width, main_height, IntoStr(Config.media_lib_primary_tag) + "s", Config.main_color, brNone); + mLibArtists->HighlightColor(Config.active_column_color); + mLibArtists->SetTimeout(ncmpcpp_window_timeout); + mLibArtists->SetItemDisplayer(Display::Generic); + + mLibAlbums = new Menu(middle_col_startx, main_start_y, middle_col_width, main_height, "Albums", Config.main_color, brNone); + mLibAlbums->HighlightColor(Config.main_highlight_color); + mLibAlbums->SetTimeout(ncmpcpp_window_timeout); + mLibAlbums->SetItemDisplayer(Display::StringPairs); + + mLibSongs = new Menu(right_col_startx, main_start_y, right_col_width, main_height, "Songs", Config.main_color, brNone); + mLibSongs->HighlightColor(Config.main_highlight_color); + mLibSongs->SetTimeout(ncmpcpp_window_timeout); + mLibSongs->SetSelectPrefix(&Config.selected_item_prefix); + mLibSongs->SetSelectSuffix(&Config.selected_item_suffix); + mLibSongs->SetItemDisplayer(Display::Songs); + mLibSongs->SetItemDisplayerUserData(&Config.song_library_format); + + wLibActiveCol = mLibArtists; +} + +void MediaLibrary::Resize() +{ + left_col_width = COLS/3-1; + middle_col_startx = left_col_width+1; + middle_col_width = COLS/3; + right_col_startx = left_col_width+middle_col_width+2; + right_col_width = COLS-COLS/3*2-1; + + mLibArtists->Resize(left_col_width, main_height); + mLibAlbums->Resize(middle_col_width, main_height); + mLibSongs->Resize(right_col_width, main_height); + + mLibAlbums->MoveTo(middle_col_startx, main_start_y); + mLibSongs->MoveTo(right_col_startx, main_start_y); +} + +void MediaLibrary::Refresh() +{ + mLibArtists->Display(); + mvvline(main_start_y, middle_col_startx-1, 0, main_height); + mLibAlbums->Display(); + mvvline(main_start_y, right_col_startx-1, 0, main_height); + mLibSongs->Display(); + if (mLibAlbums->Empty()) + { + mLibAlbums->WriteXY(0, 0, 0, "No albums found."); + mLibAlbums->Refresh(); + } +} + +void MediaLibrary::SwitchTo() +{ + if (current_screen != csLibrary +# ifdef HAVE_TAGLIB_H + && current_screen != csTinyTagEditor +# endif // HAVE_TAGLIB_H + ) + { + CLEAR_FIND_HISTORY; + + mPlaylist->Hide(); // hack, should be wCurrent, but it doesn't always have 100% width + +// redraw_screen = 1; + redraw_header = 1; + MediaLibrary::Refresh(); + + wCurrent = wLibActiveCol; + current_screen = csLibrary; + + UpdateSongList(mLibSongs); + } +} + +void MediaLibrary::Update() +{ + if (mLibArtists->Empty()) + { + CLEAR_FIND_HISTORY; + TagList list; + mLibAlbums->Clear(0); + mLibSongs->Clear(0); + Mpd->GetList(list, Config.media_lib_primary_tag); + sort(list.begin(), list.end(), CaseInsensitiveSorting()); + for (TagList::iterator it = list.begin(); it != list.end(); it++) + { + if (!it->empty()) + { + utf_to_locale(*it); + mLibArtists->AddOption(*it); + } + } + mLibArtists->Window::Clear(); + mLibArtists->Refresh(); + } + + if (!mLibArtists->Empty() && mLibAlbums->Empty() && mLibSongs->Empty()) + { + mLibAlbums->Reset(); + TagList list; + std::map maplist; + locale_to_utf(mLibArtists->Current()); + if (Config.media_lib_primary_tag == MPD_TAG_ITEM_ARTIST) + Mpd->GetAlbums(mLibArtists->Current(), list); + else + { + Mpd->StartSearch(1); + Mpd->AddSearch(Config.media_lib_primary_tag, mLibArtists->Current()); + Mpd->StartFieldSearch(MPD_TAG_ITEM_ALBUM); + Mpd->CommitSearch(list); + } + + // Version() > 13) + { + SongList noalbum_list; + Mpd->StartSearch(1); + Mpd->AddSearch(Config.media_lib_primary_tag, mLibArtists->Current()); + Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, ""); + Mpd->CommitSearch(noalbum_list); + if (!noalbum_list.empty()) + mLibAlbums->AddOption(std::make_pair("", "")); + FreeSongList(noalbum_list); + } + + for (TagList::iterator it = list.begin(); it != list.end(); it++) + { + SongList l; + Mpd->StartSearch(1); + Mpd->AddSearch(Config.media_lib_primary_tag, mLibArtists->Current()); + Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, *it); + Mpd->CommitSearch(l); + if (!l.empty() && !l[0]->GetAlbum().empty()) + { + utf_to_locale(*it); + l[0]->Localize(); + maplist[l[0]->toString(Config.media_lib_album_format)] = *it; + } + FreeSongList(l); + } + utf_to_locale(mLibArtists->Current()); + for (std::map::const_iterator it = maplist.begin(); it != maplist.end(); it++) + mLibAlbums->AddOption(make_pair(it->first, it->second)); + mLibAlbums->Window::Clear(); + mLibAlbums->Refresh(); + } + + if (!mLibArtists->Empty() && wCurrent == mLibAlbums && mLibAlbums->Empty()) + { + mLibAlbums->HighlightColor(Config.main_highlight_color); + mLibArtists->HighlightColor(Config.active_column_color); + wCurrent = wLibActiveCol = mLibArtists; + } + + if (!mLibArtists->Empty() && mLibSongs->Empty()) + { + mLibSongs->Reset(); + SongList list; + + mLibSongs->Clear(0); + Mpd->StartSearch(1); + Mpd->AddSearch(Config.media_lib_primary_tag, locale_to_utf_cpy(mLibArtists->Current())); + if (mLibAlbums->Empty()) // left for compatibility with WriteXY(0, 0, 0, "No albums found."); + mLibAlbums->Refresh(); + } + else + Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, locale_to_utf_cpy(mLibAlbums->Current().second)); + Mpd->CommitSearch(list); + + sort(list.begin(), list.end(), SortSongsByTrack); + bool bold = 0; + + for (SongList::const_iterator it = list.begin(); it != list.end(); it++) + { + for (size_t j = 0; j < mPlaylist->Size(); j++) + { + if ((*it)->GetHash() == mPlaylist->at(j).GetHash()) + { + bold = 1; + break; + } + } + mLibSongs->AddOption(**it, bold); + bold = 0; + } + FreeSongList(list); + mLibSongs->Window::Clear(); + mLibSongs->Refresh(); + } +} + +void MediaLibrary::EnterPressed(bool add_n_play) +{ + SongList list; + + if (!mLibArtists->Empty() && wCurrent == mLibArtists) + { + Mpd->StartSearch(1); + Mpd->AddSearch(Config.media_lib_primary_tag, locale_to_utf_cpy(mLibArtists->Current())); + Mpd->CommitSearch(list); + for (SongList::const_iterator it = list.begin(); it != list.end(); it++) + Mpd->QueueAddSong(**it); + if (Mpd->CommitQueue()) + { + string tag_type = IntoStr(Config.media_lib_primary_tag); + ToLower(tag_type); + ShowMessage("Adding songs of %s \"%s\"", tag_type.c_str(), mLibArtists->Current().c_str()); + Song *s = &mPlaylist->at(mPlaylist->Size()-list.size()); + if (s->GetHash() == list[0]->GetHash()) + { + if (add_n_play) + Mpd->PlayID(s->GetID()); + } + else + ShowMessage("%s", message_part_of_songs_added); + } + } + else if (wCurrent == mLibAlbums) + { + for (size_t i = 0; i < mLibSongs->Size(); i++) + Mpd->QueueAddSong(mLibSongs->at(i)); + if (Mpd->CommitQueue()) + { + ShowMessage("Adding songs from album \"%s\"", mLibAlbums->Current().second.c_str()); + Song *s = &mPlaylist->at(mPlaylist->Size()-mLibSongs->Size()); + if (s->GetHash() == mLibSongs->at(0).GetHash()) + { + if (add_n_play) + Mpd->PlayID(s->GetID()); + } + else + ShowMessage("%s", message_part_of_songs_added); + } + } + else if (wCurrent == mLibSongs) + { + if (!mLibSongs->Empty()) + { + block_item_list_update = 1; + if (Config.ncmpc_like_songs_adding && mLibSongs->isBold()) + { + long long hash = mLibSongs->Current().GetHash(); + if (add_n_play) + { + for (size_t i = 0; i < mPlaylist->Size(); i++) + { + if (mPlaylist->at(i).GetHash() == hash) + { + Mpd->Play(i); + break; + } + } + } + else + { + block_playlist_update = 1; + for (size_t i = 0; i < mPlaylist->Size(); i++) + { + if (mPlaylist->at(i).GetHash() == hash) + { + Mpd->QueueDeleteSong(i); + mPlaylist->DeleteOption(i); + i--; + } + } + Mpd->CommitQueue(); + mLibSongs->BoldOption(mLibSongs->Choice(), 0); + } + } + else + { + Song &s = mLibSongs->Current(); + int id = Mpd->AddSong(s); + if (id >= 0) + { + ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str()); + if (add_n_play) + Mpd->PlayID(id); + mLibSongs->BoldOption(mLibSongs->Choice(), 1); + } + } + } + } + FreeSongList(list); + if (!add_n_play) + { + wCurrent->Scroll(wDown); + if (wCurrent == mLibArtists) + { + mLibAlbums->Clear(0); + mLibSongs->Clear(0); + } + else if (wCurrent == mLibAlbums) + mLibSongs->Clear(0); + } +} + diff --git a/src/media_library.h b/src/media_library.h new file mode 100644 index 00000000..6f49bd5e --- /dev/null +++ b/src/media_library.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2008-2009 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 _H_MEDIA_LIBRARY +#define _H_MEDIA_LIBRARY + +#include "ncmpcpp.h" + +namespace MediaLibrary +{ + void Init(); + void Resize(); + void Refresh(); + void SwitchTo(); + void Update(); + + void EnterPressed(bool = 1); + inline void SpacePressed(); +} + +void MediaLibrary::SpacePressed() +{ + EnterPressed(0); +} + +#endif + diff --git a/src/misc.cpp b/src/misc.cpp index cecca44a..c1ed9132 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -160,3 +160,52 @@ void EscapeUnallowedChars(std::string &s) } } +void EscapeHtml(std::string &s) +{ + bool erase = 0; + for (size_t i = s.find("<"); i != std::string::npos; i = s.find("<")) + { + size_t j = s.find(">")+1; + s.replace(i, j-i, ""); + } + for (size_t i = s.find("'"); i != std::string::npos; i = s.find("'")) + s.replace(i, 6, "'"); + for (size_t i = s.find("""); i != std::string::npos; i = s.find(""")) + s.replace(i, 6, "\""); + for (size_t i = s.find("&"); i != std::string::npos; i = s.find("&")) + s.replace(i, 5, "&"); + for (size_t i = 0; i < s.length(); i++) + { + if (erase) + { + s.erase(s.begin()+i); + erase = 0; + } + if (s[i] == 13) // ascii code for windows line ending, get rid of this shit + { + s[i] = '\n'; + erase = 1; + } + else if (s[i] == '\t') + s[i] = ' '; + } +} + +void Trim(std::string &s) +{ + if (s.empty()) + return; + + size_t b = 0; + size_t e = s.length()-1; + + while (!isprint(s[b])) + b++; + while (!isprint(s[e])) + e--; + e++; + + if (b != 0 || e != s.length()-1) + s = s.substr(b, e-b); +} + diff --git a/src/misc.h b/src/misc.h index c20dc72f..c22fa40c 100644 --- a/src/misc.h +++ b/src/misc.h @@ -42,5 +42,9 @@ mpd_TagItems IntoTagItem(char); void EscapeUnallowedChars(std::string &); +void EscapeHtml(std::string &s); + +void Trim(std::string &s); + #endif diff --git a/src/ncmpcpp.cpp b/src/ncmpcpp.cpp index 2cf8fb05..219749f8 100644 --- a/src/ncmpcpp.cpp +++ b/src/ncmpcpp.cpp @@ -21,10 +21,8 @@ #include #include -#include #include #include -#include #include #include "mpdpp.h" @@ -37,10 +35,14 @@ #include "global.h" #include "help.h" #include "helpers.h" +#include "media_library.h" #include "lyrics.h" +#include "playlist.h" +#include "playlist_editor.h" #include "search_engine.h" #include "settings.h" #include "song.h" +#include "info.h" #include "status_checker.h" #include "tag_editor.h" @@ -51,44 +53,6 @@ continue; \ } -#define REFRESH_MEDIA_LIBRARY_SCREEN \ - do { \ - mLibArtists->Display(); \ - mvvline(main_start_y, middle_col_startx-1, 0, main_height); \ - mLibAlbums->Display(); \ - mvvline(main_start_y, right_col_startx-1, 0, main_height); \ - mLibSongs->Display(); \ - if (mLibAlbums->Empty()) \ - { \ - mLibAlbums->WriteXY(0, 0, 0, "No albums found."); \ - mLibAlbums->Refresh(); \ - } \ - } while (0) - -#define REFRESH_PLAYLIST_EDITOR_SCREEN \ - do { \ - mPlaylistList->Display(); \ - mvvline(main_start_y, middle_col_startx-1, 0, main_height); \ - mPlaylistEditor->Display(); \ - } while (0) - -#ifdef HAVE_TAGLIB_H -# define REFRESH_TAG_EDITOR_SCREEN \ - do { \ - mEditorLeftCol->Display(); \ - mvvline(main_start_y, tagedit_middle_col_startx-1, 0, main_height); \ - mEditorTagTypes->Display(); \ - mvvline(main_start_y, tagedit_right_col_startx-1, 0, main_height); \ - mEditorTags->Display(); \ - } while (0) -#endif // HAVE_TAGLIB_H - -#define CLEAR_FIND_HISTORY \ - do { \ - found_pos = -1; \ - vFoundPositions.clear(); \ - } while (0) - using namespace Global; using namespace MPD; @@ -102,39 +66,8 @@ ncmpcpp_keys Global::Key; Window *Global::wCurrent; Window *Global::wPrev; -Menu *Global::mPlaylist; -Menu *Global::mBrowser; -Menu< std::pair > *Global::mSearcher; - -Window *Global::wLibActiveCol; -Menu *Global::mLibArtists; -Menu *Global::mLibAlbums; -Menu *Global::mLibSongs; - -#ifdef HAVE_TAGLIB_H -Window *Global::wTagEditorActiveCol; -Menu *Global::mTagEditor; -Menu *Global::mEditorAlbums; -Menu *Global::mEditorDirs; -#endif // HAVE_TAGLIB_H -// blah, I use below in conditionals. -Menu *Global::mEditorLeftCol; -Menu *Global::mEditorTagTypes; -Menu *Global::mEditorTags; - -Window *Global::wPlaylistEditorActiveCol; -Menu *Global::mPlaylistList; -Menu *Global::mPlaylistEditor; - -Scrollpad *Global::sHelp; -Scrollpad *Global::sLyrics; -Scrollpad *Global::sInfo; - Window *Global::wHeader; Window *Global::wFooter; -#ifdef ENABLE_CLOCK -Scrollpad *Global::wClock; -#endif Connection *Global::Mpd; @@ -142,23 +75,20 @@ int Global::now_playing = -1; int Global::lock_statusbar_delay = -1; size_t Global::browsed_dir_scroll_begin = 0; +size_t Global::main_start_y; +size_t Global::main_height; +size_t Global::lyrics_scroll_begin = 0; time_t Global::timer; string Global::browsed_dir = "/"; string Global::editor_browsed_dir = "/"; string Global::editor_highlighted_dir; +string Global::info_title; NcmpcppScreen Global::current_screen; NcmpcppScreen Global::prev_screen; -#ifdef HAVE_CURL_CURL_H -pthread_t Global::lyrics_downloader; -pthread_t Global::artist_info_downloader; -bool Global::lyrics_ready = 0; -bool Global::artist_info_ready = 0; -#endif - bool Global::dont_change_now_playing = 0; bool Global::block_progressbar_update = 0; bool Global::block_playlist_update = 0; @@ -168,7 +98,8 @@ bool Global::messages_allowed = 0; bool Global::redraw_header = 1; bool Global::reload_lyrics = 0; -const char *message_part_of_songs_added = "Only part of requested songs' list added to playlist!"; +vector Global::vFoundPositions; +int Global::found_pos = 0; int main(int argc, char *argv[]) { @@ -208,8 +139,8 @@ int main(int argc, char *argv[]) InitScreen(Config.colors_enabled); init_current_locale(); - size_t main_start_y = 2; - size_t main_height = LINES-4; + main_start_y = 2; + main_height = LINES-4; if (!Config.header_visibility) { @@ -219,124 +150,24 @@ int main(int argc, char *argv[]) if (!Config.statusbar_visibility) main_height++; - mPlaylist = new Menu(0, main_start_y, COLS, main_height, Config.columns_in_playlist ? Display::Columns(Config.song_columns_list_format) : "", Config.main_color, brNone); - mPlaylist->SetTimeout(ncmpcpp_window_timeout); - mPlaylist->HighlightColor(Config.main_highlight_color); - mPlaylist->SetSelectPrefix(&Config.selected_item_prefix); - mPlaylist->SetSelectSuffix(&Config.selected_item_suffix); - mPlaylist->SetItemDisplayer(Config.columns_in_playlist ? Display::SongsInColumns : Display::Songs); - mPlaylist->SetItemDisplayerUserData(Config.columns_in_playlist ? &Config.song_columns_list_format : &Config.song_list_format); - - mBrowser = new Menu(0, main_start_y, COLS, main_height, "", Config.main_color, brNone); - mBrowser->HighlightColor(Config.main_highlight_color); - mBrowser->SetTimeout(ncmpcpp_window_timeout); - mBrowser->SetSelectPrefix(&Config.selected_item_prefix); - mBrowser->SetSelectSuffix(&Config.selected_item_suffix); - mBrowser->SetItemDisplayer(Display::Items); - - mSearcher = new Menu< std::pair >(0, main_start_y, COLS, main_height, "", Config.main_color, brNone); - mSearcher->HighlightColor(Config.main_highlight_color); - mSearcher->SetTimeout(ncmpcpp_window_timeout); - mSearcher->SetItemDisplayer(Display::SearchEngine); - mSearcher->SetSelectPrefix(&Config.selected_item_prefix); - mSearcher->SetSelectSuffix(&Config.selected_item_suffix); - - size_t left_col_width = COLS/3-1; - size_t middle_col_width = COLS/3; - size_t middle_col_startx = left_col_width+1; - size_t right_col_width = COLS-COLS/3*2-1; - size_t right_col_startx = left_col_width+middle_col_width+2; - - mLibArtists = new Menu(0, main_start_y, left_col_width, main_height, IntoStr(Config.media_lib_primary_tag) + "s", Config.main_color, brNone); - mLibArtists->HighlightColor(Config.active_column_color); - mLibArtists->SetTimeout(ncmpcpp_window_timeout); - mLibArtists->SetItemDisplayer(Display::Generic); - - mLibAlbums = new Menu(middle_col_startx, main_start_y, middle_col_width, main_height, "Albums", Config.main_color, brNone); - mLibAlbums->HighlightColor(Config.main_highlight_color); - mLibAlbums->SetTimeout(ncmpcpp_window_timeout); - mLibAlbums->SetItemDisplayer(Display::StringPairs); - - mLibSongs = new Menu(right_col_startx, main_start_y, right_col_width, main_height, "Songs", Config.main_color, brNone); - mLibSongs->HighlightColor(Config.main_highlight_color); - mLibSongs->SetTimeout(ncmpcpp_window_timeout); - mLibSongs->SetSelectPrefix(&Config.selected_item_prefix); - mLibSongs->SetSelectSuffix(&Config.selected_item_suffix); - mLibSongs->SetItemDisplayer(Display::Songs); - mLibSongs->SetItemDisplayerUserData(&Config.song_library_format); + Playlist::Init(); + Browser::Init(); + SearchEngine::Init(); + MediaLibrary::Init(); + PlaylistEditor::Init(); # ifdef HAVE_TAGLIB_H - mTagEditor = new Menu(0, main_start_y, COLS, main_height, "", Config.main_color, brNone); - mTagEditor->HighlightColor(Config.main_highlight_color); - mTagEditor->SetTimeout(ncmpcpp_window_timeout); - mTagEditor->SetItemDisplayer(Display::Generic); - - size_t tagedit_middle_col_width = 26; - size_t tagedit_left_col_width = COLS/2-tagedit_middle_col_width/2; - size_t tagedit_middle_col_startx = tagedit_left_col_width+1; - size_t tagedit_right_col_width = COLS-tagedit_left_col_width-tagedit_middle_col_width-2; - size_t tagedit_right_col_startx = tagedit_left_col_width+tagedit_middle_col_width+2; - - mEditorAlbums = new Menu(0, main_start_y, tagedit_left_col_width, main_height, "Albums", Config.main_color, brNone); - mEditorAlbums->HighlightColor(Config.active_column_color); - mEditorAlbums->SetTimeout(ncmpcpp_window_timeout); - mEditorAlbums->SetItemDisplayer(Display::StringPairs); - - mEditorDirs = new Menu(0, main_start_y, tagedit_left_col_width, main_height, "Directories", Config.main_color, brNone); - mEditorDirs->HighlightColor(Config.active_column_color); - mEditorDirs->SetTimeout(ncmpcpp_window_timeout); - mEditorDirs->SetItemDisplayer(Display::StringPairs); - mEditorLeftCol = Config.albums_in_tag_editor ? mEditorAlbums : mEditorDirs; - - mEditorTagTypes = new Menu(tagedit_middle_col_startx, main_start_y, tagedit_middle_col_width, main_height, "Tag types", Config.main_color, brNone); - mEditorTagTypes->HighlightColor(Config.main_highlight_color); - mEditorTagTypes->SetTimeout(ncmpcpp_window_timeout); - mEditorTagTypes->SetItemDisplayer(Display::Generic); - - mEditorTags = new Menu(tagedit_right_col_startx, main_start_y, tagedit_right_col_width, main_height, "Tags", Config.main_color, brNone); - mEditorTags->HighlightColor(Config.main_highlight_color); - mEditorTags->SetTimeout(ncmpcpp_window_timeout); - mEditorTags->SetSelectPrefix(&Config.selected_item_prefix); - mEditorTags->SetSelectSuffix(&Config.selected_item_suffix); - mEditorTags->SetItemDisplayer(Display::Tags); - mEditorTags->SetItemDisplayerUserData(mEditorTagTypes); -# endif // HAVE_TAGLIB_H - - mPlaylistList = new Menu(0, main_start_y, left_col_width, main_height, "Playlists", Config.main_color, brNone); - mPlaylistList->HighlightColor(Config.active_column_color); - mPlaylistList->SetTimeout(ncmpcpp_window_timeout); - mPlaylistList->SetItemDisplayer(Display::Generic); - - mPlaylistEditor = new Menu(middle_col_startx, main_start_y, middle_col_width+right_col_width+1, main_height, "Playlist's content", Config.main_color, brNone); - mPlaylistEditor->HighlightColor(Config.main_highlight_color); - mPlaylistEditor->SetTimeout(ncmpcpp_window_timeout); - mPlaylistEditor->SetSelectPrefix(&Config.selected_item_prefix); - mPlaylistEditor->SetSelectSuffix(&Config.selected_item_suffix); - mPlaylistEditor->SetItemDisplayer(Display::Songs); - mPlaylistEditor->SetItemDisplayerUserData(&Config.song_list_format); - - // set default active columns - wLibActiveCol = mLibArtists; - wPlaylistEditorActiveCol = mPlaylistList; -# ifdef HAVE_TAGLIB_H - wTagEditorActiveCol = mEditorLeftCol; + TinyTagEditor::Init(); + TagEditor::Init(); # endif // HAVE_TAGLIB_H # ifdef ENABLE_CLOCK - size_t clock_width = Config.clock_display_seconds ? 60 : 40; - size_t clock_height = 8; + Clock::Init(); # endif // ENABLE_CLOCK - sHelp = new Scrollpad(0, main_start_y, COLS, main_height, "", Config.main_color, brNone); - sHelp->SetTimeout(ncmpcpp_window_timeout); - GetKeybindings(*sHelp); - sHelp->Flush(); - - sLyrics = sHelp->EmptyClone(); - sLyrics->SetTimeout(ncmpcpp_window_timeout); - - sInfo = sHelp->EmptyClone(); - sInfo->SetTimeout(ncmpcpp_window_timeout); + Help::Init(); + Info::Init(); + Lyrics::Init(); if (Config.header_visibility) { @@ -361,22 +192,14 @@ int main(int argc, char *argv[]) Mpd->SetErrorHandler(NcmpcppErrorCallback, NULL); // local variables - vector vFoundPositions; - - int found_pos = 0; int input; - size_t lyrics_scroll_begin = 0; - - Song lyrics_song; Song edited_song; - SearchPattern sought_pattern; bool main_exit = 0; bool title_allowed = !Config.display_screens_numbers_on_start; string screen_title; - string info_title; timeval now, past; // local variables end @@ -425,10 +248,12 @@ int main(int argc, char *argv[]) case csBrowser: screen_title = "Browse: "; break; +# ifdef HAVE_TAGLIB_H case csTinyTagEditor: case csTagEditor: screen_title = "Tag editor"; break; +# endif // HAVE_TAGLIB_H case csInfo: screen_title = info_title; break; @@ -444,9 +269,11 @@ int main(int argc, char *argv[]) case csPlaylistEditor: screen_title = "Playlist editor"; break; +# ifdef ENABLE_CLOCK case csClock: screen_title = "Clock"; break; +# endif // ENABLE_CLOCK default: break; } @@ -503,336 +330,36 @@ int main(int argc, char *argv[]) if (current_screen == csHelp || current_screen == csPlaylist || current_screen == csBrowser); - else - // media library stuff - if (current_screen == csLibrary) + else if (current_screen == csLibrary) { - if (mLibArtists->Empty()) - { - CLEAR_FIND_HISTORY; - TagList list; - mLibAlbums->Clear(0); - mLibSongs->Clear(0); - Mpd->GetList(list, Config.media_lib_primary_tag); - sort(list.begin(), list.end(), CaseInsensitiveSorting()); - for (TagList::iterator it = list.begin(); it != list.end(); it++) - { - if (!it->empty()) - { - utf_to_locale(*it); - mLibArtists->AddOption(*it); - } - } - mLibArtists->Window::Clear(); - mLibArtists->Refresh(); - } - - if (!mLibArtists->Empty() && mLibAlbums->Empty() && mLibSongs->Empty()) - { - mLibAlbums->Reset(); - TagList list; - std::map maplist; - locale_to_utf(mLibArtists->Current()); - if (Config.media_lib_primary_tag == MPD_TAG_ITEM_ARTIST) - Mpd->GetAlbums(mLibArtists->Current(), list); - else - { - Mpd->StartSearch(1); - Mpd->AddSearch(Config.media_lib_primary_tag, mLibArtists->Current()); - Mpd->StartFieldSearch(MPD_TAG_ITEM_ALBUM); - Mpd->CommitSearch(list); - } - - // Version() > 13) - { - SongList noalbum_list; - Mpd->StartSearch(1); - Mpd->AddSearch(Config.media_lib_primary_tag, mLibArtists->Current()); - Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, ""); - Mpd->CommitSearch(noalbum_list); - if (!noalbum_list.empty()) - mLibAlbums->AddOption(make_pair("", "")); - FreeSongList(noalbum_list); - } - - for (TagList::iterator it = list.begin(); it != list.end(); it++) - { - SongList l; - Mpd->StartSearch(1); - Mpd->AddSearch(Config.media_lib_primary_tag, mLibArtists->Current()); - Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, *it); - Mpd->CommitSearch(l); - if (!l.empty() && !l[0]->GetAlbum().empty()) - { - utf_to_locale(*it); - l[0]->Localize(); - maplist[l[0]->toString(Config.media_lib_album_format)] = *it; - } - FreeSongList(l); - } - utf_to_locale(mLibArtists->Current()); - for (std::map::const_iterator it = maplist.begin(); it != maplist.end(); it++) - mLibAlbums->AddOption(make_pair(it->first, it->second)); - mLibAlbums->Window::Clear(); - mLibAlbums->Refresh(); - } - - if (!mLibArtists->Empty() && wCurrent == mLibAlbums && mLibAlbums->Empty()) - { - mLibAlbums->HighlightColor(Config.main_highlight_color); - mLibArtists->HighlightColor(Config.active_column_color); - wCurrent = wLibActiveCol = mLibArtists; - } - - if (!mLibArtists->Empty() && mLibSongs->Empty()) - { - mLibSongs->Reset(); - SongList list; - - mLibSongs->Clear(0); - Mpd->StartSearch(1); - Mpd->AddSearch(Config.media_lib_primary_tag, locale_to_utf_cpy(mLibArtists->Current())); - if (mLibAlbums->Empty()) // left for compatibility with WriteXY(0, 0, 0, "No albums found."); - mLibAlbums->Refresh(); - } - else - Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, locale_to_utf_cpy(mLibAlbums->Current().second)); - Mpd->CommitSearch(list); - - sort(list.begin(), list.end(), SortSongsByTrack); - bool bold = 0; - - for (SongList::const_iterator it = list.begin(); it != list.end(); it++) - { - for (size_t j = 0; j < mPlaylist->Size(); j++) - { - if ((*it)->GetHash() == mPlaylist->at(j).GetHash()) - { - bold = 1; - break; - } - } - mLibSongs->AddOption(**it, bold); - bold = 0; - } - FreeSongList(list); - mLibSongs->Window::Clear(); - mLibSongs->Refresh(); - } + MediaLibrary::Update(); } - // media library end - else - // playlist editor stuff - if (current_screen == csPlaylistEditor) + else if (current_screen == csPlaylistEditor) { - if (mPlaylistList->Empty()) - { - mPlaylistEditor->Clear(0); - TagList list; - Mpd->GetPlaylists(list); - sort(list.begin(), list.end(), CaseInsensitiveSorting()); - for (TagList::iterator it = list.begin(); it != list.end(); it++) - { - utf_to_locale(*it); - mPlaylistList->AddOption(*it); - } - mPlaylistList->Window::Clear(); - mPlaylistList->Refresh(); - } - - if (!mPlaylistList->Empty() && mPlaylistEditor->Empty()) - { - mPlaylistEditor->Reset(); - SongList list; - Mpd->GetPlaylistContent(locale_to_utf_cpy(mPlaylistList->Current()), list); - if (!list.empty()) - mPlaylistEditor->SetTitle("Playlist's content (" + IntoStr(list.size()) + " item" + (list.size() == 1 ? ")" : "s)")); - else - mPlaylistEditor->SetTitle("Playlist's content"); - bool bold = 0; - for (SongList::const_iterator it = list.begin(); it != list.end(); it++) - { - for (size_t j = 0; j < mPlaylist->Size(); j++) - { - if ((*it)->GetHash() == mPlaylist->at(j).GetHash()) - { - bold = 1; - break; - } - } - mPlaylistEditor->AddOption(**it, bold); - bold = 0; - } - FreeSongList(list); - mPlaylistEditor->Window::Clear(); - mPlaylistEditor->Display(); - } - - if (wCurrent == mPlaylistEditor && mPlaylistEditor->Empty()) - { - mPlaylistEditor->HighlightColor(Config.main_highlight_color); - mPlaylistList->HighlightColor(Config.active_column_color); - wCurrent = wPlaylistEditorActiveCol = mPlaylistList; - } - - if (mPlaylistEditor->Empty()) - { - mPlaylistEditor->WriteXY(0, 0, 0, "Playlist is empty."); - mPlaylistEditor->Refresh(); - } + PlaylistEditor::Update(); } - // playlist editor end else # ifdef HAVE_TAGLIB_H - // album editor stuff if (current_screen == csTagEditor) { - if (mEditorLeftCol->Empty()) - { - CLEAR_FIND_HISTORY; - mEditorLeftCol->Window::Clear(); - mEditorTags->Clear(); - TagList list; - if (Config.albums_in_tag_editor) - { - std::map maplist; - mEditorAlbums->WriteXY(0, 0, 0, "Fetching albums' list..."); - Mpd->GetAlbums("", list); - for (TagList::const_iterator it = list.begin(); it != list.end(); it++) - { - SongList l; - Mpd->StartSearch(1); - Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, *it); - Mpd->CommitSearch(l); - if (!l.empty()) - { - l[0]->Localize(); - maplist[l[0]->toString(Config.tag_editor_album_format)] = *it; - } - FreeSongList(l); - } - for (std::map::const_iterator it = maplist.begin(); it != maplist.end(); it++) - mEditorAlbums->AddOption(make_pair(it->first, it->second)); - } - else - { - int highlightme = -1; - Mpd->GetDirectories(editor_browsed_dir, list); - sort(list.begin(), list.end(), CaseInsensitiveSorting()); - if (editor_browsed_dir != "/") - { - size_t slash = editor_browsed_dir.rfind("/"); - string parent = slash != string::npos ? editor_browsed_dir.substr(0, slash) : "/"; - mEditorDirs->AddOption(make_pair("[..]", parent)); - } - else - { - mEditorDirs->AddOption(make_pair(".", "/")); - } - for (TagList::const_iterator it = list.begin(); it != list.end(); it++) - { - size_t slash = it->rfind("/"); - string to_display = slash != string::npos ? it->substr(slash+1) : *it; - utf_to_locale(to_display); - mEditorDirs->AddOption(make_pair(to_display, *it)); - if (*it == editor_highlighted_dir) - highlightme = mEditorDirs->Size()-1; - } - if (highlightme != -1) - mEditorDirs->Highlight(highlightme); - } - mEditorLeftCol->Display(); - mEditorTagTypes->Refresh(); - } - - if (mEditorTags->Empty()) - { - mEditorTags->Reset(); - SongList list; - if (Config.albums_in_tag_editor) - { - Mpd->StartSearch(1); - Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, mEditorAlbums->Current().second); - Mpd->CommitSearch(list); - sort(list.begin(), list.end(), CaseInsensitiveSorting()); - for (SongList::iterator it = list.begin(); it != list.end(); it++) - { - (*it)->Localize(); - mEditorTags->AddOption(**it); - } - } - else - { - Mpd->GetSongs(mEditorDirs->Current().second, list); - sort(list.begin(), list.end(), CaseInsensitiveSorting()); - for (SongList::const_iterator it = list.begin(); it != list.end(); it++) - { - (*it)->Localize(); - mEditorTags->AddOption(**it); - } - } - FreeSongList(list); - mEditorTags->Window::Clear(); - mEditorTags->Refresh(); - } - - if (/*redraw_screen && */wCurrent == mEditorTagTypes && mEditorTagTypes->Choice() < 13) - { - mEditorTags->Refresh(); -// redraw_screen = 0; - } - else if (mEditorTagTypes->Choice() >= 13) - mEditorTags->Window::Clear(); + TagEditor::Update(); } - // album editor end else # endif // HAVE_TAGLIB_H # ifdef ENABLE_CLOCK if (current_screen == csClock) { - if (clock_width <= size_t(COLS) && clock_height <= main_height) - { - time_t rawtime; - time(&rawtime); - tm *t = localtime(&rawtime); - Display::Clock(*wClock, t); - } - else - { - delete wClock; - wClock = 0; - goto SWITCHER_PLAYLIST_REDIRECT; - } + Clock::Update(); } else # endif - // lyrics stuff - if (current_screen == csLyrics && reload_lyrics) + if (current_screen == csLyrics) { - const Song &s = mPlaylist->at(now_playing); - if (!s.GetArtist().empty() && !s.GetTitle().empty()) - goto LOAD_LYRICS; - else - reload_lyrics = 0; + Lyrics::Update(); } # ifdef HAVE_CURL_CURL_H - if (artist_info_ready) - { - pthread_join(artist_info_downloader, NULL); - sInfo->Flush(); - artist_info_downloader = 0; - artist_info_ready = 0; - } - else if (lyrics_ready) - { - pthread_join(lyrics_downloader, NULL); - sLyrics->Flush(); - lyrics_downloader = 0; - lyrics_ready = 0; - } + if (!Info::Ready()) + Lyrics::Ready(); # endif wCurrent->Display(); @@ -854,7 +381,9 @@ int main(int argc, char *argv[]) break; case csLibrary: case csPlaylistEditor: +# ifdef HAVE_TAGLIB_H case csTagEditor: +# endif // HAVE_TAGLIB_H { if (Keypressed(input, Key.Up) || Keypressed(input, Key.Down) || Keypressed(input, Key.PageUp) || Keypressed(input, Key.PageDown) || Keypressed(input, Key.Home) || Keypressed(input, Key.End) || Keypressed(input, Key.FindForward) || Keypressed(input, Key.FindBackward) || Keypressed(input, Key.NextFoundPosition) || Keypressed(input, Key.PrevFoundPosition)) { @@ -888,9 +417,21 @@ int main(int argc, char *argv[]) // key mapping beginning - if (current_screen != csClock && Keypressed(input, Key.Up)) + if ( + Keypressed(input, Key.Up) +#ifdef ENABLE_CLOCK + && current_screen != csClock +# endif // ENABLE_CLOCK + ) { - if (!Config.fancy_scrolling && (wCurrent == mLibArtists || wCurrent == mPlaylistList || wCurrent == mEditorLeftCol)) + if (!Config.fancy_scrolling + && (wCurrent == mLibArtists + || wCurrent == mPlaylistList +# ifdef HAVE_TAGLIB_H + || wCurrent == mEditorLeftCol +# endif // HAVE_TAGLIB_H + ) + ) { wCurrent->SetTimeout(50); while (Keypressed(input, Key.Up)) @@ -904,9 +445,21 @@ int main(int argc, char *argv[]) else wCurrent->Scroll(wUp); } - else if (current_screen != csClock && Keypressed(input, Key.Down)) + else if ( + Keypressed(input, Key.Down) +#ifdef ENABLE_CLOCK + && current_screen != csClock +# endif // ENABLE_CLOCK + ) { - if (!Config.fancy_scrolling && (wCurrent == mLibArtists || wCurrent == mPlaylistList || wCurrent == mEditorLeftCol)) + if (!Config.fancy_scrolling + && (wCurrent == mLibArtists + || wCurrent == mPlaylistList +# ifdef HAVE_TAGLIB_H + || wCurrent == mEditorLeftCol +# endif // HAVE_TAGLIB_H + ) + ) { wCurrent->SetTimeout(50); while (Keypressed(input, Key.Down)) @@ -920,11 +473,21 @@ int main(int argc, char *argv[]) else wCurrent->Scroll(wDown); } - else if (current_screen != csClock && Keypressed(input, Key.PageUp)) + else if ( + Keypressed(input, Key.PageUp) +#ifdef ENABLE_CLOCK + && current_screen != csClock +# endif // ENABLE_CLOCK + ) { wCurrent->Scroll(wPageUp); } - else if (current_screen != csClock && Keypressed(input, Key.PageDown)) + else if ( + Keypressed(input, Key.PageDown) +#ifdef ENABLE_CLOCK + && current_screen != csClock +# endif // ENABLE_CLOCK + ) { wCurrent->Scroll(wPageDown); } @@ -955,57 +518,22 @@ int main(int argc, char *argv[]) if (!Config.statusbar_visibility) main_height++; - sHelp->Resize(COLS, main_height); - mPlaylist->Resize(COLS, main_height); - mPlaylist->SetTitle(Config.columns_in_playlist ? Display::Columns(Config.song_columns_list_format) : ""); - mBrowser->Resize(COLS, main_height); - mSearcher->Resize(COLS, main_height); - sInfo->Resize(COLS, main_height); - sLyrics->Resize(COLS, main_height); - - left_col_width = COLS/3-1; - middle_col_startx = left_col_width+1; - middle_col_width = COLS/3; - right_col_startx = left_col_width+middle_col_width+2; - right_col_width = COLS-COLS/3*2-1; - - mLibArtists->Resize(left_col_width, main_height); - mLibAlbums->Resize(middle_col_width, main_height); - mLibSongs->Resize(right_col_width, main_height); - mLibAlbums->MoveTo(middle_col_startx, main_start_y); - mLibSongs->MoveTo(right_col_startx, main_start_y); + Help::Resize(); + Playlist::Resize(); + Browser::Resize(); + SearchEngine::Resize(); + MediaLibrary::Resize(); + PlaylistEditor::Resize(); + Info::Resize(); + Lyrics::Resize(); # ifdef HAVE_TAGLIB_H mTagEditor->Resize(COLS, main_height); - - tagedit_left_col_width = COLS/2-tagedit_middle_col_width/2; - tagedit_middle_col_startx = tagedit_left_col_width+1; - tagedit_right_col_width = COLS-tagedit_left_col_width-tagedit_middle_col_width-2; - tagedit_right_col_startx = tagedit_left_col_width+tagedit_middle_col_width+2; - - mEditorAlbums->Resize(tagedit_left_col_width, main_height); - mEditorDirs->Resize(tagedit_left_col_width, main_height); - mEditorTagTypes->Resize(tagedit_middle_col_width, main_height); - mEditorTags->Resize(tagedit_right_col_width, main_height); - mEditorTagTypes->MoveTo(tagedit_middle_col_startx, main_start_y); - mEditorTags->MoveTo(tagedit_right_col_startx, main_start_y); - - mPlaylistList->Resize(left_col_width, main_height); - mPlaylistEditor->Resize(middle_col_width+right_col_width+1, main_height); - mPlaylistEditor->MoveTo(middle_col_startx, main_start_y); + TagEditor::Resize(); # endif // HAVE_TAGLIB_H # ifdef ENABLE_CLOCK - if (wClock) - { - wClock->MoveTo((COLS-clock_width)/2, (LINES-clock_height)/2); - if (current_screen == csClock) - { - mPlaylist->Hide(); - InitClock(); - wClock->Display(); - } - } + Clock::Resize(); # endif // ENABLE_CLOCK if (Config.header_visibility) @@ -1018,17 +546,17 @@ int main(int argc, char *argv[]) # ifdef HAVE_TAGLIB_H if (current_screen == csLibrary) { - REFRESH_MEDIA_LIBRARY_SCREEN; + MediaLibrary::Refresh(); } else if (current_screen == csTagEditor) { - REFRESH_TAG_EDITOR_SCREEN; + TagEditor::Refresh(); } else # endif // HAVE_TAGLIB_H if (current_screen == csPlaylistEditor) { - REFRESH_PLAYLIST_EDITOR_SCREEN; + PlaylistEditor::Refresh(); } header_update_status = 1; PlayerState mpd_state = Mpd->GetState(); @@ -1045,7 +573,7 @@ int main(int argc, char *argv[]) if (wCurrent == mBrowser && browsed_dir != "/") { mBrowser->Reset(); - goto ENTER_BROWSER_SCREEN; + Browser::EnterPressed(); } } else if (Keypressed(input, Key.Enter)) @@ -1060,773 +588,36 @@ int main(int argc, char *argv[]) } case csBrowser: { - ENTER_BROWSER_SCREEN: - - if (mBrowser->Empty()) - continue; - - const Item &item = mBrowser->Current(); - switch (item.type) - { - case itDirectory: - { - CLEAR_FIND_HISTORY; - GetDirectory(item.name, browsed_dir); - redraw_header = 1; - break; - } - case itSong: - { - block_item_list_update = 1; - if (Config.ncmpc_like_songs_adding && mBrowser->isBold()) - { - bool found = 0; - long long hash = mBrowser->Current().song->GetHash(); - for (size_t i = 0; i < mPlaylist->Size(); i++) - { - if (mPlaylist->at(i).GetHash() == hash) - { - Mpd->Play(i); - found = 1; - break; - } - } - if (found) - break; - } - Song &s = *item.song; - int id = Mpd->AddSong(s); - if (id >= 0) - { - Mpd->PlayID(id); - ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str()); - mBrowser->BoldOption(mBrowser->Choice(), 1); - } - break; - } - case itPlaylist: - { - SongList list; - Mpd->GetPlaylistContent(locale_to_utf_cpy(item.name), list); - for (SongList::const_iterator it = list.begin(); it != list.end(); it++) - Mpd->QueueAddSong(**it); - if (Mpd->CommitQueue()) - { - ShowMessage("Loading and playing playlist %s...", item.name.c_str()); - Song *s = &mPlaylist->at(mPlaylist->Size()-list.size()); - if (s->GetHash() == list[0]->GetHash()) - Mpd->PlayID(s->GetID()); - else - ShowMessage("%s", message_part_of_songs_added); - } - FreeSongList(list); - break; - } - } + Browser::EnterPressed(); break; } # ifdef HAVE_TAGLIB_H case csTinyTagEditor: { - size_t option = mTagEditor->Choice(); - LockStatusbar(); - Song &s = edited_song; - - if (option >= 8 && option <= 20) - mTagEditor->at(option).Clear(); - - switch (option-7) - { - case 1: - { - Statusbar() << fmtBold << "Title: " << fmtBoldEnd; - s.SetTitle(wFooter->GetString(s.GetTitle())); - mTagEditor->at(option) << fmtBold << "Title:" << fmtBoldEnd << ' ' << ShowTag(s.GetTitle()); - break; - } - case 2: - { - Statusbar() << fmtBold << "Artist: " << fmtBoldEnd; - s.SetArtist(wFooter->GetString(s.GetArtist())); - mTagEditor->at(option) << fmtBold << "Artist:" << fmtBoldEnd << ' ' << ShowTag(s.GetArtist()); - break; - } - case 3: - { - Statusbar() << fmtBold << "Album: " << fmtBoldEnd; - s.SetAlbum(wFooter->GetString(s.GetAlbum())); - mTagEditor->at(option) << fmtBold << "Album:" << fmtBoldEnd << ' ' << ShowTag(s.GetAlbum()); - break; - } - case 4: - { - Statusbar() << fmtBold << "Year: " << fmtBoldEnd; - s.SetYear(wFooter->GetString(s.GetYear(), 4)); - mTagEditor->at(option) << fmtBold << "Year:" << fmtBoldEnd << ' ' << ShowTag(s.GetYear()); - break; - } - case 5: - { - Statusbar() << fmtBold << "Track: " << fmtBoldEnd; - s.SetTrack(wFooter->GetString(s.GetTrack(), 3)); - mTagEditor->at(option) << fmtBold << "Track:" << fmtBoldEnd << ' ' << ShowTag(s.GetTrack()); - break; - } - case 6: - { - Statusbar() << fmtBold << "Genre: " << fmtBoldEnd; - s.SetGenre(wFooter->GetString(s.GetGenre())); - mTagEditor->at(option) << fmtBold << "Genre:" << fmtBoldEnd << ' ' << ShowTag(s.GetGenre()); - break; - } - case 7: - { - Statusbar() << fmtBold << "Composer: " << fmtBoldEnd; - s.SetComposer(wFooter->GetString(s.GetComposer())); - mTagEditor->at(option) << fmtBold << "Composer:" << fmtBoldEnd << ' ' << ShowTag(s.GetComposer()); - break; - } - case 8: - { - Statusbar() << fmtBold << "Performer: " << fmtBoldEnd; - s.SetPerformer(wFooter->GetString(s.GetPerformer())); - mTagEditor->at(option) << fmtBold << "Performer:" << fmtBoldEnd << ' ' << ShowTag(s.GetPerformer()); - break; - } - case 9: - { - Statusbar() << fmtBold << "Disc: " << fmtBoldEnd; - s.SetDisc(wFooter->GetString(s.GetDisc())); - mTagEditor->at(option) << fmtBold << "Disc:" << fmtBoldEnd << ' ' << ShowTag(s.GetDisc()); - break; - } - case 10: - { - Statusbar() << fmtBold << "Comment: " << fmtBoldEnd; - s.SetComment(wFooter->GetString(s.GetComment())); - mTagEditor->at(option) << fmtBold << "Comment:" << fmtBoldEnd << ' ' << ShowTag(s.GetComment()); - break; - } - case 12: - { - Statusbar() << fmtBold << "Filename: " << fmtBoldEnd; - string filename = s.GetNewName().empty() ? s.GetName() : s.GetNewName(); - size_t dot = filename.rfind("."); - string extension = filename.substr(dot); - filename = filename.substr(0, dot); - string new_name = wFooter->GetString(filename); - s.SetNewName(new_name + extension); - mTagEditor->at(option) << fmtBold << "Filename:" << fmtBoldEnd << ' ' << (s.GetNewName().empty() ? s.GetName() : s.GetNewName()); - break; - } - case 14: - { - ShowMessage("Updating tags..."); - if (WriteTags(s)) - { - ShowMessage("Tags updated!"); - if (s.IsFromDB()) - { - Mpd->UpdateDirectory(locale_to_utf_cpy(s.GetDirectory())); - if (prev_screen == csSearcher) - *mSearcher->Current().second = s; - } - else - { - if (wPrev == mPlaylist) - mPlaylist->Current() = s; - else if (wPrev == mBrowser) - *mBrowser->Current().song = s; - } - } - else - ShowMessage("Error writing tags!"); - } - case 15: - { - wCurrent->Clear(); - wCurrent = wPrev; - current_screen = prev_screen; -// redraw_screen = 1; - redraw_header = 1; - if (current_screen == csLibrary) - { - REFRESH_MEDIA_LIBRARY_SCREEN; - } - else if (current_screen == csPlaylistEditor) - { - REFRESH_PLAYLIST_EDITOR_SCREEN; - } - else if (current_screen == csTagEditor) - { - REFRESH_TAG_EDITOR_SCREEN; - } - break; - } - } - UnlockStatusbar(); + TinyTagEditor::EnterPressed(edited_song); break; } # endif // HAVE_TAGLIB_H case csSearcher: { - ENTER_SEARCH_ENGINE_SCREEN: - - size_t option = mSearcher->Choice(); - LockStatusbar(); - SearchPattern &s = sought_pattern; - - if (option <= 12) - mSearcher->Current().first->Clear(); - - switch (option) - { - case 0: - { - Statusbar() << fmtBold << "Any: " << fmtBoldEnd; - s.Any(wFooter->GetString(s.Any())); - *mSearcher->Current().first << fmtBold << "Any: " << fmtBoldEnd << ' ' << ShowTag(s.Any()); - break; - } - case 1: - { - Statusbar() << fmtBold << "Artist: " << fmtBoldEnd; - s.SetArtist(wFooter->GetString(s.GetArtist())); - *mSearcher->Current().first << fmtBold << "Artist: " << fmtBoldEnd << ' ' << ShowTag(s.GetArtist()); - break; - } - case 2: - { - Statusbar() << fmtBold << "Title: " << fmtBoldEnd; - s.SetTitle(wFooter->GetString(s.GetTitle())); - *mSearcher->Current().first << fmtBold << "Title: " << fmtBoldEnd << ' ' << ShowTag(s.GetTitle()); - break; - } - case 3: - { - Statusbar() << fmtBold << "Album: " << fmtBoldEnd; - s.SetAlbum(wFooter->GetString(s.GetAlbum())); - *mSearcher->Current().first << fmtBold << "Album: " << fmtBoldEnd << ' ' << ShowTag(s.GetAlbum()); - break; - } - case 4: - { - Statusbar() << fmtBold << "Filename: " << fmtBoldEnd; - s.SetFile(wFooter->GetString(s.GetFile())); - *mSearcher->Current().first << fmtBold << "Filename: " << fmtBoldEnd << ' ' << ShowTag(s.GetFile()); - break; - } - case 5: - { - Statusbar() << fmtBold << "Composer: " << fmtBoldEnd; - s.SetComposer(wFooter->GetString(s.GetComposer())); - *mSearcher->Current().first << fmtBold << "Composer: " << fmtBoldEnd << ' ' << ShowTag(s.GetComposer()); - break; - } - case 6: - { - Statusbar() << fmtBold << "Performer: " << fmtBoldEnd; - s.SetPerformer(wFooter->GetString(s.GetPerformer())); - *mSearcher->Current().first << fmtBold << "Performer:" << fmtBoldEnd << ' ' << ShowTag(s.GetPerformer()); - break; - } - case 7: - { - Statusbar() << fmtBold << "Genre: " << fmtBoldEnd; - s.SetGenre(wFooter->GetString(s.GetGenre())); - *mSearcher->Current().first << fmtBold << "Genre: " << fmtBoldEnd << ' ' << ShowTag(s.GetGenre()); - break; - } - case 8: - { - Statusbar() << fmtBold << "Year: " << fmtBoldEnd; - s.SetYear(wFooter->GetString(s.GetYear(), 4)); - *mSearcher->Current().first << fmtBold << "Year: " << fmtBoldEnd << ' ' << ShowTag(s.GetYear()); - break; - } - case 9: - { - Statusbar() << fmtBold << "Comment: " << fmtBoldEnd; - s.SetComment(wFooter->GetString(s.GetComment())); - *mSearcher->Current().first << fmtBold << "Comment: " << fmtBoldEnd << ' ' << ShowTag(s.GetComment()); - break; - } - case 11: - { - Config.search_in_db = !Config.search_in_db; - *mSearcher->Current().first << fmtBold << "Search in:" << fmtBoldEnd << ' ' << (Config.search_in_db ? "Database" : "Current playlist"); - break; - } - case 12: - { - search_match_to_pattern = !search_match_to_pattern; - *mSearcher->Current().first << fmtBold << "Search mode:" << fmtBoldEnd << ' ' << (search_match_to_pattern ? search_mode_normal : search_mode_strict); - break; - } - case 13: - { - search_case_sensitive = !search_case_sensitive; - *mSearcher->Current().first << fmtBold << "Case sensitive:" << fmtBoldEnd << ' ' << (search_case_sensitive ? "Yes" : "No"); - break; - } - case 15: - { - ShowMessage("Searching..."); - Search(s); - if (!mSearcher->Back().first) - { - if (Config.columns_in_search_engine) - mSearcher->SetTitle(Display::Columns(Config.song_columns_list_format)); - size_t found = mSearcher->Size()-search_engine_static_options; - found += 3; // don't count options inserted below - mSearcher->InsertSeparator(search_engine_reset_button+1); - mSearcher->InsertOption(search_engine_reset_button+2, make_pair((Buffer *)0, (Song *)0), 1, 1); - mSearcher->at(search_engine_reset_button+2).first = new Buffer(); - *mSearcher->at(search_engine_reset_button+2).first << Config.color1 << "Search results: " << Config.color2 << "Found " << found << (found > 1 ? " songs" : " song") << clDefault; - mSearcher->InsertSeparator(search_engine_reset_button+3); - UpdateFoundList(); - ShowMessage("Searching finished!"); - for (size_t i = 0; i < search_engine_static_options-4; i++) - mSearcher->Static(i, 1); - mSearcher->Scroll(wDown); - mSearcher->Scroll(wDown); - } - else - ShowMessage("No results found"); - break; - } - case 16: - { - CLEAR_FIND_HISTORY; - PrepareSearchEngine(sought_pattern); - ShowMessage("Search state reset"); - break; - } - default: - { - block_item_list_update = 1; - if (Config.ncmpc_like_songs_adding && mSearcher->isBold()) - { - long long hash = mSearcher->Current().second->GetHash(); - for (size_t i = 0; i < mPlaylist->Size(); i++) - { - if (mPlaylist->at(i).GetHash() == hash) - { - Mpd->Play(i); - break; - } - } - } - else - { - const Song &s = *mSearcher->Current().second; - int id = Mpd->AddSong(s); - if (id >= 0) - { - Mpd->PlayID(id); - ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str()); - mSearcher->BoldOption(mSearcher->Choice(), 1); - } - } - break; - } - } - UnlockStatusbar(); + SearchEngine::EnterPressed(); break; } case csLibrary: { - ENTER_LIBRARY_SCREEN: // same code for Key.Space, but without playing. - - SongList list; - - if (!mLibArtists->Empty() && wCurrent == mLibArtists) - { - Mpd->StartSearch(1); - Mpd->AddSearch(Config.media_lib_primary_tag, locale_to_utf_cpy(mLibArtists->Current())); - Mpd->CommitSearch(list); - for (SongList::const_iterator it = list.begin(); it != list.end(); it++) - Mpd->QueueAddSong(**it); - if (Mpd->CommitQueue()) - { - string tag_type = IntoStr(Config.media_lib_primary_tag); - ToLower(tag_type); - ShowMessage("Adding songs of %s \"%s\"", tag_type.c_str(), mLibArtists->Current().c_str()); - Song *s = &mPlaylist->at(mPlaylist->Size()-list.size()); - if (s->GetHash() == list[0]->GetHash()) - { - if (Keypressed(input, Key.Enter)) - Mpd->PlayID(s->GetID()); - } - else - ShowMessage("%s", message_part_of_songs_added); - } - } - else if (wCurrent == mLibAlbums) - { - for (size_t i = 0; i < mLibSongs->Size(); i++) - Mpd->QueueAddSong(mLibSongs->at(i)); - if (Mpd->CommitQueue()) - { - ShowMessage("Adding songs from album \"%s\"", mLibAlbums->Current().second.c_str()); - Song *s = &mPlaylist->at(mPlaylist->Size()-mLibSongs->Size()); - if (s->GetHash() == mLibSongs->at(0).GetHash()) - { - if (Keypressed(input, Key.Enter)) - Mpd->PlayID(s->GetID()); - } - else - ShowMessage("%s", message_part_of_songs_added); - } - } - else if (wCurrent == mLibSongs) - { - if (!mLibSongs->Empty()) - { - block_item_list_update = 1; - if (Config.ncmpc_like_songs_adding && mLibSongs->isBold()) - { - long long hash = mLibSongs->Current().GetHash(); - if (Keypressed(input, Key.Enter)) - { - for (size_t i = 0; i < mPlaylist->Size(); i++) - { - if (mPlaylist->at(i).GetHash() == hash) - { - Mpd->Play(i); - break; - } - } - } - else - { - block_playlist_update = 1; - for (size_t i = 0; i < mPlaylist->Size(); i++) - { - if (mPlaylist->at(i).GetHash() == hash) - { - Mpd->QueueDeleteSong(i); - mPlaylist->DeleteOption(i); - i--; - } - } - Mpd->CommitQueue(); - mLibSongs->BoldOption(mLibSongs->Choice(), 0); - } - } - else - { - Song &s = mLibSongs->Current(); - int id = Mpd->AddSong(s); - if (id >= 0) - { - ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str()); - if (Keypressed(input, Key.Enter)) - Mpd->PlayID(id); - mLibSongs->BoldOption(mLibSongs->Choice(), 1); - } - } - } - } - FreeSongList(list); - if (Keypressed(input, Key.Space)) - { - wCurrent->Scroll(wDown); - if (wCurrent == mLibArtists) - { - mLibAlbums->Clear(0); - mLibSongs->Clear(0); - } - else if (wCurrent == mLibAlbums) - mLibSongs->Clear(0); - } + MediaLibrary::EnterPressed(); break; } case csPlaylistEditor: { - ENTER_PLAYLIST_EDITOR_SCREEN: // same code for Key.Space, but without playing. - - SongList list; - - if (wCurrent == mPlaylistList && !mPlaylistList->Empty()) - { - Mpd->GetPlaylistContent(locale_to_utf_cpy(mPlaylistList->Current()), list); - for (SongList::const_iterator it = list.begin(); it != list.end(); it++) - Mpd->QueueAddSong(**it); - if (Mpd->CommitQueue()) - { - ShowMessage("Loading playlist %s...", mPlaylistList->Current().c_str()); - Song &s = mPlaylist->at(mPlaylist->Size()-list.size()); - if (s.GetHash() == list[0]->GetHash()) - { - if (Keypressed(input, Key.Enter)) - Mpd->PlayID(s.GetID()); - } - else - ShowMessage("%s", message_part_of_songs_added); - } - } - else if (wCurrent == mPlaylistEditor) - { - if (!mPlaylistEditor->Empty()) - { - block_item_list_update = 1; - if (Config.ncmpc_like_songs_adding && mPlaylistEditor->isBold()) - { - long long hash = mPlaylistEditor->Current().GetHash(); - if (Keypressed(input, Key.Enter)) - { - for (size_t i = 0; i < mPlaylist->Size(); i++) - { - if (mPlaylist->at(i).GetHash() == hash) - { - Mpd->Play(i); - break; - } - } - } - else - { - block_playlist_update = 1; - for (size_t i = 0; i < mPlaylist->Size(); i++) - { - if (mPlaylist->at(i).GetHash() == hash) - { - Mpd->QueueDeleteSong(i); - mPlaylist->DeleteOption(i); - i--; - } - } - Mpd->CommitQueue(); - mPlaylistEditor->BoldOption(mPlaylistEditor->Choice(), 0); - } - } - else - { - Song &s = mPlaylistEditor->at(mPlaylistEditor->Choice()); - int id = Mpd->AddSong(s); - if (id >= 0) - { - ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str()); - if (Keypressed(input, Key.Enter)) - Mpd->PlayID(id); - mPlaylistEditor->BoldOption(mPlaylistEditor->Choice(), 1); - } - } - } - } - FreeSongList(list); - if (Keypressed(input, Key.Space)) - wCurrent->Scroll(wDown); + PlaylistEditor::EnterPressed(); break; } # ifdef HAVE_TAGLIB_H case csTagEditor: { - if (wCurrent == mEditorDirs) - { - TagList test; - Mpd->GetDirectories(mEditorLeftCol->Current().second, test); - if (!test.empty()) - { - editor_highlighted_dir = editor_browsed_dir; - editor_browsed_dir = mEditorLeftCol->Current().second; - mEditorLeftCol->Clear(0); - mEditorLeftCol->Reset(); - } - else - ShowMessage("No subdirs found"); - break; - } - - if (mEditorTags->Empty()) // we need songs to deal with, don't we? - break; - - // if there are selected songs, perform operations only on them - SongList list; - if (mEditorTags->hasSelected()) - { - vector selected; - mEditorTags->GetSelected(selected); - for (vector::const_iterator it = selected.begin(); it != selected.end(); it++) - list.push_back(&mEditorTags->at(*it)); - } - else - for (size_t i = 0; i < mEditorTags->Size(); i++) - list.push_back(&mEditorTags->at(i)); - - SongGetFunction get = 0; - SongSetFunction set = 0; - - size_t id = mEditorTagTypes->RealChoice(); - switch (id) - { - case 0: - get = &Song::GetTitle; - set = &Song::SetTitle; - break; - case 1: - get = &Song::GetArtist; - set = &Song::SetArtist; - break; - case 2: - get = &Song::GetAlbum; - set = &Song::SetAlbum; - break; - case 3: - get = &Song::GetYear; - set = &Song::SetYear; - break; - case 4: - get = &Song::GetTrack; - set = &Song::SetTrack; - if (wCurrent == mEditorTagTypes) - { - LockStatusbar(); - Statusbar() << "Number tracks? [y/n] "; - curs_set(1); - int in = 0; - do - { - TraceMpdStatus(); - wFooter->ReadKey(in); - } - while (in != 'y' && in != 'n'); - if (in == 'y') - { - int i = 1; - for (SongList::iterator it = list.begin(); it != list.end(); it++, i++) - (*it)->SetTrack(i); - ShowMessage("Tracks numbered!"); - } - else - ShowMessage("Aborted!"); - curs_set(0); -// redraw_screen = 1; - UnlockStatusbar(); - } - break; - case 5: - get = &Song::GetGenre; - set = &Song::SetGenre; - break; - case 6: - get = &Song::GetComposer; - set = &Song::SetComposer; - break; - case 7: - get = &Song::GetPerformer; - set = &Song::SetPerformer; - break; - case 8: - get = &Song::GetDisc; - set = &Song::SetDisc; - break; - case 9: - get = &Song::GetComment; - set = &Song::SetComment; - break; - case 10: - { - if (wCurrent == mEditorTagTypes) - { - current_screen = csOther; - __deal_with_filenames(list); - current_screen = csTagEditor; -// redraw_screen = 1; - REFRESH_TAG_EDITOR_SCREEN; - } - else if (wCurrent == mEditorTags) - { - Song &s = mEditorTags->Current(); - string old_name = s.GetNewName().empty() ? s.GetName() : s.GetNewName(); - size_t last_dot = old_name.rfind("."); - string extension = old_name.substr(last_dot); - old_name = old_name.substr(0, last_dot); - LockStatusbar(); - Statusbar() << fmtBold << "New filename: " << fmtBoldEnd; - string new_name = wFooter->GetString(old_name); - UnlockStatusbar(); - if (!new_name.empty() && new_name != old_name) - s.SetNewName(new_name + extension); - mEditorTags->Scroll(wDown); - } - continue; - } - case 11: // reset - { - mEditorTags->Clear(0); - ShowMessage("Changes reset"); - continue; - } - case 12: // save - { - bool success = 1; - ShowMessage("Writing changes..."); - for (SongList::iterator it = list.begin(); it != list.end(); it++) - { - ShowMessage("Writing tags in '%s'...", (*it)->GetName().c_str()); - if (!WriteTags(**it)) - { - ShowMessage("Error writing tags in '%s'!", (*it)->GetFile().c_str()); - success = 0; - break; - } - } - if (success) - { - ShowMessage("Tags updated!"); - mEditorTagTypes->HighlightColor(Config.main_highlight_color); - mEditorTagTypes->Reset(); - wCurrent->Refresh(); - wCurrent = mEditorLeftCol; - mEditorLeftCol->HighlightColor(Config.active_column_color); - Mpd->UpdateDirectory(FindSharedDir(mEditorTags)); - } - else - mEditorTags->Clear(0); - continue; - } - case 13: // capitalize first letters - { - ShowMessage("Processing..."); - for (SongList::iterator it = list.begin(); it != list.end(); it++) - CapitalizeFirstLetters(**it); - ShowMessage("Done!"); - break; - } - case 14: // lower all letters - { - ShowMessage("Processing..."); - for (SongList::iterator it = list.begin(); it != list.end(); it++) - LowerAllLetters(**it); - ShowMessage("Done!"); - break; - } - default: - break; - } - - if (wCurrent == mEditorTagTypes && id != 0 && id != 4 && set != NULL) - { - LockStatusbar(); - Statusbar() << fmtBold << mEditorTagTypes->Current() << fmtBoldEnd << ": "; - string new_tag = wFooter->GetString((mEditorTags->Current().*get)()); - UnlockStatusbar(); - for (SongList::iterator it = list.begin(); it != list.end(); it++) - (**it.*set)(new_tag); -// redraw_screen = 1; - } - else if (wCurrent == mEditorTags && set != NULL) - { - LockStatusbar(); - Statusbar() << fmtBold << mEditorTagTypes->Current() << fmtBoldEnd << ": "; - string new_tag = wFooter->GetString((mEditorTags->Current().*get)()); - UnlockStatusbar(); - if (new_tag != (mEditorTags->Current().*get)()) - (mEditorTags->Current().*set)(new_tag); - mEditorTags->Scroll(wDown); - } + TagEditor::EnterPressed(); + break; } # endif // HAVE_TAGLIB_H default: @@ -1835,9 +626,20 @@ int main(int argc, char *argv[]) } else if (Keypressed(input, Key.Space)) { - if (Config.space_selects || wCurrent == mPlaylist || wCurrent == mEditorTags) + if (Config.space_selects + || wCurrent == mPlaylist +# ifdef HAVE_TAGLIB_H + || wCurrent == mEditorTags +# endif // HAVE_TAGLIB_H + ) { - if (wCurrent == mPlaylist || wCurrent == mEditorTags || (wCurrent == mBrowser && ((Menu *)wCurrent)->Choice() >= (browsed_dir != "/" ? 1 : 0)) || (wCurrent == mSearcher && !mSearcher->Current().first) || wCurrent == mLibSongs || wCurrent == mPlaylistEditor) + if (wCurrent == mPlaylist +# ifdef HAVE_TAGLIB_H + || wCurrent == mEditorTags +# endif // HAVE_TAGLIB_H + || (wCurrent == mBrowser && ((Menu *)wCurrent)->Choice() >= (browsed_dir != "/" ? 1 : 0)) || (wCurrent == mSearcher && !mSearcher->Current().first) + || wCurrent == mLibSongs + || wCurrent == mPlaylistEditor) { List *mList = (Menu *)wCurrent; if (mList->Empty()) @@ -1849,120 +651,22 @@ int main(int argc, char *argv[]) } else { - if (current_screen == csBrowser && !mBrowser->Empty()) + if (current_screen == csBrowser) { - const Item &item = mBrowser->Current(); - switch (item.type) - { - case itDirectory: - { - if (browsed_dir != "/" && !mBrowser->Choice()) - continue; // do not let add parent dir. - - if (Config.local_browser) - { - ShowMessage("Adding whole directories from local browser is not supported!"); - continue; - } - - SongList list; - Mpd->GetDirectoryRecursive(locale_to_utf_cpy(item.name), list); - - for (SongList::const_iterator it = list.begin(); it != list.end(); it++) - Mpd->QueueAddSong(**it); - if (Mpd->CommitQueue()) - { - ShowMessage("Added folder: %s", item.name.c_str()); - Song &s = mPlaylist->at(mPlaylist->Size()-list.size()); - if (s.GetHash() != list[0]->GetHash()) - ShowMessage("%s", message_part_of_songs_added); - } - FreeSongList(list); - break; - } - case itSong: - { - block_item_list_update = 1; - if (Config.ncmpc_like_songs_adding && mBrowser->isBold()) - { - block_playlist_update = 1; - long long hash = mBrowser->Current().song->GetHash(); - for (size_t i = 0; i < mPlaylist->Size(); i++) - { - if (mPlaylist->at(i).GetHash() == hash) - { - Mpd->QueueDeleteSong(i); - mPlaylist->DeleteOption(i); - i--; - } - } - Mpd->CommitQueue(); - mBrowser->BoldOption(mBrowser->Choice(), 0); - } - else - { - Song &s = *item.song; - if (Mpd->AddSong(s) != -1) - { - ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str()); - mBrowser->BoldOption(mBrowser->Choice(), 1); - } - } - break; - } - case itPlaylist: - { - SongList list; - Mpd->GetPlaylistContent(locale_to_utf_cpy(item.name), list); - for (SongList::const_iterator it = list.begin(); it != list.end(); it++) - Mpd->QueueAddSong(**it); - if (Mpd->CommitQueue()) - { - ShowMessage("Loading playlist %s...", item.name.c_str()); - Song &s = mPlaylist->at(mPlaylist->Size()-list.size()); - if (s.GetHash() != list[0]->GetHash()) - ShowMessage("%s", message_part_of_songs_added); - } - FreeSongList(list); - break; - } - } - mBrowser->Scroll(wDown); + Browser::SpacePressed(); } - else if (current_screen == csSearcher && !mSearcher->Current().first) + else if (current_screen == csSearcher) { - block_item_list_update = 1; - if (Config.ncmpc_like_songs_adding && mSearcher->isBold()) - { - block_playlist_update = 1; - long long hash = mSearcher->Current().second->GetHash(); - for (size_t i = 0; i < mPlaylist->Size(); i++) - { - if (mPlaylist->at(i).GetHash() == hash) - { - Mpd->QueueDeleteSong(i); - mPlaylist->DeleteOption(i); - i--; - } - } - Mpd->CommitQueue(); - mSearcher->BoldOption(mSearcher->Choice(), 0); - } - else - { - const Song &s = *mSearcher->Current().second; - if (Mpd->AddSong(s) != -1) - { - ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str()); - mSearcher->BoldOption(mSearcher->Choice(), 1); - } - } - mSearcher->Scroll(wDown); + SearchEngine::SpacePressed(); } else if (current_screen == csLibrary) - goto ENTER_LIBRARY_SCREEN; // sorry, but that's stupid to copy the same code here. + { + MediaLibrary::SpacePressed(); + } else if (current_screen == csPlaylistEditor) - goto ENTER_PLAYLIST_EDITOR_SCREEN; // same what in library screen. + { + PlaylistEditor::SpacePressed(); + } # ifdef HAVE_TAGLIB_H else if (wCurrent == mEditorLeftCol) { @@ -2599,8 +1303,10 @@ int main(int argc, char *argv[]) { if (current_screen == csBrowser) Mpd->UpdateDirectory(browsed_dir); +# ifdef HAVE_TAGLIB_H else if (current_screen == csTagEditor && !Config.albums_in_tag_editor) Mpd->UpdateDirectory(editor_browsed_dir); +# endif // HAVE_TAGLIB_H else Mpd->UpdateDirectory("/"); } @@ -2849,10 +1555,13 @@ int main(int argc, char *argv[]) else if (Keypressed(input, Key.GoToContainingDir)) { if ((wCurrent == mPlaylist && !mPlaylist->Empty()) - || (wCurrent == mSearcher && !mSearcher->Current().first) - || (wCurrent == mLibSongs && !mLibSongs->Empty()) - || (wCurrent == mPlaylistEditor && !mPlaylistEditor->Empty()) - || (wCurrent == mEditorTags && !mEditorTags->Empty())) + || (wCurrent == mSearcher && !mSearcher->Current().first) + || (wCurrent == mLibSongs && !mLibSongs->Empty()) + || (wCurrent == mPlaylistEditor && !mPlaylistEditor->Empty()) +# ifdef HAVE_TAGLIB_H + || (wCurrent == mEditorTags && !mEditorTags->Empty()) +# endif // HAVE_TAGLIB_H + ) { size_t id = ((Menu *)wCurrent)->Choice(); Song *s = 0; @@ -2870,9 +1579,11 @@ int main(int argc, char *argv[]) case csPlaylistEditor: s = &mPlaylistEditor->at(id); break; +# ifdef HAVE_TAGLIB_H case csTagEditor: s = &mEditorTags->at(id); break; +# endif // HAVE_TAGLIB_H default: break; } @@ -2893,7 +1604,7 @@ int main(int argc, char *argv[]) break; } } - goto SWITCHER_BROWSER_REDIRECT; + Browser::SwitchTo(); } } else if (Keypressed(input, Key.StartSearching)) @@ -2904,7 +1615,7 @@ int main(int argc, char *argv[]) mSearcher->Highlighting(0); mSearcher->Refresh(); mSearcher->Highlighting(1); - goto ENTER_SEARCH_ENGINE_SCREEN; + SearchEngine::EnterPressed(); } } else if (Keypressed(input, Key.GoToPosition)) @@ -2926,7 +1637,15 @@ int main(int argc, char *argv[]) } else if (Keypressed(input, Key.ReverseSelection)) { - if (wCurrent == mPlaylist || wCurrent == mBrowser || (wCurrent == mSearcher && !mSearcher->Current().first) || wCurrent == mLibSongs || wCurrent == mPlaylistEditor || wCurrent == mEditorTags) + if (wCurrent == mPlaylist + || wCurrent == mBrowser + || (wCurrent == mSearcher && !mSearcher->Current().first) + || wCurrent == mLibSongs + || wCurrent == mPlaylistEditor +# ifdef HAVE_TAGLIB_H + || wCurrent == mEditorTags +# endif // HAVE_TAGLIB_H + ) { List *mList = reinterpret_cast *>(wCurrent); @@ -2943,7 +1662,15 @@ int main(int argc, char *argv[]) } else if (Keypressed(input, Key.DeselectAll)) { - if (wCurrent == mPlaylist || wCurrent == mBrowser || wCurrent == mSearcher || wCurrent == mLibSongs || wCurrent == mPlaylistEditor || wCurrent == mEditorTags) + if (wCurrent == mPlaylist + || wCurrent == mBrowser + || wCurrent == mSearcher + || wCurrent == mLibSongs + || wCurrent == mPlaylistEditor +# ifdef HAVE_TAGLIB_H + || wCurrent == mEditorTags +# endif // HAVE_TAGLIB_H + ) { List *mList = reinterpret_cast *>(wCurrent); if (mList->hasSelected()) @@ -3086,11 +1813,11 @@ int main(int argc, char *argv[]) // redraw_screen = 1; if (current_screen == csLibrary) { - REFRESH_MEDIA_LIBRARY_SCREEN; + MediaLibrary::Refresh(); } else if (current_screen == csPlaylistEditor) { - REFRESH_PLAYLIST_EDITOR_SCREEN; + PlaylistEditor::Refresh(); } else wCurrent->Refresh(); @@ -3188,10 +1915,14 @@ int main(int argc, char *argv[]) { if ((current_screen == csHelp || current_screen == csSearcher +# ifdef HAVE_TAGLIB_H || current_screen == csTinyTagEditor - || wCurrent == mEditorTagTypes) + || wCurrent == mEditorTagTypes +# endif // HAVE_TAGLIB_H + ) && (current_screen != csSearcher - || mSearcher->Current().first)) + || mSearcher->Current().first) + ) continue; string how = Keypressed(input, Key.FindForward) ? "forward" : "backward"; @@ -3248,6 +1979,7 @@ int main(int argc, char *argv[]) else name = mPlaylistEditor->at(i).toString(Config.song_list_format); break; +# ifdef HAVE_TAGLIB_H case csTagEditor: if (wCurrent == mEditorLeftCol) name = mEditorLeftCol->at(i).first; @@ -3301,6 +2033,7 @@ int main(int argc, char *argv[]) } } break; +# endif // HAVE_TAGLIB_H default: break; } @@ -3420,427 +2153,60 @@ int main(int argc, char *argv[]) } else if (Keypressed(input, Key.SongInfo)) { - if (wCurrent == sInfo) - { - wCurrent->Hide(); - current_screen = prev_screen; - wCurrent = wPrev; -// redraw_screen = 1; - redraw_header = 1; - if (current_screen == csLibrary) - { - REFRESH_MEDIA_LIBRARY_SCREEN; - } - else if (current_screen == csPlaylistEditor) - { - REFRESH_PLAYLIST_EDITOR_SCREEN; - } -# ifdef HAVE_TAGLIB_H - else if (current_screen == csTagEditor) - { - REFRESH_TAG_EDITOR_SCREEN; - } -# endif // HAVE_TAGLIB_H - } - else if ( - (wCurrent == mPlaylist && !mPlaylist->Empty()) - || (wCurrent == mBrowser && mBrowser->Current().type == itSong) - || (wCurrent == mSearcher && !mSearcher->Current().first) - || (wCurrent == mLibSongs && !mLibSongs->Empty()) - || (wCurrent == mPlaylistEditor && !mPlaylistEditor->Empty()) - || (wCurrent == mEditorTags && !mEditorTags->Empty())) - { - Song *s = 0; - size_t id = ((Menu *)wCurrent)->Choice(); - switch (current_screen) - { - case csPlaylist: - s = &mPlaylist->at(id); - break; - case csBrowser: - s = mBrowser->at(id).song; - break; - case csSearcher: - s = mSearcher->at(id).second; - break; - case csLibrary: - s = &mLibSongs->at(id); - break; - case csPlaylistEditor: - s = &mPlaylistEditor->at(id); - break; - case csTagEditor: - s = &mEditorTags->at(id); - break; - default: - break; - } - wPrev = wCurrent; - wCurrent = sInfo; - prev_screen = current_screen; - current_screen = csInfo; - redraw_header = 1; - info_title = "Song info"; - sInfo->Clear(); - GetInfo(*s, *sInfo); - sInfo->Flush(); - sInfo->Hide(); - } + Info::GetSong(); } # ifdef HAVE_CURL_CURL_H else if (Keypressed(input, Key.ArtistInfo)) { - if (wCurrent == sInfo) - { - wCurrent->Hide(); - current_screen = prev_screen; - wCurrent = wPrev; -// redraw_screen = 1; - redraw_header = 1; - if (current_screen == csLibrary) - { - REFRESH_MEDIA_LIBRARY_SCREEN; - } - else if (current_screen == csPlaylistEditor) - { - REFRESH_PLAYLIST_EDITOR_SCREEN; - } -# ifdef HAVE_TAGLIB_H - else if (current_screen == csTagEditor) - { - REFRESH_TAG_EDITOR_SCREEN; - } -# endif // HAVE_TAGLIB_H - } - else if ( - (wCurrent == mPlaylist && !mPlaylist->Empty()) - || (wCurrent == mBrowser && mBrowser->Current().type == itSong) - || (wCurrent == mSearcher && !mSearcher->Current().first) - || (wCurrent == mLibArtists && !mLibArtists->Empty()) - || (wCurrent == mLibSongs && !mLibSongs->Empty()) - || (wCurrent == mPlaylistEditor && !mPlaylistEditor->Empty()) - || (wCurrent == mEditorTags && !mEditorTags->Empty())) - { - if (artist_info_downloader) - { - ShowMessage("Artist's info is being downloaded..."); - continue; - } - - string *artist = new string(); - int id = ((Menu *)wCurrent)->Choice(); - switch (current_screen) - { - case csPlaylist: - *artist = mPlaylist->at(id).GetArtist(); - break; - case csBrowser: - *artist = mBrowser->at(id).song->GetArtist(); - break; - case csSearcher: - *artist = mSearcher->at(id).second->GetArtist(); - break; - case csLibrary: - *artist = mLibArtists->at(id); - break; - case csPlaylistEditor: - *artist = mPlaylistEditor->at(id).GetArtist(); - break; - case csTagEditor: - *artist = mEditorTags->at(id).GetArtist(); - break; - default: - break; - } - if (!artist->empty()) - { - wPrev = wCurrent; - wCurrent = sInfo; - prev_screen = current_screen; - current_screen = csInfo; - redraw_header = 1; - info_title = "Artist's info - " + *artist; - sInfo->Clear(); - sInfo->WriteXY(0, 0, 0, "Fetching artist's info..."); - sInfo->Refresh(); - if (!artist_info_downloader) - { - pthread_create(&artist_info_downloader, NULL, GetArtistInfo, artist); - } - } - else - delete artist; - } + Info::GetArtist(); } # endif // HAVE_CURL_CURL_H else if (Keypressed(input, Key.Lyrics)) { - if (wCurrent == sLyrics) - { - wCurrent->Hide(); - current_screen = prev_screen; - wCurrent = wPrev; -// redraw_screen = 1; - redraw_header = 1; - if (current_screen == csLibrary) - { - REFRESH_MEDIA_LIBRARY_SCREEN; - } - else if (current_screen == csPlaylistEditor) - { - REFRESH_PLAYLIST_EDITOR_SCREEN; - } -# ifdef HAVE_TAGLIB_H - else if (current_screen == csTagEditor) - { - REFRESH_TAG_EDITOR_SCREEN; - } -# endif // HAVE_TAGLIB_H - } - else if ( - (wCurrent == mPlaylist && !mPlaylist->Empty()) - || (wCurrent == mBrowser && mBrowser->Current().type == itSong) - || (wCurrent == mSearcher && !mSearcher->Current().first) - || (wCurrent == mLibSongs && !mLibSongs->Empty()) - || (wCurrent == mPlaylistEditor && !mPlaylistEditor->Empty()) - || (wCurrent == mEditorTags && !mEditorTags->Empty())) - { - LOAD_LYRICS: - -# ifdef HAVE_CURL_CURL_H - if (lyrics_downloader) - { - ShowMessage("Lyrics are being downloaded..."); - continue; - } -# endif - - Song *s = 0; - int id; - - if (reload_lyrics) - { - current_screen = csPlaylist; - wCurrent = mPlaylist; - reload_lyrics = 0; - id = now_playing; - } - else - id = ((Menu *)wCurrent)->Choice(); - - switch (current_screen) - { - case csPlaylist: - s = &mPlaylist->at(id); - break; - case csBrowser: - s = mBrowser->at(id).song; - break; - case csSearcher: - s = mSearcher->at(id).second; - break; - case csLibrary: - s = &mLibSongs->at(id); - break; - case csPlaylistEditor: - s = &mPlaylistEditor->at(id); - break; - case csTagEditor: - s = &mEditorTags->at(id); - break; - default: - break; - } - if (!s->GetArtist().empty() && !s->GetTitle().empty()) - { - lyrics_scroll_begin = 0; - lyrics_song = *s; - wPrev = wCurrent; - prev_screen = current_screen; - wCurrent = sLyrics; - current_screen = csLyrics; - redraw_header = 1; - sLyrics->Clear(); - sLyrics->WriteXY(0, 0, 0, "Fetching lyrics..."); - sLyrics->Refresh(); -# ifdef HAVE_CURL_CURL_H - if (!lyrics_downloader) - { - pthread_create(&lyrics_downloader, NULL, GetLyrics, s); - } -# else - GetLyrics(s); - sLyrics->Flush(); -# endif - } - } + Lyrics::Get(); } else if (Keypressed(input, Key.Help)) { - if (current_screen != csHelp && current_screen != csTinyTagEditor) - { - wCurrent = sHelp; - wCurrent->Hide(); - current_screen = csHelp; - redraw_header = 1; - } + Help::SwitchTo(); } else if (Keypressed(input, Key.ScreenSwitcher)) { if (current_screen == csPlaylist) - goto SWITCHER_BROWSER_REDIRECT; + Browser::SwitchTo(); else - goto SWITCHER_PLAYLIST_REDIRECT; + Playlist::SwitchTo(); } else if (Keypressed(input, Key.Playlist)) { - SWITCHER_PLAYLIST_REDIRECT: - if (current_screen != csPlaylist && current_screen != csTinyTagEditor) - { - CLEAR_FIND_HISTORY; - wCurrent = mPlaylist; - wCurrent->Hide(); - current_screen = csPlaylist; -// redraw_screen = 1; - redraw_header = 1; - } + Playlist::SwitchTo(); } else if (Keypressed(input, Key.Browser)) { - SWITCHER_BROWSER_REDIRECT: - if (current_screen != csBrowser && current_screen != csTinyTagEditor) - { - CLEAR_FIND_HISTORY; - mBrowser->Empty() ? GetDirectory(browsed_dir) : UpdateItemList(mBrowser); - wCurrent = mBrowser; - wCurrent->Hide(); - current_screen = csBrowser; -// redraw_screen = 1; - redraw_header = 1; - } + Browser::SwitchTo(); } else if (Keypressed(input, Key.SearchEngine)) { - if (current_screen != csSearcher && current_screen != csTinyTagEditor) - { - CLEAR_FIND_HISTORY; - if (mSearcher->Empty()) - PrepareSearchEngine(sought_pattern); - wCurrent = mSearcher; - wCurrent->Hide(); - current_screen = csSearcher; -// redraw_screen = 1; - redraw_header = 1; - if (!mSearcher->Back().first) - { - wCurrent->WriteXY(0, 0, 0, "Updating list..."); - UpdateFoundList(); - } - } + SearchEngine::SwitchTo(); } else if (Keypressed(input, Key.MediaLibrary)) { - if (current_screen != csLibrary && current_screen != csTinyTagEditor) - { - CLEAR_FIND_HISTORY; - - mPlaylist->Hide(); // hack, should be wCurrent, but it doesn't always have 100% width - -// redraw_screen = 1; - redraw_header = 1; - REFRESH_MEDIA_LIBRARY_SCREEN; - - wCurrent = wLibActiveCol; - current_screen = csLibrary; - - UpdateSongList(mLibSongs); - } + MediaLibrary::SwitchTo(); } else if (Keypressed(input, Key.PlaylistEditor)) { - if (current_screen != csPlaylistEditor && current_screen != csTinyTagEditor) - { - CLEAR_FIND_HISTORY; - - mPlaylist->Hide(); // hack, should be wCurrent, but it doesn't always have 100% width - -// redraw_screen = 1; - redraw_header = 1; - REFRESH_PLAYLIST_EDITOR_SCREEN; - - wCurrent = wPlaylistEditorActiveCol; - current_screen = csPlaylistEditor; - - UpdateSongList(mPlaylistEditor); - } + PlaylistEditor::SwitchTo(); } # ifdef HAVE_TAGLIB_H else if (Keypressed(input, Key.TagEditor)) { CHECK_MPD_MUSIC_DIR; - if (current_screen != csTagEditor && current_screen != csTinyTagEditor) - { - CLEAR_FIND_HISTORY; - - mPlaylist->Hide(); // hack, should be wCurrent, but it doesn't always have 100% width - -// redraw_screen = 1; - redraw_header = 1; - REFRESH_TAG_EDITOR_SCREEN; - - if (mEditorTagTypes->Empty()) - { - mEditorTagTypes->AddOption("Title"); - mEditorTagTypes->AddOption("Artist"); - mEditorTagTypes->AddOption("Album"); - mEditorTagTypes->AddOption("Year"); - mEditorTagTypes->AddOption("Track"); - mEditorTagTypes->AddOption("Genre"); - mEditorTagTypes->AddOption("Composer"); - mEditorTagTypes->AddOption("Performer"); - mEditorTagTypes->AddOption("Disc"); - mEditorTagTypes->AddOption("Comment"); - mEditorTagTypes->AddSeparator(); - mEditorTagTypes->AddOption("Filename"); - mEditorTagTypes->AddSeparator(); - mEditorTagTypes->AddOption("Options", 1, 1, 0); - mEditorTagTypes->AddSeparator(); - mEditorTagTypes->AddOption("Reset"); - mEditorTagTypes->AddOption("Save"); - mEditorTagTypes->AddSeparator(); - mEditorTagTypes->AddOption("Capitalize First Letters"); - mEditorTagTypes->AddOption("lower all letters"); - } - - wCurrent = wTagEditorActiveCol; - current_screen = csTagEditor; - } + TagEditor::SwitchTo(); } # endif // HAVE_TAGLIB_H # ifdef ENABLE_CLOCK else if (Keypressed(input, Key.Clock)) { - if (clock_width > size_t(COLS) || clock_height > main_height) - { - ShowMessage("Screen is too small to display clock!"); - } - else if (current_screen != csClock && current_screen != csTinyTagEditor) - { - if (!wClock) - { - wClock = new Scrollpad((COLS-clock_width)/2, (LINES-clock_height)/2, clock_width, clock_height-1, "", Config.main_color, Border(Config.main_color)); - wClock->SetTimeout(ncmpcpp_window_timeout); - } - - CLEAR_FIND_HISTORY; - wCurrent = wClock; - mPlaylist->Hide(); - current_screen = csClock; -// redraw_screen = 1; - redraw_header = 1; - InitClock(); - wCurrent->Display(); - } + Clock::SwitchTo(); } # endif // ENABLE_CLOCK else if (Keypressed(input, Key.Quit)) diff --git a/src/ncmpcpp.h b/src/ncmpcpp.h index e65b3e80..b6465bee 100644 --- a/src/ncmpcpp.h +++ b/src/ncmpcpp.h @@ -26,6 +26,12 @@ #include "scrollpad.h" #include "misc.h" +#define CLEAR_FIND_HISTORY \ + do { \ + found_pos = -1; \ + vFoundPositions.clear(); \ + } while (0) + typedef std::pair string_pair; enum NcmpcppScreen @@ -33,14 +39,20 @@ enum NcmpcppScreen csHelp, csPlaylist, csBrowser, +# ifdef HAVE_TAGLIB_H csTinyTagEditor, +# endif // HAVE_TAGLIB_H csInfo, csSearcher, csLibrary, csLyrics, csPlaylistEditor, +# ifdef HAVE_TAGLIB_H csTagEditor, +# endif // HAVE_TAGLIB_H +# ifdef ENABLE_CLOCK csClock, +# endif // ENABLE_CLOCK csOther }; @@ -48,5 +60,7 @@ const int ncmpcpp_window_timeout = 500; const std::string home_folder = getenv("HOME") ? getenv("HOME") : ""; +const char * const message_part_of_songs_added = "Only part of requested songs' list added to playlist!"; + #endif diff --git a/src/playlist.cpp b/src/playlist.cpp new file mode 100644 index 00000000..a58d7122 --- /dev/null +++ b/src/playlist.cpp @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2008-2009 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 "display.h" +#include "global.h" +#include "menu.h" +#include "playlist.h" +#include "song.h" + +using namespace Global; + +Menu *Global::mPlaylist; + +void Playlist::Init() +{ + mPlaylist = new Menu(0, main_start_y, COLS, main_height, Config.columns_in_playlist ? Display::Columns(Config.song_columns_list_format) : "", Config.main_color, brNone); + mPlaylist->SetTimeout(ncmpcpp_window_timeout); + mPlaylist->HighlightColor(Config.main_highlight_color); + mPlaylist->SetSelectPrefix(&Config.selected_item_prefix); + mPlaylist->SetSelectSuffix(&Config.selected_item_suffix); + mPlaylist->SetItemDisplayer(Config.columns_in_playlist ? Display::SongsInColumns : Display::Songs); + mPlaylist->SetItemDisplayerUserData(Config.columns_in_playlist ? &Config.song_columns_list_format : &Config.song_list_format); +} + +void Playlist::Resize() +{ + mPlaylist->Resize(COLS, main_height); + mPlaylist->SetTitle(Config.columns_in_playlist ? Display::Columns(Config.song_columns_list_format) : ""); +} + +void Playlist::SwitchTo() +{ + if (current_screen != csPlaylist +# ifdef HAVE_TAGLIB_H + && current_screen != csTinyTagEditor +# endif // HAVE_TAGLIB_H + ) + { + CLEAR_FIND_HISTORY; + wCurrent = mPlaylist; + wCurrent->Hide(); + current_screen = csPlaylist; +// redraw_screen = 1; + redraw_header = 1; + } +} + diff --git a/src/playlist.h b/src/playlist.h new file mode 100644 index 00000000..19b14b0b --- /dev/null +++ b/src/playlist.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2008-2009 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 _PLAYLIST_H +#define _PLAYLIST_H + +namespace Playlist +{ + void Init(); + void Resize(); + void SwitchTo(); +} + +#endif + diff --git a/src/playlist_editor.cpp b/src/playlist_editor.cpp new file mode 100644 index 00000000..3386b547 --- /dev/null +++ b/src/playlist_editor.cpp @@ -0,0 +1,244 @@ +/*************************************************************************** + * Copyright (C) 2008-2009 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 "charset.h" +#include "display.h" +#include "global.h" +#include "helpers.h" +#include "playlist_editor.h" +#include "mpdpp.h" +#include "status_checker.h" + +using namespace Global; +using namespace MPD; +using std::string; + +Window *Global::wPlaylistEditorActiveCol; +Menu *Global::mPlaylistList; +Menu *Global::mPlaylistEditor; + +namespace PlaylistEditor +{ + size_t left_col_width; + size_t right_col_startx; + size_t right_col_width; +} + +void PlaylistEditor::Init() +{ + left_col_width = COLS/3-1; + right_col_startx = left_col_width+1; + right_col_width = COLS-left_col_width-1; + + mPlaylistList = new Menu(0, main_start_y, left_col_width, main_height, "Playlists", Config.main_color, brNone); + mPlaylistList->HighlightColor(Config.active_column_color); + mPlaylistList->SetTimeout(ncmpcpp_window_timeout); + mPlaylistList->SetItemDisplayer(Display::Generic); + + mPlaylistEditor = new Menu(right_col_startx, main_start_y, right_col_width, main_height, "Playlist's content", Config.main_color, brNone); + mPlaylistEditor->HighlightColor(Config.main_highlight_color); + mPlaylistEditor->SetTimeout(ncmpcpp_window_timeout); + mPlaylistEditor->SetSelectPrefix(&Config.selected_item_prefix); + mPlaylistEditor->SetSelectSuffix(&Config.selected_item_suffix); + mPlaylistEditor->SetItemDisplayer(Display::Songs); + mPlaylistEditor->SetItemDisplayerUserData(&Config.song_list_format); + + wPlaylistEditorActiveCol = mPlaylistList; +} + +void PlaylistEditor::Resize() +{ + left_col_width = COLS/3-1; + right_col_startx = left_col_width+1; + right_col_width = COLS-left_col_width-1; + + mPlaylistList->Resize(left_col_width, main_height); + mPlaylistEditor->Resize(right_col_width, main_height); + + mPlaylistEditor->MoveTo(right_col_startx, main_start_y); +} + +void PlaylistEditor::Refresh() +{ + mPlaylistList->Display(); + mvvline(main_start_y, right_col_startx-1, 0, main_height); + mPlaylistEditor->Display(); +} + +void PlaylistEditor::SwitchTo() +{ + if (current_screen != csPlaylistEditor +# ifdef HAVE_TAGLIB_H + && current_screen != csTinyTagEditor +# endif // HAVE_TAGLIB_H + ) + { + CLEAR_FIND_HISTORY; + + mPlaylist->Hide(); // hack, should be wCurrent, but it doesn't always have 100% width + +// redraw_screen = 1; + redraw_header = 1; + PlaylistEditor::Refresh(); + + wCurrent = wPlaylistEditorActiveCol; + current_screen = csPlaylistEditor; + + UpdateSongList(mPlaylistEditor); + } +} + +void PlaylistEditor::Update() +{ + if (mPlaylistList->Empty()) + { + mPlaylistEditor->Clear(0); + TagList list; + Mpd->GetPlaylists(list); + sort(list.begin(), list.end(), CaseInsensitiveSorting()); + for (TagList::iterator it = list.begin(); it != list.end(); it++) + { + utf_to_locale(*it); + mPlaylistList->AddOption(*it); + } + mPlaylistList->Window::Clear(); + mPlaylistList->Refresh(); + } + + if (!mPlaylistList->Empty() && mPlaylistEditor->Empty()) + { + mPlaylistEditor->Reset(); + SongList list; + Mpd->GetPlaylistContent(locale_to_utf_cpy(mPlaylistList->Current()), list); + if (!list.empty()) + mPlaylistEditor->SetTitle("Playlist's content (" + IntoStr(list.size()) + " item" + (list.size() == 1 ? ")" : "s)")); + else + mPlaylistEditor->SetTitle("Playlist's content"); + bool bold = 0; + for (SongList::const_iterator it = list.begin(); it != list.end(); it++) + { + for (size_t j = 0; j < mPlaylist->Size(); j++) + { + if ((*it)->GetHash() == mPlaylist->at(j).GetHash()) + { + bold = 1; + break; + } + } + mPlaylistEditor->AddOption(**it, bold); + bold = 0; + } + FreeSongList(list); + mPlaylistEditor->Window::Clear(); + mPlaylistEditor->Display(); + } + + if (wCurrent == mPlaylistEditor && mPlaylistEditor->Empty()) + { + mPlaylistEditor->HighlightColor(Config.main_highlight_color); + mPlaylistList->HighlightColor(Config.active_column_color); + wCurrent = wPlaylistEditorActiveCol = mPlaylistList; + } + + if (mPlaylistEditor->Empty()) + { + mPlaylistEditor->WriteXY(0, 0, 0, "Playlist is empty."); + mPlaylistEditor->Refresh(); + } +} + +void PlaylistEditor::EnterPressed(bool add_n_play) +{ + SongList list; + + if (wCurrent == mPlaylistList && !mPlaylistList->Empty()) + { + Mpd->GetPlaylistContent(locale_to_utf_cpy(mPlaylistList->Current()), list); + for (SongList::const_iterator it = list.begin(); it != list.end(); it++) + Mpd->QueueAddSong(**it); + if (Mpd->CommitQueue()) + { + ShowMessage("Loading playlist %s...", mPlaylistList->Current().c_str()); + Song &s = mPlaylist->at(mPlaylist->Size()-list.size()); + if (s.GetHash() == list[0]->GetHash()) + { + if (add_n_play) + Mpd->PlayID(s.GetID()); + } + else + ShowMessage("%s", message_part_of_songs_added); + } + } + else if (wCurrent == mPlaylistEditor) + { + if (!mPlaylistEditor->Empty()) + { + block_item_list_update = 1; + if (Config.ncmpc_like_songs_adding && mPlaylistEditor->isBold()) + { + long long hash = mPlaylistEditor->Current().GetHash(); + if (add_n_play) + { + for (size_t i = 0; i < mPlaylist->Size(); i++) + { + if (mPlaylist->at(i).GetHash() == hash) + { + Mpd->Play(i); + break; + } + } + } + else + { + block_playlist_update = 1; + for (size_t i = 0; i < mPlaylist->Size(); i++) + { + if (mPlaylist->at(i).GetHash() == hash) + { + Mpd->QueueDeleteSong(i); + mPlaylist->DeleteOption(i); + i--; + } + } + Mpd->CommitQueue(); + mPlaylistEditor->BoldOption(mPlaylistEditor->Choice(), 0); + } + } + else + { + Song &s = mPlaylistEditor->at(mPlaylistEditor->Choice()); + int id = Mpd->AddSong(s); + if (id >= 0) + { + ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str()); + if (add_n_play) + Mpd->PlayID(id); + mPlaylistEditor->BoldOption(mPlaylistEditor->Choice(), 1); + } + } + } + } + FreeSongList(list); + if (!add_n_play) + wCurrent->Scroll(wDown); +} + diff --git a/src/playlist_editor.h b/src/playlist_editor.h new file mode 100644 index 00000000..d493ab6d --- /dev/null +++ b/src/playlist_editor.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2008-2009 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 _PLAYLIST_EDITOR_H +#define _PLAYLIST_EDITOR_H + +#include "ncmpcpp.h" + +namespace PlaylistEditor +{ + void Init(); + void Resize(); + void Refresh(); + void SwitchTo(); + void Update(); + + void EnterPressed(bool = 1); + inline void SpacePressed(); +} + +void PlaylistEditor::SpacePressed() +{ + EnterPressed(0); +} + +#endif + diff --git a/src/search_engine.cpp b/src/search_engine.cpp index d00778e9..79d9005e 100644 --- a/src/search_engine.cpp +++ b/src/search_engine.cpp @@ -23,17 +23,262 @@ #include "helpers.h" #include "search_engine.h" #include "settings.h" +#include "status_checker.h" using namespace MPD; using namespace Global; using std::string; +Menu< std::pair > *Global::mSearcher; + bool Global::search_match_to_pattern = 1; bool Global::search_case_sensitive = 0; const char *Global::search_mode_normal = "Match if tag contains searched phrase"; const char *Global::search_mode_strict = "Match only if both values are the same"; +namespace +{ + SearchPattern sought; +} + +void SearchEngine::Init() +{ + mSearcher = new Menu< std::pair >(0, main_start_y, COLS, main_height, "", Config.main_color, brNone); + mSearcher->HighlightColor(Config.main_highlight_color); + mSearcher->SetTimeout(ncmpcpp_window_timeout); + mSearcher->SetItemDisplayer(Display::SearchEngine); + mSearcher->SetSelectPrefix(&Config.selected_item_prefix); + mSearcher->SetSelectSuffix(&Config.selected_item_suffix); +} + +void SearchEngine::Resize() +{ + mSearcher->Resize(COLS, main_height); +} + +void SearchEngine::SwitchTo() +{ + if (current_screen != csSearcher +# ifdef HAVE_TAGLIB_H + && current_screen != csTinyTagEditor +# endif // HAVE_TAGLIB_H + ) + { + CLEAR_FIND_HISTORY; + if (mSearcher->Empty()) + PrepareSearchEngine(); + wCurrent = mSearcher; + wCurrent->Hide(); + current_screen = csSearcher; +// redraw_screen = 1; + redraw_header = 1; + if (!mSearcher->Back().first) + { + wCurrent->WriteXY(0, 0, 0, "Updating list..."); + UpdateFoundList(); + } + } +} + +void SearchEngine::EnterPressed() +{ + size_t option = mSearcher->Choice(); + LockStatusbar(); + SearchPattern &s = sought; + + if (option <= 12) + mSearcher->Current().first->Clear(); + + switch (option) + { + case 0: + { + Statusbar() << fmtBold << "Any: " << fmtBoldEnd; + s.Any(wFooter->GetString(s.Any())); + *mSearcher->Current().first << fmtBold << "Any: " << fmtBoldEnd << ' ' << ShowTag(s.Any()); + break; + } + case 1: + { + Statusbar() << fmtBold << "Artist: " << fmtBoldEnd; + s.SetArtist(wFooter->GetString(s.GetArtist())); + *mSearcher->Current().first << fmtBold << "Artist: " << fmtBoldEnd << ' ' << ShowTag(s.GetArtist()); + break; + } + case 2: + { + Statusbar() << fmtBold << "Title: " << fmtBoldEnd; + s.SetTitle(wFooter->GetString(s.GetTitle())); + *mSearcher->Current().first << fmtBold << "Title: " << fmtBoldEnd << ' ' << ShowTag(s.GetTitle()); + break; + } + case 3: + { + Statusbar() << fmtBold << "Album: " << fmtBoldEnd; + s.SetAlbum(wFooter->GetString(s.GetAlbum())); + *mSearcher->Current().first << fmtBold << "Album: " << fmtBoldEnd << ' ' << ShowTag(s.GetAlbum()); + break; + } + case 4: + { + Statusbar() << fmtBold << "Filename: " << fmtBoldEnd; + s.SetFile(wFooter->GetString(s.GetFile())); + *mSearcher->Current().first << fmtBold << "Filename: " << fmtBoldEnd << ' ' << ShowTag(s.GetFile()); + break; + } + case 5: + { + Statusbar() << fmtBold << "Composer: " << fmtBoldEnd; + s.SetComposer(wFooter->GetString(s.GetComposer())); + *mSearcher->Current().first << fmtBold << "Composer: " << fmtBoldEnd << ' ' << ShowTag(s.GetComposer()); + break; + } + case 6: + { + Statusbar() << fmtBold << "Performer: " << fmtBoldEnd; + s.SetPerformer(wFooter->GetString(s.GetPerformer())); + *mSearcher->Current().first << fmtBold << "Performer:" << fmtBoldEnd << ' ' << ShowTag(s.GetPerformer()); + break; + } + case 7: + { + Statusbar() << fmtBold << "Genre: " << fmtBoldEnd; + s.SetGenre(wFooter->GetString(s.GetGenre())); + *mSearcher->Current().first << fmtBold << "Genre: " << fmtBoldEnd << ' ' << ShowTag(s.GetGenre()); + break; + } + case 8: + { + Statusbar() << fmtBold << "Year: " << fmtBoldEnd; + s.SetYear(wFooter->GetString(s.GetYear(), 4)); + *mSearcher->Current().first << fmtBold << "Year: " << fmtBoldEnd << ' ' << ShowTag(s.GetYear()); + break; + } + case 9: + { + Statusbar() << fmtBold << "Comment: " << fmtBoldEnd; + s.SetComment(wFooter->GetString(s.GetComment())); + *mSearcher->Current().first << fmtBold << "Comment: " << fmtBoldEnd << ' ' << ShowTag(s.GetComment()); + break; + } + case 11: + { + Config.search_in_db = !Config.search_in_db; + *mSearcher->Current().first << fmtBold << "Search in:" << fmtBoldEnd << ' ' << (Config.search_in_db ? "Database" : "Current playlist"); + break; + } + case 12: + { + search_match_to_pattern = !search_match_to_pattern; + *mSearcher->Current().first << fmtBold << "Search mode:" << fmtBoldEnd << ' ' << (search_match_to_pattern ? search_mode_normal : search_mode_strict); + break; + } + case 13: + { + search_case_sensitive = !search_case_sensitive; + *mSearcher->Current().first << fmtBold << "Case sensitive:" << fmtBoldEnd << ' ' << (search_case_sensitive ? "Yes" : "No"); + break; + } + case 15: + { + ShowMessage("Searching..."); + Search(); + if (!mSearcher->Back().first) + { + if (Config.columns_in_search_engine) + mSearcher->SetTitle(Display::Columns(Config.song_columns_list_format)); + size_t found = mSearcher->Size()-search_engine_static_options; + found += 3; // don't count options inserted below + mSearcher->InsertSeparator(search_engine_reset_button+1); + mSearcher->InsertOption(search_engine_reset_button+2, std::make_pair((Buffer *)0, (Song *)0), 1, 1); + mSearcher->at(search_engine_reset_button+2).first = new Buffer(); + *mSearcher->at(search_engine_reset_button+2).first << Config.color1 << "Search results: " << Config.color2 << "Found " << found << (found > 1 ? " songs" : " song") << clDefault; + mSearcher->InsertSeparator(search_engine_reset_button+3); + UpdateFoundList(); + ShowMessage("Searching finished!"); + for (size_t i = 0; i < search_engine_static_options-4; i++) + mSearcher->Static(i, 1); + mSearcher->Scroll(wDown); + mSearcher->Scroll(wDown); + } + else + ShowMessage("No results found"); + break; + } + case 16: + { + CLEAR_FIND_HISTORY; + PrepareSearchEngine(); + ShowMessage("Search state reset"); + break; + } + default: + { + block_item_list_update = 1; + if (Config.ncmpc_like_songs_adding && mSearcher->isBold()) + { + long long hash = mSearcher->Current().second->GetHash(); + for (size_t i = 0; i < mPlaylist->Size(); i++) + { + if (mPlaylist->at(i).GetHash() == hash) + { + Mpd->Play(i); + break; + } + } + } + else + { + const Song &s = *mSearcher->Current().second; + int id = Mpd->AddSong(s); + if (id >= 0) + { + Mpd->PlayID(id); + ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str()); + mSearcher->BoldOption(mSearcher->Choice(), 1); + } + } + break; + } + } + UnlockStatusbar(); +} + +void SearchEngine::SpacePressed() +{ + if (mSearcher->Current().first) + return; + + block_item_list_update = 1; + if (Config.ncmpc_like_songs_adding && mSearcher->isBold()) + { + block_playlist_update = 1; + long long hash = mSearcher->Current().second->GetHash(); + for (size_t i = 0; i < mPlaylist->Size(); i++) + { + if (mPlaylist->at(i).GetHash() == hash) + { + Mpd->QueueDeleteSong(i); + mPlaylist->DeleteOption(i); + i--; + } + } + Mpd->CommitQueue(); + mSearcher->BoldOption(mSearcher->Choice(), 0); + } + else + { + const Song &s = *mSearcher->Current().second; + if (Mpd->AddSong(s) != -1) + { + ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str()); + mSearcher->BoldOption(mSearcher->Choice(), 1); + } + } + mSearcher->Scroll(wDown); +} + void UpdateFoundList() { bool bold = 0; @@ -52,8 +297,10 @@ void UpdateFoundList() } } -void PrepareSearchEngine(SearchPattern &s) +void PrepareSearchEngine() { + SearchPattern &s = sought; + for (size_t i = 0; i < mSearcher->Size(); i++) { try @@ -101,11 +348,13 @@ void PrepareSearchEngine(SearchPattern &s) *mSearcher->at(16).first << "Reset"; } -void Search(SearchPattern s) +void Search() { - if (s.Empty()) + if (sought.Empty()) return; + SearchPattern s = sought; + SongList list; if (Config.search_in_db) Mpd->GetDirectoryRecursive("/", list); diff --git a/src/search_engine.h b/src/search_engine.h index 0c03d4ca..e892a81b 100644 --- a/src/search_engine.h +++ b/src/search_engine.h @@ -24,6 +24,16 @@ #include "mpdpp.h" #include "ncmpcpp.h" +namespace SearchEngine +{ + void Init(); + void Resize(); + void SwitchTo(); + + void EnterPressed(); + void SpacePressed(); +} + class SearchPattern : public MPD::Song { public: @@ -42,8 +52,8 @@ const size_t search_engine_search_button = 15; const size_t search_engine_reset_button = 16; void UpdateFoundList(); -void PrepareSearchEngine(SearchPattern &s); -void Search(SearchPattern); +void PrepareSearchEngine(); +void Search(); #endif diff --git a/src/tag_editor.cpp b/src/tag_editor.cpp index 05e1cce1..ffe21366 100644 --- a/src/tag_editor.cpp +++ b/src/tag_editor.cpp @@ -33,11 +33,583 @@ #include "display.h" #include "global.h" #include "helpers.h" +#include "media_library.h" +#include "playlist_editor.h" #include "status_checker.h" using namespace Global; using namespace MPD; +Menu *Global::mTagEditor; + +Window *Global::wTagEditorActiveCol; +Menu *Global::mEditorAlbums; +Menu *Global::mEditorDirs; +Menu *Global::mEditorLeftCol; +Menu *Global::mEditorTagTypes; +Menu *Global::mEditorTags; + +void TinyTagEditor::Init() +{ + mTagEditor = new Menu(0, main_start_y, COLS, main_height, "", Config.main_color, brNone); + mTagEditor->HighlightColor(Config.main_highlight_color); + mTagEditor->SetTimeout(ncmpcpp_window_timeout); + mTagEditor->SetItemDisplayer(Display::Generic); +} + +void TinyTagEditor::EnterPressed(Song &s) +{ + size_t option = mTagEditor->Choice(); + LockStatusbar(); + + if (option >= 8 && option <= 20) + mTagEditor->at(option).Clear(); + + switch (option-7) + { + case 1: + { + Statusbar() << fmtBold << "Title: " << fmtBoldEnd; + s.SetTitle(wFooter->GetString(s.GetTitle())); + mTagEditor->at(option) << fmtBold << "Title:" << fmtBoldEnd << ' ' << ShowTag(s.GetTitle()); + break; + } + case 2: + { + Statusbar() << fmtBold << "Artist: " << fmtBoldEnd; + s.SetArtist(wFooter->GetString(s.GetArtist())); + mTagEditor->at(option) << fmtBold << "Artist:" << fmtBoldEnd << ' ' << ShowTag(s.GetArtist()); + break; + } + case 3: + { + Statusbar() << fmtBold << "Album: " << fmtBoldEnd; + s.SetAlbum(wFooter->GetString(s.GetAlbum())); + mTagEditor->at(option) << fmtBold << "Album:" << fmtBoldEnd << ' ' << ShowTag(s.GetAlbum()); + break; + } + case 4: + { + Statusbar() << fmtBold << "Year: " << fmtBoldEnd; + s.SetYear(wFooter->GetString(s.GetYear(), 4)); + mTagEditor->at(option) << fmtBold << "Year:" << fmtBoldEnd << ' ' << ShowTag(s.GetYear()); + break; + } + case 5: + { + Statusbar() << fmtBold << "Track: " << fmtBoldEnd; + s.SetTrack(wFooter->GetString(s.GetTrack(), 3)); + mTagEditor->at(option) << fmtBold << "Track:" << fmtBoldEnd << ' ' << ShowTag(s.GetTrack()); + break; + } + case 6: + { + Statusbar() << fmtBold << "Genre: " << fmtBoldEnd; + s.SetGenre(wFooter->GetString(s.GetGenre())); + mTagEditor->at(option) << fmtBold << "Genre:" << fmtBoldEnd << ' ' << ShowTag(s.GetGenre()); + break; + } + case 7: + { + Statusbar() << fmtBold << "Composer: " << fmtBoldEnd; + s.SetComposer(wFooter->GetString(s.GetComposer())); + mTagEditor->at(option) << fmtBold << "Composer:" << fmtBoldEnd << ' ' << ShowTag(s.GetComposer()); + break; + } + case 8: + { + Statusbar() << fmtBold << "Performer: " << fmtBoldEnd; + s.SetPerformer(wFooter->GetString(s.GetPerformer())); + mTagEditor->at(option) << fmtBold << "Performer:" << fmtBoldEnd << ' ' << ShowTag(s.GetPerformer()); + break; + } + case 9: + { + Statusbar() << fmtBold << "Disc: " << fmtBoldEnd; + s.SetDisc(wFooter->GetString(s.GetDisc())); + mTagEditor->at(option) << fmtBold << "Disc:" << fmtBoldEnd << ' ' << ShowTag(s.GetDisc()); + break; + } + case 10: + { + Statusbar() << fmtBold << "Comment: " << fmtBoldEnd; + s.SetComment(wFooter->GetString(s.GetComment())); + mTagEditor->at(option) << fmtBold << "Comment:" << fmtBoldEnd << ' ' << ShowTag(s.GetComment()); + break; + } + case 12: + { + Statusbar() << fmtBold << "Filename: " << fmtBoldEnd; + string filename = s.GetNewName().empty() ? s.GetName() : s.GetNewName(); + size_t dot = filename.rfind("."); + string extension = filename.substr(dot); + filename = filename.substr(0, dot); + string new_name = wFooter->GetString(filename); + s.SetNewName(new_name + extension); + mTagEditor->at(option) << fmtBold << "Filename:" << fmtBoldEnd << ' ' << (s.GetNewName().empty() ? s.GetName() : s.GetNewName()); + break; + } + case 14: + { + ShowMessage("Updating tags..."); + if (WriteTags(s)) + { + ShowMessage("Tags updated!"); + if (s.IsFromDB()) + { + Mpd->UpdateDirectory(locale_to_utf_cpy(s.GetDirectory())); + if (prev_screen == csSearcher) + *mSearcher->Current().second = s; + } + else + { + if (wPrev == mPlaylist) + mPlaylist->Current() = s; + else if (wPrev == mBrowser) + *mBrowser->Current().song = s; + } + } + else + ShowMessage("Error writing tags!"); + } + case 15: + { + wCurrent->Clear(); + wCurrent = wPrev; + current_screen = prev_screen; + redraw_header = 1; + if (current_screen == csLibrary) + { + MediaLibrary::Refresh(); + } + else if (current_screen == csPlaylistEditor) + { + PlaylistEditor::Refresh(); + } + else if (current_screen == csTagEditor) + { + TagEditor::Refresh(); + } + break; + } + } + UnlockStatusbar(); +} + +namespace TagEditor +{ + const size_t middle_col_width = 26; + size_t left_col_width; + size_t middle_col_startx; + size_t right_col_width; + size_t right_col_startx; +} + +void TagEditor::Init() +{ + left_col_width = COLS/2-middle_col_width/2; + middle_col_startx = left_col_width+1; + right_col_width = COLS-left_col_width-middle_col_width-2; + right_col_startx = left_col_width+middle_col_width+2; + + mEditorAlbums = new Menu(0, main_start_y, left_col_width, main_height, "Albums", Config.main_color, brNone); + mEditorAlbums->HighlightColor(Config.active_column_color); + mEditorAlbums->SetTimeout(ncmpcpp_window_timeout); + mEditorAlbums->SetItemDisplayer(Display::StringPairs); + + mEditorDirs = new Menu(0, main_start_y, left_col_width, main_height, "Directories", Config.main_color, brNone); + mEditorDirs->HighlightColor(Config.active_column_color); + mEditorDirs->SetTimeout(ncmpcpp_window_timeout); + mEditorDirs->SetItemDisplayer(Display::StringPairs); + mEditorLeftCol = Config.albums_in_tag_editor ? mEditorAlbums : mEditorDirs; + + mEditorTagTypes = new Menu(middle_col_startx, main_start_y, middle_col_width, main_height, "Tag types", Config.main_color, brNone); + mEditorTagTypes->HighlightColor(Config.main_highlight_color); + mEditorTagTypes->SetTimeout(ncmpcpp_window_timeout); + mEditorTagTypes->SetItemDisplayer(Display::Generic); + + mEditorTags = new Menu(right_col_startx, main_start_y, right_col_width, main_height, "Tags", Config.main_color, brNone); + mEditorTags->HighlightColor(Config.main_highlight_color); + mEditorTags->SetTimeout(ncmpcpp_window_timeout); + mEditorTags->SetSelectPrefix(&Config.selected_item_prefix); + mEditorTags->SetSelectSuffix(&Config.selected_item_suffix); + mEditorTags->SetItemDisplayer(Display::Tags); + mEditorTags->SetItemDisplayerUserData(mEditorTagTypes); + + wTagEditorActiveCol = mEditorLeftCol; +} + +void TagEditor::Resize() +{ + left_col_width = COLS/2-middle_col_width/2; + middle_col_startx = left_col_width+1; + right_col_width = COLS-left_col_width-middle_col_width-2; + right_col_startx = left_col_width+middle_col_width+2; + + mEditorAlbums->Resize(left_col_width, main_height); + mEditorDirs->Resize(left_col_width, main_height); + mEditorTagTypes->Resize(middle_col_width, main_height); + mEditorTags->Resize(right_col_width, main_height); + + mEditorTagTypes->MoveTo(middle_col_startx, main_start_y); + mEditorTags->MoveTo(right_col_startx, main_start_y); +} + +void TagEditor::Refresh() +{ + mEditorLeftCol->Display(); + mvvline(main_start_y, middle_col_startx-1, 0, main_height); + mEditorTagTypes->Display(); + mvvline(main_start_y, right_col_startx-1, 0, main_height); + mEditorTags->Display(); +} + +void TagEditor::SwitchTo() +{ + if (current_screen != csTagEditor && current_screen != csTinyTagEditor) + { + CLEAR_FIND_HISTORY; + + mPlaylist->Hide(); // hack, should be wCurrent, but it doesn't always have 100% width + +// redraw_screen = 1; + redraw_header = 1; + TagEditor::Refresh(); + + if (mEditorTagTypes->Empty()) + { + mEditorTagTypes->AddOption("Title"); + mEditorTagTypes->AddOption("Artist"); + mEditorTagTypes->AddOption("Album"); + mEditorTagTypes->AddOption("Year"); + mEditorTagTypes->AddOption("Track"); + mEditorTagTypes->AddOption("Genre"); + mEditorTagTypes->AddOption("Composer"); + mEditorTagTypes->AddOption("Performer"); + mEditorTagTypes->AddOption("Disc"); + mEditorTagTypes->AddOption("Comment"); + mEditorTagTypes->AddSeparator(); + mEditorTagTypes->AddOption("Filename"); + mEditorTagTypes->AddSeparator(); + mEditorTagTypes->AddOption("Options", 1, 1, 0); + mEditorTagTypes->AddSeparator(); + mEditorTagTypes->AddOption("Reset"); + mEditorTagTypes->AddOption("Save"); + mEditorTagTypes->AddSeparator(); + mEditorTagTypes->AddOption("Capitalize First Letters"); + mEditorTagTypes->AddOption("lower all letters"); + } + + wCurrent = wTagEditorActiveCol; + current_screen = csTagEditor; + } +} + +void TagEditor::Update() +{ + if (mEditorLeftCol->Empty()) + { + CLEAR_FIND_HISTORY; + mEditorLeftCol->Window::Clear(); + mEditorTags->Clear(); + TagList list; + if (Config.albums_in_tag_editor) + { + std::map maplist; + mEditorAlbums->WriteXY(0, 0, 0, "Fetching albums' list..."); + Mpd->GetAlbums("", list); + for (TagList::const_iterator it = list.begin(); it != list.end(); it++) + { + SongList l; + Mpd->StartSearch(1); + Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, *it); + Mpd->CommitSearch(l); + if (!l.empty()) + { + l[0]->Localize(); + maplist[l[0]->toString(Config.tag_editor_album_format)] = *it; + } + FreeSongList(l); + } + for (std::map::const_iterator it = maplist.begin(); it != maplist.end(); it++) + mEditorAlbums->AddOption(make_pair(it->first, it->second)); + } + else + { + int highlightme = -1; + Mpd->GetDirectories(editor_browsed_dir, list); + sort(list.begin(), list.end(), CaseInsensitiveSorting()); + if (editor_browsed_dir != "/") + { + size_t slash = editor_browsed_dir.rfind("/"); + string parent = slash != string::npos ? editor_browsed_dir.substr(0, slash) : "/"; + mEditorDirs->AddOption(make_pair("[..]", parent)); + } + else + { + mEditorDirs->AddOption(make_pair(".", "/")); + } + for (TagList::const_iterator it = list.begin(); it != list.end(); it++) + { + size_t slash = it->rfind("/"); + string to_display = slash != string::npos ? it->substr(slash+1) : *it; + utf_to_locale(to_display); + mEditorDirs->AddOption(make_pair(to_display, *it)); + if (*it == editor_highlighted_dir) + highlightme = mEditorDirs->Size()-1; + } + if (highlightme != -1) + mEditorDirs->Highlight(highlightme); + } + mEditorLeftCol->Display(); + mEditorTagTypes->Refresh(); + } + + if (mEditorTags->Empty()) + { + mEditorTags->Reset(); + SongList list; + if (Config.albums_in_tag_editor) + { + Mpd->StartSearch(1); + Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, mEditorAlbums->Current().second); + Mpd->CommitSearch(list); + sort(list.begin(), list.end(), CaseInsensitiveSorting()); + for (SongList::iterator it = list.begin(); it != list.end(); it++) + { + (*it)->Localize(); + mEditorTags->AddOption(**it); + } + } + else + { + Mpd->GetSongs(mEditorDirs->Current().second, list); + sort(list.begin(), list.end(), CaseInsensitiveSorting()); + for (SongList::const_iterator it = list.begin(); it != list.end(); it++) + { + (*it)->Localize(); + mEditorTags->AddOption(**it); + } + } + FreeSongList(list); + mEditorTags->Window::Clear(); + mEditorTags->Refresh(); + } + + if (/*redraw_screen && */wCurrent == mEditorTagTypes && mEditorTagTypes->Choice() < 13) + { + mEditorTags->Refresh(); +// redraw_screen = 0; + } + else if (mEditorTagTypes->Choice() >= 13) + mEditorTags->Window::Clear(); +} + +void TagEditor::EnterPressed() +{ + if (wCurrent == mEditorDirs) + { + TagList test; + Mpd->GetDirectories(mEditorLeftCol->Current().second, test); + if (!test.empty()) + { + editor_highlighted_dir = editor_browsed_dir; + editor_browsed_dir = mEditorLeftCol->Current().second; + mEditorLeftCol->Clear(0); + mEditorLeftCol->Reset(); + } + else + ShowMessage("No subdirs found"); + return; + } + + if (mEditorTags->Empty()) // we need songs to deal with, don't we? + return; + + // if there are selected songs, perform operations only on them + SongList list; + if (mEditorTags->hasSelected()) + { + vector selected; + mEditorTags->GetSelected(selected); + for (vector::const_iterator it = selected.begin(); it != selected.end(); it++) + list.push_back(&mEditorTags->at(*it)); + } + else + for (size_t i = 0; i < mEditorTags->Size(); i++) + list.push_back(&mEditorTags->at(i)); + + SongGetFunction get = 0; + SongSetFunction set = 0; + + size_t id = mEditorTagTypes->RealChoice(); + switch (id) + { + case 0: + get = &Song::GetTitle; + set = &Song::SetTitle; + break; + case 1: + get = &Song::GetArtist; + set = &Song::SetArtist; + break; + case 2: + get = &Song::GetAlbum; + set = &Song::SetAlbum; + break; + case 3: + get = &Song::GetYear; + set = &Song::SetYear; + break; + case 4: + get = &Song::GetTrack; + set = &Song::SetTrack; + if (wCurrent == mEditorTagTypes) + { + LockStatusbar(); + Statusbar() << "Number tracks? [y/n] "; + curs_set(1); + int in = 0; + do + { + TraceMpdStatus(); + wFooter->ReadKey(in); + } + while (in != 'y' && in != 'n'); + if (in == 'y') + { + int i = 1; + for (SongList::iterator it = list.begin(); it != list.end(); it++, i++) + (*it)->SetTrack(i); + ShowMessage("Tracks numbered!"); + } + else + ShowMessage("Aborted!"); + curs_set(0); + UnlockStatusbar(); + } + break; + case 5: + get = &Song::GetGenre; + set = &Song::SetGenre; + break; + case 6: + get = &Song::GetComposer; + set = &Song::SetComposer; + break; + case 7: + get = &Song::GetPerformer; + set = &Song::SetPerformer; + break; + case 8: + get = &Song::GetDisc; + set = &Song::SetDisc; + break; + case 9: + get = &Song::GetComment; + set = &Song::SetComment; + break; + case 10: + { + if (wCurrent == mEditorTagTypes) + { + current_screen = csOther; + __deal_with_filenames(list); + current_screen = csTagEditor; + TagEditor::Refresh(); + } + else if (wCurrent == mEditorTags) + { + Song &s = mEditorTags->Current(); + string old_name = s.GetNewName().empty() ? s.GetName() : s.GetNewName(); + size_t last_dot = old_name.rfind("."); + string extension = old_name.substr(last_dot); + old_name = old_name.substr(0, last_dot); + LockStatusbar(); + Statusbar() << fmtBold << "New filename: " << fmtBoldEnd; + string new_name = wFooter->GetString(old_name); + UnlockStatusbar(); + if (!new_name.empty() && new_name != old_name) + s.SetNewName(new_name + extension); + mEditorTags->Scroll(wDown); + } + return; + } + case 11: // reset + { + mEditorTags->Clear(0); + ShowMessage("Changes reset"); + return; + } + case 12: // save + { + bool success = 1; + ShowMessage("Writing changes..."); + for (SongList::iterator it = list.begin(); it != list.end(); it++) + { + ShowMessage("Writing tags in '%s'...", (*it)->GetName().c_str()); + if (!WriteTags(**it)) + { + ShowMessage("Error writing tags in '%s'!", (*it)->GetFile().c_str()); + success = 0; + break; + } + } + if (success) + { + ShowMessage("Tags updated!"); + mEditorTagTypes->HighlightColor(Config.main_highlight_color); + mEditorTagTypes->Reset(); + wCurrent->Refresh(); + wCurrent = mEditorLeftCol; + mEditorLeftCol->HighlightColor(Config.active_column_color); + Mpd->UpdateDirectory(FindSharedDir(mEditorTags)); + } + else + mEditorTags->Clear(0); + return; + } + case 13: // capitalize first letters + { + ShowMessage("Processing..."); + for (SongList::iterator it = list.begin(); it != list.end(); it++) + CapitalizeFirstLetters(**it); + ShowMessage("Done!"); + break; + } + case 14: // lower all letters + { + ShowMessage("Processing..."); + for (SongList::iterator it = list.begin(); it != list.end(); it++) + LowerAllLetters(**it); + ShowMessage("Done!"); + break; + } + default: + break; + } + + if (wCurrent == mEditorTagTypes && id != 0 && id != 4 && set != NULL) + { + LockStatusbar(); + Statusbar() << fmtBold << mEditorTagTypes->Current() << fmtBoldEnd << ": "; + string new_tag = wFooter->GetString((mEditorTags->Current().*get)()); + UnlockStatusbar(); + for (SongList::iterator it = list.begin(); it != list.end(); it++) + (**it.*set)(new_tag); + } + else if (wCurrent == mEditorTags && set != NULL) + { + LockStatusbar(); + Statusbar() << fmtBold << mEditorTagTypes->Current() << fmtBoldEnd << ": "; + string new_tag = wFooter->GetString((mEditorTags->Current().*get)()); + UnlockStatusbar(); + if (new_tag != (mEditorTags->Current().*get)()) + (mEditorTags->Current().*set)(new_tag); + mEditorTags->Scroll(wDown); + } +} + namespace { const string patterns_list_file = config_dir + "patterns.list"; diff --git a/src/tag_editor.h b/src/tag_editor.h index 10675e98..0700385c 100644 --- a/src/tag_editor.h +++ b/src/tag_editor.h @@ -32,6 +32,25 @@ #include "mpdpp.h" #include "settings.h" +namespace TinyTagEditor +{ + void Init(); + + void EnterPressed(MPD::Song &); +} + +namespace TagEditor +{ + void Init(); + void Resize(); + void Refresh(); + void SwitchTo(); + + void Update(); + + void EnterPressed(); +} + typedef void (MPD::Song::*SongSetFunction)(const std::string &); typedef std::string (MPD::Song::*SongGetFunction)() const;