actions: add support for range selection and make a few actions work on ranges

This commit is contained in:
Andrzej Rybczak
2015-05-23 22:55:04 +02:00
parent 274c075ffd
commit 1b6cb65f3a
10 changed files with 119 additions and 38 deletions

1
NEWS
View File

@@ -26,6 +26,7 @@ ncmpcpp-0.7 (????-??-??)
* Searching in text fields now respects regular expression configuration. * Searching in text fields now respects regular expression configuration.
* Monolithic 'press_space' action was split into 'add_item_to_playlist', 'toggle_lyrics_update_on_song_change' and 'toggle_visualization_type'. * Monolithic 'press_space' action was split into 'add_item_to_playlist', 'toggle_lyrics_update_on_song_change' and 'toggle_visualization_type'.
* Sorting actions were rebound to Ctrl-S. * Sorting actions were rebound to Ctrl-S.
* Support for range selection was added (bound to Ctrl-V by default). In addition, sorting, reversing and shuffling items in playlist now works on ranges.
ncmpcpp-0.6.4 (2015-05-02) ncmpcpp-0.6.4 (2015-05-02)

View File

@@ -415,6 +415,9 @@
#def_key "l" #def_key "l"
# show_lyrics # show_lyrics
# #
#def_key "ctrl_v"
# select_range
#
#def_key "v" #def_key "v"
# reverse_selection # reverse_selection
# #

View File

