diff --git a/src/Makefile.am b/src/Makefile.am index a2d85ff5..8729f874 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -67,6 +67,7 @@ noinst_HEADERS = \ curl_handle.h \ display.h \ error.h \ + exec_item.h \ global.h \ help.h \ helpers.h \ diff --git a/src/actions.cpp b/src/actions.cpp index 28e4e704..7eb24372 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -1769,6 +1769,11 @@ void SelectAlbum::Run() } } +bool AddSelectedItems::canBeRun() const +{ + return myScreen != mySelectedItemsAdder; +} + void AddSelectedItems::Run() { mySelectedItemsAdder->switchTo(); diff --git a/src/actions.h b/src/actions.h index 2cf65c43..d3c4a736 100644 --- a/src/actions.h +++ b/src/actions.h @@ -703,6 +703,7 @@ struct AddSelectedItems : public Action AddSelectedItems() : Action(aAddSelectedItems, "add_selected_items") { } protected: + virtual bool canBeRun() const; virtual void Run(); }; diff --git a/src/browser.cpp b/src/browser.cpp index 3d6e2fbb..23bc1b5e 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -143,7 +143,7 @@ void Browser::enterPressed() } case itSong: { - myPlaylist->Add(*item.song, 1); + addSongToPlaylist(*item.song, true, -1); break; } case itPlaylist: @@ -191,7 +191,7 @@ void Browser::spacePressed() list.reserve(items.size()); for (MPD::ItemList::const_iterator it = items.begin(); it != items.end(); ++it) list.push_back(*it->song); - result = myPlaylist->Add(list, 0); + result = addSongsToPlaylist(list, false, -1); } else # endif // !WIN32 @@ -202,7 +202,7 @@ void Browser::spacePressed() } case itSong: { - myPlaylist->Add(*item.song, 0); + addSongToPlaylist(*item.song, false); break; } case itPlaylist: diff --git a/src/exec_item.h b/src/exec_item.h new file mode 100644 index 00000000..f63f6bbe --- /dev/null +++ b/src/exec_item.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2008-2012 by Andrzej Rybczak * + * electricityispower@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef _EXEC_ITEM_H +#define _EXEC_ITEM_H + +#include + +template struct ExecItem +{ + typedef ItemT Item; + typedef std::function Function; + + ExecItem() { } + ExecItem(const Item &item_, Function f) : m_item(item_), m_exec(f) { } + + Function &exec() { return m_exec; } + const Function &exec() const { return m_exec; } + + Item &item() { return m_item; } + const Item &item() const { return m_item; } + +private: + Item m_item; + Function m_exec; +}; + +#endif // _EXEC_ITEM_H diff --git a/src/helpers.cpp b/src/helpers.cpp index 3634d5c0..012c5df4 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -18,8 +18,65 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ +#include + #include "helpers.h" #include "playlist.h" +#include "statusbar.h" + +bool addSongToPlaylist(const MPD::Song &s, bool play, size_t position) +{ + bool result = false; + if (Config.ncmpc_like_songs_adding && myPlaylist->checkForSong(s)) + { + auto &w = myPlaylist->main(); + if (play) + { + auto song = std::find(w.beginV(), w.endV(), s); + assert(song != w.endV()); + Mpd.PlayID(song->getID()); + result = true; + } + else + { + Mpd.StartCommandsList(); + for (auto it = w.rbeginV(); it != w.rendV(); ++it) + if (*it == s) + Mpd.Delete(it->getPosition()); + Mpd.CommitCommandsList(); + // we return false in this case + } + } + else + { + position = std::min(position, Mpd.GetPlaylistLength()); + int id = Mpd.AddSong(s, position); + if (id >= 0) + { + Statusbar::msg("Added to playlist: %s", + s.toString(Config.song_status_format_no_colors, Config.tags_separator).c_str() + ); + if (play) + Mpd.PlayID(id); + result = true; + } + } + return result; +} + +bool addSongsToPlaylist(const MPD::SongList &list, bool play, size_t position) +{ + if (list.empty()) + return false; + position = std::min(position, Mpd.GetPlaylistLength()); + Mpd.StartCommandsList(); + for (auto s = list.rbegin(); s != list.rend(); ++s) + if (Mpd.AddSong(*s, position) < 0) + break; + if (play) + Mpd.Play(position); + return Mpd.CommitCommandsList(); +} std::string Timestamp(time_t t) { diff --git a/src/helpers.h b/src/helpers.h index 13a6a365..7e6d39fb 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -466,6 +466,9 @@ template void ShowTag(T &buf, const std::string &tag) buf << tag; } +bool addSongToPlaylist(const MPD::Song &s, bool play, size_t position = -1); +bool addSongsToPlaylist(const MPD::SongList &list, bool play, size_t position = -1); + std::string Timestamp(time_t t); void markSongsInPlaylist(std::shared_ptr pl); diff --git a/src/media_library.cpp b/src/media_library.cpp index e7403097..51ba6da0 100644 --- a/src/media_library.cpp +++ b/src/media_library.cpp @@ -869,11 +869,11 @@ void MediaLibrary::LocateSong(const MPD::Song &s) void MediaLibrary::AddToPlaylist(bool add_n_play) { if (isActiveWindow(Songs) && !Songs.empty()) - myPlaylist->Add(Songs.current().value(), add_n_play); + addSongToPlaylist(Songs.current().value(), add_n_play); else { auto list = getSelectedSongs(); - if (myPlaylist->Add(list, add_n_play)) + if (addSongsToPlaylist(list, add_n_play)) { if ((!Tags.empty() && isActiveWindow(Tags)) || (isActiveWindow(Albums) && Albums.current().value().Date == AllTracksMarker)) diff --git a/src/playlist.cpp b/src/playlist.cpp index 0d255906..98b279fc 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -318,75 +318,9 @@ std::string Playlist::TotalLength() return result.str(); } -bool Playlist::Add(const MPD::Song &s, bool play, int position) -{ - if (Config.ncmpc_like_songs_adding && checkForSong(s)) - { - size_t hash = s.getHash(); - if (play) - { - for (size_t i = 0; i < w.size(); ++i) - { - if (w.at(i).value().getHash() == hash) - { - Mpd.Play(i); - break; - } - } - return true; - } - else - { - Mpd.StartCommandsList(); - for (size_t i = 0; i < w.size(); ++i) - if (w[i].value().getHash() == hash) - Mpd.Delete(i); - Mpd.CommitCommandsList(); - return false; - } - } - else - { - int id = Mpd.AddSong(s, position); - if (id >= 0) - { - Statusbar::msg("Added to playlist: %s", s.toString(Config.song_status_format_no_colors, Config.tags_separator).c_str()); - if (play) - Mpd.PlayID(id); - return true; - } - else - return false; - } -} - -bool Playlist::Add(const MPD::SongList &l, bool play, int position) -{ - if (l.empty()) - return false; - - Mpd.StartCommandsList(); - if (position < 0) - { - for (auto it = l.begin(); it != l.end(); ++it) - if (Mpd.AddSong(*it) < 0) - break; - } - else - { - for (auto j = l.rbegin(); j != l.rend(); ++j) - if (Mpd.AddSong(*j, position) < 0) - break; - } - if (!Mpd.CommitCommandsList()) - return false; - if (play) - PlayNewlyAddedSongs(); - return true; -} - void Playlist::PlayNewlyAddedSongs() { + // FIXME for removal bool is_filtered = w.isFiltered(); w.showAll(); size_t old_size = w.size(); diff --git a/src/playlist.h b/src/playlist.h index 79bf2a09..cfef8b55 100644 --- a/src/playlist.h +++ b/src/playlist.h @@ -74,8 +74,6 @@ struct Playlist : public Screen>, public Filterable, public void UpdateTimer(); timeval Timer() const { return itsTimer; } - bool Add(const MPD::Song &s, bool play, int position = -1); - bool Add(const MPD::SongList &l, bool play, int position = -1); void PlayNewlyAddedSongs(); void SetSelectedItemsPriority(int prio); diff --git a/src/playlist_editor.cpp b/src/playlist_editor.cpp index 56e1c64b..9bb99ff9 100644 --- a/src/playlist_editor.cpp +++ b/src/playlist_editor.cpp @@ -236,7 +236,7 @@ void PlaylistEditor::AddToPlaylist(bool add_n_play) } } else if (isActiveWindow(Content) && !Content.empty()) - myPlaylist->Add(Content.current().value(), add_n_play); + addSongToPlaylist(Content.current().value(), add_n_play); if (!add_n_play) w->scroll(NC::wDown); diff --git a/src/screen.h b/src/screen.h index 7c40f2a1..a82012d4 100644 --- a/src/screen.h +++ b/src/screen.h @@ -121,20 +121,20 @@ template struct Screen : public BasicScreen typedef typename std::add_lvalue_reference::type WindowReference; private: - template struct access { }; - template struct access { + template struct getObject { }; + template struct getObject { static Result apply(WindowType w) { return *w; } }; - template struct access { + template struct getObject { static Result apply(WindowReference w) { return w; } }; - typedef access< + typedef getObject< std::is_pointer::value, typename std::add_lvalue_reference< typename std::remove_pointer::type >::type - > accessor; + > Accessor; public: Screen() { } @@ -143,7 +143,7 @@ public: virtual ~Screen() { } virtual bool isActiveWindow(const NC::Window &w_) OVERRIDE { - return &accessor::apply(w) == &w_; + return &Accessor::apply(w) == &w_; } /// Since some screens contain more that one window @@ -151,17 +151,17 @@ public: /// active /// @return address to window object cast to void * virtual void *activeWindow() OVERRIDE { - return &accessor::apply(w); + return &Accessor::apply(w); } /// Refreshes whole screen virtual void refresh() OVERRIDE { - accessor::apply(w).display(); + Accessor::apply(w).display(); } /// Refreshes active window of the screen virtual void refreshWindow() OVERRIDE { - accessor::apply(w).display(); + Accessor::apply(w).display(); } /// Scrolls the screen by given amount of lines and @@ -169,14 +169,14 @@ public: /// loop that holds main loop until user releases the key /// @param where indicates where one wants to scroll virtual void scroll(NC::Where where) OVERRIDE { - accessor::apply(w).scroll(where); + Accessor::apply(w).scroll(where); } /// Invoked after there was one of mouse buttons pressed /// @param me struct that contains coords of where the click /// had its place and button actions virtual void mouseButtonPressed(MEVENT me) OVERRIDE { - genericMouseButtonPressed(accessor::apply(w), me); + genericMouseButtonPressed(Accessor::apply(w), me); } /// @return currently active window diff --git a/src/search_engine.cpp b/src/search_engine.cpp index 2b1e5552..d2eb5ec9 100644 --- a/src/search_engine.cpp +++ b/src/search_engine.cpp @@ -217,7 +217,7 @@ void SearchEngine::enterPressed() reset(); } else - myPlaylist->Add(w.current().value().song(), 1); + addSongToPlaylist(w.current().value().song(), true); if (option < SearchButton) Statusbar::unlock(); @@ -235,7 +235,7 @@ void SearchEngine::spacePressed() return; } - myPlaylist->Add(w.current().value().song(), 0); + addSongToPlaylist(w.current().value().song(), false); w.scroll(NC::wDown); } diff --git a/src/sel_items_adder.cpp b/src/sel_items_adder.cpp index cdfb3175..6b29526f 100644 --- a/src/sel_items_adder.cpp +++ b/src/sel_items_adder.cpp @@ -19,218 +19,155 @@ ***************************************************************************/ #include -#include "charset.h" + #include "browser.h" -#include "display.h" #include "global.h" +#include "helpers.h" #include "mpdpp.h" #include "playlist.h" -#include "playlist_editor.h" #include "sel_items_adder.h" #include "settings.h" -#include "status.h" #include "statusbar.h" #include "utility/comparators.h" -using Global::MainHeight; -using Global::MainStartY; -using Global::myScreen; -using Global::myOldScreen; - SelectedItemsAdder *mySelectedItemsAdder; -SelectedItemsAdder::SelectedItemsAdder() : itsPSWidth(35), itsPSHeight(11) +namespace {// + +void DisplayComponent(SelectedItemsAdder::Component &menu) { - SetDimensions(); - itsPlaylistSelector = new NC::Menu((COLS-itsWidth)/2, (MainHeight-itsHeight)/2+MainStartY, itsWidth, itsHeight, "Add selected item(s) to...", Config.main_color, Config.window_border); - itsPlaylistSelector->cyclicScrolling(Config.use_cyclic_scrolling); - itsPlaylistSelector->centeredCursor(Config.centered_cursor); - itsPlaylistSelector->setHighlightColor(Config.main_highlight_color); - itsPlaylistSelector->setItemDisplayer(Display::Default); + menu << menu.drawn()->value().item(); +} + +} + +SelectedItemsAdder::SelectedItemsAdder() +{ + using Global::MainHeight; + using Global::MainStartY; + setDimensions(); - itsPositionSelector = new NC::Menu((COLS-itsPSWidth)/2, (MainHeight-itsPSHeight)/2+MainStartY, itsPSWidth, itsPSHeight, "Where?", Config.main_color, Config.window_border); - itsPositionSelector->cyclicScrolling(Config.use_cyclic_scrolling); - itsPositionSelector->centeredCursor(Config.centered_cursor); - itsPositionSelector->setHighlightColor(Config.main_highlight_color); - itsPositionSelector->setItemDisplayer(Display::Default); - itsPositionSelector->addItem("At the end of playlist"); - itsPositionSelector->addItem("At the beginning of playlist"); - itsPositionSelector->addItem("After current track"); - itsPositionSelector->addItem("After current album"); - itsPositionSelector->addItem("After highlighted item"); - itsPositionSelector->addSeparator(); - itsPositionSelector->addItem("Cancel"); + m_playlist_selector = Component( + (COLS-m_playlist_selector_width)/2, + MainStartY+(MainHeight-m_playlist_selector_height)/2, + m_playlist_selector_width, + m_playlist_selector_height, + "Add selected item(s) to...", + Config.main_color, + Config.window_border + ); + m_playlist_selector.cyclicScrolling(Config.use_cyclic_scrolling); + m_playlist_selector.centeredCursor(Config.centered_cursor); + m_playlist_selector.setHighlightColor(Config.main_highlight_color); + m_playlist_selector.setItemDisplayer(DisplayComponent); - w = itsPlaylistSelector; + m_position_selector = Component( + (COLS-m_position_selector_width)/2, + MainStartY+(MainHeight-m_position_selector_height)/2, + m_position_selector_width, + m_position_selector_height, + "Where?", + Config.main_color, + Config.window_border + ); + m_position_selector.cyclicScrolling(Config.use_cyclic_scrolling); + m_position_selector.centeredCursor(Config.centered_cursor); + m_position_selector.setHighlightColor(Config.main_highlight_color); + m_position_selector.setItemDisplayer(DisplayComponent); + + typedef SelectedItemsAdder Self; + m_position_selector.addItem(Component::Item::Type("At the end of playlist", + std::bind(&Self::addAtTheEndOfPlaylist, this) + )); + m_position_selector.addItem(Component::Item::Type("At the beginning of playlist", + std::bind(&Self::addAtTheBeginningOfPlaylist, this) + )); + m_position_selector.addItem(Component::Item::Type("After current song", + std::bind(&Self::addAfterCurrentSong, this) + )); + m_position_selector.addItem(Component::Item::Type("After current album", + std::bind(&Self::addAfterCurrentAlbum, this) + )); + m_position_selector.addItem(Component::Item::Type("After highlighted item", + std::bind(&Self::addAfterHighlightedSong, this) + )); + m_position_selector.addSeparator(); + m_position_selector.addItem(Component::Item::Type("Cancel", + std::bind(&Self::cancel, this) + )); + + w = &m_playlist_selector; } void SelectedItemsAdder::switchTo() { - if (myScreen == this) - { - myOldScreen->switchTo(); - return; - } - auto hs = dynamic_cast(myScreen); + using Global::myScreen; + + assert(myScreen != this); + auto hs = hasSongs(myScreen); if (!hs || !hs->allowsSelection()) return; - // default to main window - w = itsPlaylistSelector; - - // resize() can fall back to old screen, so we need it updated - myOldScreen = myScreen; + Statusbar::msg(1, "Fetching selected songs..."); + m_selected_items = hs->getSelectedSongs(); + if (m_selected_items.empty()) + { + Statusbar::msg("List of selected items is empty"); + return; + } if (hasToBeResized) resize(); - bool playlists_not_active = myScreen == myBrowser && myBrowser->isLocal(); - if (playlists_not_active) - Statusbar::msg("Local items can't be added to stored playlists"); - - w->clear(); - w->reset(); - if (myOldScreen != myPlaylist) - w->addItem("Current MPD playlist", 0, 0); - w->addItem("New playlist", 0, playlists_not_active); - w->addSeparator(); - - auto playlists = Mpd.GetPlaylists(); - std::sort(playlists.begin(), playlists.end(), - LocaleBasedSorting(std::locale(), Config.ignore_leading_the)); - for (auto it = playlists.begin(); it != playlists.end(); ++it) - w->addItem(*it, 0, playlists_not_active); - w->addSeparator(); - w->addItem("Cancel"); + populatePlaylistSelector(myScreen); + // default to main window + w = &m_playlist_selector; myScreen = this; } void SelectedItemsAdder::resize() { - SetDimensions(); - if (itsHeight < 5) // screen too low to display this window - return myOldScreen->switchTo(); - itsPlaylistSelector->resize(itsWidth, itsHeight); - itsPlaylistSelector->moveTo((COLS-itsWidth)/2, (MainHeight-itsHeight)/2+MainStartY); - size_t poss_width = std::min(itsPSWidth, size_t(COLS)); - size_t poss_height = std::min(itsPSHeight, size_t(MainHeight)); - itsPositionSelector->resize(poss_width, poss_height); - itsPositionSelector->moveTo((COLS-poss_width)/2, (MainHeight-poss_height)/2+MainStartY); - if (myOldScreen && myOldScreen->hasToBeResized) // resize background window + using Global::MainHeight; + using Global::MainStartY; + setDimensions(); + m_playlist_selector.resize(m_playlist_selector_width, m_playlist_selector_height); + m_playlist_selector.moveTo( + (COLS-m_playlist_selector_width)/2, + MainStartY+(MainHeight-m_playlist_selector_height)/2 + ); + m_position_selector.resize(m_position_selector_width, m_position_selector_height); + m_position_selector.moveTo( + (COLS-m_position_selector_width)/2, + MainStartY+(MainHeight-m_position_selector_height)/2 + ); + if (m_old_screen && m_old_screen->hasToBeResized) // resize background window { - myOldScreen->resize(); - myOldScreen->refresh(); + m_old_screen->resize(); + m_old_screen->refresh(); } hasToBeResized = 0; } void SelectedItemsAdder::refresh() { - if (w == itsPositionSelector) + if (isActiveWindow(m_position_selector)) { - itsPlaylistSelector->display(); - itsPositionSelector->display(); + m_playlist_selector.display(); + m_position_selector.display(); } - else - itsPlaylistSelector->display(); + else if (isActiveWindow(m_playlist_selector)) + m_playlist_selector.display(); } std::wstring SelectedItemsAdder::title() { - return myOldScreen->title(); + return m_old_screen->title(); } void SelectedItemsAdder::enterPressed() { - size_t pos = w->choice(); - - // adding to current playlist is disabled when playlist is active - if (w == itsPlaylistSelector && myOldScreen == myPlaylist && pos == 0) - pos++; - - MPD::SongList list; - if ((w != itsPlaylistSelector || pos != 0) && pos != w->size()-1) - list = dynamic_cast(*myOldScreen).getSelectedSongs(); - - if (w == itsPlaylistSelector) - { - if (pos == 0) // add to mpd playlist - { - w = itsPositionSelector; - itsPositionSelector->reset(); - return; - } - else if (pos == 1) // create new playlist - { - Statusbar::lock(); - Statusbar::put() << "Save playlist as: "; - std::string playlist = Global::wFooter->getString(); - Statusbar::unlock(); - if (!playlist.empty()) - { - Mpd.StartCommandsList(); - for (auto it = list.begin(); it != list.end(); ++it) - Mpd.AddToPlaylist(playlist, *it); - if (Mpd.CommitCommandsList()) - Statusbar::msg("Selected item(s) added to playlist \"%s\"", playlist.c_str()); - } - } - else if (pos > 1 && pos < w->size()-1) // add items to existing playlist - { - std::string playlist = w->current().value(); - Mpd.StartCommandsList(); - for (auto it = list.begin(); it != list.end(); ++it) - Mpd.AddToPlaylist(playlist, *it); - if (Mpd.CommitCommandsList()) - Statusbar::msg("Selected item(s) added to playlist \"%s\"", w->current().value().c_str()); - } - } - else - { - // disable adding after current track/album when stopped - if (pos > 1 && pos < 4 && !Mpd.isPlaying()) - { - Statusbar::msg("Player is stopped"); - return; - } - - bool successful_operation; - if (pos == 0) // end of playlist - { - successful_operation = myPlaylist->Add(list, 0); - } - else if (pos == 1) // beginning of playlist - { - successful_operation = myPlaylist->Add(list, 0, 0); - } - else if (pos == 2) // after currently playing track - { - successful_operation = myPlaylist->Add(list, 0, Mpd.GetCurrentlyPlayingSongPos()+1); - } - else if (pos == 3) // after currently playing album - { - std::string album = myPlaylist->nowPlayingSong().getAlbum(); - int i; - for (i = Mpd.GetCurrentlyPlayingSongPos()+1; i < int(myPlaylist->main().size()); ++i) - if (myPlaylist->main()[i].value().getAlbum() != album) - break; - successful_operation = myPlaylist->Add(list, 0, i); - } - else if (pos == 4) // after highlighted item - { - successful_operation = myPlaylist->Add(list, 0, std::min(myPlaylist->main().choice()+1, myPlaylist->main().size())); - } - else - { - w = itsPlaylistSelector; - return; - } - - if (successful_operation) - Statusbar::msg("Selected item(s) added"); - } - switchTo(); + w->current().value().exec()(); } void SelectedItemsAdder::mouseButtonPressed(MEVENT me) @@ -247,9 +184,138 @@ void SelectedItemsAdder::mouseButtonPressed(MEVENT me) Screen::mouseButtonPressed(me); } -void SelectedItemsAdder::SetDimensions() +void SelectedItemsAdder::populatePlaylistSelector(BasicScreen *old_screen) { - itsWidth = COLS*0.6; - itsHeight = std::min(size_t(LINES*0.6), MainHeight); + typedef SelectedItemsAdder Self; + m_old_screen = old_screen; + m_playlist_selector.reset(); + m_playlist_selector.clear(); + if (old_screen != myPlaylist) + { + m_playlist_selector.addItem(Component::Item::Type("Current playlist", + std::bind(&Self::addToCurrentPlaylist, this) + )); + } + m_playlist_selector.addItem(Component::Item::Type("New playlist", + std::bind(&Self::addToNewPlaylist, this) + )); + m_playlist_selector.addSeparator(); + + // stored playlists don't support songs from outside of mpd database + if (old_screen != myBrowser || !myBrowser->isLocal()) + { + auto playlists = Mpd.GetPlaylists(); + std::sort(playlists.begin(), playlists.end(), + LocaleBasedSorting(std::locale(), Config.ignore_leading_the)); + for (auto pl = playlists.begin(); pl != playlists.end(); ++pl) + { + m_playlist_selector.addItem(Component::Item::Type(*pl, + std::bind(&Self::addToExistingPlaylist, this, *pl) + )); + } + if (!playlists.empty()) + m_playlist_selector.addSeparator(); + } + m_playlist_selector.addItem(Component::Item::Type("Cancel", + std::bind(&Self::cancel, this) + )); } +void SelectedItemsAdder::addToCurrentPlaylist() +{ + w = &m_position_selector; + m_position_selector.reset(); +} + +void SelectedItemsAdder::addToNewPlaylist() const +{ + Statusbar::lock(); + Statusbar::put() << "Save playlist as: "; + std::string playlist = Global::wFooter->getString(); + Statusbar::unlock(); + if (!playlist.empty()) + addToExistingPlaylist(playlist); +} + +void SelectedItemsAdder::addToExistingPlaylist(const std::string &playlist) const +{ + Mpd.StartCommandsList(); + for (auto s = m_selected_items.begin(); s != m_selected_items.end(); ++s) + Mpd.AddToPlaylist(playlist, *s); + if (Mpd.CommitCommandsList()) + Statusbar::msg("Selected item(s) added to playlist \"%s\"", playlist.c_str()); +} + +void SelectedItemsAdder::addAtTheEndOfPlaylist() const +{ + bool success = addSongsToPlaylist(m_selected_items, false); + if (success) + exitSuccessfully(); +} + +void SelectedItemsAdder::addAtTheBeginningOfPlaylist() const +{ + bool success = addSongsToPlaylist(m_selected_items, false, 0); + if (success) + exitSuccessfully(); +} + +void SelectedItemsAdder::addAfterCurrentSong() const +{ + if (!Mpd.isPlaying()) + return; + size_t pos = Mpd.GetCurrentlyPlayingSongPos(); + bool success = addSongsToPlaylist(m_selected_items, false, pos); + if (success) + exitSuccessfully(); +} + +void SelectedItemsAdder::addAfterCurrentAlbum() const +{ + if (!Mpd.isPlaying()) + return; + auto &pl = myPlaylist->main(); + size_t pos = Mpd.GetCurrentlyPlayingSongPos(); + withUnfilteredMenu(pl, [&pos, &pl]() { + std::string album = pl[pos].value().getAlbum(); + while (pos < pl.size() && pl[pos].value().getAlbum() == album) + ++pos; + }); + bool success = addSongsToPlaylist(m_selected_items, false, pos); + if (success) + exitSuccessfully(); +} + +void SelectedItemsAdder::addAfterHighlightedSong() const +{ + size_t pos = myPlaylist->main().current().value().getPosition(); + ++pos; + bool success = addSongsToPlaylist(m_selected_items, false, pos); + if (success) + exitSuccessfully(); +} + +void SelectedItemsAdder::cancel() +{ + if (isActiveWindow(m_playlist_selector)) + m_old_screen->switchTo(); + else if (isActiveWindow(m_position_selector)) + w = &m_playlist_selector; +} + +void SelectedItemsAdder::exitSuccessfully() const +{ + Statusbar::msg("Selected items added"); + m_old_screen->switchTo(); +} + +void SelectedItemsAdder::setDimensions() +{ + using Global::MainHeight; + + m_playlist_selector_width = COLS*0.6; + m_playlist_selector_height = std::min(MainHeight, size_t(LINES*0.66)); + + m_position_selector_width = std::min(size_t(35), size_t(COLS)); + m_position_selector_height = std::min(size_t(11), MainHeight); +} diff --git a/src/sel_items_adder.h b/src/sel_items_adder.h index dd19dbfa..21dc56c7 100644 --- a/src/sel_items_adder.h +++ b/src/sel_items_adder.h @@ -21,13 +21,16 @@ #ifndef _SEL_ITEMS_ADDER_H #define _SEL_ITEMS_ADDER_H +#include "exec_item.h" #include "screen.h" +#include "song.h" -struct SelectedItemsAdder : public Screen *> +struct SelectedItemsAdder : public Screen> *> { + typedef typename std::remove_pointer::type Component; + SelectedItemsAdder(); - // Screen< NC::Menu > implementation virtual void switchTo() OVERRIDE; virtual void resize() OVERRIDE; virtual void refresh() OVERRIDE; @@ -47,16 +50,33 @@ protected: virtual bool isLockable() OVERRIDE { return false; } private: - void SetDimensions(); + void populatePlaylistSelector(BasicScreen *screen); - NC::Menu *itsPlaylistSelector; - NC::Menu *itsPositionSelector; + void addToCurrentPlaylist(); + void addToNewPlaylist() const; + void addToExistingPlaylist(const std::string &playlist) const; + void addAtTheEndOfPlaylist() const; + void addAtTheBeginningOfPlaylist() const; + void addAfterCurrentSong() const; + void addAfterCurrentAlbum() const; + void addAfterHighlightedSong() const; + void cancel(); + void exitSuccessfully() const; - size_t itsPSWidth; - size_t itsPSHeight; + void setDimensions(); - size_t itsWidth; - size_t itsHeight; + BasicScreen *m_old_screen; + + size_t m_playlist_selector_width; + size_t m_playlist_selector_height; + + size_t m_position_selector_width; + size_t m_position_selector_height; + + Component m_playlist_selector; + Component m_position_selector; + + MPD::SongList m_selected_items; }; extern SelectedItemsAdder *mySelectedItemsAdder; diff --git a/src/song.h b/src/song.h index 8d27f2a4..ada69b93 100644 --- a/src/song.h +++ b/src/song.h @@ -74,6 +74,9 @@ struct Song virtual std::string toString(const std::string &fmt, const std::string &tags_separator, const std::string &escape_chars = "") const; + bool operator==(const Song &rhs) const { return m_hash == rhs.m_hash; } + bool operator!=(const Song &rhs) const { return m_hash != rhs.m_hash; } + static std::string ShowTime(unsigned length); static bool isFormatOk(const std::string &type, const std::string &fmt); diff --git a/src/statusbar.cpp b/src/statusbar.cpp index 90e4fa0c..90379f9c 100644 --- a/src/statusbar.cpp +++ b/src/statusbar.cpp @@ -34,6 +34,25 @@ bool statusbarBlockUpdate = false; bool progressbarBlockUpdate = false; bool statusbarAllowUnlock = true; +void showMessage(int time, const char *format, va_list list) +{ + if (Global::ShowMessages && statusbarAllowUnlock) + { + statusbarLockTime = Global::Timer; + statusbarLockDelay = time; + if (Config.statusbar_visibility) + statusbarBlockUpdate = true; + else + progressbarBlockUpdate = true; + wFooter->goToXY(0, Config.statusbar_visibility); + *wFooter << NC::fmtBoldEnd; + wmove(wFooter->raw(), Config.statusbar_visibility, 0); + vw_printw(wFooter->raw(), format, list); + wclrtoeol(wFooter->raw()); + wFooter->refresh(); + } +} + } void Progressbar::lock() @@ -148,24 +167,18 @@ NC::Window &Statusbar::put() void Statusbar::msg(const char *format, ...) { - if (Global::ShowMessages && statusbarAllowUnlock) - { - statusbarLockTime = Global::Timer; - statusbarLockDelay = Config.message_delay_time; - if (Config.statusbar_visibility) - statusbarBlockUpdate = 1; - else - progressbarBlockUpdate = 1; - wFooter->goToXY(0, Config.statusbar_visibility); - *wFooter << NC::fmtBoldEnd; - va_list list; - va_start(list, format); - wmove(wFooter->raw(), Config.statusbar_visibility, 0); - vw_printw(wFooter->raw(), format, list); - wclrtoeol(wFooter->raw()); - va_end(list); - wFooter->refresh(); - } + va_list list; + va_start(list, format); + showMessage(Config.message_delay_time, format, list); + va_end(list); +} + +void Statusbar::msg(int time, const char *format, ...) +{ + va_list list; + va_start(list, format); + showMessage(time, format, list); + va_end(list); } void Statusbar::Helpers::mpd() diff --git a/src/statusbar.h b/src/statusbar.h index 77236387..e56db09c 100644 --- a/src/statusbar.h +++ b/src/statusbar.h @@ -62,6 +62,9 @@ NC::Window &put(); /// displays message in statusbar for period of time set in configuration file void msg(const char *format, ...) GNUC_PRINTF(1, 2); +/// displays message in statusbar for given period of time +void msg(int time, const char *format, ...) GNUC_PRINTF(2, 3); + namespace Helpers {// /// called when statusbar window detects incoming idle notification