replace ProxySongList with NC::List and SongList
This commit is contained in:
@@ -40,6 +40,7 @@ ncmpcpp_SOURCES = \
|
||||
settings.cpp \
|
||||
song.cpp \
|
||||
song_info.cpp \
|
||||
song_list.cpp \
|
||||
sort_playlist.cpp \
|
||||
status.cpp \
|
||||
statusbar.cpp \
|
||||
@@ -56,6 +57,7 @@ INCLUDES= $(all_includes)
|
||||
# the library search path.
|
||||
ncmpcpp_LDFLAGS = $(all_libraries)
|
||||
noinst_HEADERS = \
|
||||
helpers/song_iterator_maker.h \
|
||||
utility/comparators.h \
|
||||
utility/conversion.h \
|
||||
utility/functional.h \
|
||||
@@ -90,7 +92,6 @@ noinst_HEADERS = \
|
||||
mutable_song.h \
|
||||
outputs.h \
|
||||
playlist_editor.h \
|
||||
proxy_song_list.h \
|
||||
regex_filter.h \
|
||||
runnable_item.h \
|
||||
screen.h \
|
||||
@@ -103,6 +104,7 @@ noinst_HEADERS = \
|
||||
settings.h \
|
||||
song.h \
|
||||
song_info.h \
|
||||
song_list.h \
|
||||
sort_playlist.h \
|
||||
status.h \
|
||||
statusbar.h \
|
||||
|
||||
266
src/actions.cpp
266
src/actions.cpp
@@ -81,6 +81,10 @@ boost::array<
|
||||
|
||||
void populateActions();
|
||||
|
||||
bool scrollTagCanBeRun(NC::List *&list, SongList *&songs);
|
||||
void scrollTagUpRun(NC::List *list, SongList *songs, MPD::Song::GetFunction get);
|
||||
void scrollTagDownRun(NC::List *list, SongList *songs, MPD::Song::GetFunction get);
|
||||
|
||||
void seek();
|
||||
void findItem(const SearchDirection direction);
|
||||
void listsChangeFinisher();
|
||||
@@ -358,102 +362,42 @@ void ScrollDown::run()
|
||||
|
||||
bool ScrollUpArtist::canBeRun()
|
||||
{
|
||||
return proxySongList(myScreen);
|
||||
return scrollTagCanBeRun(m_list, m_songs);
|
||||
}
|
||||
|
||||
void ScrollUpArtist::run()
|
||||
{
|
||||
auto pl = proxySongList(myScreen);
|
||||
assert(pl);
|
||||
if (pl.empty())
|
||||
return;
|
||||
size_t pos = pl.choice();
|
||||
if (MPD::Song *s = pl.getSong(pos))
|
||||
{
|
||||
std::string artist = s->getArtist();
|
||||
while (pos > 0)
|
||||
{
|
||||
s = pl.getSong(--pos);
|
||||
if (!s || s->getArtist() != artist)
|
||||
break;
|
||||
}
|
||||
pl.highlight(pos);
|
||||
}
|
||||
scrollTagUpRun(m_list, m_songs, &MPD::Song::getArtist);
|
||||
}
|
||||
|
||||
bool ScrollUpAlbum::canBeRun()
|
||||
{
|
||||
return proxySongList(myScreen);
|
||||
return scrollTagCanBeRun(m_list, m_songs);
|
||||
}
|
||||
|
||||
void ScrollUpAlbum::run()
|
||||
{
|
||||
auto pl = proxySongList(myScreen);
|
||||
assert(pl);
|
||||
if (pl.empty())
|
||||
return;
|
||||
size_t pos = pl.choice();
|
||||
if (MPD::Song *s = pl.getSong(pos))
|
||||
{
|
||||
std::string album = s->getAlbum();
|
||||
while (pos > 0)
|
||||
{
|
||||
s = pl.getSong(--pos);
|
||||
if (!s || s->getAlbum() != album)
|
||||
break;
|
||||
}
|
||||
pl.highlight(pos);
|
||||
}
|
||||
scrollTagUpRun(m_list, m_songs, &MPD::Song::getAlbum);
|
||||
}
|
||||
|
||||
bool ScrollDownArtist::canBeRun()
|
||||
{
|
||||
return proxySongList(myScreen);
|
||||
return scrollTagCanBeRun(m_list, m_songs);
|
||||
}
|
||||
|
||||
void ScrollDownArtist::run()
|
||||
{
|
||||
auto pl = proxySongList(myScreen);
|
||||
assert(pl);
|
||||
if (pl.empty())
|
||||
return;
|
||||
size_t pos = pl.choice();
|
||||
if (MPD::Song *s = pl.getSong(pos))
|
||||
{
|
||||
std::string artist = s->getArtist();
|
||||
while (pos < pl.size() - 1)
|
||||
{
|
||||
s = pl.getSong(++pos);
|
||||
if (!s || s->getArtist() != artist)
|
||||
break;
|
||||
}
|
||||
pl.highlight(pos);
|
||||
}
|
||||
scrollTagDownRun(m_list, m_songs, &MPD::Song::getArtist);
|
||||
}
|
||||
|
||||
bool ScrollDownAlbum::canBeRun()
|
||||
{
|
||||
return proxySongList(myScreen);
|
||||
return scrollTagCanBeRun(m_list, m_songs);
|
||||
}
|
||||
|
||||
void ScrollDownAlbum::run()
|
||||
{
|
||||
auto pl = proxySongList(myScreen);
|
||||
assert(pl);
|
||||
if (pl.empty())
|
||||
return;
|
||||
size_t pos = pl.choice();
|
||||
if (MPD::Song *s = pl.getSong(pos))
|
||||
{
|
||||
std::string album = s->getAlbum();
|
||||
while (pos < pl.size() - 1)
|
||||
{
|
||||
s = pl.getSong(++pos);
|
||||
if (!s || s->getAlbum() != album)
|
||||
break;
|
||||
}
|
||||
pl.highlight(pos);
|
||||
}
|
||||
scrollTagDownRun(m_list, m_songs, &MPD::Song::getAlbum);
|
||||
}
|
||||
|
||||
void PageUp::run()
|
||||
@@ -543,19 +487,6 @@ void PressSpace::run()
|
||||
myScreen->spacePressed();
|
||||
}
|
||||
|
||||
bool SelectItem::canBeRun()
|
||||
{
|
||||
hs = hasSongs(myScreen);
|
||||
return hs != nullptr && hs->allowsSelection();
|
||||
}
|
||||
|
||||
void SelectItem::run()
|
||||
{
|
||||
hs->selectCurrent();
|
||||
myScreen->scroll(NC::Scroll::Down);
|
||||
listsChangeFinisher();
|
||||
}
|
||||
|
||||
bool PreviousColumn::canBeRun()
|
||||
{
|
||||
auto hc = hasColumns(myScreen);
|
||||
@@ -1011,7 +942,7 @@ void ToggleDisplayMode::run()
|
||||
case DisplayMode::Classic:
|
||||
Config.playlist_display_mode = DisplayMode::Columns;
|
||||
myPlaylist->main().setItemDisplayer(std::bind(
|
||||
Display::SongsInColumns, ph::_1, myPlaylist->proxySongList()
|
||||
Display::SongsInColumns, ph::_1, std::cref(myPlaylist->main())
|
||||
));
|
||||
if (Config.titles_visibility)
|
||||
myPlaylist->main().setTitle(Display::Columns(myPlaylist->main().getWidth()));
|
||||
@@ -1021,7 +952,7 @@ void ToggleDisplayMode::run()
|
||||
case DisplayMode::Columns:
|
||||
Config.playlist_display_mode = DisplayMode::Classic;
|
||||
myPlaylist->main().setItemDisplayer(std::bind(
|
||||
Display::Songs, ph::_1, myPlaylist->proxySongList(), std::cref(Config.song_list_format)
|
||||
Display::Songs, ph::_1, std::cref(myPlaylist->main()), std::cref(Config.song_list_format)
|
||||
));
|
||||
myPlaylist->main().setTitle("");
|
||||
}
|
||||
@@ -1072,13 +1003,13 @@ void ToggleDisplayMode::run()
|
||||
case DisplayMode::Classic:
|
||||
Config.playlist_editor_display_mode = DisplayMode::Columns;
|
||||
myPlaylistEditor->Content.setItemDisplayer(std::bind(
|
||||
Display::SongsInColumns, ph::_1, myPlaylistEditor->contentProxyList()
|
||||
Display::SongsInColumns, ph::_1, std::cref(myPlaylistEditor->Content)
|
||||
));
|
||||
break;
|
||||
case DisplayMode::Columns:
|
||||
Config.playlist_editor_display_mode = DisplayMode::Classic;
|
||||
myPlaylistEditor->Content.setItemDisplayer(std::bind(
|
||||
Display::Songs, ph::_1, myPlaylistEditor->contentProxyList(), std::cref(Config.song_list_format)
|
||||
Display::Songs, ph::_1, std::cref(myPlaylistEditor->Content), std::cref(Config.song_list_format)
|
||||
));
|
||||
break;
|
||||
}
|
||||
@@ -1285,8 +1216,8 @@ void SetVolume::run()
|
||||
bool EditSong::canBeRun()
|
||||
{
|
||||
# ifdef HAVE_TAGLIB_H
|
||||
return currentSong(myScreen)
|
||||
&& isMPDMusicDirSet();
|
||||
m_song = currentSong(myScreen);
|
||||
return m_song != nullptr && isMPDMusicDirSet();
|
||||
# else
|
||||
return false;
|
||||
# endif // HAVE_TAGLIB_H
|
||||
@@ -1295,8 +1226,7 @@ bool EditSong::canBeRun()
|
||||
void EditSong::run()
|
||||
{
|
||||
# ifdef HAVE_TAGLIB_H
|
||||
auto s = currentSong(myScreen);
|
||||
myTinyTagEditor->SetEdited(*s);
|
||||
myTinyTagEditor->SetEdited(*m_song);
|
||||
myTinyTagEditor->switchTo();
|
||||
# endif // HAVE_TAGLIB_H
|
||||
}
|
||||
@@ -1530,24 +1460,24 @@ void EditLyrics::run()
|
||||
|
||||
bool JumpToBrowser::canBeRun()
|
||||
{
|
||||
return currentSong(myScreen);
|
||||
m_song = currentSong(myScreen);
|
||||
return m_song != nullptr;
|
||||
}
|
||||
|
||||
void JumpToBrowser::run()
|
||||
{
|
||||
auto s = currentSong(myScreen);
|
||||
myBrowser->locateSong(*s);
|
||||
myBrowser->locateSong(*m_song);
|
||||
}
|
||||
|
||||
bool JumpToMediaLibrary::canBeRun()
|
||||
{
|
||||
return currentSong(myScreen);
|
||||
m_song = currentSong(myScreen);
|
||||
return m_song != nullptr;
|
||||
}
|
||||
|
||||
void JumpToMediaLibrary::run()
|
||||
{
|
||||
auto s = currentSong(myScreen);
|
||||
myLibrary->LocateSong(*s);
|
||||
myLibrary->LocateSong(*m_song);
|
||||
}
|
||||
|
||||
bool JumpToPlaylistEditor::canBeRun()
|
||||
@@ -1598,8 +1528,8 @@ void ToggleScreenLock::run()
|
||||
bool JumpToTagEditor::canBeRun()
|
||||
{
|
||||
# ifdef HAVE_TAGLIB_H
|
||||
return currentSong(myScreen)
|
||||
&& isMPDMusicDirSet();
|
||||
m_song = currentSong(myScreen);
|
||||
return m_song != nullptr && isMPDMusicDirSet();
|
||||
# else
|
||||
return false;
|
||||
# endif // HAVE_TAGLIB_H
|
||||
@@ -1608,8 +1538,7 @@ bool JumpToTagEditor::canBeRun()
|
||||
void JumpToTagEditor::run()
|
||||
{
|
||||
# ifdef HAVE_TAGLIB_H
|
||||
auto s = currentSong(myScreen);
|
||||
myTagEditor->LocateSong(*s);
|
||||
myTagEditor->LocateSong(*m_song);
|
||||
# endif // HAVE_TAGLIB_H
|
||||
}
|
||||
|
||||
@@ -1656,71 +1585,87 @@ void JumpToPositionInSong::run()
|
||||
Statusbar::print("Invalid format ([m]:[ss], [s]s, [%]%, [%] accepted)");
|
||||
}
|
||||
|
||||
bool SelectItem::canBeRun()
|
||||
{
|
||||
m_list = dynamic_cast<NC::List *>(myScreen->activeWindow());
|
||||
return m_list != nullptr
|
||||
&& !m_list->empty()
|
||||
&& m_list->currentP()->isSelectable();
|
||||
}
|
||||
|
||||
void SelectItem::run()
|
||||
{
|
||||
auto current = m_list->currentP();
|
||||
current->setSelected(!current->isSelected());
|
||||
myScreen->scroll(NC::Scroll::Down);
|
||||
listsChangeFinisher();
|
||||
}
|
||||
|
||||
bool ReverseSelection::canBeRun()
|
||||
{
|
||||
auto w = hasSongs(myScreen);
|
||||
return w && w->allowsSelection();
|
||||
m_list = dynamic_cast<NC::List *>(myScreen->activeWindow());
|
||||
return m_list != nullptr;
|
||||
}
|
||||
|
||||
void ReverseSelection::run()
|
||||
{
|
||||
auto w = hasSongs(myScreen);
|
||||
w->reverseSelection();
|
||||
for (auto &p : *m_list)
|
||||
p.setSelected(!p.isSelected());
|
||||
Statusbar::print("Selection reversed");
|
||||
}
|
||||
|
||||
bool RemoveSelection::canBeRun()
|
||||
{
|
||||
return proxySongList(myScreen);
|
||||
m_list = dynamic_cast<NC::List *>(myScreen->activeWindow());
|
||||
return m_list != nullptr;
|
||||
}
|
||||
|
||||
void RemoveSelection::run()
|
||||
{
|
||||
auto pl = proxySongList(myScreen);
|
||||
for (size_t i = 0; i < pl.size(); ++i)
|
||||
pl.setSelected(i, false);
|
||||
for (auto &p : *m_list)
|
||||
p.setSelected(false);
|
||||
Statusbar::print("Selection removed");
|
||||
}
|
||||
|
||||
bool SelectAlbum::canBeRun()
|
||||
{
|
||||
auto w = hasSongs(myScreen);
|
||||
return w && w->allowsSelection() && w->proxySongList();
|
||||
auto *w = myScreen->activeWindow();
|
||||
if (m_list != static_cast<void *>(w))
|
||||
m_list = dynamic_cast<NC::List *>(w);
|
||||
if (m_songs != static_cast<void *>(w))
|
||||
m_songs = dynamic_cast<SongList *>(w);
|
||||
return m_list != nullptr && !m_list->empty()
|
||||
&& m_songs != nullptr;
|
||||
}
|
||||
|
||||
void SelectAlbum::run()
|
||||
{
|
||||
auto pl = proxySongList(myScreen);
|
||||
assert(pl);
|
||||
if (pl.empty())
|
||||
const auto front = m_songs->beginS(), current = m_songs->currentS(), end = m_songs->endS();
|
||||
auto *s = current->get<Bit::Song>();
|
||||
if (s == nullptr)
|
||||
return;
|
||||
size_t pos = pl.choice();
|
||||
if (MPD::Song *s = pl.getSong(pos))
|
||||
auto get = &MPD::Song::getAlbum;
|
||||
const std::string tag = s->getTags(get);
|
||||
// go up
|
||||
for (auto it = current; it != front;)
|
||||
{
|
||||
std::string album = s->getAlbum();
|
||||
// select song under cursor
|
||||
pl.setSelected(pos, true);
|
||||
// go up
|
||||
while (pos > 0)
|
||||
{
|
||||
s = pl.getSong(--pos);
|
||||
if (!s || s->getAlbum() != album)
|
||||
break;
|
||||
else
|
||||
pl.setSelected(pos, true);
|
||||
}
|
||||
// go down
|
||||
pos = pl.choice();
|
||||
while (pos < pl.size() - 1)
|
||||
{
|
||||
s = pl.getSong(++pos);
|
||||
if (!s || s->getAlbum() != album)
|
||||
break;
|
||||
else
|
||||
pl.setSelected(pos, true);
|
||||
}
|
||||
Statusbar::print("Album around cursor position selected");
|
||||
--it;
|
||||
s = it->get<Bit::Song>();
|
||||
if (s == nullptr || s->getTags(get) != tag)
|
||||
break;
|
||||
it->get<Bit::Properties>().setSelected(true);
|
||||
}
|
||||
// go down
|
||||
for (auto it = current;;)
|
||||
{
|
||||
it->get<Bit::Properties>().setSelected(true);
|
||||
if (++it == end)
|
||||
break;
|
||||
s = it->get<Bit::Song>();
|
||||
if (s == nullptr || s->getTags(get) != tag)
|
||||
break;
|
||||
}
|
||||
Statusbar::print("Album around cursor position selected");
|
||||
}
|
||||
|
||||
bool AddSelectedItems::canBeRun()
|
||||
@@ -2600,6 +2545,53 @@ void populateActions()
|
||||
insert_action(new Actions::ShowServerInfo());
|
||||
}
|
||||
|
||||
bool scrollTagCanBeRun(NC::List *&list, SongList *&songs)
|
||||
{
|
||||
auto w = myScreen->activeWindow();
|
||||
if (list != static_cast<void *>(w))
|
||||
list = dynamic_cast<NC::List *>(w);
|
||||
if (songs != static_cast<void *>(w))
|
||||
songs = dynamic_cast<SongList *>(w);
|
||||
return list != nullptr && !list->empty()
|
||||
&& songs != nullptr;
|
||||
}
|
||||
|
||||
void scrollTagUpRun(NC::List *list, SongList *songs, MPD::Song::GetFunction get)
|
||||
{
|
||||
const auto front = songs->beginS();
|
||||
auto it = songs->currentS();
|
||||
if (auto *s = it->get<Bit::Song>())
|
||||
{
|
||||
const std::string tag = s->getTags(get);
|
||||
while (it != front)
|
||||
{
|
||||
--it;
|
||||
s = it->get<Bit::Song>();
|
||||
if (s == nullptr || s->getTags(get) != tag)
|
||||
break;
|
||||
}
|
||||
list->highlight(it-front);
|
||||
}
|
||||
}
|
||||
|
||||
void scrollTagDownRun(NC::List *list, SongList *songs, MPD::Song::GetFunction get)
|
||||
{
|
||||
const auto front = songs->beginS(), back = --songs->endS();
|
||||
auto it = songs->currentS();
|
||||
if (auto *s = it->get<Bit::Song>())
|
||||
{
|
||||
const std::string tag = s->getTags(get);
|
||||
while (it != back)
|
||||
{
|
||||
++it;
|
||||
s = it->get<Bit::Song>();
|
||||
if (s == nullptr || s->getTags(get) != tag)
|
||||
break;
|
||||
}
|
||||
list->highlight(it-front);
|
||||
}
|
||||
}
|
||||
|
||||
void seek()
|
||||
{
|
||||
using Global::wHeader;
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "interfaces.h"
|
||||
#include "window.h"
|
||||
|
||||
struct SongList;
|
||||
|
||||
namespace Actions {
|
||||
|
||||
enum class Type
|
||||
@@ -34,7 +36,7 @@ enum class Type
|
||||
MacroUtility = 0,
|
||||
Dummy, MouseEvent, ScrollUp, ScrollDown, ScrollUpArtist, ScrollUpAlbum,
|
||||
ScrollDownArtist, ScrollDownAlbum, PageUp, PageDown, MoveHome, MoveEnd,
|
||||
ToggleInterface, JumpToParentDirectory, PressEnter, PressSpace, SelectItem, PreviousColumn,
|
||||
ToggleInterface, JumpToParentDirectory, PressEnter, PressSpace, PreviousColumn,
|
||||
NextColumn, MasterScreen, SlaveScreen, VolumeUp, VolumeDown, DeletePlaylistItems,
|
||||
DeleteStoredPlaylist, DeleteBrowserItems, ReplaySong, Previous, Next, Pause,
|
||||
Stop, ExecuteCommand, SavePlaylist, MoveSortOrderUp, MoveSortOrderDown,
|
||||
@@ -46,7 +48,7 @@ enum class Type
|
||||
SetCrossfade, SetVolume, EditSong, EditLibraryTag, EditLibraryAlbum, EditDirectoryName,
|
||||
EditPlaylistName, EditLyrics, JumpToBrowser, JumpToMediaLibrary,
|
||||
JumpToPlaylistEditor, ToggleScreenLock, JumpToTagEditor, JumpToPositionInSong,
|
||||
ReverseSelection, RemoveSelection, SelectAlbum, AddSelectedItems,
|
||||
SelectItem, ReverseSelection, RemoveSelection, SelectAlbum, AddSelectedItems,
|
||||
CropMainPlaylist, CropPlaylist, ClearMainPlaylist, ClearPlaylist, SortPlaylist,
|
||||
ReversePlaylist, Find, FindItemForward, FindItemBackward,
|
||||
NextFoundItem, PreviousFoundItem, ToggleFindMode, ToggleReplayGainMode,
|
||||
@@ -161,6 +163,10 @@ struct ScrollUpArtist : public BaseAction
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
NC::List *m_list;
|
||||
SongList *m_songs;
|
||||
};
|
||||
|
||||
struct ScrollUpAlbum : public BaseAction
|
||||
@@ -170,6 +176,10 @@ struct ScrollUpAlbum : public BaseAction
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
NC::List *m_list;
|
||||
SongList *m_songs;
|
||||
};
|
||||
|
||||
struct ScrollDownArtist : public BaseAction
|
||||
@@ -179,6 +189,10 @@ struct ScrollDownArtist : public BaseAction
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
NC::List *m_list;
|
||||
SongList *m_songs;
|
||||
};
|
||||
|
||||
struct ScrollDownAlbum : public BaseAction
|
||||
@@ -188,6 +202,10 @@ struct ScrollDownAlbum : public BaseAction
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
NC::List *m_list;
|
||||
SongList *m_songs;
|
||||
};
|
||||
|
||||
struct PageUp : public BaseAction
|
||||
@@ -255,18 +273,6 @@ protected:
|
||||
virtual void run();
|
||||
};
|
||||
|
||||
struct SelectItem : public BaseAction
|
||||
{
|
||||
SelectItem() : BaseAction(Type::SelectItem, "select_item") { }
|
||||
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
HasSongs *hs;
|
||||
};
|
||||
|
||||
struct PreviousColumn : public BaseAction
|
||||
{
|
||||
PreviousColumn() : BaseAction(Type::PreviousColumn, "previous_column") { }
|
||||
@@ -631,6 +637,9 @@ struct EditSong : public BaseAction
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
const MPD::Song *m_song;
|
||||
};
|
||||
|
||||
struct EditLibraryTag : public BaseAction
|
||||
@@ -685,6 +694,9 @@ struct JumpToBrowser : public BaseAction
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
const MPD::Song *m_song;
|
||||
};
|
||||
|
||||
struct JumpToMediaLibrary : public BaseAction
|
||||
@@ -694,6 +706,9 @@ struct JumpToMediaLibrary : public BaseAction
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
const MPD::Song *m_song;
|
||||
};
|
||||
|
||||
struct JumpToPlaylistEditor : public BaseAction
|
||||
@@ -720,6 +735,9 @@ struct JumpToTagEditor : public BaseAction
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
const MPD::Song *m_song;
|
||||
};
|
||||
|
||||
struct JumpToPositionInSong : public BaseAction
|
||||
@@ -731,6 +749,18 @@ protected:
|
||||
virtual void run();
|
||||
};
|
||||
|
||||
struct SelectItem : public BaseAction
|
||||
{
|
||||
SelectItem() : BaseAction(Type::SelectItem, "select_item") { }
|
||||
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
NC::List *m_list;
|
||||
};
|
||||
|
||||
struct ReverseSelection : public BaseAction
|
||||
{
|
||||
ReverseSelection() : BaseAction(Type::ReverseSelection, "reverse_selection") { }
|
||||
@@ -738,6 +768,9 @@ struct ReverseSelection : public BaseAction
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
NC::List *m_list;
|
||||
};
|
||||
|
||||
struct RemoveSelection : public BaseAction
|
||||
@@ -747,6 +780,9 @@ struct RemoveSelection : public BaseAction
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
NC::List *m_list;
|
||||
};
|
||||
|
||||
struct SelectAlbum : public BaseAction
|
||||
@@ -756,6 +792,10 @@ struct SelectAlbum : public BaseAction
|
||||
protected:
|
||||
virtual bool canBeRun();
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
NC::List *m_list;
|
||||
SongList *m_songs;
|
||||
};
|
||||
|
||||
struct AddSelectedItems : public BaseAction
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "tag_editor.h"
|
||||
#include "title.h"
|
||||
#include "tags.h"
|
||||
#include "helpers/song_iterator_maker.h"
|
||||
#include "utility/comparators.h"
|
||||
#include "utility/string.h"
|
||||
#include "configuration.h"
|
||||
@@ -69,8 +70,63 @@ void clearDirectory(const std::string &directory);
|
||||
std::string itemToString(const MPD::Item &item);
|
||||
bool browserEntryMatcher(const Regex::Regex &rx, const MPD::Item &item, bool filter);
|
||||
|
||||
template <bool Const>
|
||||
struct SongExtractor
|
||||
{
|
||||
typedef SongExtractor type;
|
||||
|
||||
typedef typename NC::Menu<MPD::Item>::Item MenuItem;
|
||||
typedef typename std::conditional<Const, const MenuItem, MenuItem>::type Item;
|
||||
typedef typename std::conditional<Const, const MPD::Song, MPD::Song>::type Song;
|
||||
|
||||
Song *operator()(Item &item) const
|
||||
{
|
||||
Song *ptr = nullptr;
|
||||
if (item.value().type() == MPD::Item::Type::Song)
|
||||
ptr = const_cast<Song *>(&item.value().song());
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
SongIterator BrowserWindow::currentS()
|
||||
{
|
||||
return makeSongIterator_<MPD::Item>(current(), SongExtractor<false>());
|
||||
}
|
||||
|
||||
ConstSongIterator BrowserWindow::currentS() const
|
||||
{
|
||||
return makeConstSongIterator_<MPD::Item>(current(), SongExtractor<true>());
|
||||
}
|
||||
|
||||
SongIterator BrowserWindow::beginS()
|
||||
{
|
||||
return makeSongIterator_<MPD::Item>(begin(), SongExtractor<false>());
|
||||
}
|
||||
|
||||
ConstSongIterator BrowserWindow::beginS() const
|
||||
{
|
||||
return makeConstSongIterator_<MPD::Item>(begin(), SongExtractor<true>());
|
||||
}
|
||||
|
||||
SongIterator BrowserWindow::endS()
|
||||
{
|
||||
return makeSongIterator_<MPD::Item>(end(), SongExtractor<false>());
|
||||
}
|
||||
|
||||
ConstSongIterator BrowserWindow::endS() const
|
||||
{
|
||||
return makeConstSongIterator_<MPD::Item>(end(), SongExtractor<true>());
|
||||
}
|
||||
|
||||
std::vector<MPD::Song> BrowserWindow::getSelectedSongs()
|
||||
{
|
||||
return {}; // TODO
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
Browser::Browser()
|
||||
: m_update_request(true)
|
||||
, m_local_browser(false)
|
||||
@@ -83,7 +139,7 @@ Browser::Browser()
|
||||
w.centeredCursor(Config.centered_cursor);
|
||||
w.setSelectedPrefix(Config.selected_item_prefix);
|
||||
w.setSelectedSuffix(Config.selected_item_suffix);
|
||||
w.setItemDisplayer(std::bind(Display::Items, ph::_1, proxySongList()));
|
||||
w.setItemDisplayer(std::bind(Display::Items, ph::_1, std::cref(w)));
|
||||
}
|
||||
|
||||
void Browser::resize()
|
||||
@@ -110,7 +166,7 @@ void Browser::resize()
|
||||
void Browser::switchTo()
|
||||
{
|
||||
SwitchTo::execute(this);
|
||||
markSongsInPlaylist(proxySongList());
|
||||
markSongsInPlaylist(w);
|
||||
drawHeader();
|
||||
}
|
||||
|
||||
@@ -295,34 +351,6 @@ bool Browser::find(SearchDirection direction, bool wrap, bool skip_current)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
ProxySongList Browser::proxySongList()
|
||||
{
|
||||
return ProxySongList(w, [](NC::Menu<MPD::Item>::Item &item) -> MPD::Song * {
|
||||
MPD::Song *ptr = 0;
|
||||
if (item.value().type() == MPD::Item::Type::Song)
|
||||
ptr = const_cast<MPD::Song *>(&item.value().song());
|
||||
return ptr;
|
||||
});
|
||||
}
|
||||
|
||||
bool Browser::allowsSelection()
|
||||
{
|
||||
size_t root = inRootDirectory() ? 0 : 1;
|
||||
return !w.empty() && w.choice() >= root;
|
||||
}
|
||||
|
||||
void Browser::selectCurrent()
|
||||
{
|
||||
size_t current = w.choice();
|
||||
w[current].setSelected(!w[current].isSelected());
|
||||
}
|
||||
|
||||
void Browser::reverseSelection()
|
||||
{
|
||||
size_t offset = inRootDirectory() ? 0 : 1;
|
||||
reverseSelectionHelper(w.begin()+offset, w.end());
|
||||
}
|
||||
|
||||
std::vector<MPD::Song> Browser::getSelectedSongs()
|
||||
{
|
||||
std::vector<MPD::Song> songs;
|
||||
@@ -446,7 +474,7 @@ void Browser::getDirectory(std::string directory)
|
||||
if (!isRootDirectory(directory))
|
||||
{
|
||||
// make it so that display function doesn't have to handle special cases
|
||||
w.addItem(MPD::Directory(directory + "/.."));
|
||||
w.addItem(MPD::Directory(directory + "/.."), NC::List::Properties::None);
|
||||
}
|
||||
|
||||
for (const auto &item : items)
|
||||
@@ -468,8 +496,10 @@ void Browser::getDirectory(std::string directory)
|
||||
}
|
||||
case MPD::Item::Type::Song:
|
||||
{
|
||||
bool is_bold = myPlaylist->checkForSong(item.song());
|
||||
w.addItem(std::move(item), is_bold);
|
||||
auto properties = NC::List::Properties::Selectable;
|
||||
if (myPlaylist->checkForSong(item.song()))
|
||||
properties |= NC::List::Properties::Bold;
|
||||
w.addItem(std::move(item), properties);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,12 +25,29 @@
|
||||
#include "mpdpp.h"
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
#include "song_list.h"
|
||||
|
||||
struct Browser: Screen<NC::Menu<MPD::Item>>, HasSongs, Searchable, Tabbable
|
||||
struct BrowserWindow: NC::Menu<MPD::Item>, SongList
|
||||
{
|
||||
BrowserWindow() { }
|
||||
BrowserWindow(NC::Menu<MPD::Item> &&base)
|
||||
: NC::Menu<MPD::Item>(std::move(base)) { }
|
||||
|
||||
virtual SongIterator currentS() OVERRIDE;
|
||||
virtual ConstSongIterator currentS() const OVERRIDE;
|
||||
virtual SongIterator beginS() OVERRIDE;
|
||||
virtual ConstSongIterator beginS() const OVERRIDE;
|
||||
virtual SongIterator endS() OVERRIDE;
|
||||
virtual ConstSongIterator endS() const OVERRIDE;
|
||||
|
||||
virtual std::vector<MPD::Song> getSelectedSongs() OVERRIDE;
|
||||
};
|
||||
|
||||
struct Browser: Screen<BrowserWindow>, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
Browser();
|
||||
|
||||
// Screen< NC::Menu<MPD::Item> > implementation
|
||||
// Screen<BrowserWindow> implementation
|
||||
virtual void resize() OVERRIDE;
|
||||
virtual void switchTo() OVERRIDE;
|
||||
|
||||
@@ -53,11 +70,6 @@ struct Browser: Screen<NC::Menu<MPD::Item>>, HasSongs, Searchable, Tabbable
|
||||
virtual bool find(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE;
|
||||
|
||||
// HasSongs implementation
|
||||
virtual ProxySongList proxySongList() OVERRIDE;
|
||||
|
||||
virtual bool allowsSelection() OVERRIDE;
|
||||
virtual void selectCurrent() OVERRIDE;
|
||||
virtual void reverseSelection() OVERRIDE;
|
||||
virtual std::vector<MPD::Song> getSelectedSongs() OVERRIDE;
|
||||
|
||||
// private members
|
||||
|
||||
@@ -77,27 +77,30 @@ const wchar_t *toColumnName(char c)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void setProperties(NC::Menu<T> &menu, const MPD::Song &s, const ProxySongList &pl, bool &separate_albums,
|
||||
bool &is_now_playing, bool &is_selected, bool &discard_colors)
|
||||
void setProperties(NC::Menu<T> &menu, const MPD::Song &s, const SongList &list,
|
||||
bool &separate_albums, bool &is_now_playing, bool &is_selected, bool &discard_colors)
|
||||
{
|
||||
size_t drawn_pos = menu.drawn() - menu.begin();
|
||||
separate_albums = false;
|
||||
if (Config.playlist_separate_albums)
|
||||
{
|
||||
size_t next_pos = drawn_pos+1;
|
||||
auto next = next_pos < pl.size() ? pl.getSong(next_pos) : 0;
|
||||
if (next && next->getAlbum() != s.getAlbum())
|
||||
separate_albums = true;
|
||||
auto next = list.beginS() + drawn_pos + 1;
|
||||
if (next != list.endS())
|
||||
{
|
||||
auto next_s = next->get<Bit::Song>();
|
||||
if (next_s != nullptr && next_s->getAlbum() != s.getAlbum())
|
||||
separate_albums = true;
|
||||
}
|
||||
}
|
||||
if (separate_albums)
|
||||
{
|
||||
menu << NC::Format::Underline;
|
||||
mvwhline(menu.raw(), menu.getY(), 0, KEY_SPACE, menu.getWidth());
|
||||
}
|
||||
|
||||
|
||||
is_selected = menu.drawn()->isSelected();
|
||||
discard_colors = Config.discard_colors_if_item_is_selected && is_selected;
|
||||
|
||||
|
||||
int song_pos = drawn_pos;
|
||||
is_now_playing = Status::State::player() != MPD::psStop && myPlaylist->isActiveWindow(menu)
|
||||
&& song_pos == Status::State::currentSongPosition();
|
||||
@@ -106,11 +109,10 @@ void setProperties(NC::Menu<T> &menu, const MPD::Song &s, const ProxySongList &p
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void showSongs(NC::Menu<T> &menu, const MPD::Song &s,
|
||||
const ProxySongList &pl, const Format::AST<char> &ast)
|
||||
void showSongs(NC::Menu<T> &menu, const MPD::Song &s, const SongList &list, const Format::AST<char> &ast)
|
||||
{
|
||||
bool separate_albums, is_now_playing, is_selected, discard_colors;
|
||||
setProperties(menu, s, pl, separate_albums, is_now_playing, is_selected, discard_colors);
|
||||
setProperties(menu, s, list, separate_albums, is_now_playing, is_selected, discard_colors);
|
||||
|
||||
const size_t y = menu.getY();
|
||||
NC::Buffer right_aligned;
|
||||
@@ -134,14 +136,14 @@ void showSongs(NC::Menu<T> &menu, const MPD::Song &s,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void showSongsInColumns(NC::Menu<T> &menu, const MPD::Song &s, const ProxySongList &pl)
|
||||
void showSongsInColumns(NC::Menu<T> &menu, const MPD::Song &s, const SongList &list)
|
||||
{
|
||||
if (Config.columns.empty())
|
||||
return;
|
||||
|
||||
|
||||
bool separate_albums, is_now_playing, is_selected, discard_colors;
|
||||
setProperties(menu, s, pl, separate_albums, is_now_playing, is_selected, discard_colors);
|
||||
|
||||
setProperties(menu, s, list, separate_albums, is_now_playing, is_selected, discard_colors);
|
||||
|
||||
int width;
|
||||
int y = menu.getY();
|
||||
int remained_width = menu.getWidth();
|
||||
@@ -163,7 +165,7 @@ void showSongsInColumns(NC::Menu<T> &menu, const MPD::Song &s, const ProxySongLi
|
||||
// and next column, so we substract it now and restore later.
|
||||
if (it != last)
|
||||
--width;
|
||||
|
||||
|
||||
if (it == Config.columns.begin() && (is_now_playing || is_selected))
|
||||
{
|
||||
// here comes the shitty part. if we applied now playing or selected
|
||||
@@ -187,11 +189,11 @@ void showSongsInColumns(NC::Menu<T> &menu, const MPD::Song &s, const ProxySongLi
|
||||
width -= offset;
|
||||
remained_width -= offset;
|
||||
}
|
||||
|
||||
|
||||
// if column doesn't fit into screen, discard it and any other after it.
|
||||
if (remained_width-width < 0 || width < 0 /* this one may come from (*) */)
|
||||
break;
|
||||
|
||||
|
||||
std::wstring tag;
|
||||
for (size_t i = 0; i < it->type.length(); ++i)
|
||||
{
|
||||
@@ -204,16 +206,16 @@ void showSongsInColumns(NC::Menu<T> &menu, const MPD::Song &s, const ProxySongLi
|
||||
if (tag.empty() && it->display_empty_tag)
|
||||
tag = ToWString(Config.empty_tag);
|
||||
wideCut(tag, width);
|
||||
|
||||
|
||||
if (!discard_colors && it->color != NC::Color::Default)
|
||||
menu << it->color;
|
||||
|
||||
|
||||
int x_off = 0;
|
||||
// if column uses right alignment, calculate proper offset.
|
||||
// otherwise just assume offset is 0, ie. we start from the left.
|
||||
if (it->right_alignment)
|
||||
x_off = std::max(0, width - int(wideLength(tag)));
|
||||
|
||||
|
||||
whline(menu.raw(), KEY_SPACE, width);
|
||||
menu.goToXY(x + x_off, y);
|
||||
menu << tag;
|
||||
@@ -224,11 +226,11 @@ void showSongsInColumns(NC::Menu<T> &menu, const MPD::Song &s, const ProxySongLi
|
||||
menu << ' ';
|
||||
remained_width -= width+1;
|
||||
}
|
||||
|
||||
|
||||
if (!discard_colors && it->color != NC::Color::Default)
|
||||
menu << NC::Color::End;
|
||||
}
|
||||
|
||||
|
||||
// here comes the shitty part, second chapter. here we apply
|
||||
// now playing suffix or/and make room for selected suffix
|
||||
// (as it will be applied in Menu::Refresh when this function
|
||||
@@ -243,7 +245,7 @@ void showSongsInColumns(NC::Menu<T> &menu, const MPD::Song &s, const ProxySongLi
|
||||
}
|
||||
if (is_selected)
|
||||
menu.goToXY(menu.getWidth() - Config.selected_item_suffix_length, y);
|
||||
|
||||
|
||||
if (separate_albums)
|
||||
menu << NC::Format::NoUnderline;
|
||||
}
|
||||
@@ -320,15 +322,14 @@ std::string Display::Columns(size_t list_width)
|
||||
return result;
|
||||
}
|
||||
|
||||
void Display::SongsInColumns(NC::Menu< MPD::Song >& menu, const ProxySongList &pl)
|
||||
void Display::SongsInColumns(NC::Menu<MPD::Song> &menu, const SongList &list)
|
||||
{
|
||||
showSongsInColumns(menu, menu.drawn()->value(), pl);
|
||||
showSongsInColumns(menu, menu.drawn()->value(), list);
|
||||
}
|
||||
|
||||
void Display::Songs(NC::Menu< MPD::Song >& menu,
|
||||
const ProxySongList &pl, const Format::AST<char> &ast)
|
||||
void Display::Songs(NC::Menu<MPD::Song> &menu, const SongList &list, const Format::AST<char> &ast)
|
||||
{
|
||||
showSongs(menu, menu.drawn()->value(), pl, ast);
|
||||
showSongs(menu, menu.drawn()->value(), list, ast);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TAGLIB_H
|
||||
@@ -354,7 +355,7 @@ void Display::Tags(NC::Menu<MPD::MutableSong> &menu)
|
||||
}
|
||||
#endif // HAVE_TAGLIB_H
|
||||
|
||||
void Display::Items(NC::Menu<MPD::Item> &menu, const ProxySongList &pl)
|
||||
void Display::Items(NC::Menu<MPD::Item> &menu, const SongList &list)
|
||||
{
|
||||
const MPD::Item &item = menu.drawn()->value();
|
||||
switch (item.type())
|
||||
@@ -368,10 +369,10 @@ void Display::Items(NC::Menu<MPD::Item> &menu, const ProxySongList &pl)
|
||||
switch (Config.browser_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
showSongs(menu, item.song(), pl, Config.song_list_format);
|
||||
showSongs(menu, item.song(), list, Config.song_list_format);
|
||||
break;
|
||||
case DisplayMode::Columns:
|
||||
showSongsInColumns(menu, item.song(), pl);
|
||||
showSongsInColumns(menu, item.song(), list);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -382,7 +383,7 @@ void Display::Items(NC::Menu<MPD::Item> &menu, const ProxySongList &pl)
|
||||
}
|
||||
}
|
||||
|
||||
void Display::SEItems(NC::Menu<SEItem> &menu, const ProxySongList &pl)
|
||||
void Display::SEItems(NC::Menu<SEItem> &menu, const SongList &list)
|
||||
{
|
||||
const SEItem &si = menu.drawn()->value();
|
||||
if (si.isSong())
|
||||
@@ -390,10 +391,10 @@ void Display::SEItems(NC::Menu<SEItem> &menu, const ProxySongList &pl)
|
||||
switch (Config.search_engine_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
showSongs(menu, si.song(), pl, Config.song_list_format);
|
||||
showSongs(menu, si.song(), list, Config.song_list_format);
|
||||
break;
|
||||
case DisplayMode::Columns:
|
||||
showSongsInColumns(menu, si.song(), pl);
|
||||
showSongsInColumns(menu, si.song(), list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,20 +26,21 @@
|
||||
#include "menu.h"
|
||||
#include "mutable_song.h"
|
||||
#include "search_engine.h"
|
||||
#include "song_list.h"
|
||||
|
||||
namespace Display {
|
||||
|
||||
std::string Columns(size_t);
|
||||
|
||||
void SongsInColumns(NC::Menu<MPD::Song> &menu, const ProxySongList &pl);
|
||||
void SongsInColumns(NC::Menu<MPD::Song> &menu, const SongList &list);
|
||||
|
||||
void Songs(NC::Menu<MPD::Song> &menu, const ProxySongList &pl, const Format::AST<char> &ast);
|
||||
void Songs(NC::Menu<MPD::Song> &menu, const SongList &list, const Format::AST<char> &ast);
|
||||
|
||||
void Tags(NC::Menu<MPD::MutableSong> &menu);
|
||||
|
||||
void SEItems(NC::Menu<SEItem> &menu, const ProxySongList &pl);
|
||||
void SEItems(NC::Menu<SEItem> &menu, const SongList &list);
|
||||
|
||||
void Items(NC::Menu<MPD::Item> &menu, const ProxySongList &pl);
|
||||
void Items(NC::Menu<MPD::Item> &menu, const SongList &list);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,69 @@
|
||||
#include "playlist.h"
|
||||
#include "statusbar.h"
|
||||
|
||||
const MPD::Song *currentSong(const BaseScreen *screen)
|
||||
{
|
||||
const MPD::Song *ptr = nullptr;
|
||||
const auto *list = dynamic_cast<const SongList *>(screen->activeWindow());
|
||||
if (list != nullptr)
|
||||
{
|
||||
const auto it = list->currentS();
|
||||
if (it != list->endS())
|
||||
ptr = it->get<Bit::Song>();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
typedef std::vector<MPD::Song>::const_iterator VectorSongIterator;
|
||||
bool addSongsToPlaylist(VectorSongIterator first, VectorSongIterator last, bool play, int position)
|
||||
{
|
||||
bool result = true;
|
||||
auto addSongNoError = [&](VectorSongIterator song) -> int {
|
||||
try
|
||||
{
|
||||
return Mpd.AddSong(*song, position);
|
||||
}
|
||||
catch (MPD::ServerError &e)
|
||||
{
|
||||
Status::handleServerError(e);
|
||||
result = false;
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
if (last-first >= 1)
|
||||
{
|
||||
int id;
|
||||
while (true)
|
||||
{
|
||||
id = addSongNoError(first);
|
||||
if (id >= 0)
|
||||
break;
|
||||
++first;
|
||||
if (first == last)
|
||||
return result;
|
||||
}
|
||||
|
||||
if (position == -1)
|
||||
{
|
||||
++first;
|
||||
for(; first != last; ++first)
|
||||
addSongNoError(first);
|
||||
}
|
||||
else
|
||||
{
|
||||
++position;
|
||||
--last;
|
||||
for (; first != last; --last)
|
||||
addSongNoError(last);
|
||||
}
|
||||
if (play)
|
||||
Mpd.PlayID(id);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool addSongToPlaylist(const MPD::Song &s, bool play, int position)
|
||||
{
|
||||
bool result = false;
|
||||
@@ -81,12 +144,15 @@ std::string Timestamp(time_t t)
|
||||
return result;
|
||||
}
|
||||
|
||||
void markSongsInPlaylist(ProxySongList pl)
|
||||
void markSongsInPlaylist(SongList &list)
|
||||
{
|
||||
size_t list_size = pl.size();
|
||||
for (size_t i = 0; i < list_size; ++i)
|
||||
if (auto s = pl.getSong(i))
|
||||
pl.setBold(i, myPlaylist->checkForSong(*s));
|
||||
MPD::Song *s;
|
||||
for (auto &p : list)
|
||||
{
|
||||
s = p.get<Bit::Song>();
|
||||
if (s != nullptr)
|
||||
p.get<Bit::Properties>().setBold(myPlaylist->checkForSong(*s));
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring Scroller(const std::wstring &str, size_t &pos, size_t width)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "mpdpp.h"
|
||||
#include "screen.h"
|
||||
#include "settings.h"
|
||||
#include "song_list.h"
|
||||
#include "status.h"
|
||||
#include "utility/string.h"
|
||||
#include "utility/type_conversions.h"
|
||||
@@ -93,24 +94,6 @@ inline HasSongs *hasSongs(BaseScreen *screen)
|
||||
return dynamic_cast<HasSongs *>(screen);
|
||||
}
|
||||
|
||||
inline ProxySongList proxySongList(BaseScreen *screen)
|
||||
{
|
||||
auto pl = ProxySongList();
|
||||
auto hs = hasSongs(screen);
|
||||
if (hs)
|
||||
pl = hs->proxySongList();
|
||||
return pl;
|
||||
}
|
||||
|
||||
inline MPD::Song *currentSong(BaseScreen *screen)
|
||||
{
|
||||
MPD::Song *ptr = 0;
|
||||
auto pl = proxySongList(screen);
|
||||
if (pl && !pl.empty())
|
||||
ptr = pl.currentSong();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
bool hasSelected(Iterator first, Iterator last)
|
||||
{
|
||||
@@ -314,12 +297,6 @@ void cropPlaylist(NC::Menu<MPD::Song> &m, F delete_fun)
|
||||
deleteSelectedSongs(m, delete_fun);
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
std::function<void (ItemT)> vectorMoveInserter(std::vector<ItemT> &v)
|
||||
{
|
||||
return [&](ItemT item) { v.push_back(std::move(item)); };
|
||||
}
|
||||
|
||||
template <typename Iterator> std::string getSharedDirectory(Iterator first, Iterator last)
|
||||
{
|
||||
assert(first != last);
|
||||
@@ -384,68 +361,25 @@ template <typename BufferT> void ShowTag(BufferT &buf, const std::string &tag)
|
||||
buf << tag;
|
||||
}
|
||||
|
||||
template <typename SongIterator>
|
||||
bool addSongsToPlaylist(SongIterator first, SongIterator last, bool play, int position)
|
||||
{
|
||||
bool result = true;
|
||||
auto addSongNoError = [&](SongIterator song) -> int {
|
||||
try
|
||||
{
|
||||
return Mpd.AddSong(*song, position);
|
||||
}
|
||||
catch (MPD::ServerError &e)
|
||||
{
|
||||
Status::handleServerError(e);
|
||||
result = false;
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
if (last-first >= 1)
|
||||
{
|
||||
int id;
|
||||
while (true)
|
||||
{
|
||||
id = addSongNoError(first);
|
||||
if (id >= 0)
|
||||
break;
|
||||
++first;
|
||||
if (first == last)
|
||||
return result;
|
||||
}
|
||||
|
||||
if (position == -1)
|
||||
{
|
||||
++first;
|
||||
for(; first != last; ++first)
|
||||
addSongNoError(first);
|
||||
}
|
||||
else
|
||||
{
|
||||
++position;
|
||||
--last;
|
||||
for (; first != last; --last)
|
||||
addSongNoError(last);
|
||||
}
|
||||
if (play)
|
||||
Mpd.PlayID(id);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline const char *withErrors(bool success)
|
||||
{
|
||||
return success ? "" : " " "(with errors)";
|
||||
}
|
||||
|
||||
|
||||
bool addSongsToPlaylist(std::vector<MPD::Song>::const_iterator first,
|
||||
std::vector<MPD::Song>::const_iterator last,
|
||||
bool play, int position);
|
||||
|
||||
bool addSongToPlaylist(const MPD::Song &s, bool play, int position = -1);
|
||||
|
||||
const MPD::Song *currentSong(const BaseScreen *screen);
|
||||
|
||||
std::string timeFormat(const char *format, time_t t);
|
||||
|
||||
std::string Timestamp(time_t t);
|
||||
|
||||
void markSongsInPlaylist(ProxySongList pl);
|
||||
void markSongsInPlaylist(SongList &list);
|
||||
|
||||
std::wstring Scroller(const std::wstring &str, size_t &pos, size_t width);
|
||||
void writeCyclicBuffer(const NC::WBuffer &buf, NC::Window &w, size_t &start_pos,
|
||||
|
||||
47
src/helpers/song_iterator_maker.h
Normal file
47
src/helpers/song_iterator_maker.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008-2014 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 NCMPCPP_HELPERS_SONG_ITERATOR_MAKER_H
|
||||
#define NCMPCPP_HELPERS_SONG_ITERATOR_MAKER_H
|
||||
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <boost/iterator/zip_iterator.hpp>
|
||||
#include "menu.h"
|
||||
#include "song_list.h"
|
||||
|
||||
template <typename ItemT, typename TransformT>
|
||||
SongIterator makeSongIterator_(typename NC::Menu<ItemT>::Iterator it, TransformT &&map)
|
||||
{
|
||||
return SongIterator(boost::make_zip_iterator(boost::make_tuple(
|
||||
typename NC::Menu<ItemT>::PropertiesIterator(it),
|
||||
boost::make_transform_iterator(it, std::forward<TransformT>(map))
|
||||
)));
|
||||
}
|
||||
|
||||
template <typename ItemT, typename TransformT>
|
||||
ConstSongIterator makeConstSongIterator_(typename NC::Menu<ItemT>::ConstIterator it, TransformT &&map)
|
||||
{
|
||||
return ConstSongIterator(boost::make_zip_iterator(boost::make_tuple(
|
||||
typename NC::Menu<ItemT>::ConstPropertiesIterator(it),
|
||||
boost::make_transform_iterator(it, std::forward<TransformT>(map))
|
||||
)));
|
||||
}
|
||||
|
||||
#endif // NCMPCPP_HELPERS_SONG_ITERATOR_MAKER_H
|
||||
@@ -21,12 +21,13 @@
|
||||
#ifndef NCMPCPP_INTERFACES_H
|
||||
#define NCMPCPP_INTERFACES_H
|
||||
|
||||
#include <boost/range/detail/any_iterator.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <string>
|
||||
#include "enums.h"
|
||||
#include "gcc.h"
|
||||
#include "screen.h"
|
||||
#include "song.h"
|
||||
#include "proxy_song_list.h"
|
||||
|
||||
struct Searchable
|
||||
{
|
||||
@@ -38,11 +39,6 @@ struct Searchable
|
||||
|
||||
struct HasSongs
|
||||
{
|
||||
virtual ProxySongList proxySongList() = 0;
|
||||
|
||||
virtual bool allowsSelection() = 0;
|
||||
virtual void reverseSelection() = 0;
|
||||
virtual void selectCurrent() = 0;
|
||||
virtual std::vector<MPD::Song> getSelectedSongs() = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -34,7 +34,9 @@
|
||||
#include "media_library.h"
|
||||
#include "status.h"
|
||||
#include "statusbar.h"
|
||||
#include "helpers/song_iterator_maker.h"
|
||||
#include "utility/comparators.h"
|
||||
#include "utility/functional.h"
|
||||
#include "utility/type_conversions.h"
|
||||
#include "title.h"
|
||||
#include "screen_switcher.h"
|
||||
@@ -202,7 +204,7 @@ MediaLibrary::MediaLibrary()
|
||||
Songs.setSelectedPrefix(Config.selected_item_prefix);
|
||||
Songs.setSelectedSuffix(Config.selected_item_suffix);
|
||||
Songs.setItemDisplayer(std::bind(
|
||||
Display::Songs, ph::_1, songsProxyList(), std::cref(Config.song_library_format)
|
||||
Display::Songs, ph::_1, std::cref(Songs), std::cref(Config.song_library_format)
|
||||
));
|
||||
|
||||
w = &Tags;
|
||||
@@ -257,7 +259,7 @@ void MediaLibrary::refresh()
|
||||
void MediaLibrary::switchTo()
|
||||
{
|
||||
SwitchTo::execute(this);
|
||||
markSongsInPlaylist(songsProxyList());
|
||||
markSongsInPlaylist(Songs);
|
||||
drawHeader();
|
||||
refresh();
|
||||
}
|
||||
@@ -418,14 +420,19 @@ void MediaLibrary::update()
|
||||
size_t idx = 0;
|
||||
for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s, ++idx)
|
||||
{
|
||||
bool is_playlist = myPlaylist->checkForSong(*s);
|
||||
bool in_playlist = myPlaylist->checkForSong(*s);
|
||||
if (idx < Songs.size())
|
||||
{
|
||||
Songs[idx].value() = std::move(*s);
|
||||
Songs[idx].setBold(is_playlist);
|
||||
Songs[idx].setBold(in_playlist);
|
||||
}
|
||||
else
|
||||
Songs.addItem(std::move(*s), is_playlist);
|
||||
{
|
||||
auto properties = NC::List::Properties::Selectable;
|
||||
if (in_playlist)
|
||||
properties |= NC::List::Properties::Bold;
|
||||
Songs.addItem(std::move(*s), properties);
|
||||
}
|
||||
};
|
||||
if (idx < Songs.size())
|
||||
Songs.resizeList(idx);
|
||||
@@ -601,56 +608,6 @@ bool MediaLibrary::find(SearchDirection direction, bool wrap, bool skip_current)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
ProxySongList MediaLibrary::proxySongList()
|
||||
{
|
||||
auto ptr = ProxySongList();
|
||||
if (isActiveWindow(Songs))
|
||||
ptr = songsProxyList();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool MediaLibrary::allowsSelection()
|
||||
{
|
||||
return (isActiveWindow(Tags) && !Tags.empty())
|
||||
|| (isActiveWindow(Albums) && !Albums.empty() && !Albums.current()->value().isAllTracksEntry())
|
||||
|| (isActiveWindow(Songs) && !Songs.empty());
|
||||
}
|
||||
|
||||
void MediaLibrary::selectCurrent()
|
||||
{
|
||||
if (isActiveWindow(Tags))
|
||||
{
|
||||
size_t idx = Tags.choice();
|
||||
Tags[idx].setSelected(!Tags[idx].isSelected());
|
||||
}
|
||||
else if (isActiveWindow(Albums))
|
||||
{
|
||||
size_t idx = Albums.choice();
|
||||
Albums[idx].setSelected(!Albums[idx].isSelected());
|
||||
}
|
||||
else if (isActiveWindow(Songs))
|
||||
{
|
||||
size_t idx = Songs.choice();
|
||||
Songs[idx].setSelected(!Songs[idx].isSelected());
|
||||
}
|
||||
}
|
||||
|
||||
void MediaLibrary::reverseSelection()
|
||||
{
|
||||
if (isActiveWindow(Tags))
|
||||
reverseSelectionHelper(Tags.begin(), Tags.end());
|
||||
else if (isActiveWindow(Albums))
|
||||
{
|
||||
// omit "All tracks"
|
||||
if (Albums.size() > 1)
|
||||
reverseSelectionHelper(Albums.begin(), Albums.end()-2);
|
||||
else
|
||||
reverseSelectionHelper(Albums.begin(), Albums.end());
|
||||
}
|
||||
else if (isActiveWindow(Songs))
|
||||
reverseSelectionHelper(Songs.begin(), Songs.end());
|
||||
}
|
||||
|
||||
std::vector<MPD::Song> MediaLibrary::getSelectedSongs()
|
||||
{
|
||||
std::vector<MPD::Song> result;
|
||||
@@ -717,14 +674,7 @@ std::vector<MPD::Song> MediaLibrary::getSelectedSongs()
|
||||
}
|
||||
}
|
||||
else if (isActiveWindow(Songs))
|
||||
{
|
||||
for (const auto &s : Songs)
|
||||
if (s.isSelected())
|
||||
result.push_back(s.value());
|
||||
// if no item is selected, add current one
|
||||
if (result.empty() && !Songs.empty())
|
||||
result.push_back(Songs.current()->value());
|
||||
}
|
||||
Songs.getSelectedSongs();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -837,13 +787,6 @@ int MediaLibrary::Columns()
|
||||
return 3;
|
||||
}
|
||||
|
||||
ProxySongList MediaLibrary::songsProxyList()
|
||||
{
|
||||
return ProxySongList(Songs, [](NC::Menu<MPD::Song>::Item &item) {
|
||||
return &item.value();
|
||||
});
|
||||
}
|
||||
|
||||
void MediaLibrary::toggleSortMode()
|
||||
{
|
||||
Config.media_library_sort_by_mtime = !Config.media_library_sort_by_mtime;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "interfaces.h"
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
#include "song_list.h"
|
||||
|
||||
struct MediaLibrary: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
@@ -56,11 +57,6 @@ struct MediaLibrary: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tab
|
||||
virtual bool find(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE;
|
||||
|
||||
// HasSongs implementation
|
||||
virtual ProxySongList proxySongList() OVERRIDE;
|
||||
|
||||
virtual bool allowsSelection() OVERRIDE;
|
||||
virtual void selectCurrent() OVERRIDE;
|
||||
virtual void reverseSelection() OVERRIDE;
|
||||
virtual std::vector<MPD::Song> getSelectedSongs() OVERRIDE;
|
||||
|
||||
// HasColumns implementation
|
||||
@@ -75,7 +71,6 @@ struct MediaLibrary: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tab
|
||||
void toggleColumnsMode();
|
||||
int Columns();
|
||||
void LocateSong(const MPD::Song &);
|
||||
ProxySongList songsProxyList();
|
||||
void toggleSortMode();
|
||||
|
||||
void requestTagsUpdate() { m_tags_update_request = true; }
|
||||
@@ -135,7 +130,7 @@ struct MediaLibrary: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tab
|
||||
|
||||
NC::Menu<PrimaryTag> Tags;
|
||||
NC::Menu<AlbumEntry> Albums;
|
||||
NC::Menu<MPD::Song> Songs;
|
||||
SongMenu Songs;
|
||||
|
||||
private:
|
||||
void AddToPlaylist(bool);
|
||||
|
||||
230
src/menu.h
230
src/menu.h
@@ -22,6 +22,8 @@
|
||||
#define NCMPCPP_MENU_H
|
||||
|
||||
#include <boost/iterator/indirect_iterator.hpp>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <boost/range/detail/any_iterator.hpp>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
@@ -33,21 +35,150 @@
|
||||
|
||||
namespace NC {
|
||||
|
||||
struct List
|
||||
{
|
||||
struct Properties
|
||||
{
|
||||
enum Type {
|
||||
None = 0,
|
||||
Bold = (1 << 0),
|
||||
Selectable = (1 << 1),
|
||||
Selected = (1 << 2),
|
||||
Inactive = (1 << 3),
|
||||
Separator = (1 << 4)
|
||||
};
|
||||
|
||||
Properties(Type properties = Selectable)
|
||||
: m_properties(properties)
|
||||
{ }
|
||||
|
||||
void setBold(bool is_bold)
|
||||
{
|
||||
if (is_bold)
|
||||
m_properties |= Bold;
|
||||
else
|
||||
m_properties &= ~Bold;
|
||||
}
|
||||
void setSelectable(bool is_selectable)
|
||||
{
|
||||
if (is_selectable)
|
||||
m_properties |= Selectable;
|
||||
else
|
||||
m_properties &= ~(Selectable | Selected);
|
||||
}
|
||||
void setSelected(bool is_selected)
|
||||
{
|
||||
if (!isSelectable())
|
||||
return;
|
||||
if (is_selected)
|
||||
m_properties |= Selected;
|
||||
else
|
||||
m_properties &= ~Selected;
|
||||
}
|
||||
void setInactive(bool is_inactive)
|
||||
{
|
||||
if (is_inactive)
|
||||
m_properties |= Inactive;
|
||||
else
|
||||
m_properties &= ~Inactive;
|
||||
}
|
||||
void setSeparator(bool is_separator)
|
||||
{
|
||||
if (is_separator)
|
||||
m_properties |= Separator;
|
||||
else
|
||||
m_properties &= ~Separator;
|
||||
}
|
||||
|
||||
bool isBold() const { return m_properties & Bold; }
|
||||
bool isSelectable() const { return m_properties & Selectable; }
|
||||
bool isSelected() const { return m_properties & Selected; }
|
||||
bool isInactive() const { return m_properties & Inactive; }
|
||||
bool isSeparator() const { return m_properties & Separator; }
|
||||
|
||||
private:
|
||||
unsigned m_properties;
|
||||
};
|
||||
|
||||
template <typename ValueT>
|
||||
using PropertiesIterator = boost::range_detail::any_iterator<
|
||||
ValueT,
|
||||
boost::random_access_traversal_tag,
|
||||
ValueT &,
|
||||
std::ptrdiff_t
|
||||
>;
|
||||
|
||||
typedef PropertiesIterator<Properties> Iterator;
|
||||
typedef PropertiesIterator<const Properties> ConstIterator;
|
||||
|
||||
virtual ~List() { }
|
||||
|
||||
virtual bool empty() const = 0;
|
||||
virtual size_t size() const = 0;
|
||||
virtual size_t choice() const = 0;
|
||||
virtual void highlight(size_t pos) = 0;
|
||||
|
||||
virtual Iterator currentP() = 0;
|
||||
virtual ConstIterator currentP() const = 0;
|
||||
virtual Iterator beginP() = 0;
|
||||
virtual ConstIterator beginP() const = 0;
|
||||
virtual Iterator endP() = 0;
|
||||
virtual ConstIterator endP() const = 0;
|
||||
};
|
||||
|
||||
inline List::Properties::Type operator|(List::Properties::Type lhs, List::Properties::Type rhs)
|
||||
{
|
||||
return List::Properties::Type(unsigned(lhs) | unsigned(rhs));
|
||||
}
|
||||
inline List::Properties::Type &operator|=(List::Properties::Type &lhs, List::Properties::Type rhs)
|
||||
{
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
inline List::Properties::Type operator&(List::Properties::Type lhs, List::Properties::Type rhs)
|
||||
{
|
||||
return List::Properties::Type(unsigned(lhs) & unsigned(rhs));
|
||||
}
|
||||
inline List::Properties::Type &operator&=(List::Properties::Type &lhs, List::Properties::Type rhs)
|
||||
{
|
||||
lhs = lhs & rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
// for range-based for loop
|
||||
inline List::Iterator begin(List &list) { return list.beginP(); }
|
||||
inline List::ConstIterator begin(const List &list) { return list.beginP(); }
|
||||
inline List::Iterator end(List &list) { return list.endP(); }
|
||||
inline List::ConstIterator end(const List &list) { return list.endP(); }
|
||||
|
||||
/// This template class is generic menu capable of
|
||||
/// holding any std::vector compatible values.
|
||||
template <typename ItemT> class Menu : public Window
|
||||
template <typename ItemT> struct Menu : Window, List
|
||||
{
|
||||
public:
|
||||
struct Item
|
||||
struct Item : List::Properties
|
||||
{
|
||||
template <bool Const>
|
||||
struct PropertiesExtractor
|
||||
{
|
||||
typedef PropertiesExtractor type;
|
||||
|
||||
typedef typename std::conditional<Const, const Properties, Properties>::type Properties_;
|
||||
typedef typename std::conditional<Const, const Item, Item>::type Item_;
|
||||
|
||||
Properties_ &operator()(Item_ &i) const {
|
||||
return static_cast<Properties_ &>(i);
|
||||
}
|
||||
};
|
||||
|
||||
typedef ItemT Type;
|
||||
|
||||
friend class Menu<ItemT>;
|
||||
friend struct Menu<ItemT>;
|
||||
|
||||
Item()
|
||||
: m_is_bold(false), m_is_selected(false), m_is_inactive(false), m_is_separator(false) { }
|
||||
Item(ItemT value_, bool is_bold, bool is_inactive)
|
||||
: m_value(value_), m_is_bold(is_bold), m_is_selected(false), m_is_inactive(is_inactive), m_is_separator(false) { }
|
||||
Item() { }
|
||||
Item(ItemT value_, Properties::Type properties)
|
||||
: Properties(properties)
|
||||
, m_value(value_)
|
||||
{ }
|
||||
|
||||
ItemT &value() { return m_value; }
|
||||
const ItemT &value() const { return m_value; }
|
||||
@@ -55,29 +186,16 @@ public:
|
||||
ItemT &operator*() { return m_value; }
|
||||
const ItemT &operator*() const { return m_value; }
|
||||
|
||||
void setBold(bool is_bold) { m_is_bold = is_bold; }
|
||||
void setSelected(bool is_selected) { m_is_selected = is_selected; }
|
||||
void setInactive(bool is_inactive) { m_is_inactive = is_inactive; }
|
||||
void setSeparator(bool is_separator) { m_is_separator = is_separator; }
|
||||
|
||||
bool isBold() const { return m_is_bold; }
|
||||
bool isSelected() const { return m_is_selected; }
|
||||
bool isInactive() const { return m_is_inactive; }
|
||||
bool isSeparator() const { return m_is_separator; }
|
||||
|
||||
private:
|
||||
static Item mkSeparator()
|
||||
{
|
||||
Item item;
|
||||
item.m_is_separator = true;
|
||||
item.setSelectable(false);
|
||||
item.setSeparator(true);
|
||||
return item;
|
||||
}
|
||||
|
||||
ItemT m_value;
|
||||
bool m_is_bold;
|
||||
bool m_is_selected;
|
||||
bool m_is_inactive;
|
||||
bool m_is_separator;
|
||||
};
|
||||
|
||||
typedef typename std::vector<Item>::iterator Iterator;
|
||||
@@ -98,6 +216,15 @@ public:
|
||||
typedef std::reverse_iterator<ValueIterator> ReverseValueIterator;
|
||||
typedef std::reverse_iterator<ConstValueIterator> ConstReverseValueIterator;
|
||||
|
||||
typedef boost::transform_iterator<
|
||||
typename Item::template PropertiesExtractor<false>,
|
||||
Iterator
|
||||
> PropertiesIterator;
|
||||
typedef boost::transform_iterator<
|
||||
typename Item::template PropertiesExtractor<true>,
|
||||
ConstIterator
|
||||
> ConstPropertiesIterator;
|
||||
|
||||
/// Function helper prototype used to display each option on the screen.
|
||||
/// If not set by setItemDisplayer(), menu won't display anything.
|
||||
/// @see setItemDisplayer()
|
||||
@@ -120,21 +247,14 @@ public:
|
||||
/// @param size requested size
|
||||
void resizeList(size_t new_size);
|
||||
|
||||
/// Adds new option to list
|
||||
/// @param item object that has to be added
|
||||
/// @param is_bold defines the initial state of bold attribute
|
||||
/// @param is_inactive defines the initial state of static attribute
|
||||
void addItem(ItemT item, bool is_bold = false, bool is_inactive = false);
|
||||
/// Adds a new option to list
|
||||
void addItem(ItemT item, Properties::Type properties = Properties::Selectable);
|
||||
|
||||
/// Adds separator to list
|
||||
void addSeparator();
|
||||
|
||||
/// Inserts new option to list at given position
|
||||
/// @param pos initial position of inserted item
|
||||
/// @param item object that has to be inserted
|
||||
/// @param is_bold defines the initial state of bold attribute
|
||||
/// @param is_inactive defines the initial state of static attribute
|
||||
void insertItem(size_t pos, const ItemT &Item, bool is_bold = false, bool is_inactive = false);
|
||||
/// Inserts a new option to the list at given position
|
||||
void insertItem(size_t pos, ItemT item, Properties::Type properties = Properties::Selectable);
|
||||
|
||||
/// Inserts separator to list at given position
|
||||
/// @param pos initial position of inserted separator
|
||||
@@ -149,12 +269,19 @@ public:
|
||||
/// @return true if the position is reachable, false otherwise
|
||||
bool Goto(size_t y);
|
||||
|
||||
/// Checks if list is empty
|
||||
/// @return true if list is empty, false otherwise
|
||||
virtual bool empty() const OVERRIDE { return m_items.empty(); }
|
||||
|
||||
/// @return size of the list
|
||||
virtual size_t size() const OVERRIDE { return m_items.size(); }
|
||||
|
||||
/// @return currently highlighted position
|
||||
virtual size_t choice() const OVERRIDE;
|
||||
|
||||
/// Highlights given position
|
||||
/// @param pos position to be highlighted
|
||||
void highlight(size_t pos);
|
||||
|
||||
/// @return currently highlighted position
|
||||
size_t choice() const;
|
||||
virtual void highlight(size_t position) OVERRIDE;
|
||||
|
||||
/// Refreshes the menu window
|
||||
/// @see Window::refresh()
|
||||
@@ -201,13 +328,6 @@ public:
|
||||
/// @param state state of centered cursor
|
||||
void centeredCursor(bool state) { m_autocenter_cursor = state; }
|
||||
|
||||
/// Checks if list is empty
|
||||
/// @return true if list is empty, false otherwise
|
||||
bool empty() const { return m_items.empty(); }
|
||||
|
||||
/// @return size of the list
|
||||
size_t size() const { return m_items.size(); }
|
||||
|
||||
/// @return currently drawn item. The result is defined only within
|
||||
/// drawing function that is called by refresh()
|
||||
/// @see refresh()
|
||||
@@ -261,8 +381,26 @@ public:
|
||||
ReverseValueIterator rendV() { return ReverseValueIterator(beginV()); }
|
||||
ConstReverseValueIterator rendV() const { return ConstReverseValueIterator(beginV()); }
|
||||
|
||||
private:
|
||||
virtual List::Iterator currentP() OVERRIDE {
|
||||
return List::Iterator(PropertiesIterator(m_items.begin() + m_highlight));
|
||||
}
|
||||
virtual List::ConstIterator currentP() const OVERRIDE {
|
||||
return List::ConstIterator(ConstPropertiesIterator(m_items.begin() + m_highlight));
|
||||
}
|
||||
virtual List::Iterator beginP() OVERRIDE {
|
||||
return List::Iterator(PropertiesIterator(m_items.begin()));
|
||||
}
|
||||
virtual List::ConstIterator beginP() const OVERRIDE {
|
||||
return List::ConstIterator(ConstPropertiesIterator(m_items.begin()));
|
||||
}
|
||||
virtual List::Iterator endP() OVERRIDE {
|
||||
return List::Iterator(PropertiesIterator(m_items.end()));
|
||||
}
|
||||
virtual List::ConstIterator endP() const OVERRIDE {
|
||||
return List::ConstIterator(ConstPropertiesIterator(m_items.end()));
|
||||
}
|
||||
|
||||
private:
|
||||
bool isHighlightable(size_t pos)
|
||||
{
|
||||
return !m_items[pos].isSeparator()
|
||||
|
||||
@@ -114,9 +114,9 @@ void Menu<ItemT>::resizeList(size_t new_size)
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::addItem(ItemT item, bool is_bold, bool is_inactive)
|
||||
void Menu<ItemT>::addItem(ItemT item, Properties::Type properties)
|
||||
{
|
||||
m_items.push_back(Item(std::move(item), is_bold, is_inactive));
|
||||
m_items.push_back(Item(std::move(item), properties));
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
@@ -126,9 +126,9 @@ void Menu<ItemT>::addSeparator()
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::insertItem(size_t pos, const ItemT &item, bool is_bold, bool is_inactive)
|
||||
void Menu<ItemT>::insertItem(size_t pos, ItemT item, Properties::Type properties)
|
||||
{
|
||||
m_items.insert(m_items.begin()+pos, Item(item, is_bold, is_inactive));
|
||||
m_items.insert(m_items.begin()+pos, Item(std::move(item), properties));
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
@@ -181,9 +181,9 @@ void Menu<ItemT>::refresh()
|
||||
}
|
||||
|
||||
size_t line = 0;
|
||||
const size_t end = m_beginning+m_height;
|
||||
const size_t end_ = m_beginning+m_height;
|
||||
m_drawn_position = m_beginning;
|
||||
for (; m_drawn_position < end; ++m_drawn_position, ++line)
|
||||
for (; m_drawn_position < end_; ++m_drawn_position, ++line)
|
||||
{
|
||||
goToXY(0, line);
|
||||
if (m_drawn_position >= m_items.size())
|
||||
|
||||
@@ -102,8 +102,10 @@ void Outputs::FetchList()
|
||||
w.clear();
|
||||
for (MPD::OutputIterator out = Mpd.GetOutputs(), end; out != end; ++out)
|
||||
{
|
||||
bool enabled = out->enabled();
|
||||
w.addItem(std::move(*out), enabled);
|
||||
auto properties = NC::List::Properties::Selectable;
|
||||
if (out->enabled())
|
||||
properties |= NC::List::Properties::Bold;
|
||||
w.addItem(std::move(*out), properties);
|
||||
}
|
||||
if (myScreen == this)
|
||||
w.refresh();
|
||||
|
||||
@@ -31,7 +31,9 @@
|
||||
#include "song.h"
|
||||
#include "status.h"
|
||||
#include "statusbar.h"
|
||||
#include "helpers/song_iterator_maker.h"
|
||||
#include "utility/comparators.h"
|
||||
#include "utility/functional.h"
|
||||
#include "title.h"
|
||||
|
||||
using Global::MainHeight;
|
||||
@@ -63,12 +65,12 @@ Playlist::Playlist()
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
w.setItemDisplayer(std::bind(
|
||||
Display::Songs, ph::_1, proxySongList(), std::cref(Config.song_list_format)
|
||||
Display::Songs, ph::_1, std::cref(w), std::cref(Config.song_list_format)
|
||||
));
|
||||
break;
|
||||
case DisplayMode::Columns:
|
||||
w.setItemDisplayer(std::bind(
|
||||
Display::SongsInColumns, ph::_1, proxySongList()
|
||||
Display::SongsInColumns, ph::_1, std::cref(w)
|
||||
));
|
||||
break;
|
||||
}
|
||||
@@ -176,37 +178,9 @@ bool Playlist::find(SearchDirection direction, bool wrap, bool skip_current)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
ProxySongList Playlist::proxySongList()
|
||||
{
|
||||
return ProxySongList(w, [](NC::Menu<MPD::Song>::Item &item) {
|
||||
return &item.value();
|
||||
});
|
||||
}
|
||||
|
||||
bool Playlist::allowsSelection()
|
||||
{
|
||||
return !w.empty();
|
||||
}
|
||||
|
||||
void Playlist::selectCurrent()
|
||||
{
|
||||
w.current()->setSelected(!w.current()->isSelected());
|
||||
}
|
||||
|
||||
void Playlist::reverseSelection()
|
||||
{
|
||||
reverseSelectionHelper(w.begin(), w.end());
|
||||
}
|
||||
|
||||
std::vector<MPD::Song> Playlist::getSelectedSongs()
|
||||
{
|
||||
std::vector<MPD::Song> result;
|
||||
for (auto it = w.begin(); it != w.end(); ++it)
|
||||
if (it->isSelected())
|
||||
result.push_back(it->value());
|
||||
if (result.empty() && !w.empty())
|
||||
result.push_back(w.current()->value());
|
||||
return result;
|
||||
return w.getSelectedSongs();
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
@@ -28,12 +28,13 @@
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
#include "song.h"
|
||||
#include "song_list.h"
|
||||
|
||||
struct Playlist: Screen<NC::Menu<MPD::Song>>, HasSongs, Searchable, Tabbable
|
||||
struct Playlist: Screen<SongMenu>, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
Playlist();
|
||||
|
||||
// Screen<NC::Menu<MPD::Song>> implementation
|
||||
// Screen<SongMenu> implementation
|
||||
virtual void switchTo() OVERRIDE;
|
||||
virtual void resize() OVERRIDE;
|
||||
|
||||
@@ -56,11 +57,6 @@ struct Playlist: Screen<NC::Menu<MPD::Song>>, HasSongs, Searchable, Tabbable
|
||||
virtual bool find(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE;
|
||||
|
||||
// HasSongs implementation
|
||||
virtual ProxySongList proxySongList() OVERRIDE;
|
||||
|
||||
virtual bool allowsSelection() OVERRIDE;
|
||||
virtual void selectCurrent() OVERRIDE;
|
||||
virtual void reverseSelection() OVERRIDE;
|
||||
virtual std::vector<MPD::Song> getSelectedSongs() OVERRIDE;
|
||||
|
||||
// private members
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#include "status.h"
|
||||
#include "statusbar.h"
|
||||
#include "tag_editor.h"
|
||||
#include "helpers/song_iterator_maker.h"
|
||||
#include "utility/functional.h"
|
||||
#include "utility/comparators.h"
|
||||
#include "title.h"
|
||||
#include "screen_switcher.h"
|
||||
@@ -86,14 +88,14 @@ PlaylistEditor::PlaylistEditor()
|
||||
switch (Config.playlist_editor_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
Content.setItemDisplayer(
|
||||
std::bind(Display::Songs, ph::_1, contentProxyList(), std::cref(Config.song_list_format)
|
||||
Content.setItemDisplayer(std::bind(
|
||||
Display::Songs, ph::_1, std::cref(Content), std::cref(Config.song_list_format)
|
||||
));
|
||||
break;
|
||||
case DisplayMode::Columns:
|
||||
Content.setItemDisplayer(
|
||||
std::bind(Display::SongsInColumns, ph::_1, contentProxyList())
|
||||
);
|
||||
Content.setItemDisplayer(std::bind(
|
||||
Display::SongsInColumns, ph::_1, std::cref(Content)
|
||||
));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -134,7 +136,7 @@ void PlaylistEditor::refresh()
|
||||
void PlaylistEditor::switchTo()
|
||||
{
|
||||
SwitchTo::execute(this);
|
||||
markSongsInPlaylist(contentProxyList());
|
||||
markSongsInPlaylist(Content);
|
||||
drawHeader();
|
||||
refresh();
|
||||
}
|
||||
@@ -171,14 +173,19 @@ void PlaylistEditor::update()
|
||||
MPD::SongIterator s = Mpd.GetPlaylistContent(Playlists.current()->value().path()), end;
|
||||
for (; s != end; ++s, ++idx)
|
||||
{
|
||||
bool is_bold = myPlaylist->checkForSong(*s);
|
||||
bool in_playlist = myPlaylist->checkForSong(*s);
|
||||
if (idx < Content.size())
|
||||
{
|
||||
Content[idx].setBold(is_bold);
|
||||
Content[idx].setBold(in_playlist);
|
||||
Content[idx].value() = std::move(*s);
|
||||
}
|
||||
else
|
||||
Content.addItem(std::move(*s), is_bold);
|
||||
{
|
||||
auto properties = NC::List::Properties::Selectable;
|
||||
if (in_playlist)
|
||||
properties |= NC::List::Properties::Bold;
|
||||
Content.addItem(std::move(*s), properties);
|
||||
}
|
||||
}
|
||||
if (idx < Content.size())
|
||||
Content.resizeList(idx);
|
||||
@@ -218,13 +225,6 @@ int PlaylistEditor::windowTimeout()
|
||||
return Screen<WindowType>::windowTimeout();
|
||||
}
|
||||
|
||||
ProxySongList PlaylistEditor::contentProxyList()
|
||||
{
|
||||
return ProxySongList(Content, [](NC::Menu<MPD::Song>::Item &item) {
|
||||
return &item.value();
|
||||
});
|
||||
}
|
||||
|
||||
void PlaylistEditor::AddToPlaylist(bool add_n_play)
|
||||
{
|
||||
if (isActiveWindow(Playlists) && !Playlists.empty())
|
||||
@@ -353,36 +353,6 @@ bool PlaylistEditor::find(SearchDirection direction, bool wrap, bool skip_curren
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
ProxySongList PlaylistEditor::proxySongList()
|
||||
{
|
||||
auto ptr = ProxySongList();
|
||||
if (isActiveWindow(Content))
|
||||
ptr = contentProxyList();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool PlaylistEditor::allowsSelection()
|
||||
{
|
||||
return (isActiveWindow(Playlists) && !Playlists.empty())
|
||||
|| (isActiveWindow(Content) && !Content.empty());
|
||||
}
|
||||
|
||||
void PlaylistEditor::selectCurrent()
|
||||
{
|
||||
if (isActiveWindow(Playlists))
|
||||
Playlists.current()->setSelected(!Playlists.current()->isSelected());
|
||||
else if (isActiveWindow(Content))
|
||||
Content.current()->setSelected(!Content.current()->isSelected());
|
||||
}
|
||||
|
||||
void PlaylistEditor::reverseSelection()
|
||||
{
|
||||
if (isActiveWindow(Playlists))
|
||||
reverseSelectionHelper(Playlists.begin(), Playlists.end());
|
||||
else if (isActiveWindow(Content))
|
||||
reverseSelectionHelper(Content.begin(), Content.end());
|
||||
}
|
||||
|
||||
std::vector<MPD::Song> PlaylistEditor::getSelectedSongs()
|
||||
{
|
||||
std::vector<MPD::Song> result;
|
||||
@@ -412,14 +382,7 @@ std::vector<MPD::Song> PlaylistEditor::getSelectedSongs()
|
||||
}
|
||||
}
|
||||
else if (isActiveWindow(Content))
|
||||
{
|
||||
for (auto &e : Content)
|
||||
if (e.isSelected())
|
||||
result.push_back(e.value());
|
||||
// if no item is selected, add current one
|
||||
if (result.empty() && !Content.empty())
|
||||
result.push_back(Content.current()->value());
|
||||
}
|
||||
result = Content.getSelectedSongs();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "interfaces.h"
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
#include "song_list.h"
|
||||
|
||||
struct PlaylistEditor: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
@@ -56,11 +57,6 @@ struct PlaylistEditor: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, T
|
||||
virtual bool find(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE;
|
||||
|
||||
// HasSongs implementation
|
||||
virtual ProxySongList proxySongList() OVERRIDE;
|
||||
|
||||
virtual bool allowsSelection() OVERRIDE;
|
||||
virtual void selectCurrent() OVERRIDE;
|
||||
virtual void reverseSelection() OVERRIDE;
|
||||
virtual std::vector<MPD::Song> getSelectedSongs() OVERRIDE;
|
||||
|
||||
// HasColumns implementation
|
||||
@@ -77,10 +73,9 @@ struct PlaylistEditor: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, T
|
||||
void requestContentsUpdate() { m_content_update_requested = true; }
|
||||
|
||||
virtual void Locate(const MPD::Playlist &playlist);
|
||||
ProxySongList contentProxyList();
|
||||
|
||||
NC::Menu<MPD::Playlist> Playlists;
|
||||
NC::Menu<MPD::Song> Content;
|
||||
SongMenu Content;
|
||||
|
||||
private:
|
||||
void AddToPlaylist(bool);
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008-2014 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 NCMPCPP_PROXY_SONG_LIST_H
|
||||
#define NCMPCPP_PROXY_SONG_LIST_H
|
||||
|
||||
#include "menu.h"
|
||||
#include "song.h"
|
||||
|
||||
/// This fancy class provides a way to use NC::Menu<T> template instantiations
|
||||
/// with different Ts in a uniform manner. Note that since it provides methods
|
||||
/// such as getSong or currentSong, it's biased towards menus that somehow
|
||||
/// contain songs.
|
||||
///
|
||||
/// Dependent types are T and F. T is type of items stored inside Menu, whereas
|
||||
/// F is a function that takes Menu<T>::Item and converts it into MPD::Song pointer.
|
||||
/// For Menu<MPD::Song> this is just taking address of given MPD::Song, but e.g.
|
||||
/// Menu<MPD::Item> returns not null pointer only if requested position actually
|
||||
/// contains a song and not directory or playlist.
|
||||
class ProxySongList
|
||||
{
|
||||
struct Interface
|
||||
{
|
||||
virtual ~Interface() { }
|
||||
|
||||
virtual bool empty() = 0;
|
||||
virtual size_t size() = 0;
|
||||
virtual size_t choice() = 0;
|
||||
virtual void highlight(size_t pos) = 0;
|
||||
|
||||
virtual bool isSelected(size_t pos) = 0;
|
||||
virtual void setSelected(size_t pos, bool selected) = 0;
|
||||
|
||||
virtual bool isBold(size_t pos) = 0;
|
||||
virtual void setBold(size_t pos, bool bold) = 0;
|
||||
|
||||
virtual MPD::Song *getSong(size_t pos) = 0;
|
||||
virtual MPD::Song *currentSong() = 0;
|
||||
};
|
||||
|
||||
template <typename T, typename F> struct Impl : Interface
|
||||
{
|
||||
typedef typename NC::Menu<T> Menu;
|
||||
|
||||
Impl(Menu &menu, F f) : m_menu(menu), m_song_getter(f) { }
|
||||
virtual ~Impl() { }
|
||||
|
||||
virtual bool empty() { return m_menu.empty(); }
|
||||
virtual size_t size() { return m_menu.size(); }
|
||||
virtual size_t choice() { return m_menu.choice(); }
|
||||
virtual void highlight(size_t pos) { m_menu.highlight(pos); }
|
||||
|
||||
virtual bool isSelected(size_t pos) {
|
||||
assert(pos < m_menu.size());
|
||||
return m_menu[pos].isSelected();
|
||||
}
|
||||
virtual void setSelected(size_t pos, bool selected) {
|
||||
assert(pos < m_menu.size());
|
||||
m_menu[pos].setSelected(selected);
|
||||
}
|
||||
|
||||
virtual bool isBold(size_t pos) {
|
||||
assert(pos < m_menu.size());
|
||||
return m_menu[pos].isBold();
|
||||
}
|
||||
virtual void setBold(size_t pos, bool bold) {
|
||||
assert(pos < m_menu.size());
|
||||
m_menu[pos].setBold(bold);
|
||||
}
|
||||
|
||||
virtual MPD::Song *getSong(size_t pos) {
|
||||
assert(pos < m_menu.size());
|
||||
return m_song_getter(m_menu[pos]);
|
||||
}
|
||||
virtual MPD::Song *currentSong() {
|
||||
if (!m_menu.empty())
|
||||
return getSong(m_menu.choice());
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
Menu &m_menu;
|
||||
F m_song_getter;
|
||||
};
|
||||
|
||||
std::shared_ptr<Interface> m_impl;
|
||||
|
||||
public:
|
||||
ProxySongList() { }
|
||||
|
||||
template <typename T, typename F>
|
||||
ProxySongList(typename NC::Menu<T> &menu, F f) : m_impl(new Impl<T, F>(menu, f)) { }
|
||||
|
||||
bool empty() const { return m_impl->empty(); }
|
||||
size_t size() const { return m_impl->size(); }
|
||||
size_t choice() const { return m_impl->choice(); }
|
||||
void highlight(size_t pos) const { m_impl->highlight(pos); }
|
||||
|
||||
bool isSelected(size_t pos) const { return m_impl->isSelected(pos); }
|
||||
void setSelected(size_t pos, bool selected) const { m_impl->setSelected(pos, selected); }
|
||||
|
||||
bool isBold(size_t pos) const { return m_impl->isBold(pos); }
|
||||
void setBold(size_t pos, bool bold) const{ m_impl->setBold(pos, bold); }
|
||||
|
||||
MPD::Song *getSong(size_t pos) const { return m_impl->getSong(pos); }
|
||||
MPD::Song *currentSong() const { return m_impl->currentSong(); }
|
||||
|
||||
/// @return true if there is no underlying menu object, false otherwise
|
||||
operator bool() const { return m_impl.get() != 0; }
|
||||
};
|
||||
|
||||
#endif // NCMPCPP_PROXY_SONG_LIST_H
|
||||
33
src/screen.h
33
src/screen.h
@@ -38,10 +38,11 @@ struct BaseScreen
|
||||
virtual ~BaseScreen() { }
|
||||
|
||||
/// @see Screen::isActiveWindow()
|
||||
virtual bool isActiveWindow(const NC::Window &w_) = 0;
|
||||
virtual bool isActiveWindow(const NC::Window &w_) const = 0;
|
||||
|
||||
/// @see Screen::activeWindow()
|
||||
virtual void *activeWindow() = 0;
|
||||
virtual NC::Window *activeWindow() = 0;
|
||||
virtual const NC::Window *activeWindow() const = 0;
|
||||
|
||||
/// @see Screen::refresh()
|
||||
virtual void refresh() = 0;
|
||||
@@ -123,19 +124,26 @@ template <typename WindowT> struct Screen : public BaseScreen
|
||||
{
|
||||
typedef WindowT WindowType;
|
||||
typedef typename std::add_lvalue_reference<WindowType>::type WindowReference;
|
||||
typedef typename std::add_lvalue_reference<
|
||||
typename std::add_const<WindowType>::type
|
||||
>::type ConstWindowReference;
|
||||
|
||||
private:
|
||||
template <bool IsPointer, typename Result> struct getObject { };
|
||||
template <typename Result> struct getObject<true, Result> {
|
||||
static Result apply(WindowType w) { return *w; }
|
||||
template <bool IsPointer, typename Result, typename ConstResult>
|
||||
struct getObject {
|
||||
static Result &apply(WindowReference w) { return w; }
|
||||
static ConstResult &constApply(ConstWindowReference w) { return w; }
|
||||
};
|
||||
template <typename Result> struct getObject<false, Result> {
|
||||
static Result apply(WindowReference w) { return w; }
|
||||
template <typename Result, typename ConstResult>
|
||||
struct getObject<true, Result, ConstResult> {
|
||||
static Result &apply(WindowType w) { return *w; }
|
||||
static ConstResult &constApply(const WindowType w) { return *w; }
|
||||
};
|
||||
|
||||
typedef getObject<
|
||||
std::is_pointer<WindowT>::value,
|
||||
typename std::add_lvalue_reference<
|
||||
typename std::remove_pointer<WindowT>::type,
|
||||
typename std::add_const<
|
||||
typename std::remove_pointer<WindowT>::type
|
||||
>::type
|
||||
> Accessor;
|
||||
@@ -146,17 +154,20 @@ public:
|
||||
|
||||
virtual ~Screen() { }
|
||||
|
||||
virtual bool isActiveWindow(const NC::Window &w_) OVERRIDE {
|
||||
return &Accessor::apply(w) == &w_;
|
||||
virtual bool isActiveWindow(const NC::Window &w_) const OVERRIDE {
|
||||
return &Accessor::constApply(w) == &w_;
|
||||
}
|
||||
|
||||
/// Since some screens contain more that one window
|
||||
/// it's useful to determine the one that is being
|
||||
/// active
|
||||
/// @return address to window object cast to void *
|
||||
virtual void *activeWindow() OVERRIDE {
|
||||
virtual NC::Window *activeWindow() OVERRIDE {
|
||||
return &Accessor::apply(w);
|
||||
}
|
||||
virtual const NC::Window *activeWindow() const OVERRIDE {
|
||||
return &Accessor::constApply(w);
|
||||
}
|
||||
|
||||
/// Refreshes whole screen
|
||||
virtual void refresh() OVERRIDE {
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "settings.h"
|
||||
#include "status.h"
|
||||
#include "statusbar.h"
|
||||
#include "helpers/song_iterator_maker.h"
|
||||
#include "utility/comparators.h"
|
||||
#include "title.h"
|
||||
#include "screen_switcher.h"
|
||||
@@ -74,8 +75,63 @@ namespace pos {
|
||||
std::string SEItemToString(const SEItem &ei);
|
||||
bool SEItemEntryMatcher(const Regex::Regex &rx, const NC::Menu<SEItem>::Item &item, bool filter);
|
||||
|
||||
template <bool Const>
|
||||
struct SongExtractor
|
||||
{
|
||||
typedef SongExtractor type;
|
||||
|
||||
typedef typename NC::Menu<SEItem>::Item MenuItem;
|
||||
typedef typename std::conditional<Const, const MenuItem, MenuItem>::type Item;
|
||||
typedef typename std::conditional<Const, const MPD::Song, MPD::Song>::type Song;
|
||||
|
||||
Song *operator()(Item &item) const
|
||||
{
|
||||
Song *ptr = nullptr;
|
||||
if (!item.isSeparator() && item.value().isSong())
|
||||
ptr = &item.value().song();
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
SongIterator SearchEngineWindow::currentS()
|
||||
{
|
||||
return makeSongIterator_<SEItem>(current(), SongExtractor<false>());
|
||||
}
|
||||
|
||||
ConstSongIterator SearchEngineWindow::currentS() const
|
||||
{
|
||||
return makeConstSongIterator_<SEItem>(current(), SongExtractor<true>());
|
||||
}
|
||||
|
||||
SongIterator SearchEngineWindow::beginS()
|
||||
{
|
||||
return makeSongIterator_<SEItem>(begin(), SongExtractor<false>());
|
||||
}
|
||||
|
||||
ConstSongIterator SearchEngineWindow::beginS() const
|
||||
{
|
||||
return makeConstSongIterator_<SEItem>(begin(), SongExtractor<true>());
|
||||
}
|
||||
|
||||
SongIterator SearchEngineWindow::endS()
|
||||
{
|
||||
return makeSongIterator_<SEItem>(end(), SongExtractor<false>());
|
||||
}
|
||||
|
||||
ConstSongIterator SearchEngineWindow::endS() const
|
||||
{
|
||||
return makeConstSongIterator_<SEItem>(end(), SongExtractor<true>());
|
||||
}
|
||||
|
||||
std::vector<MPD::Song> SearchEngineWindow::getSelectedSongs()
|
||||
{
|
||||
return {}; // TODO
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
const char *SearchEngine::ConstraintsNames[] =
|
||||
{
|
||||
"Any",
|
||||
@@ -109,7 +165,7 @@ SearchEngine::SearchEngine()
|
||||
w.setHighlightColor(Config.main_highlight_color);
|
||||
w.cyclicScrolling(Config.use_cyclic_scrolling);
|
||||
w.centeredCursor(Config.centered_cursor);
|
||||
w.setItemDisplayer(std::bind(Display::SEItems, ph::_1, proxySongList()));
|
||||
w.setItemDisplayer(std::bind(Display::SEItems, ph::_1, std::cref(w)));
|
||||
w.setSelectedPrefix(Config.selected_item_prefix);
|
||||
w.setSelectedSuffix(Config.selected_item_suffix);
|
||||
SearchMode = &SearchModes[Config.search_engine_default_search_mode];
|
||||
@@ -140,7 +196,7 @@ void SearchEngine::switchTo()
|
||||
SwitchTo::execute(this);
|
||||
if (w.empty())
|
||||
Prepare();
|
||||
markSongsInPlaylist(proxySongList());
|
||||
markSongsInPlaylist(w);
|
||||
drawHeader();
|
||||
}
|
||||
|
||||
@@ -190,10 +246,10 @@ void SearchEngine::enterPressed()
|
||||
size_t found = w.size()-SearchEngine::StaticOptions;
|
||||
found += 3; // don't count options inserted below
|
||||
w.insertSeparator(ResetButton+1);
|
||||
w.insertItem(ResetButton+2, SEItem(), 1, 1);
|
||||
w.insertItem(ResetButton+2, SEItem(), NC::List::Properties::Bold | NC::List::Properties::Inactive);
|
||||
w.at(ResetButton+2).value().mkBuffer() << Config.color1 << "Search results: " << Config.color2 << "Found " << found << (found > 1 ? " songs" : " song") << NC::Color::Default;
|
||||
w.insertSeparator(ResetButton+3);
|
||||
markSongsInPlaylist(proxySongList());
|
||||
markSongsInPlaylist(w);
|
||||
Statusbar::print("Searching finished");
|
||||
if (Config.block_search_constraints_change)
|
||||
for (size_t i = 0; i < StaticOptions-4; ++i)
|
||||
@@ -276,31 +332,6 @@ bool SearchEngine::find(SearchDirection direction, bool wrap, bool skip_current)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
ProxySongList SearchEngine::proxySongList()
|
||||
{
|
||||
return ProxySongList(w, [](NC::Menu<SEItem>::Item &item) -> MPD::Song * {
|
||||
MPD::Song *ptr = 0;
|
||||
if (!item.isSeparator() && item.value().isSong())
|
||||
ptr = &item.value().song();
|
||||
return ptr;
|
||||
});
|
||||
}
|
||||
|
||||
bool SearchEngine::allowsSelection()
|
||||
{
|
||||
return w.current()->value().isSong();
|
||||
}
|
||||
|
||||
void SearchEngine::selectCurrent()
|
||||
{
|
||||
w.current()->setSelected(!w.current()->isSelected());
|
||||
}
|
||||
|
||||
void SearchEngine::reverseSelection()
|
||||
{
|
||||
reverseSelectionHelper(w.begin()+std::min(StaticOptions, w.size()), w.end());
|
||||
}
|
||||
|
||||
std::vector<MPD::Song> SearchEngine::getSelectedSongs()
|
||||
{
|
||||
std::vector<MPD::Song> result;
|
||||
@@ -328,6 +359,9 @@ void SearchEngine::Prepare()
|
||||
w.setTitle("");
|
||||
w.clear();
|
||||
w.resizeList(StaticOptions-3);
|
||||
|
||||
for (auto &item : w)
|
||||
item.setSelectable(false);
|
||||
|
||||
w.at(ConstraintsNumber).setSeparator(true);
|
||||
w.at(SearchButton-1).setSeparator(true);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "mpdpp.h"
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
#include "song_list.h"
|
||||
|
||||
struct SEItem
|
||||
{
|
||||
@@ -74,11 +75,27 @@ private:
|
||||
MPD::Song m_song;
|
||||
};
|
||||
|
||||
struct SearchEngine: Screen<NC::Menu<SEItem>>, HasSongs, Searchable, Tabbable
|
||||
struct SearchEngineWindow: NC::Menu<SEItem>, SongList
|
||||
{
|
||||
SearchEngineWindow() { }
|
||||
SearchEngineWindow(NC::Menu<SEItem> &&base)
|
||||
: NC::Menu<SEItem>(std::move(base)) { }
|
||||
|
||||
virtual SongIterator currentS() OVERRIDE;
|
||||
virtual ConstSongIterator currentS() const OVERRIDE;
|
||||
virtual SongIterator beginS() OVERRIDE;
|
||||
virtual ConstSongIterator beginS() const OVERRIDE;
|
||||
virtual SongIterator endS() OVERRIDE;
|
||||
virtual ConstSongIterator endS() const OVERRIDE;
|
||||
|
||||
virtual std::vector<MPD::Song> getSelectedSongs() OVERRIDE;
|
||||
};
|
||||
|
||||
struct SearchEngine: Screen<SearchEngineWindow>, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
SearchEngine();
|
||||
|
||||
// Screen< NC::Menu<SEItem> > implementation
|
||||
// Screen<SearchEngineWindow> implementation
|
||||
virtual void resize() OVERRIDE;
|
||||
virtual void switchTo() OVERRIDE;
|
||||
|
||||
@@ -101,11 +118,6 @@ struct SearchEngine: Screen<NC::Menu<SEItem>>, HasSongs, Searchable, Tabbable
|
||||
virtual bool find(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE;
|
||||
|
||||
// HasSongs implementation
|
||||
virtual ProxySongList proxySongList() OVERRIDE;
|
||||
|
||||
virtual bool allowsSelection() OVERRIDE;
|
||||
virtual void selectCurrent() OVERRIDE;
|
||||
virtual void reverseSelection() OVERRIDE;
|
||||
virtual std::vector<MPD::Song> getSelectedSongs() OVERRIDE;
|
||||
|
||||
// private members
|
||||
|
||||
@@ -106,14 +106,14 @@ void SelectedItemsAdder::switchTo()
|
||||
using Global::myScreen;
|
||||
|
||||
auto hs = hasSongs(myScreen);
|
||||
if (!hs || !hs->allowsSelection())
|
||||
if (!hs)
|
||||
return;
|
||||
|
||||
Statusbar::print(1, "Fetching selected songs...");
|
||||
m_selected_items = hs->getSelectedSongs();
|
||||
if (m_selected_items.empty())
|
||||
{
|
||||
Statusbar::print("List of selected items is empty");
|
||||
Statusbar::print("No selected songs");
|
||||
return;
|
||||
}
|
||||
populatePlaylistSelector(myScreen);
|
||||
|
||||
@@ -93,7 +93,7 @@ void SongInfo::switchTo()
|
||||
switchToPreviousScreen();
|
||||
}
|
||||
|
||||
void SongInfo::PrepareSong(MPD::Song &s)
|
||||
void SongInfo::PrepareSong(const MPD::Song &s)
|
||||
{
|
||||
w << NC::Format::Bold << Config.color1 << "Filename: " << NC::Format::NoBold << Config.color2 << s.getName() << '\n' << NC::Color::End;
|
||||
w << NC::Format::Bold << "Directory: " << NC::Format::NoBold << Config.color2;
|
||||
|
||||
@@ -55,7 +55,7 @@ struct SongInfo: Screen<NC::Scrollpad>, Tabbable
|
||||
static const Metadata Tags[];
|
||||
|
||||
private:
|
||||
void PrepareSong(MPD::Song &);
|
||||
void PrepareSong(const MPD::Song &s);
|
||||
};
|
||||
|
||||
extern SongInfo *mySongInfo;
|
||||
|
||||
83
src/song_list.cpp
Normal file
83
src/song_list.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008-2014 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 "helpers/song_iterator_maker.h"
|
||||
#include "song_info.h"
|
||||
#include "utility/functional.h"
|
||||
|
||||
namespace {
|
||||
|
||||
template <bool Const>
|
||||
struct SongExtractor
|
||||
{
|
||||
typedef SongExtractor type;
|
||||
|
||||
typedef typename NC::Menu<MPD::Song>::Item MenuItem;
|
||||
typedef typename std::conditional<Const, const MenuItem, MenuItem>::type Item;
|
||||
typedef typename std::conditional<Const, const MPD::Song, MPD::Song>::type Song;
|
||||
|
||||
Song *operator()(Item &item) const
|
||||
{
|
||||
return &item.value();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
SongIterator SongMenu::currentS()
|
||||
{
|
||||
return makeSongIterator_<MPD::Song>(current(), SongExtractor<false>());
|
||||
}
|
||||
|
||||
ConstSongIterator SongMenu::currentS() const
|
||||
{
|
||||
return makeConstSongIterator_<MPD::Song>(current(), SongExtractor<true>());
|
||||
}
|
||||
|
||||
SongIterator SongMenu::beginS()
|
||||
{
|
||||
return makeSongIterator_<MPD::Song>(begin(), SongExtractor<false>());
|
||||
}
|
||||
|
||||
ConstSongIterator SongMenu::beginS() const
|
||||
{
|
||||
return makeConstSongIterator_<MPD::Song>(begin(), SongExtractor<true>());
|
||||
}
|
||||
|
||||
SongIterator SongMenu::endS()
|
||||
{
|
||||
return makeSongIterator_<MPD::Song>(end(), SongExtractor<false>());
|
||||
}
|
||||
|
||||
ConstSongIterator SongMenu::endS() const
|
||||
{
|
||||
return makeConstSongIterator_<MPD::Song>(end(), SongExtractor<true>());
|
||||
}
|
||||
|
||||
std::vector<MPD::Song> SongMenu::getSelectedSongs()
|
||||
{
|
||||
std::vector<MPD::Song> result;
|
||||
for (auto it = begin(); it != end(); ++it)
|
||||
if (it->isSelected())
|
||||
result.push_back(it->value());
|
||||
if (result.empty() && !empty())
|
||||
result.push_back(current()->value());
|
||||
return result;
|
||||
}
|
||||
@@ -450,17 +450,17 @@ void Status::Changes::playlist(unsigned previous_version)
|
||||
myPlaylist->reloadRemaining();
|
||||
|
||||
if (isVisible(myBrowser))
|
||||
markSongsInPlaylist(myBrowser->proxySongList());
|
||||
markSongsInPlaylist(myBrowser->main());
|
||||
if (isVisible(mySearcher))
|
||||
markSongsInPlaylist(mySearcher->proxySongList());
|
||||
markSongsInPlaylist(mySearcher->main());
|
||||
if (isVisible(myLibrary))
|
||||
{
|
||||
markSongsInPlaylist(myLibrary->songsProxyList());
|
||||
markSongsInPlaylist(myLibrary->Songs);
|
||||
myLibrary->Songs.refresh();
|
||||
}
|
||||
if (isVisible(myPlaylistEditor))
|
||||
{
|
||||
markSongsInPlaylist(myPlaylistEditor->contentProxyList());
|
||||
markSongsInPlaylist(myPlaylistEditor->Content);
|
||||
myPlaylistEditor->Content.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include "playlist.h"
|
||||
#include "song_info.h"
|
||||
#include "statusbar.h"
|
||||
#include "helpers/song_iterator_maker.h"
|
||||
#include "utility/functional.h"
|
||||
#include "utility/comparators.h"
|
||||
#include "title.h"
|
||||
#include "tags.h"
|
||||
@@ -85,8 +87,60 @@ std::string SongToString(const MPD::MutableSong &s);
|
||||
bool DirEntryMatcher(const Regex::Regex &rx, const std::pair<std::string, std::string> &dir, bool filter);
|
||||
bool SongEntryMatcher(const Regex::Regex &rx, const MPD::MutableSong &s);
|
||||
|
||||
template <bool Const>
|
||||
struct SongExtractor
|
||||
{
|
||||
typedef SongExtractor type;
|
||||
|
||||
typedef typename NC::Menu<MPD::MutableSong>::Item MenuItem;
|
||||
typedef typename std::conditional<Const, const MenuItem, MenuItem>::type Item;
|
||||
typedef typename std::conditional<Const, const MPD::Song, MPD::Song>::type Song;
|
||||
|
||||
Song *operator()(Item &item) const
|
||||
{
|
||||
return &item.value();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
SongIterator TagsWindow::currentS()
|
||||
{
|
||||
return makeSongIterator_<MPD::MutableSong>(current(), SongExtractor<false>());
|
||||
}
|
||||
|
||||
ConstSongIterator TagsWindow::currentS() const
|
||||
{
|
||||
return makeConstSongIterator_<MPD::MutableSong>(current(), SongExtractor<true>());
|
||||
}
|
||||
|
||||
SongIterator TagsWindow::beginS()
|
||||
{
|
||||
return makeSongIterator_<MPD::MutableSong>(begin(), SongExtractor<false>());
|
||||
}
|
||||
|
||||
ConstSongIterator TagsWindow::beginS() const
|
||||
{
|
||||
return makeConstSongIterator_<MPD::MutableSong>(begin(), SongExtractor<true>());
|
||||
}
|
||||
|
||||
SongIterator TagsWindow::endS()
|
||||
{
|
||||
return makeSongIterator_<MPD::MutableSong>(end(), SongExtractor<false>());
|
||||
}
|
||||
|
||||
ConstSongIterator TagsWindow::endS() const
|
||||
{
|
||||
return makeConstSongIterator_<MPD::MutableSong>(end(), SongExtractor<true>());
|
||||
}
|
||||
|
||||
std::vector<MPD::Song> TagsWindow::getSelectedSongs()
|
||||
{
|
||||
return {}; // TODO
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
TagEditor::TagEditor() : FParser(0), FParserHelper(0), FParserLegend(0), FParserPreview(0), itsBrowsedDir("/")
|
||||
{
|
||||
PatternsFile = Config.ncmpcpp_directory + "patterns.list";
|
||||
@@ -115,7 +169,7 @@ TagEditor::TagEditor() : FParser(0), FParserHelper(0), FParserLegend(0), FParser
|
||||
TagTypes->addSeparator();
|
||||
if (Config.titles_visibility)
|
||||
{
|
||||
TagTypes->addItem("Options", 1, 1);
|
||||
TagTypes->addItem("Options", NC::List::Properties::Bold | NC::List::Properties::Inactive);
|
||||
TagTypes->addSeparator();
|
||||
}
|
||||
TagTypes->addItem("Capitalize First Letters");
|
||||
@@ -124,7 +178,7 @@ TagEditor::TagEditor() : FParser(0), FParserHelper(0), FParserLegend(0), FParser
|
||||
TagTypes->addItem("Reset");
|
||||
TagTypes->addItem("Save");
|
||||
|
||||
Tags = new NC::Menu<MPD::MutableSong>(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, Config.titles_visibility ? "Tags" : "", Config.main_color, NC::Border());
|
||||
Tags = new TagsWindow(NC::Menu<MPD::MutableSong>(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, Config.titles_visibility ? "Tags" : "", Config.main_color, NC::Border()));
|
||||
Tags->setHighlightColor(Config.main_highlight_color);
|
||||
Tags->cyclicScrolling(Config.use_cyclic_scrolling);
|
||||
Tags->centeredCursor(Config.centered_cursor);
|
||||
@@ -337,7 +391,7 @@ void TagEditor::enterPressed()
|
||||
if (!Patterns.empty())
|
||||
{
|
||||
FParser->addSeparator();
|
||||
FParser->addItem("Recent patterns", 1, 1);
|
||||
FParser->addItem("Recent patterns", NC::List::Properties::Bold | NC::List::Properties::Inactive);
|
||||
FParser->addSeparator();
|
||||
for (std::list<std::string>::const_iterator it = Patterns.begin(); it != Patterns.end(); ++it)
|
||||
FParser->addItem(*it);
|
||||
@@ -752,31 +806,6 @@ bool TagEditor::find(SearchDirection direction, bool wrap, bool skip_current)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
ProxySongList TagEditor::proxySongList()
|
||||
{
|
||||
auto ptr = ProxySongList();
|
||||
if (w == Tags)
|
||||
ptr = ProxySongList(*Tags, [](NC::Menu<MPD::MutableSong>::Item &item) {
|
||||
return &item.value();
|
||||
});
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool TagEditor::allowsSelection()
|
||||
{
|
||||
return w == Tags && !Tags->empty();
|
||||
}
|
||||
|
||||
void TagEditor::selectCurrent()
|
||||
{
|
||||
Tags->current()->setSelected(!Tags->current()->isSelected());
|
||||
}
|
||||
|
||||
void TagEditor::reverseSelection()
|
||||
{
|
||||
reverseSelectionHelper(Tags->begin(), Tags->end());
|
||||
}
|
||||
|
||||
std::vector<MPD::Song> TagEditor::getSelectedSongs()
|
||||
{
|
||||
std::vector<MPD::Song> result;
|
||||
|
||||
@@ -31,6 +31,23 @@
|
||||
#include "mutable_song.h"
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
#include "song_list.h"
|
||||
|
||||
struct TagsWindow: NC::Menu<MPD::MutableSong>, SongList
|
||||
{
|
||||
TagsWindow() { }
|
||||
TagsWindow(NC::Menu<MPD::MutableSong> &&base)
|
||||
: NC::Menu<MPD::MutableSong>(std::move(base)) { }
|
||||
|
||||
virtual SongIterator currentS() OVERRIDE;
|
||||
virtual ConstSongIterator currentS() const OVERRIDE;
|
||||
virtual SongIterator beginS() OVERRIDE;
|
||||
virtual ConstSongIterator beginS() const OVERRIDE;
|
||||
virtual SongIterator endS() OVERRIDE;
|
||||
virtual ConstSongIterator endS() const OVERRIDE;
|
||||
|
||||
virtual std::vector<MPD::Song> getSelectedSongs() OVERRIDE;
|
||||
};
|
||||
|
||||
struct TagEditor: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
@@ -59,11 +76,6 @@ struct TagEditor: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tabbab
|
||||
virtual bool find(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE;
|
||||
|
||||
// HasSongs implementation
|
||||
virtual ProxySongList proxySongList() OVERRIDE;
|
||||
|
||||
virtual bool allowsSelection() OVERRIDE;
|
||||
virtual void selectCurrent() OVERRIDE;
|
||||
virtual void reverseSelection() OVERRIDE;
|
||||
virtual std::vector<MPD::Song> getSelectedSongs() OVERRIDE;
|
||||
|
||||
// HasColumns implementation
|
||||
@@ -79,7 +91,7 @@ struct TagEditor: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tabbab
|
||||
|
||||
NC::Menu< std::pair<std::string, std::string> > *Dirs;
|
||||
NC::Menu<std::string> *TagTypes;
|
||||
NC::Menu<MPD::MutableSong> *Tags;
|
||||
TagsWindow *Tags;
|
||||
|
||||
private:
|
||||
void SetDimensions(size_t, size_t);
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
#include <boost/locale/encoding_utf.hpp>
|
||||
#include <utility>
|
||||
|
||||
template <typename ValueT>
|
||||
struct pointer_extractor
|
||||
{
|
||||
typedef pointer_extractor type;
|
||||
ValueT *operator()(ValueT &v) const { return &v; }
|
||||
};
|
||||
|
||||
// identity function object
|
||||
struct id_
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user