@@ -89,6 +89,15 @@ void seek();
void findItem(const SearchDirection direction); void findItem(const SearchDirection direction);
void listsChangeFinisher(); void listsChangeFinisher();
template <typename Iterator>
bool findSelectedRangeAndPrintInfoIfNot(Iterator &first, Iterator &last)
{
bool success = findSelectedRange(first, last);
if (!success)
Statusbar::print("No range selected");
return success;
}
} }
namespace Actions { namespace Actions {
@@ -1173,11 +1182,19 @@ void ToggleRepeat::run()
Mpd.SetRepeat(!Status::State::repeat()); Mpd.SetRepeat(!Status::State::repeat());
} }
bool Shuffle::canBeRun()
{
if (myScreen != myPlaylist)
return false;
m_begin = myPlaylist->main().begin();
m_end = myPlaylist->main().end();
return findSelectedRangeAndPrintInfoIfNot(m_begin, m_end);
}
void Shuffle::run() void Shuffle::run()
{ {
auto begin = myPlaylist->main().begin(), end = myPlaylist->main().end(); auto begin = myPlaylist->main().begin();
auto range = getSelectedRange(begin, end); Mpd.ShuffleRange(m_begin-begin, m_end-begin);
Mpd.ShuffleRange(range.first-begin, range.second-begin);
Statusbar::print("Range shuffled"); Statusbar::print("Range shuffled");
} }
@@ -1654,6 +1671,23 @@ void SelectItem::run()
current->setSelected(!current->isSelected()); current->setSelected(!current->isSelected());
} }
bool SelectRange::canBeRun()
{
m_list = dynamic_cast<NC::List *>(myScreen->activeWindow());
if (m_list == nullptr)
return false;
m_begin = m_list->beginP();
m_end = m_list->endP();
return findRange(m_begin, m_end);
}
void SelectRange::run()
{
for (; m_begin != m_end; ++m_begin)
m_begin->setSelected(true);
Statusbar::print("Range selected");
}
bool ReverseSelection::canBeRun() bool ReverseSelection::canBeRun()
{ {
m_list = dynamic_cast<NC::List *>(myScreen->activeWindow()); m_list = dynamic_cast<NC::List *>(myScreen->activeWindow());
@@ -1793,7 +1827,10 @@ void ClearPlaylist::run()
bool SortPlaylist::canBeRun() bool SortPlaylist::canBeRun()
{ {
return myScreen == myPlaylist; if (myScreen != myPlaylist)
return false;
auto first = myPlaylist->main().begin(), last = myPlaylist->main().end();
return findSelectedRangeAndPrintInfoIfNot(first, last);
} }
void SortPlaylist::run() void SortPlaylist::run()
@@ -1803,12 +1840,21 @@ void SortPlaylist::run()
bool ReversePlaylist::canBeRun() bool ReversePlaylist::canBeRun()
{ {
return myScreen == myPlaylist; if (myScreen != myPlaylist)
return false;
m_begin = myPlaylist->main().begin();
m_end = myPlaylist->main().end();
return findSelectedRangeAndPrintInfoIfNot(m_begin, m_end);
} }
void ReversePlaylist::run() void ReversePlaylist::run()
{ {
myPlaylist->Reverse(); Statusbar::print("Reversing range...");
Mpd.StartCommandsList();
for (--m_end; m_begin < m_end; ++m_begin, --m_end)
Mpd.Swap(m_begin->value().getPosition(), m_end->value().getPosition());
Mpd.CommitCommandsList();
Statusbar::print("Range reversed");
} }
bool Find::canBeRun() bool Find::canBeRun()
@@ -2512,6 +2558,7 @@ void populateActions()
insert_action(new Actions::JumpToParentDirectory()); insert_action(new Actions::JumpToParentDirectory());
insert_action(new Actions::PressEnter()); insert_action(new Actions::PressEnter());
insert_action(new Actions::SelectItem()); insert_action(new Actions::SelectItem());
insert_action(new Actions::SelectRange());
insert_action(new Actions::PreviousColumn()); insert_action(new Actions::PreviousColumn());
insert_action(new Actions::NextColumn()); insert_action(new Actions::NextColumn());
insert_action(new Actions::MasterScreen()); insert_action(new Actions::MasterScreen());

View File

@@ -49,7 +49,7 @@ enum class Type
SetCrossfade, SetVolume, EditSong, EditLibraryTag, EditLibraryAlbum, EditDirectoryName, SetCrossfade, SetVolume, EditSong, EditLibraryTag, EditLibraryAlbum, EditDirectoryName,
EditPlaylistName, EditLyrics, JumpToBrowser, JumpToMediaLibrary, EditPlaylistName, EditLyrics, JumpToBrowser, JumpToMediaLibrary,
JumpToPlaylistEditor, ToggleScreenLock, JumpToTagEditor, JumpToPositionInSong, JumpToPlaylistEditor, ToggleScreenLock, JumpToTagEditor, JumpToPositionInSong,
SelectItem, ReverseSelection, RemoveSelection, SelectAlbum, AddSelectedItems, SelectItem, SelectRange, ReverseSelection, RemoveSelection, SelectAlbum, AddSelectedItems,
CropMainPlaylist, CropPlaylist, ClearMainPlaylist, ClearPlaylist, SortPlaylist, CropMainPlaylist, CropPlaylist, ClearMainPlaylist, ClearPlaylist, SortPlaylist,
ReversePlaylist, Find, FindItemForward, FindItemBackward, ReversePlaylist, Find, FindItemForward, FindItemBackward,
NextFoundItem, PreviousFoundItem, ToggleFindMode, ToggleReplayGainMode, NextFoundItem, PreviousFoundItem, ToggleFindMode, ToggleReplayGainMode,
@@ -581,7 +581,11 @@ struct Shuffle: BaseAction
Shuffle(): BaseAction(Type::Shuffle, "shuffle") { } Shuffle(): BaseAction(Type::Shuffle, "shuffle") { }
private: private:
virtual bool canBeRun() OVERRIDE;
virtual void run() OVERRIDE; virtual void run() OVERRIDE;
NC::Menu<MPD::Song>::ConstIterator m_begin;
NC::Menu<MPD::Song>::ConstIterator m_end;
}; };
struct ToggleRandom: BaseAction struct ToggleRandom: BaseAction
@@ -776,6 +780,19 @@ private:
NC::List *m_list; NC::List *m_list;
}; };
struct SelectRange: BaseAction
{
SelectRange(): BaseAction(Type::SelectRange, "select_range") { }
private:
virtual bool canBeRun() OVERRIDE;
virtual void run() OVERRIDE;
NC::List *m_list;
NC::List::Iterator m_begin;
NC::List::Iterator m_end;
};
struct ReverseSelection: BaseAction struct ReverseSelection: BaseAction
{ {
ReverseSelection(): BaseAction(Type::ReverseSelection, "reverse_selection") { } ReverseSelection(): BaseAction(Type::ReverseSelection, "reverse_selection") { }
@@ -869,6 +886,9 @@ struct ReversePlaylist: BaseAction
private: private:
virtual bool canBeRun() OVERRIDE; virtual bool canBeRun() OVERRIDE;
virtual void run() OVERRIDE; virtual void run() OVERRIDE;
NC::Menu<MPD::Song>::ConstIterator m_begin;
NC::Menu<MPD::Song>::ConstIterator m_end;
}; };
struct Find: BaseAction struct Find: BaseAction

View File

@@ -630,6 +630,8 @@ void BindingsConfiguration::generateDefaults()
bind(k, Actions::Type::JumpToPositionInSong); bind(k, Actions::Type::JumpToPositionInSong);
if (notBound(k = stringToKey("l"))) if (notBound(k = stringToKey("l")))
bind(k, Actions::Type::ShowLyrics); bind(k, Actions::Type::ShowLyrics);
if (notBound(k = stringToKey("ctrl_v")))
bind(k, Actions::Type::SelectRange);
if (notBound(k = stringToKey("v"))) if (notBound(k = stringToKey("v")))
bind(k, Actions::Type::ReverseSelection); bind(k, Actions::Type::ReverseSelection);
if (notBound(k = stringToKey("V"))) if (notBound(k = stringToKey("V")))

View File

@@ -178,6 +178,7 @@ void write_bindings(NC::Scrollpad &w)
w << '\n'; w << '\n';
key(w, Type::ToggleAddMode, "Toggle add mode (add or remove/always add)"); key(w, Type::ToggleAddMode, "Toggle add mode (add or remove/always add)");
key(w, Type::ToggleMouse, "Toggle mouse support"); key(w, Type::ToggleMouse, "Toggle mouse support");
key(w, Type::SelectRange, "Select range");
key(w, Type::ReverseSelection, "Reverse selection"); key(w, Type::ReverseSelection, "Reverse selection");
key(w, Type::RemoveSelection, "Remove selection"); key(w, Type::RemoveSelection, "Remove selection");
key(w, Type::SelectItem, "Select current item"); key(w, Type::SelectItem, "Select current item");
@@ -191,7 +192,6 @@ void write_bindings(NC::Scrollpad &w)
key(w, Type::ToggleConsume, "Toggle consume mode"); key(w, Type::ToggleConsume, "Toggle consume mode");
key(w, Type::ToggleReplayGainMode, "Toggle replay gain mode"); key(w, Type::ToggleReplayGainMode, "Toggle replay gain mode");
key(w, Type::ToggleBitrateVisibility, "Toggle bitrate visibility"); key(w, Type::ToggleBitrateVisibility, "Toggle bitrate visibility");
key(w, Type::Shuffle, "Shuffle selected range in playlist");
key(w, Type::ToggleCrossfade, "Toggle crossfade mode"); key(w, Type::ToggleCrossfade, "Toggle crossfade mode");
key(w, Type::SetCrossfade, "Set crossfade"); key(w, Type::SetCrossfade, "Set crossfade");
key(w, Type::SetVolume, "Set volume"); key(w, Type::SetVolume, "Set volume");
@@ -239,8 +239,9 @@ void write_bindings(NC::Scrollpad &w)
key(w, Type::EditSong, "Edit song"); key(w, Type::EditSong, "Edit song");
# endif // HAVE_TAGLIB_H # endif // HAVE_TAGLIB_H
key(w, Type::SavePlaylist, "Save playlist"); key(w, Type::SavePlaylist, "Save playlist");
key(w, Type::SortPlaylist, "Sort playlist"); key(w, Type::Shuffle, "Shuffle range");
key(w, Type::ReversePlaylist, "Reverse playlist"); key(w, Type::SortPlaylist, "Sort range");
key(w, Type::ReversePlaylist, "Reverse range");
key(w, Type::JumpToPlayingSong, "Jump to current song"); key(w, Type::JumpToPlayingSong, "Jump to current song");
key(w, Type::TogglePlayingSongCentering, "Toggle playing song centering"); key(w, Type::TogglePlayingSongCentering, "Toggle playing song centering");

View File

@@ -113,21 +113,40 @@ std::vector<Iterator> getSelected(Iterator first, Iterator last)
return result; return result;
} }
/// @return selected range within given range or original range if no item is selected /// @return true if range that begins and ends with selected items was found
template <typename Iterator> template <typename Iterator>
std::pair<Iterator, Iterator> getSelectedRange(Iterator first, Iterator second) bool findRange(Iterator &first, Iterator &last)
{ {
auto result = std::make_pair(first, second); for (; first != last; ++first)
if (hasSelected(first, second))
{ {
while (!result.first->isSelected()) if (first->isSelected())
++result.first; break;
do
--result.second;
while (!result.second->isSelected());
++result.second;
} }
return result; if (first == last)
return false;
--last;
for (; first != last; --last)
{
if (last->isSelected())
break;
}
++last;
return true;
}
/// @return true if fully selected range was found, false otherwise.
template <typename Iterator>
bool findSelectedRange(Iterator &first, Iterator &last)
{
if (!findRange(first, last))
return false;
// we have range, now check if it's filled with selected items
for (auto it = first; it != last; ++it)
{
if (!it->isSelected())
return false;
}
return true;
} }
template <typename T> template <typename T>

View File

@@ -197,18 +197,6 @@ MPD::Song Playlist::nowPlayingSong()
return s; return s;
} }
void Playlist::Reverse()
{
Statusbar::print("Reversing playlist order...");
auto begin = w.begin(), end = w.end();
std::tie(begin, end) = getSelectedRange(begin, end);
Mpd.StartCommandsList();
for (--end; begin < end; ++begin, --end)
Mpd.Swap(begin->value().getPosition(), end->value().getPosition());
Mpd.CommitCommandsList();
Statusbar::print("Playlist reversed");
}
void Playlist::EnableHighlighting() void Playlist::EnableHighlighting()
{ {
w.setHighlighting(true); w.setHighlighting(true);

View File

@@ -62,8 +62,7 @@ struct Playlist: Screen<SongMenu>, HasSongs, Searchable, Tabbable
// private members // private members
MPD::Song nowPlayingSong(); MPD::Song nowPlayingSong();
void Reverse();
void EnableHighlighting(); void EnableHighlighting();
void SetSelectedItemsPriority(int prio); void SetSelectedItemsPriority(int prio);

View File

@@ -156,8 +156,9 @@ void SortPlaylistDialog::sort() const
{ {
auto &pl = myPlaylist->main(); auto &pl = myPlaylist->main();
auto begin = pl.begin(), end = pl.end(); auto begin = pl.begin(), end = pl.end();
std::tie(begin, end) = getSelectedRange(begin, end); if (!findSelectedRange(begin, end))
return;
size_t start_pos = begin - pl.begin(); size_t start_pos = begin - pl.begin();
std::vector<MPD::Song> playlist; std::vector<MPD::Song> playlist;
playlist.reserve(end - begin); playlist.reserve(end - begin);
@@ -203,7 +204,7 @@ void SortPlaylistDialog::sort() const
Mpd.StartCommandsList(); Mpd.StartCommandsList();
quick_sort(playlist.begin(), playlist.end()); quick_sort(playlist.begin(), playlist.end());
Mpd.CommitCommandsList(); Mpd.CommitCommandsList();
Statusbar::print("Playlist sorted"); Statusbar::print("Range sorted");
switchToPreviousScreen(); switchToPreviousScreen();
} }