new feature: apply filter to screen (Ctrl-F)
if one applies a filter, only items that contain this filter will be displayed. works on all screens.
This commit is contained in:
2
doc/keys
2
doc/keys
@@ -82,6 +82,8 @@
|
|||||||
#
|
#
|
||||||
#key_update_db = 'u'
|
#key_update_db = 'u'
|
||||||
#
|
#
|
||||||
|
#key_apply_filter = 6
|
||||||
|
#
|
||||||
#key_find_forward = '/'
|
#key_find_forward = '/'
|
||||||
#
|
#
|
||||||
#key_find_backward = '?'
|
#key_find_backward = '?'
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ void Browser::Init()
|
|||||||
w->SetSelectPrefix(&Config.selected_item_prefix);
|
w->SetSelectPrefix(&Config.selected_item_prefix);
|
||||||
w->SetSelectSuffix(&Config.selected_item_suffix);
|
w->SetSelectSuffix(&Config.selected_item_suffix);
|
||||||
w->SetItemDisplayer(Display::Items);
|
w->SetItemDisplayer(Display::Items);
|
||||||
|
w->SetGetStringFunction(ItemToString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Browser::Resize()
|
void Browser::Resize()
|
||||||
@@ -437,3 +438,31 @@ void Browser::UpdateItemList()
|
|||||||
w->Refresh();
|
w->Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Browser::ItemToString(const MPD::Item &item, void *)
|
||||||
|
{
|
||||||
|
switch (item.type)
|
||||||
|
{
|
||||||
|
case MPD::itDirectory:
|
||||||
|
{
|
||||||
|
if (item.song)
|
||||||
|
return "[..]";
|
||||||
|
return "[" + ExtractTopDirectory(item.name) + "]";
|
||||||
|
}
|
||||||
|
case MPD::itSong:
|
||||||
|
{
|
||||||
|
if (!Config.columns_in_browser)
|
||||||
|
return item.song->toString(Config.song_list_format);
|
||||||
|
else
|
||||||
|
return Playlist::SongInColumnsToString(*item.song, &Config.song_columns_list_format);
|
||||||
|
}
|
||||||
|
case MPD::itPlaylist:
|
||||||
|
{
|
||||||
|
return Config.browser_playlist_prefix.Str() + item.name;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ class Browser : public Screen< Menu<MPD::Item> >
|
|||||||
virtual void ReverseSelection();
|
virtual void ReverseSelection();
|
||||||
virtual void GetSelectedSongs(MPD::SongList &);
|
virtual void GetSelectedSongs(MPD::SongList &);
|
||||||
|
|
||||||
|
virtual void ApplyFilter(const std::string &s) { w->ApplyFilter(s, itsBrowsedDir == "/" ? 0 : 1); }
|
||||||
|
|
||||||
virtual List *GetList() { return w; }
|
virtual List *GetList() { return w; }
|
||||||
|
|
||||||
const std::string &CurrentDir() { return itsBrowsedDir; }
|
const std::string &CurrentDir() { return itsBrowsedDir; }
|
||||||
@@ -53,6 +55,8 @@ class Browser : public Screen< Menu<MPD::Item> >
|
|||||||
void UpdateItemList();
|
void UpdateItemList();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
static std::string ItemToString(const MPD::Item &, void *);
|
||||||
|
|
||||||
size_t itsScrollBeginning;
|
size_t itsScrollBeginning;
|
||||||
|
|
||||||
std::string itsBrowsedDir;
|
std::string itsBrowsedDir;
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ void Help::GetKeybindings()
|
|||||||
*w << DisplayKeys(Key.SetCrossfade) << "Set crossfade\n";
|
*w << DisplayKeys(Key.SetCrossfade) << "Set crossfade\n";
|
||||||
*w << DisplayKeys(Key.UpdateDB) << "Start a music database update\n\n";
|
*w << DisplayKeys(Key.UpdateDB) << "Start a music database update\n\n";
|
||||||
|
|
||||||
|
*w << DisplayKeys(Key.ApplyFilter) << "Apply filter\n";
|
||||||
*w << DisplayKeys(Key.FindForward) << "Forward find\n";
|
*w << DisplayKeys(Key.FindForward) << "Forward find\n";
|
||||||
*w << DisplayKeys(Key.FindBackward) << "Backward find\n";
|
*w << DisplayKeys(Key.FindBackward) << "Backward find\n";
|
||||||
*w << DisplayKeys(Key.PrevFoundPosition) << "Go to previous found position\n";
|
*w << DisplayKeys(Key.PrevFoundPosition) << "Go to previous found position\n";
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "mpdpp.h"
|
#include "mpdpp.h"
|
||||||
#include "ncmpcpp.h"
|
#include "ncmpcpp.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "status.h"
|
||||||
|
|
||||||
bool ConnectToMPD();
|
bool ConnectToMPD();
|
||||||
void ParseArgv(int, char **);
|
void ParseArgv(int, char **);
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ void MediaLibrary::Init()
|
|||||||
Albums->HighlightColor(Config.main_highlight_color);
|
Albums->HighlightColor(Config.main_highlight_color);
|
||||||
Albums->SetTimeout(ncmpcpp_window_timeout);
|
Albums->SetTimeout(ncmpcpp_window_timeout);
|
||||||
Albums->SetItemDisplayer(Display::StringPairs);
|
Albums->SetItemDisplayer(Display::StringPairs);
|
||||||
|
Albums->SetGetStringFunction(StringPairToString);
|
||||||
|
|
||||||
Songs = new Menu<Song>(itsRightColStartX, main_start_y, itsRightColWidth, main_height, "Songs", Config.main_color, brNone);
|
Songs = new Menu<Song>(itsRightColStartX, main_start_y, itsRightColWidth, main_height, "Songs", Config.main_color, brNone);
|
||||||
Songs->HighlightColor(Config.main_highlight_color);
|
Songs->HighlightColor(Config.main_highlight_color);
|
||||||
@@ -66,6 +67,7 @@ void MediaLibrary::Init()
|
|||||||
Songs->SetSelectSuffix(&Config.selected_item_suffix);
|
Songs->SetSelectSuffix(&Config.selected_item_suffix);
|
||||||
Songs->SetItemDisplayer(Display::Songs);
|
Songs->SetItemDisplayer(Display::Songs);
|
||||||
Songs->SetItemDisplayerUserData(&Config.song_library_format);
|
Songs->SetItemDisplayerUserData(&Config.song_library_format);
|
||||||
|
Songs->SetGetStringFunction(SongToString);
|
||||||
|
|
||||||
w = Artists;
|
w = Artists;
|
||||||
}
|
}
|
||||||
@@ -428,6 +430,16 @@ void MediaLibrary::AddToPlaylist(bool add_n_play)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string MediaLibrary::StringPairToString(const string_pair &pair, void *)
|
||||||
|
{
|
||||||
|
return pair.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MediaLibrary::SongToString(const MPD::Song &s, void *)
|
||||||
|
{
|
||||||
|
return s.toString(Config.song_library_format);
|
||||||
|
}
|
||||||
|
|
||||||
bool MediaLibrary::SortSongsByTrack(Song *a, Song *b)
|
bool MediaLibrary::SortSongsByTrack(Song *a, Song *b)
|
||||||
{
|
{
|
||||||
if (a->GetDisc() == b->GetDisc())
|
if (a->GetDisc() == b->GetDisc())
|
||||||
|
|||||||
@@ -45,11 +45,15 @@ class MediaLibrary : public Screen<Window>
|
|||||||
virtual void ReverseSelection() { Songs->ReverseSelection(); }
|
virtual void ReverseSelection() { Songs->ReverseSelection(); }
|
||||||
virtual void GetSelectedSongs(MPD::SongList &);
|
virtual void GetSelectedSongs(MPD::SongList &);
|
||||||
|
|
||||||
|
virtual void ApplyFilter(const std::string &s) { GetList()->ApplyFilter(s); }
|
||||||
|
|
||||||
virtual List *GetList();
|
virtual List *GetList();
|
||||||
|
|
||||||
void NextColumn();
|
void NextColumn();
|
||||||
void PrevColumn();
|
void PrevColumn();
|
||||||
|
|
||||||
|
static std::string StringPairToString(const string_pair &pair, void *);
|
||||||
|
|
||||||
Menu<std::string> *Artists;
|
Menu<std::string> *Artists;
|
||||||
Menu<string_pair> *Albums;
|
Menu<string_pair> *Albums;
|
||||||
Menu<MPD::Song> *Songs;
|
Menu<MPD::Song> *Songs;
|
||||||
@@ -57,6 +61,8 @@ class MediaLibrary : public Screen<Window>
|
|||||||
protected:
|
protected:
|
||||||
void AddToPlaylist(bool);
|
void AddToPlaylist(bool);
|
||||||
|
|
||||||
|
static std::string SongToString(const MPD::Song &s, void *);
|
||||||
|
|
||||||
static bool SortSongsByTrack(MPD::Song *, MPD::Song *);
|
static bool SortSongsByTrack(MPD::Song *, MPD::Song *);
|
||||||
|
|
||||||
static size_t itsLeftColWidth;
|
static size_t itsLeftColWidth;
|
||||||
|
|||||||
@@ -43,3 +43,7 @@ bool List::Deselect()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <> std::string Menu<std::string>::GetOption(size_t pos)
|
||||||
|
{
|
||||||
|
return itsOptionsPtr->at(pos) ? (*itsOptionsPtr)[pos]->Item : "";
|
||||||
|
}
|
||||||
|
|||||||
211
src/menu.h
211
src/menu.h
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "strbuffer.h"
|
#include "strbuffer.h"
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
class List
|
class List
|
||||||
{
|
{
|
||||||
@@ -48,11 +49,21 @@ class List
|
|||||||
void SelectCurrent();
|
void SelectCurrent();
|
||||||
void ReverseSelection(size_t = 0);
|
void ReverseSelection(size_t = 0);
|
||||||
bool Deselect();
|
bool Deselect();
|
||||||
|
|
||||||
|
virtual void ApplyFilter(const std::string &, size_t = 0, bool = 0) = 0;
|
||||||
|
virtual const std::string &GetFilter() = 0;
|
||||||
|
virtual std::string GetOption(size_t) = 0;
|
||||||
|
|
||||||
|
virtual bool isFiltered() = 0;
|
||||||
|
//virtual void ShowAll() = 0;
|
||||||
|
//virtual void ShowFiltered() = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T> class Menu : public Window, public List
|
template <class T> class Menu : public Window, public List
|
||||||
{
|
{
|
||||||
typedef void (*ItemDisplayer) (const T &, void *, Menu<T> *);
|
typedef void (*ItemDisplayer) (const T &, void *, Menu<T> *);
|
||||||
|
typedef std::string (*GetStringFunction) (const T &, void *);
|
||||||
|
|
||||||
struct Option
|
struct Option
|
||||||
{
|
{
|
||||||
@@ -77,6 +88,9 @@ template <class T> class Menu : public Window, public List
|
|||||||
void SetItemDisplayer(ItemDisplayer ptr) { itsItemDisplayer = ptr; }
|
void SetItemDisplayer(ItemDisplayer ptr) { itsItemDisplayer = ptr; }
|
||||||
void SetItemDisplayerUserData(void *data) { itsItemDisplayerUserdata = data; }
|
void SetItemDisplayerUserData(void *data) { itsItemDisplayerUserdata = data; }
|
||||||
|
|
||||||
|
void SetGetStringFunction(GetStringFunction f) { itsGetStringFunction = f; }
|
||||||
|
void SetGetStringFunctionUserData(void *data) { itsGetStringFunctionUserData = data; }
|
||||||
|
|
||||||
void Reserve(size_t size);
|
void Reserve(size_t size);
|
||||||
void ResizeBuffer(size_t size);
|
void ResizeBuffer(size_t size);
|
||||||
void AddOption(const T &item, bool is_bold = 0, bool is_static = 0);
|
void AddOption(const T &item, bool is_bold = 0, bool is_static = 0);
|
||||||
@@ -101,6 +115,15 @@ template <class T> class Menu : public Window, public List
|
|||||||
virtual size_t Choice() const;
|
virtual size_t Choice() const;
|
||||||
virtual size_t RealChoice() const;
|
virtual size_t RealChoice() const;
|
||||||
|
|
||||||
|
virtual void ApplyFilter(const std::string &filter, size_t beginning = 0, bool case_sensitive = 0);
|
||||||
|
virtual const std::string &GetFilter();
|
||||||
|
virtual std::string GetOption(size_t pos);
|
||||||
|
|
||||||
|
virtual bool isFiltered() { return itsOptionsPtr == &itsFilteredOptions; }
|
||||||
|
|
||||||
|
void ShowAll() { itsOptionsPtr = &itsOptions; }
|
||||||
|
void ShowFiltered() { itsOptionsPtr = &itsFilteredOptions; }
|
||||||
|
|
||||||
virtual void Refresh();
|
virtual void Refresh();
|
||||||
virtual void Scroll(Where);
|
virtual void Scroll(Where);
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
@@ -112,7 +135,7 @@ template <class T> class Menu : public Window, public List
|
|||||||
void HighlightColor(Color col) { itsHighlightColor = col; }
|
void HighlightColor(Color col) { itsHighlightColor = col; }
|
||||||
void Highlighting(bool hl) { highlightEnabled = hl; }
|
void Highlighting(bool hl) { highlightEnabled = hl; }
|
||||||
|
|
||||||
virtual bool Empty() const { return itsOptions.empty(); }
|
virtual bool Empty() const { return itsOptionsPtr->empty(); }
|
||||||
|
|
||||||
T &Back();
|
T &Back();
|
||||||
const T &Back() const;
|
const T &Back() const;
|
||||||
@@ -129,8 +152,15 @@ template <class T> class Menu : public Window, public List
|
|||||||
protected:
|
protected:
|
||||||
ItemDisplayer itsItemDisplayer;
|
ItemDisplayer itsItemDisplayer;
|
||||||
void *itsItemDisplayerUserdata;
|
void *itsItemDisplayerUserdata;
|
||||||
|
GetStringFunction itsGetStringFunction;
|
||||||
|
void *itsGetStringFunctionUserData;
|
||||||
|
|
||||||
|
std::string itsFilter;
|
||||||
|
|
||||||
|
std::vector<Option *> *itsOptionsPtr;
|
||||||
std::vector<Option *> itsOptions;
|
std::vector<Option *> itsOptions;
|
||||||
|
std::vector<Option *> itsFilteredOptions;
|
||||||
|
std::vector<size_t> itsFilteredRealPositions;
|
||||||
|
|
||||||
int itsBeginning;
|
int itsBeginning;
|
||||||
int itsHighlight;
|
int itsHighlight;
|
||||||
@@ -152,6 +182,9 @@ template <class T> Menu<T>::Menu(size_t startx,
|
|||||||
: Window(startx, starty, width, height, title, color, border),
|
: Window(startx, starty, width, height, title, color, border),
|
||||||
itsItemDisplayer(0),
|
itsItemDisplayer(0),
|
||||||
itsItemDisplayerUserdata(0),
|
itsItemDisplayerUserdata(0),
|
||||||
|
itsGetStringFunction(0),
|
||||||
|
itsGetStringFunctionUserData(0),
|
||||||
|
itsOptionsPtr(&itsOptions),
|
||||||
itsBeginning(0),
|
itsBeginning(0),
|
||||||
itsHighlight(0),
|
itsHighlight(0),
|
||||||
itsHighlightColor(itsBaseColor),
|
itsHighlightColor(itsBaseColor),
|
||||||
@@ -215,9 +248,21 @@ template <class T> void Menu<T>::DeleteOption(size_t pos)
|
|||||||
{
|
{
|
||||||
if (itsOptions.empty())
|
if (itsOptions.empty())
|
||||||
return;
|
return;
|
||||||
|
if (itsOptionsPtr == &itsFilteredOptions)
|
||||||
|
{
|
||||||
|
delete itsOptions.at(itsFilteredRealPositions[pos]);
|
||||||
|
itsOptions.erase(itsOptions.begin()+itsFilteredRealPositions[pos]);
|
||||||
|
itsFilteredOptions.erase(itsFilteredOptions.begin()+pos);
|
||||||
|
itsFilteredRealPositions.erase(itsFilteredRealPositions.begin()+pos);
|
||||||
|
for (size_t i = pos; i < itsFilteredRealPositions.size(); i++)
|
||||||
|
itsFilteredRealPositions[i]--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
delete itsOptions.at(pos);
|
delete itsOptions.at(pos);
|
||||||
itsOptions.erase(itsOptions.begin()+pos);
|
itsOptions.erase(itsOptions.begin()+pos);
|
||||||
if (itsOptions.empty())
|
}
|
||||||
|
if (itsOptionsPtr->empty())
|
||||||
Window::Clear();
|
Window::Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,36 +287,42 @@ void Menu<T>::Swap(size_t one, size_t two)
|
|||||||
|
|
||||||
template <class T> void Menu<T>::Refresh()
|
template <class T> void Menu<T>::Refresh()
|
||||||
{
|
{
|
||||||
if (itsOptions.empty())
|
if (itsOptionsPtr->empty())
|
||||||
{
|
{
|
||||||
Window::Refresh();
|
Window::Refresh();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int MaxBeginning = itsOptions.size() < itsHeight ? 0 : itsOptions.size()-itsHeight;
|
int MaxBeginning = itsOptionsPtr->size() < itsHeight ? 0 : itsOptionsPtr->size()-itsHeight;
|
||||||
if (itsHighlight > itsBeginning+int(itsHeight)-1)
|
if (itsHighlight > itsBeginning+int(itsHeight)-1)
|
||||||
itsBeginning = itsHighlight-itsHeight+1;
|
itsBeginning = itsHighlight-itsHeight+1;
|
||||||
if (itsBeginning < 0)
|
if (itsBeginning < 0)
|
||||||
itsBeginning = 0;
|
itsBeginning = 0;
|
||||||
else if (itsBeginning > MaxBeginning)
|
else if (itsBeginning > MaxBeginning)
|
||||||
itsBeginning = MaxBeginning;
|
itsBeginning = MaxBeginning;
|
||||||
if (!itsOptions.empty() && itsHighlight > int(itsOptions.size())-1)
|
if (!itsOptionsPtr->empty() && itsHighlight > int(itsOptionsPtr->size())-1)
|
||||||
itsHighlight = itsOptions.size()-1;
|
itsHighlight = itsOptionsPtr->size()-1;
|
||||||
|
if (!(*itsOptionsPtr)[itsHighlight]) // it shouldn't be on separator.
|
||||||
|
{
|
||||||
|
Scroll(wUp);
|
||||||
|
if (!(*itsOptionsPtr)[itsHighlight]) // if it's still on separator, move in other direction.
|
||||||
|
Scroll(wDown);
|
||||||
|
}
|
||||||
size_t line = 0;
|
size_t line = 0;
|
||||||
for (size_t i = itsBeginning; i < itsBeginning+itsHeight; i++)
|
for (size_t i = itsBeginning; i < itsBeginning+itsHeight; i++)
|
||||||
{
|
{
|
||||||
GotoXY(0, line);
|
GotoXY(0, line);
|
||||||
if (i >= itsOptions.size())
|
if (i >= itsOptionsPtr->size())
|
||||||
{
|
{
|
||||||
for (; line < itsHeight; line++)
|
for (; line < itsHeight; line++)
|
||||||
mvwhline(itsWindow, line, 0, 32, itsWidth);
|
mvwhline(itsWindow, line, 0, 32, itsWidth);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!itsOptions[i]) // separator
|
if (!(*itsOptionsPtr)[i]) // separator
|
||||||
{
|
{
|
||||||
mvwhline(itsWindow, line++, 0, 0, itsWidth);
|
mvwhline(itsWindow, line++, 0, 0, itsWidth);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (itsOptions[i]->isBold)
|
if ((*itsOptionsPtr)[i]->isBold)
|
||||||
Bold(1);
|
Bold(1);
|
||||||
if (highlightEnabled && int(i) == itsHighlight)
|
if (highlightEnabled && int(i) == itsHighlight)
|
||||||
{
|
{
|
||||||
@@ -279,18 +330,18 @@ template <class T> void Menu<T>::Refresh()
|
|||||||
*this << itsHighlightColor;
|
*this << itsHighlightColor;
|
||||||
}
|
}
|
||||||
mvwhline(itsWindow, line, 0, 32, itsWidth);
|
mvwhline(itsWindow, line, 0, 32, itsWidth);
|
||||||
if (itsOptions[i]->isSelected && itsSelectedPrefix)
|
if ((*itsOptionsPtr)[i]->isSelected && itsSelectedPrefix)
|
||||||
*this << *itsSelectedPrefix;
|
*this << *itsSelectedPrefix;
|
||||||
if (itsItemDisplayer)
|
if (itsItemDisplayer)
|
||||||
itsItemDisplayer(itsOptions[i]->Item, itsItemDisplayerUserdata, this);
|
itsItemDisplayer((*itsOptionsPtr)[i]->Item, itsItemDisplayerUserdata, this);
|
||||||
if (itsOptions[i]->isSelected && itsSelectedSuffix)
|
if ((*itsOptionsPtr)[i]->isSelected && itsSelectedSuffix)
|
||||||
*this << *itsSelectedSuffix;
|
*this << *itsSelectedSuffix;
|
||||||
if (highlightEnabled && int(i) == itsHighlight)
|
if (highlightEnabled && int(i) == itsHighlight)
|
||||||
{
|
{
|
||||||
*this << clEnd;
|
*this << clEnd;
|
||||||
Reverse(0);
|
Reverse(0);
|
||||||
}
|
}
|
||||||
if (itsOptions[i]->isBold)
|
if ((*itsOptionsPtr)[i]->isBold)
|
||||||
Bold(0);
|
Bold(0);
|
||||||
line++;
|
line++;
|
||||||
}
|
}
|
||||||
@@ -299,10 +350,10 @@ template <class T> void Menu<T>::Refresh()
|
|||||||
|
|
||||||
template <class T> void Menu<T>::Scroll(Where where)
|
template <class T> void Menu<T>::Scroll(Where where)
|
||||||
{
|
{
|
||||||
if (itsOptions.empty())
|
if (itsOptionsPtr->empty())
|
||||||
return;
|
return;
|
||||||
int MaxHighlight = itsOptions.size()-1;
|
int MaxHighlight = itsOptionsPtr->size()-1;
|
||||||
int MaxBeginning = itsOptions.size() < itsHeight ? 0 : itsOptions.size()-itsHeight;
|
int MaxBeginning = itsOptionsPtr->size() < itsHeight ? 0 : itsOptionsPtr->size()-itsHeight;
|
||||||
int MaxCurrentHighlight = itsBeginning+itsHeight-1;
|
int MaxCurrentHighlight = itsBeginning+itsHeight-1;
|
||||||
switch (where)
|
switch (where)
|
||||||
{
|
{
|
||||||
@@ -321,7 +372,7 @@ template <class T> void Menu<T>::Scroll(Where where)
|
|||||||
{
|
{
|
||||||
itsHighlight--;
|
itsHighlight--;
|
||||||
}
|
}
|
||||||
if (!itsOptions[itsHighlight] || itsOptions[itsHighlight]->isStatic)
|
if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
|
||||||
{
|
{
|
||||||
Scroll(itsHighlight == 0 ? wDown : wUp);
|
Scroll(itsHighlight == 0 ? wDown : wUp);
|
||||||
}
|
}
|
||||||
@@ -342,7 +393,7 @@ template <class T> void Menu<T>::Scroll(Where where)
|
|||||||
{
|
{
|
||||||
itsHighlight++;
|
itsHighlight++;
|
||||||
}
|
}
|
||||||
if (!itsOptions[itsHighlight] || itsOptions[itsHighlight]->isStatic)
|
if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
|
||||||
{
|
{
|
||||||
Scroll(itsHighlight == MaxHighlight ? wUp : wDown);
|
Scroll(itsHighlight == MaxHighlight ? wUp : wDown);
|
||||||
}
|
}
|
||||||
@@ -358,7 +409,7 @@ template <class T> void Menu<T>::Scroll(Where where)
|
|||||||
if (itsHighlight < 0)
|
if (itsHighlight < 0)
|
||||||
itsHighlight = 0;
|
itsHighlight = 0;
|
||||||
}
|
}
|
||||||
if (!itsOptions[itsHighlight] || itsOptions[itsHighlight]->isStatic)
|
if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
|
||||||
{
|
{
|
||||||
Scroll(itsHighlight == 0 ? wDown: wUp);
|
Scroll(itsHighlight == 0 ? wDown: wUp);
|
||||||
}
|
}
|
||||||
@@ -374,7 +425,7 @@ template <class T> void Menu<T>::Scroll(Where where)
|
|||||||
if (itsHighlight > MaxHighlight)
|
if (itsHighlight > MaxHighlight)
|
||||||
itsHighlight = MaxHighlight;
|
itsHighlight = MaxHighlight;
|
||||||
}
|
}
|
||||||
if (!itsOptions[itsHighlight] || itsOptions[itsHighlight]->isStatic)
|
if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
|
||||||
{
|
{
|
||||||
Scroll(itsHighlight == MaxHighlight ? wUp : wDown);
|
Scroll(itsHighlight == MaxHighlight ? wUp : wDown);
|
||||||
}
|
}
|
||||||
@@ -384,7 +435,7 @@ template <class T> void Menu<T>::Scroll(Where where)
|
|||||||
{
|
{
|
||||||
itsHighlight = 0;
|
itsHighlight = 0;
|
||||||
itsBeginning = 0;
|
itsBeginning = 0;
|
||||||
if (!itsOptions[itsHighlight] || itsOptions[itsHighlight]->isStatic)
|
if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
|
||||||
{
|
{
|
||||||
Scroll(itsHighlight == 0 ? wDown : wUp);
|
Scroll(itsHighlight == 0 ? wDown : wUp);
|
||||||
}
|
}
|
||||||
@@ -394,7 +445,7 @@ template <class T> void Menu<T>::Scroll(Where where)
|
|||||||
{
|
{
|
||||||
itsHighlight = MaxHighlight;
|
itsHighlight = MaxHighlight;
|
||||||
itsBeginning = MaxBeginning;
|
itsBeginning = MaxBeginning;
|
||||||
if (!itsOptions[itsHighlight] || itsOptions[itsHighlight]->isStatic)
|
if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
|
||||||
{
|
{
|
||||||
Scroll(itsHighlight == MaxHighlight ? wUp : wDown);
|
Scroll(itsHighlight == MaxHighlight ? wUp : wDown);
|
||||||
}
|
}
|
||||||
@@ -414,46 +465,55 @@ template <class T> void Menu<T>::Clear(bool clrscr)
|
|||||||
for (option_iterator it = itsOptions.begin(); it != itsOptions.end(); it++)
|
for (option_iterator it = itsOptions.begin(); it != itsOptions.end(); it++)
|
||||||
delete *it;
|
delete *it;
|
||||||
itsOptions.clear();
|
itsOptions.clear();
|
||||||
|
itsFilteredOptions.clear();
|
||||||
|
itsFilteredRealPositions.clear();
|
||||||
|
itsFilter.clear();
|
||||||
|
itsOptionsPtr = &itsOptions;
|
||||||
if (clrscr)
|
if (clrscr)
|
||||||
Window::Clear();
|
Window::Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> bool Menu<T>::isBold(int id)
|
template <class T> bool Menu<T>::isBold(int id)
|
||||||
{
|
{
|
||||||
return itsOptions.at(id == -1 ? itsHighlight : id)->isBold;
|
id = id == -1 ? itsHighlight : id;
|
||||||
|
if (!itsOptionsPtr->at(id))
|
||||||
|
return 0;
|
||||||
|
return (*itsOptionsPtr)[id]->isBold;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> void Menu<T>::Select(int id, bool value)
|
template <class T> void Menu<T>::Select(int id, bool value)
|
||||||
{
|
{
|
||||||
if (!itsOptions.at(id))
|
if (!itsOptionsPtr->at(id))
|
||||||
return;
|
return;
|
||||||
itsOptions[id]->isSelected = value;
|
(*itsOptionsPtr)[id]->isSelected = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> void Menu<T>::Static(int id, bool value)
|
template <class T> void Menu<T>::Static(int id, bool value)
|
||||||
{
|
{
|
||||||
if (!itsOptions.at(id))
|
if (!itsOptionsPtr->at(id))
|
||||||
return;
|
return;
|
||||||
itsOptions[id]->isStatic = value;
|
(*itsOptionsPtr)[id]->isStatic = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> bool Menu<T>::isSelected(int id) const
|
template <class T> bool Menu<T>::isSelected(int id) const
|
||||||
{
|
{
|
||||||
if (!itsOptions.at(id == -1 ? itsHighlight : id))
|
id = id == -1 ? itsHighlight : id;
|
||||||
|
if (!itsOptionsPtr->at(id))
|
||||||
return 0;
|
return 0;
|
||||||
return itsOptions[id == -1 ? itsHighlight : id]->isSelected;
|
return (*itsOptionsPtr)[id]->isSelected;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> bool Menu<T>::isStatic(int id) const
|
template <class T> bool Menu<T>::isStatic(int id) const
|
||||||
{
|
{
|
||||||
if (!itsOptions.at(id == -1 ? itsHighlight : id))
|
id = id == -1 ? itsHighlight : id;
|
||||||
|
if (!itsOptionsPtr->at(id))
|
||||||
return 1;
|
return 1;
|
||||||
return itsOptions[id == -1 ? itsHighlight : id]->isStatic;
|
return (*itsOptionsPtr)[id]->isStatic;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> bool Menu<T>::hasSelected() const
|
template <class T> bool Menu<T>::hasSelected() const
|
||||||
{
|
{
|
||||||
for (option_const_iterator it = itsOptions.begin(); it != itsOptions.end(); it++)
|
for (option_const_iterator it = itsOptionsPtr->begin(); it != itsOptionsPtr->end(); it++)
|
||||||
if (*it && (*it)->isSelected)
|
if (*it && (*it)->isSelected)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
@@ -461,8 +521,8 @@ template <class T> bool Menu<T>::hasSelected() const
|
|||||||
|
|
||||||
template <class T> void Menu<T>::GetSelected(std::vector<size_t> &v) const
|
template <class T> void Menu<T>::GetSelected(std::vector<size_t> &v) const
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < itsOptions.size(); i++)
|
for (size_t i = 0; i < itsOptionsPtr->size(); i++)
|
||||||
if (itsOptions[i]->isSelected)
|
if ((*itsOptionsPtr)[i]->isSelected)
|
||||||
v.push_back(i);
|
v.push_back(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,7 +534,7 @@ template <class T> void Menu<T>::Highlight(size_t pos)
|
|||||||
|
|
||||||
template <class T> size_t Menu<T>::Size() const
|
template <class T> size_t Menu<T>::Size() const
|
||||||
{
|
{
|
||||||
return itsOptions.size();
|
return itsOptionsPtr->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> size_t Menu<T>::Choice() const
|
template <class T> size_t Menu<T>::Choice() const
|
||||||
@@ -485,66 +545,113 @@ template <class T> size_t Menu<T>::Choice() const
|
|||||||
template <class T> size_t Menu<T>::RealChoice() const
|
template <class T> size_t Menu<T>::RealChoice() const
|
||||||
{
|
{
|
||||||
size_t result = 0;
|
size_t result = 0;
|
||||||
for (option_const_iterator it = itsOptions.begin(); it != itsOptions.begin()+itsHighlight; it++)
|
for (option_const_iterator it = itsOptionsPtr->begin(); it != itsOptionsPtr->begin()+itsHighlight; it++)
|
||||||
if (*it && !(*it)->isStatic)
|
if (*it && !(*it)->isStatic)
|
||||||
result++;
|
result++;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T> void Menu<T>::ApplyFilter(const std::string &filter, size_t beginning, bool case_sensitive)
|
||||||
|
{
|
||||||
|
itsFilter = filter;
|
||||||
|
if (!case_sensitive)
|
||||||
|
ToLower(itsFilter);
|
||||||
|
itsFilteredRealPositions.clear();
|
||||||
|
itsFilteredOptions.clear();
|
||||||
|
itsOptionsPtr = &itsOptions;
|
||||||
|
if (itsFilter.empty())
|
||||||
|
return;
|
||||||
|
for (size_t i = 0; i < beginning; i++)
|
||||||
|
{
|
||||||
|
itsFilteredRealPositions.push_back(i);
|
||||||
|
itsFilteredOptions.push_back(itsOptions[i]);
|
||||||
|
}
|
||||||
|
std::string option;
|
||||||
|
for (size_t i = beginning; i < itsOptions.size(); i++)
|
||||||
|
{
|
||||||
|
option = GetOption(i);
|
||||||
|
if (!case_sensitive)
|
||||||
|
ToLower(option);
|
||||||
|
if (option.find(itsFilter) != std::string::npos)
|
||||||
|
{
|
||||||
|
itsFilteredRealPositions.push_back(i);
|
||||||
|
itsFilteredOptions.push_back(itsOptions[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itsOptionsPtr = &itsFilteredOptions;
|
||||||
|
if (itsOptionsPtr->empty()) // oops, we didn't find anything
|
||||||
|
Window::Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T> const std::string &Menu<T>::GetFilter()
|
||||||
|
{
|
||||||
|
return itsFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T> std::string Menu<T>::GetOption(size_t pos)
|
||||||
|
{
|
||||||
|
if (itsOptionsPtr->at(pos) && itsGetStringFunction)
|
||||||
|
return itsGetStringFunction((*itsOptionsPtr)[pos]->Item, itsGetStringFunctionUserData);
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> std::string Menu<std::string>::GetOption(size_t pos);
|
||||||
|
|
||||||
template <class T> T &Menu<T>::Back()
|
template <class T> T &Menu<T>::Back()
|
||||||
{
|
{
|
||||||
if (!itsOptions.back())
|
if (!itsOptionsPtr->back())
|
||||||
throw InvalidItem();
|
throw InvalidItem();
|
||||||
return itsOptions.back()->Item;
|
return itsOptionsPtr->back()->Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> const T &Menu<T>::Back() const
|
template <class T> const T &Menu<T>::Back() const
|
||||||
{
|
{
|
||||||
if (!itsOptions.back())
|
if (!itsOptionsPtr->back())
|
||||||
throw InvalidItem();
|
throw InvalidItem();
|
||||||
return itsOptions.back()->Item;
|
return itsOptionsPtr->back()->Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> T &Menu<T>::Current()
|
template <class T> T &Menu<T>::Current()
|
||||||
{
|
{
|
||||||
if (!itsOptions.at(itsHighlight))
|
if (!itsOptionsPtr->at(itsHighlight))
|
||||||
throw InvalidItem();
|
throw InvalidItem();
|
||||||
return itsOptions[itsHighlight]->Item;
|
return (*itsOptionsPtr)[itsHighlight]->Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> const T &Menu<T>::Current() const
|
template <class T> const T &Menu<T>::Current() const
|
||||||
{
|
{
|
||||||
if (!itsOptions.at(itsHighlight))
|
if (!itsOptionsPtr->at(itsHighlight))
|
||||||
throw InvalidItem();
|
throw InvalidItem();
|
||||||
return itsOptions[itsHighlight]->Item;
|
return (*itsOptionsPtr)[itsHighlight]->Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> T &Menu<T>::at(size_t i)
|
template <class T> T &Menu<T>::at(size_t i)
|
||||||
{
|
{
|
||||||
if (!itsOptions.at(i))
|
if (!itsOptionsPtr->at(i))
|
||||||
throw InvalidItem();
|
throw InvalidItem();
|
||||||
return itsOptions[i]->Item;
|
return (*itsOptionsPtr)[i]->Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> const T &Menu<T>::at(size_t i) const
|
template <class T> const T &Menu<T>::at(size_t i) const
|
||||||
{
|
{
|
||||||
if (!itsOptions.at(i))
|
if (!itsOptions->at(i))
|
||||||
throw InvalidItem();
|
throw InvalidItem();
|
||||||
return itsOptions.at(i)->Item;
|
return (*itsOptionsPtr)[i]->Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> const T &Menu<T>::operator[](size_t i) const
|
template <class T> const T &Menu<T>::operator[](size_t i) const
|
||||||
{
|
{
|
||||||
if (!itsOptions[i])
|
if (!(*itsOptionsPtr)[i])
|
||||||
throw InvalidItem();
|
throw InvalidItem();
|
||||||
return itsOptions[i]->Item;
|
return (*itsOptionsPtr)[i]->Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> T &Menu<T>::operator[](size_t i)
|
template <class T> T &Menu<T>::operator[](size_t i)
|
||||||
{
|
{
|
||||||
if (!itsOptions[i])
|
if (!(*itsOptionsPtr)[i])
|
||||||
throw InvalidItem();
|
throw InvalidItem();
|
||||||
return itsOptions[i]->Item;
|
return (*itsOptionsPtr)[i]->Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> Menu<T> *Menu<T>::EmptyClone() const
|
template <class T> Menu<T> *Menu<T>::EmptyClone() const
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ using std::string;
|
|||||||
|
|
||||||
const char *MPD::Message::PartOfSongsAdded = "Only part of requested songs' list added to playlist!";
|
const char *MPD::Message::PartOfSongsAdded = "Only part of requested songs' list added to playlist!";
|
||||||
const char *MPD::Message::FullPlaylist = "Playlist is full!";
|
const char *MPD::Message::FullPlaylist = "Playlist is full!";
|
||||||
|
const char *MPD::Message::FunctionDisabledFilteringEnabled = "Function disabled due to enabled filtering in playlist";
|
||||||
|
|
||||||
Connection::Connection() : isConnected(0),
|
Connection::Connection() : isConnected(0),
|
||||||
itsErrorCode(0),
|
itsErrorCode(0),
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ namespace MPD
|
|||||||
{
|
{
|
||||||
extern const char *PartOfSongsAdded;
|
extern const char *PartOfSongsAdded;
|
||||||
extern const char *FullPlaylist;
|
extern const char *FullPlaylist;
|
||||||
|
extern const char *FunctionDisabledFilteringEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum QueueCommandType { qctAdd, qctAddToPlaylist, qctDelete, qctDeleteID, qctMove, qctPlaylistMove, qctDeleteFromPlaylist };
|
enum QueueCommandType { qctAdd, qctAddToPlaylist, qctDelete, qctDeleteID, qctMove, qctPlaylistMove, qctDeleteFromPlaylist };
|
||||||
|
|||||||
208
src/ncmpcpp.cpp
208
src/ncmpcpp.cpp
@@ -161,7 +161,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
wFooter = new Window(0, footer_start_y, COLS, footer_height, "", Config.statusbar_color, brNone);
|
wFooter = new Window(0, footer_start_y, COLS, footer_height, "", Config.statusbar_color, brNone);
|
||||||
wFooter->SetTimeout(ncmpcpp_window_timeout);
|
wFooter->SetTimeout(ncmpcpp_window_timeout);
|
||||||
wFooter->SetGetStringHelper(TraceMpdStatus);
|
wFooter->SetGetStringHelper(StatusbarGetStringHelper);
|
||||||
wFooter->Display();
|
wFooter->Display();
|
||||||
|
|
||||||
myScreen = myPlaylist;
|
myScreen = myPlaylist;
|
||||||
@@ -180,6 +180,7 @@ int main(int argc, char *argv[])
|
|||||||
string screen_title;
|
string screen_title;
|
||||||
|
|
||||||
timeval now, past;
|
timeval now, past;
|
||||||
|
|
||||||
// local variables end
|
// local variables end
|
||||||
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
@@ -266,7 +267,17 @@ int main(int argc, char *argv[])
|
|||||||
# endif // HAVE_TAGLIB_H
|
# endif // HAVE_TAGLIB_H
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (Keypressed(input, Key.Up) || Keypressed(input, Key.Down) || Keypressed(input, Key.PageUp) || Keypressed(input, Key.PageDown) || Keypressed(input, Key.Home) || Keypressed(input, Key.End) || Keypressed(input, Key.FindForward) || Keypressed(input, Key.FindBackward) || Keypressed(input, Key.NextFoundPosition) || Keypressed(input, Key.PrevFoundPosition))
|
if (Keypressed(input, Key.Up)
|
||||||
|
|| Keypressed(input, Key.Down)
|
||||||
|
|| Keypressed(input, Key.PageUp)
|
||||||
|
|| Keypressed(input, Key.PageDown)
|
||||||
|
|| Keypressed(input, Key.Home)
|
||||||
|
|| Keypressed(input, Key.End)
|
||||||
|
|| Keypressed(input, Key.ApplyFilter)
|
||||||
|
|| Keypressed(input, Key.FindForward)
|
||||||
|
|| Keypressed(input, Key.FindBackward)
|
||||||
|
|| Keypressed(input, Key.NextFoundPosition)
|
||||||
|
|| Keypressed(input, Key.PrevFoundPosition))
|
||||||
{
|
{
|
||||||
if (myScreen->Cmp() == myLibrary->Artists)
|
if (myScreen->Cmp() == myLibrary->Artists)
|
||||||
{
|
{
|
||||||
@@ -438,7 +449,7 @@ int main(int argc, char *argv[])
|
|||||||
myPlaylist->Main()->GetSelected(list);
|
myPlaylist->Main()->GetSelected(list);
|
||||||
for (vector<size_t>::const_reverse_iterator it = list.rbegin(); it != ((const vector<size_t> &)list).rend(); it++)
|
for (vector<size_t>::const_reverse_iterator it = list.rbegin(); it != ((const vector<size_t> &)list).rend(); it++)
|
||||||
{
|
{
|
||||||
Mpd->QueueDeleteSong(*it);
|
Mpd->QueueDeleteSongId((*myPlaylist->Main())[*it].GetID());
|
||||||
myPlaylist->Main()->DeleteOption(*it);
|
myPlaylist->Main()->DeleteOption(*it);
|
||||||
}
|
}
|
||||||
ShowMessage("Selected items deleted!");
|
ShowMessage("Selected items deleted!");
|
||||||
@@ -452,9 +463,9 @@ int main(int argc, char *argv[])
|
|||||||
size_t id = myPlaylist->Main()->Choice();
|
size_t id = myPlaylist->Main()->Choice();
|
||||||
TraceMpdStatus();
|
TraceMpdStatus();
|
||||||
timer = time(NULL);
|
timer = time(NULL);
|
||||||
if (size_t(myPlaylist->NowPlaying) > id) // needed for keeping proper
|
if (myPlaylist->NowPlaying > myPlaylist->CurrentSong()->GetPosition()) // needed for keeping proper
|
||||||
myPlaylist->NowPlaying--; // position of now playing song.
|
myPlaylist->NowPlaying--; // position of now playing song.
|
||||||
Mpd->QueueDeleteSong(id);
|
Mpd->QueueDeleteSongId(myPlaylist->CurrentSong()->GetID());
|
||||||
myPlaylist->Main()->DeleteOption(id);
|
myPlaylist->Main()->DeleteOption(id);
|
||||||
myPlaylist->Main()->Refresh();
|
myPlaylist->Main()->Refresh();
|
||||||
myPlaylist->Main()->ReadKey(input);
|
myPlaylist->Main()->ReadKey(input);
|
||||||
@@ -597,6 +608,12 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
if (myScreen == myPlaylist && !myPlaylist->Main()->Empty())
|
if (myScreen == myPlaylist && !myPlaylist->Main()->Empty())
|
||||||
{
|
{
|
||||||
|
if (myPlaylist->Main()->isFiltered())
|
||||||
|
{
|
||||||
|
ShowMessage("%s", MPD::Message::FunctionDisabledFilteringEnabled);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Playlist::BlockUpdate = 1;
|
Playlist::BlockUpdate = 1;
|
||||||
myPlaylist->Main()->SetTimeout(50);
|
myPlaylist->Main()->SetTimeout(50);
|
||||||
if (myPlaylist->Main()->hasSelected())
|
if (myPlaylist->Main()->hasSelected())
|
||||||
@@ -700,6 +717,12 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
if (myScreen == myPlaylist && !myPlaylist->Main()->Empty())
|
if (myScreen == myPlaylist && !myPlaylist->Main()->Empty())
|
||||||
{
|
{
|
||||||
|
if (myPlaylist->Main()->isFiltered())
|
||||||
|
{
|
||||||
|
ShowMessage("%s", MPD::Message::FunctionDisabledFilteringEnabled);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Playlist::BlockUpdate = 1;
|
Playlist::BlockUpdate = 1;
|
||||||
myPlaylist->Main()->SetTimeout(50);
|
myPlaylist->Main()->SetTimeout(50);
|
||||||
if (myPlaylist->Main()->hasSelected())
|
if (myPlaylist->Main()->hasSelected())
|
||||||
@@ -830,7 +853,10 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
if (!myPlaylist->isPlaying())
|
if (!myPlaylist->isPlaying())
|
||||||
continue;
|
continue;
|
||||||
if (!myPlaylist->NowPlayingSong().GetTotalLength())
|
|
||||||
|
const Song &s = Mpd->GetCurrentSong();
|
||||||
|
|
||||||
|
if (!s.GetTotalLength())
|
||||||
{
|
{
|
||||||
ShowMessage("Unknown item length!");
|
ShowMessage("Unknown item length!");
|
||||||
continue;
|
continue;
|
||||||
@@ -842,7 +868,6 @@ int main(int argc, char *argv[])
|
|||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
|
|
||||||
songpos = Mpd->GetElapsedTime();
|
songpos = Mpd->GetElapsedTime();
|
||||||
const Song &s = myPlaylist->NowPlayingSong();
|
|
||||||
|
|
||||||
while (Keypressed(input, Key.SeekForward) || Keypressed(input, Key.SeekBackward))
|
while (Keypressed(input, Key.SeekForward) || Keypressed(input, Key.SeekBackward))
|
||||||
{
|
{
|
||||||
@@ -888,15 +913,30 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
Config.columns_in_playlist = !Config.columns_in_playlist;
|
Config.columns_in_playlist = !Config.columns_in_playlist;
|
||||||
ShowMessage("Playlist display mode: %s", Config.columns_in_playlist ? "Columns" : "Classic");
|
ShowMessage("Playlist display mode: %s", Config.columns_in_playlist ? "Columns" : "Classic");
|
||||||
myPlaylist->Main()->SetItemDisplayer(Config.columns_in_playlist ? Display::SongsInColumns : Display::Songs);
|
|
||||||
myPlaylist->Main()->SetItemDisplayerUserData(Config.columns_in_playlist ? &Config.song_columns_list_format : &Config.song_list_format);
|
if (Config.columns_in_playlist)
|
||||||
myPlaylist->Main()->SetTitle(Config.columns_in_playlist ? Display::Columns(Config.song_columns_list_format) : "");
|
{
|
||||||
|
myPlaylist->Main()->SetItemDisplayer(Display::SongsInColumns);
|
||||||
|
myPlaylist->Main()->SetItemDisplayerUserData(&Config.song_columns_list_format);
|
||||||
|
myPlaylist->Main()->SetTitle(Display::Columns(Config.song_columns_list_format));
|
||||||
|
myPlaylist->Main()->SetGetStringFunction(Playlist::SongInColumnsToString);
|
||||||
|
myPlaylist->Main()->SetGetStringFunctionUserData(&Config.song_columns_list_format);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
myPlaylist->Main()->SetItemDisplayer(Display::Songs);
|
||||||
|
myPlaylist->Main()->SetItemDisplayerUserData(&Config.song_list_format);
|
||||||
|
myPlaylist->Main()->SetTitle("");
|
||||||
|
myPlaylist->Main()->SetGetStringFunction(Playlist::SongToString);
|
||||||
|
myPlaylist->Main()->SetGetStringFunctionUserData(&Config.song_list_format);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (myScreen == myBrowser)
|
else if (myScreen == myBrowser)
|
||||||
{
|
{
|
||||||
Config.columns_in_browser = !Config.columns_in_browser;
|
Config.columns_in_browser = !Config.columns_in_browser;
|
||||||
ShowMessage("Browser display mode: %s", Config.columns_in_browser ? "Columns" : "Classic");
|
ShowMessage("Browser display mode: %s", Config.columns_in_browser ? "Columns" : "Classic");
|
||||||
myBrowser->Main()->SetTitle(Config.columns_in_browser ? Display::Columns(Config.song_columns_list_format) : "");
|
myBrowser->Main()->SetTitle(Config.columns_in_browser ? Display::Columns(Config.song_columns_list_format) : "");
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (myScreen == mySearcher)
|
else if (myScreen == mySearcher)
|
||||||
{
|
{
|
||||||
@@ -921,7 +961,7 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
Config.autocenter_mode = !Config.autocenter_mode;
|
Config.autocenter_mode = !Config.autocenter_mode;
|
||||||
ShowMessage("Auto center mode: %s", Config.autocenter_mode ? "On" : "Off");
|
ShowMessage("Auto center mode: %s", Config.autocenter_mode ? "On" : "Off");
|
||||||
if (Config.autocenter_mode && myPlaylist->isPlaying())
|
if (Config.autocenter_mode && myPlaylist->isPlaying() && !myPlaylist->Main()->isFiltered())
|
||||||
myPlaylist->Main()->Highlight(myPlaylist->NowPlaying);
|
myPlaylist->Main()->Highlight(myPlaylist->NowPlaying);
|
||||||
}
|
}
|
||||||
else if (Keypressed(input, Key.UpdateDB))
|
else if (Keypressed(input, Key.UpdateDB))
|
||||||
@@ -937,7 +977,13 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
else if (Keypressed(input, Key.GoToNowPlaying))
|
else if (Keypressed(input, Key.GoToNowPlaying))
|
||||||
{
|
{
|
||||||
if (myScreen == myPlaylist && myPlaylist->isPlaying())
|
if (myScreen != myPlaylist || !myPlaylist->isPlaying())
|
||||||
|
continue;
|
||||||
|
if (myPlaylist->Main()->isFiltered())
|
||||||
|
{
|
||||||
|
ShowMessage("%s", MPD::Message::FunctionDisabledFilteringEnabled);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
myPlaylist->Main()->Highlight(myPlaylist->NowPlaying);
|
myPlaylist->Main()->Highlight(myPlaylist->NowPlaying);
|
||||||
}
|
}
|
||||||
else if (Keypressed(input, Key.ToggleRepeat))
|
else if (Keypressed(input, Key.ToggleRepeat))
|
||||||
@@ -1163,7 +1209,10 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
if (!myPlaylist->isPlaying())
|
if (!myPlaylist->isPlaying())
|
||||||
continue;
|
continue;
|
||||||
if (!myPlaylist->NowPlayingSong().GetTotalLength())
|
|
||||||
|
const Song &s = Mpd->GetCurrentSong();
|
||||||
|
|
||||||
|
if (!s.GetTotalLength())
|
||||||
{
|
{
|
||||||
ShowMessage("Unknown item length!");
|
ShowMessage("Unknown item length!");
|
||||||
continue;
|
continue;
|
||||||
@@ -1173,7 +1222,7 @@ int main(int argc, char *argv[])
|
|||||||
string position = wFooter->GetString(3);
|
string position = wFooter->GetString(3);
|
||||||
int newpos = StrToInt(position);
|
int newpos = StrToInt(position);
|
||||||
if (newpos > 0 && newpos < 100 && !position.empty())
|
if (newpos > 0 && newpos < 100 && !position.empty())
|
||||||
Mpd->Seek(myPlaylist->NowPlayingSong().GetTotalLength()*newpos/100.0);
|
Mpd->Seek(s.GetTotalLength()*newpos/100.0);
|
||||||
UnlockStatusbar();
|
UnlockStatusbar();
|
||||||
}
|
}
|
||||||
else if (Keypressed(input, Key.ReverseSelection))
|
else if (Keypressed(input, Key.ReverseSelection))
|
||||||
@@ -1317,6 +1366,11 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
else if (Keypressed(input, Key.Crop))
|
else if (Keypressed(input, Key.Crop))
|
||||||
{
|
{
|
||||||
|
if (myPlaylist->Main()->isFiltered())
|
||||||
|
{
|
||||||
|
ShowMessage("%s", MPD::Message::FunctionDisabledFilteringEnabled);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (myPlaylist->Main()->hasSelected())
|
if (myPlaylist->Main()->hasSelected())
|
||||||
{
|
{
|
||||||
for (int i = myPlaylist->Main()->Size()-1; i >= 0; i--)
|
for (int i = myPlaylist->Main()->Size()-1; i >= 0; i--)
|
||||||
@@ -1354,6 +1408,34 @@ int main(int argc, char *argv[])
|
|||||||
Mpd->ClearPlaylist();
|
Mpd->ClearPlaylist();
|
||||||
ShowMessage("Cleared playlist!");
|
ShowMessage("Cleared playlist!");
|
||||||
}
|
}
|
||||||
|
else if (Keypressed(input, Key.ApplyFilter))
|
||||||
|
{
|
||||||
|
List *mList = myScreen->GetList();
|
||||||
|
|
||||||
|
if (!mList)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CLEAR_FIND_HISTORY;
|
||||||
|
|
||||||
|
LockStatusbar();
|
||||||
|
Statusbar() << fmtBold << "Apply filter: " << fmtBoldEnd;
|
||||||
|
wFooter->SetGetStringHelper(StatusbarApplyFilterImmediately);
|
||||||
|
wFooter->GetString(mList->GetFilter());
|
||||||
|
wFooter->SetGetStringHelper(StatusbarGetStringHelper);
|
||||||
|
UnlockStatusbar();
|
||||||
|
|
||||||
|
if (mList->isFiltered())
|
||||||
|
ShowMessage("Using filter '%s'", mList->GetFilter().c_str());
|
||||||
|
else
|
||||||
|
ShowMessage("Filtering disabled");
|
||||||
|
|
||||||
|
if (myScreen == myPlaylist)
|
||||||
|
{
|
||||||
|
timer = time(NULL);
|
||||||
|
myPlaylist->Main()->Highlighting(1);
|
||||||
|
redraw_header = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (Keypressed(input, Key.FindForward) || Keypressed(input, Key.FindBackward))
|
else if (Keypressed(input, Key.FindForward) || Keypressed(input, Key.FindBackward))
|
||||||
{
|
{
|
||||||
List *mList = myScreen->GetList();
|
List *mList = myScreen->GetList();
|
||||||
@@ -1376,103 +1458,7 @@ int main(int argc, char *argv[])
|
|||||||
ShowMessage("Searching...");
|
ShowMessage("Searching...");
|
||||||
for (size_t i = (myScreen == mySearcher ? SearchEngine::StaticOptions : 0); i < mList->Size(); i++)
|
for (size_t i = (myScreen == mySearcher ? SearchEngine::StaticOptions : 0); i < mList->Size(); i++)
|
||||||
{
|
{
|
||||||
string name;
|
string name = mList->GetOption(i);
|
||||||
if (myScreen == myPlaylist)
|
|
||||||
{
|
|
||||||
name = myPlaylist->Main()->at(i).toString(Config.song_list_format);
|
|
||||||
}
|
|
||||||
else if (myScreen == myBrowser)
|
|
||||||
{
|
|
||||||
switch (myBrowser->Main()->at(i).type)
|
|
||||||
{
|
|
||||||
case itDirectory:
|
|
||||||
name = ExtractTopDirectory(myBrowser->Main()->at(i).name);
|
|
||||||
break;
|
|
||||||
case itSong:
|
|
||||||
name = myBrowser->Main()->at(i).song->toString(Config.song_list_format);
|
|
||||||
break;
|
|
||||||
case itPlaylist:
|
|
||||||
name = Config.browser_playlist_prefix.Str();
|
|
||||||
name += myBrowser->Main()->at(i).name;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (myScreen == mySearcher)
|
|
||||||
{
|
|
||||||
name = mySearcher->Main()->at(i).second->toString(Config.song_list_format);
|
|
||||||
}
|
|
||||||
else if (myScreen == myLibrary)
|
|
||||||
{
|
|
||||||
if (myScreen->Cmp() == myLibrary->Artists)
|
|
||||||
name = myLibrary->Artists->at(i);
|
|
||||||
else if (myScreen->Cmp() == myLibrary->Albums)
|
|
||||||
name = myLibrary->Albums->at(i).first;
|
|
||||||
else
|
|
||||||
name = myLibrary->Songs->at(i).toString(Config.song_library_format);
|
|
||||||
}
|
|
||||||
else if (myScreen == myPlaylistEditor)
|
|
||||||
{
|
|
||||||
if (myScreen->Cmp() == myPlaylistEditor->Playlists)
|
|
||||||
name = myPlaylistEditor->Playlists->at(i);
|
|
||||||
else
|
|
||||||
name = myPlaylistEditor->Content->at(i).toString(Config.song_list_format);
|
|
||||||
}
|
|
||||||
# ifdef HAVE_TAGLIB_H
|
|
||||||
else if (myScreen == myTagEditor)
|
|
||||||
{
|
|
||||||
if (myScreen->Cmp() == myTagEditor->LeftColumn)
|
|
||||||
name = myTagEditor->LeftColumn->at(i).first;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const Song &s = myTagEditor->Tags->at(i);
|
|
||||||
switch (myTagEditor->TagTypes->Choice())
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
name = s.GetTitle();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
name = s.GetArtist();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
name = s.GetAlbum();
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
name = s.GetYear();
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
name = s.GetTrack();
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
name = s.GetGenre();
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
name = s.GetComposer();
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
name = s.GetPerformer();
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
name = s.GetDisc();
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
name = s.GetComment();
|
|
||||||
break;
|
|
||||||
case 11:
|
|
||||||
if (s.GetNewName().empty())
|
|
||||||
name = s.GetName();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = s.GetName();
|
|
||||||
name += " -> ";
|
|
||||||
name += s.GetNewName();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# endif // HAVE_TAGLIB_H
|
|
||||||
ToLower(name);
|
ToLower(name);
|
||||||
if (name.find(findme) != string::npos && !mList->isStatic(i))
|
if (name.find(findme) != string::npos && !mList->isStatic(i))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ void Playlist::Init()
|
|||||||
w->SetSelectSuffix(&Config.selected_item_suffix);
|
w->SetSelectSuffix(&Config.selected_item_suffix);
|
||||||
w->SetItemDisplayer(Config.columns_in_playlist ? Display::SongsInColumns : Display::Songs);
|
w->SetItemDisplayer(Config.columns_in_playlist ? Display::SongsInColumns : Display::Songs);
|
||||||
w->SetItemDisplayerUserData(Config.columns_in_playlist ? &Config.song_columns_list_format : &Config.song_list_format);
|
w->SetItemDisplayerUserData(Config.columns_in_playlist ? &Config.song_columns_list_format : &Config.song_list_format);
|
||||||
|
w->SetGetStringFunction(Config.columns_in_playlist ? SongInColumnsToString : SongToString);
|
||||||
|
w->SetGetStringFunctionUserData(Config.columns_in_playlist ? &Config.song_columns_list_format : &Config.song_list_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Playlist::SwitchTo()
|
void Playlist::SwitchTo()
|
||||||
@@ -56,6 +58,7 @@ void Playlist::SwitchTo()
|
|||||||
|
|
||||||
CLEAR_FIND_HISTORY;
|
CLEAR_FIND_HISTORY;
|
||||||
myScreen = this;
|
myScreen = this;
|
||||||
|
w->Window::Clear();
|
||||||
redraw_header = 1;
|
redraw_header = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +118,15 @@ std::string Playlist::TotalLength()
|
|||||||
|
|
||||||
result << '(' << w->Size() << (w->Size() == 1 ? " item" : " items");
|
result << '(' << w->Size() << (w->Size() == 1 ? " item" : " items");
|
||||||
|
|
||||||
|
if (w->isFiltered())
|
||||||
|
{
|
||||||
|
w->ShowAll();
|
||||||
|
size_t real_size = w->Size();
|
||||||
|
w->ShowFiltered();
|
||||||
|
if (w->Size() != real_size)
|
||||||
|
result << " (out of " << Mpd->GetPlaylistLength() << ")";
|
||||||
|
}
|
||||||
|
|
||||||
if (length)
|
if (length)
|
||||||
{
|
{
|
||||||
result << ", length: ";
|
result << ", length: ";
|
||||||
@@ -162,3 +174,22 @@ const MPD::Song &Playlist::NowPlayingSong()
|
|||||||
static MPD::Song null;
|
static MPD::Song null;
|
||||||
return isPlaying() ? w->at(NowPlaying) : null;
|
return isPlaying() ? w->at(NowPlaying) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Playlist::SongToString(const MPD::Song &s, void *data)
|
||||||
|
{
|
||||||
|
return s.toString(*static_cast<std::string *>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Playlist::SongInColumnsToString(const MPD::Song &s, void *data)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
std::string fmt = *static_cast<std::string *>(data);
|
||||||
|
for (std::string i = GetLineValue(fmt, '{', '}', 1); !i.empty(); i = GetLineValue(fmt, '{', '}', 1))
|
||||||
|
{
|
||||||
|
result += "%";
|
||||||
|
result += i;
|
||||||
|
result += " ";
|
||||||
|
}
|
||||||
|
return s.toString(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,11 +46,16 @@ class Playlist : public Screen< Menu<MPD::Song> >
|
|||||||
virtual void ReverseSelection() { w->ReverseSelection(); }
|
virtual void ReverseSelection() { w->ReverseSelection(); }
|
||||||
virtual void GetSelectedSongs(MPD::SongList &);
|
virtual void GetSelectedSongs(MPD::SongList &);
|
||||||
|
|
||||||
|
virtual void ApplyFilter(const std::string &s) { w->ApplyFilter(s); }
|
||||||
|
|
||||||
virtual List *GetList() { return w; }
|
virtual List *GetList() { return w; }
|
||||||
|
|
||||||
bool isPlaying() { return NowPlaying >= 0 && !w->Empty(); }
|
bool isPlaying() { return NowPlaying >= 0 && !w->Empty(); }
|
||||||
const MPD::Song &NowPlayingSong();
|
const MPD::Song &NowPlayingSong();
|
||||||
|
|
||||||
|
static std::string SongToString(const MPD::Song &, void *);
|
||||||
|
static std::string SongInColumnsToString(const MPD::Song &, void *);
|
||||||
|
|
||||||
int NowPlaying;
|
int NowPlaying;
|
||||||
int OldPlaying;
|
int OldPlaying;
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ void PlaylistEditor::Init()
|
|||||||
Content->SetSelectSuffix(&Config.selected_item_suffix);
|
Content->SetSelectSuffix(&Config.selected_item_suffix);
|
||||||
Content->SetItemDisplayer(Display::Songs);
|
Content->SetItemDisplayer(Display::Songs);
|
||||||
Content->SetItemDisplayerUserData(&Config.song_list_format);
|
Content->SetItemDisplayerUserData(&Config.song_list_format);
|
||||||
|
Content->SetGetStringFunction(Playlist::SongToString);
|
||||||
|
Content->SetGetStringFunctionUserData(&Config.song_list_format);
|
||||||
|
|
||||||
w = Playlists;
|
w = Playlists;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ class PlaylistEditor : public Screen<Window>
|
|||||||
virtual void ReverseSelection() { Content->ReverseSelection(); }
|
virtual void ReverseSelection() { Content->ReverseSelection(); }
|
||||||
virtual void GetSelectedSongs(MPD::SongList &);
|
virtual void GetSelectedSongs(MPD::SongList &);
|
||||||
|
|
||||||
|
virtual void ApplyFilter(const std::string &s) { GetList()->ApplyFilter(s); }
|
||||||
|
|
||||||
virtual List *GetList();
|
virtual List *GetList();
|
||||||
|
|
||||||
void NextColumn();
|
void NextColumn();
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ class BasicScreen
|
|||||||
virtual void ReverseSelection() { }
|
virtual void ReverseSelection() { }
|
||||||
virtual void GetSelectedSongs(MPD::SongList &) { }
|
virtual void GetSelectedSongs(MPD::SongList &) { }
|
||||||
|
|
||||||
|
virtual void ApplyFilter(const std::string &) { }
|
||||||
|
|
||||||
virtual List *GetList() = 0;
|
virtual List *GetList() = 0;
|
||||||
|
|
||||||
bool hasToBeResized;
|
bool hasToBeResized;
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ void SearchEngine::Init()
|
|||||||
w->SetItemDisplayer(Display::SearchEngine);
|
w->SetItemDisplayer(Display::SearchEngine);
|
||||||
w->SetSelectPrefix(&Config.selected_item_prefix);
|
w->SetSelectPrefix(&Config.selected_item_prefix);
|
||||||
w->SetSelectSuffix(&Config.selected_item_suffix);
|
w->SetSelectSuffix(&Config.selected_item_suffix);
|
||||||
|
w->SetGetStringFunction(SearchEngineOptionToString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchEngine::Resize()
|
void SearchEngine::Resize()
|
||||||
@@ -552,3 +553,11 @@ void SearchEngine::Search()
|
|||||||
FreeSongList(list);
|
FreeSongList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string SearchEngine::SearchEngineOptionToString(const std::pair<Buffer *, MPD::Song *> &pair, void *)
|
||||||
|
{
|
||||||
|
if (!Config.columns_in_search_engine)
|
||||||
|
return pair.second->toString(Config.song_list_format);
|
||||||
|
else
|
||||||
|
return Playlist::SongInColumnsToString(*pair.second, &Config.song_columns_list_format);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ class SearchEngine : public Screen< Menu< std::pair<Buffer *, MPD::Song *> > >
|
|||||||
virtual void ReverseSelection() { w->ReverseSelection(StaticOptions); }
|
virtual void ReverseSelection() { w->ReverseSelection(StaticOptions); }
|
||||||
virtual void GetSelectedSongs(MPD::SongList &);
|
virtual void GetSelectedSongs(MPD::SongList &);
|
||||||
|
|
||||||
virtual List *GetList() { return w; }
|
virtual void ApplyFilter(const std::string &s) { w->ApplyFilter(s, StaticOptions); }
|
||||||
|
|
||||||
|
virtual List *GetList() { return w->Size() >= StaticOptions ? w : 0; }
|
||||||
|
|
||||||
void UpdateFoundList();
|
void UpdateFoundList();
|
||||||
|
|
||||||
@@ -70,6 +72,8 @@ class SearchEngine : public Screen< Menu< std::pair<Buffer *, MPD::Song *> > >
|
|||||||
void Prepare();
|
void Prepare();
|
||||||
void Search();
|
void Search();
|
||||||
|
|
||||||
|
static std::string SearchEngineOptionToString(const std::pair<Buffer *, MPD::Song *> &, void *);
|
||||||
|
|
||||||
SearchPattern itsPattern;
|
SearchPattern itsPattern;
|
||||||
|
|
||||||
static bool MatchToPattern;
|
static bool MatchToPattern;
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ void DefaultKeys(ncmpcpp_keys &keys)
|
|||||||
keys.ToggleCrossfade[0] = 'x';
|
keys.ToggleCrossfade[0] = 'x';
|
||||||
keys.SetCrossfade[0] = 'X';
|
keys.SetCrossfade[0] = 'X';
|
||||||
keys.UpdateDB[0] = 'u';
|
keys.UpdateDB[0] = 'u';
|
||||||
|
keys.ApplyFilter[0] = 6;
|
||||||
keys.FindForward[0] = '/';
|
keys.FindForward[0] = '/';
|
||||||
keys.FindBackward[0] = '?';
|
keys.FindBackward[0] = '?';
|
||||||
keys.NextFoundPosition[0] = '.';
|
keys.NextFoundPosition[0] = '.';
|
||||||
@@ -181,6 +182,7 @@ void DefaultKeys(ncmpcpp_keys &keys)
|
|||||||
keys.ToggleCrossfade[1] = null_key;
|
keys.ToggleCrossfade[1] = null_key;
|
||||||
keys.SetCrossfade[1] = null_key;
|
keys.SetCrossfade[1] = null_key;
|
||||||
keys.UpdateDB[1] = null_key;
|
keys.UpdateDB[1] = null_key;
|
||||||
|
keys.ApplyFilter[1] = null_key;
|
||||||
keys.FindForward[1] = null_key;
|
keys.FindForward[1] = null_key;
|
||||||
keys.FindBackward[1] = null_key;
|
keys.FindBackward[1] = null_key;
|
||||||
keys.NextFoundPosition[1] = null_key;
|
keys.NextFoundPosition[1] = null_key;
|
||||||
@@ -354,6 +356,8 @@ void ReadKeys(ncmpcpp_keys &keys)
|
|||||||
GetKeys(key, keys.SetCrossfade);
|
GetKeys(key, keys.SetCrossfade);
|
||||||
else if (key.find("key_update_db ") != string::npos)
|
else if (key.find("key_update_db ") != string::npos)
|
||||||
GetKeys(key, keys.UpdateDB);
|
GetKeys(key, keys.UpdateDB);
|
||||||
|
else if (key.find("key_apply_filter ") != string::npos)
|
||||||
|
GetKeys(key, keys.ApplyFilter);
|
||||||
else if (key.find("key_find_forward ") != string::npos)
|
else if (key.find("key_find_forward ") != string::npos)
|
||||||
GetKeys(key, keys.FindForward);
|
GetKeys(key, keys.FindForward);
|
||||||
else if (key.find("key_find_backward ") != string::npos)
|
else if (key.find("key_find_backward ") != string::npos)
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ struct ncmpcpp_keys
|
|||||||
int ToggleCrossfade[2];
|
int ToggleCrossfade[2];
|
||||||
int SetCrossfade[2];
|
int SetCrossfade[2];
|
||||||
int UpdateDB[2];
|
int UpdateDB[2];
|
||||||
|
int ApplyFilter[2];
|
||||||
int FindForward[2];
|
int FindForward[2];
|
||||||
int FindBackward[2];
|
int FindBackward[2];
|
||||||
int NextFoundPosition[2];
|
int NextFoundPosition[2];
|
||||||
|
|||||||
@@ -61,6 +61,18 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StatusbarGetStringHelper(const std::wstring &)
|
||||||
|
{
|
||||||
|
TraceMpdStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusbarApplyFilterImmediately(const std::wstring &ws)
|
||||||
|
{
|
||||||
|
myScreen->ApplyFilter(ToString(ws));
|
||||||
|
myScreen->RefreshWindow();
|
||||||
|
TraceMpdStatus();
|
||||||
|
}
|
||||||
|
|
||||||
void LockStatusbar()
|
void LockStatusbar()
|
||||||
{
|
{
|
||||||
if (Config.statusbar_visibility)
|
if (Config.statusbar_visibility)
|
||||||
@@ -130,7 +142,7 @@ void NcmpcppErrorCallback(Connection *Mpd, int errorid, const char *msg, void *)
|
|||||||
Mpd->SetPassword(password);
|
Mpd->SetPassword(password);
|
||||||
Mpd->SendPassword();
|
Mpd->SendPassword();
|
||||||
Mpd->UpdateStatus();
|
Mpd->UpdateStatus();
|
||||||
wFooter->SetGetStringHelper(TraceMpdStatus);
|
wFooter->SetGetStringHelper(StatusbarGetStringHelper);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ShowMessage("%s", msg);
|
ShowMessage("%s", msg);
|
||||||
@@ -161,6 +173,8 @@ void NcmpcppStatusChanged(Connection *Mpd, StatusChanges changed, void *)
|
|||||||
{
|
{
|
||||||
if (!Playlist::BlockUpdate)
|
if (!Playlist::BlockUpdate)
|
||||||
{
|
{
|
||||||
|
bool was_filtered = myPlaylist->Main()->isFiltered();
|
||||||
|
myPlaylist->Main()->ShowAll();
|
||||||
SongList list;
|
SongList list;
|
||||||
size_t playlist_length = Mpd->GetPlaylistLength();
|
size_t playlist_length = Mpd->GetPlaylistLength();
|
||||||
if (playlist_length != myPlaylist->Main()->Size())
|
if (playlist_length != myPlaylist->Main()->Size())
|
||||||
@@ -212,6 +226,8 @@ void NcmpcppStatusChanged(Connection *Mpd, StatusChanges changed, void *)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (was_filtered)
|
||||||
|
myPlaylist->ApplyFilter(myPlaylist->Main()->GetFilter());
|
||||||
FreeSongList(list);
|
FreeSongList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,7 +332,7 @@ void NcmpcppStatusChanged(Connection *Mpd, StatusChanges changed, void *)
|
|||||||
}
|
}
|
||||||
catch (std::out_of_range &) { }
|
catch (std::out_of_range &) { }
|
||||||
myPlaylist->Main()->BoldOption(myPlaylist->NowPlaying, 1);
|
myPlaylist->Main()->BoldOption(myPlaylist->NowPlaying, 1);
|
||||||
if (Config.autocenter_mode)
|
if (Config.autocenter_mode && !myPlaylist->Main()->isFiltered())
|
||||||
myPlaylist->Main()->Highlight(myPlaylist->NowPlaying);
|
myPlaylist->Main()->Highlight(myPlaylist->NowPlaying);
|
||||||
repeat_one_allowed = 0;
|
repeat_one_allowed = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -34,5 +34,8 @@ void NcmpcppErrorCallback(MPD::Connection *, int, const char *, void *);
|
|||||||
Window &Statusbar();
|
Window &Statusbar();
|
||||||
void ShowMessage(const char *, ...);
|
void ShowMessage(const char *, ...);
|
||||||
|
|
||||||
|
void StatusbarGetStringHelper(const std::wstring &);
|
||||||
|
void StatusbarApplyFilterImmediately(const std::wstring &);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -304,11 +304,14 @@ void TagEditor::Init()
|
|||||||
Albums->HighlightColor(Config.active_column_color);
|
Albums->HighlightColor(Config.active_column_color);
|
||||||
Albums->SetTimeout(ncmpcpp_window_timeout);
|
Albums->SetTimeout(ncmpcpp_window_timeout);
|
||||||
Albums->SetItemDisplayer(Display::StringPairs);
|
Albums->SetItemDisplayer(Display::StringPairs);
|
||||||
|
Albums->SetGetStringFunction(MediaLibrary::StringPairToString);
|
||||||
|
|
||||||
Dirs = new Menu<string_pair>(0, main_start_y, LeftColumnWidth, main_height, "Directories", Config.main_color, brNone);
|
Dirs = new Menu<string_pair>(0, main_start_y, LeftColumnWidth, main_height, "Directories", Config.main_color, brNone);
|
||||||
Dirs->HighlightColor(Config.active_column_color);
|
Dirs->HighlightColor(Config.active_column_color);
|
||||||
Dirs->SetTimeout(ncmpcpp_window_timeout);
|
Dirs->SetTimeout(ncmpcpp_window_timeout);
|
||||||
Dirs->SetItemDisplayer(Display::StringPairs);
|
Dirs->SetItemDisplayer(Display::StringPairs);
|
||||||
|
Dirs->SetGetStringFunction(MediaLibrary::StringPairToString);
|
||||||
|
|
||||||
LeftColumn = Config.albums_in_tag_editor ? Albums : Dirs;
|
LeftColumn = Config.albums_in_tag_editor ? Albums : Dirs;
|
||||||
|
|
||||||
TagTypes = new Menu<string>(MiddleColumnStartX, main_start_y, MiddleColumnWidth, main_height, "Tag types", Config.main_color, brNone);
|
TagTypes = new Menu<string>(MiddleColumnStartX, main_start_y, MiddleColumnWidth, main_height, "Tag types", Config.main_color, brNone);
|
||||||
@@ -323,6 +326,8 @@ void TagEditor::Init()
|
|||||||
Tags->SetSelectSuffix(&Config.selected_item_suffix);
|
Tags->SetSelectSuffix(&Config.selected_item_suffix);
|
||||||
Tags->SetItemDisplayer(Display::Tags);
|
Tags->SetItemDisplayer(Display::Tags);
|
||||||
Tags->SetItemDisplayerUserData(TagTypes);
|
Tags->SetItemDisplayerUserData(TagTypes);
|
||||||
|
Tags->SetGetStringFunction(TagToString);
|
||||||
|
Tags->SetGetStringFunctionUserData(TagTypes);
|
||||||
|
|
||||||
w = LeftColumn;
|
w = LeftColumn;
|
||||||
}
|
}
|
||||||
@@ -734,6 +739,16 @@ void TagEditor::GetSelectedSongs(MPD::SongList &v)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TagEditor::ApplyFilter(const std::string &s)
|
||||||
|
{
|
||||||
|
if (w == Dirs)
|
||||||
|
Dirs->ApplyFilter(s, 1);
|
||||||
|
else if (w == Albums)
|
||||||
|
Albums->ApplyFilter(s);
|
||||||
|
else if (w == Tags)
|
||||||
|
Tags->ApplyFilter(s);
|
||||||
|
}
|
||||||
|
|
||||||
List *TagEditor::GetList()
|
List *TagEditor::GetList()
|
||||||
{
|
{
|
||||||
if (w == LeftColumn)
|
if (w == LeftColumn)
|
||||||
@@ -961,6 +976,53 @@ void TagEditor::LowerAllLetters(Song &s)
|
|||||||
s.SetComment(conv);
|
s.SetComment(conv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string TagEditor::TagToString(const MPD::Song &s, void *data)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
switch (static_cast<Menu<string> *>(data)->Choice())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
result = s.GetTitle();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
result = s.GetArtist();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
result = s.GetAlbum();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
result = s.GetYear();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
result = s.GetTrack();
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
result = s.GetGenre();
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
result = s.GetComposer();
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
result = s.GetPerformer();
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
result = s.GetDisc();
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
result = s.GetComment();
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
if (s.GetNewName().empty())
|
||||||
|
result = s.GetName();
|
||||||
|
else
|
||||||
|
result = s.GetName() + " -> " + s.GetNewName();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result.empty() ? Config.empty_tag : result;
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const string patterns_list_file = config_dir + "patterns.list";
|
const string patterns_list_file = config_dir + "patterns.list";
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ extern TinyTagEditor *myTinyTagEditor;
|
|||||||
class TagEditor : public Screen<Window>
|
class TagEditor : public Screen<Window>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
TagEditor() : itsBrowsedDir("/") { }
|
||||||
|
|
||||||
virtual void Init();
|
virtual void Init();
|
||||||
virtual void Resize();
|
virtual void Resize();
|
||||||
virtual void SwitchTo();
|
virtual void SwitchTo();
|
||||||
@@ -78,6 +80,8 @@ class TagEditor : public Screen<Window>
|
|||||||
virtual void ReverseSelection() { Tags->ReverseSelection(); }
|
virtual void ReverseSelection() { Tags->ReverseSelection(); }
|
||||||
virtual void GetSelectedSongs(MPD::SongList &);
|
virtual void GetSelectedSongs(MPD::SongList &);
|
||||||
|
|
||||||
|
virtual void ApplyFilter(const std::string &);
|
||||||
|
|
||||||
virtual List *GetList();
|
virtual List *GetList();
|
||||||
|
|
||||||
void NextColumn();
|
void NextColumn();
|
||||||
@@ -99,6 +103,8 @@ class TagEditor : public Screen<Window>
|
|||||||
static void CapitalizeFirstLetters(MPD::Song &);
|
static void CapitalizeFirstLetters(MPD::Song &);
|
||||||
static void LowerAllLetters(MPD::Song &);
|
static void LowerAllLetters(MPD::Song &);
|
||||||
|
|
||||||
|
static std::string TagToString(const MPD::Song &, void *);
|
||||||
|
|
||||||
std::string itsBrowsedDir;
|
std::string itsBrowsedDir;
|
||||||
std::string itsHighlightedDir;
|
std::string itsHighlightedDir;
|
||||||
|
|
||||||
|
|||||||
@@ -424,7 +424,7 @@ string Window::GetString(const string &base, size_t length, size_t width, bool e
|
|||||||
mvwhline(itsWindow, y, minx, '*', maxx-minx);
|
mvwhline(itsWindow, y, minx, '*', maxx-minx);
|
||||||
|
|
||||||
if (itsGetStringHelper)
|
if (itsGetStringHelper)
|
||||||
itsGetStringHelper();
|
itsGetStringHelper(tmp);
|
||||||
|
|
||||||
wmove(itsWindow, y, x);
|
wmove(itsWindow, y, x);
|
||||||
input = wgetch(itsWindow);
|
input = wgetch(itsWindow);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ enum Format { fmtNone = 100, fmtBold, fmtBoldEnd, fmtReverse, fmtReverseEnd, fmt
|
|||||||
enum Border { brNone, brBlack, brRed, brGreen, brYellow, brBlue, brMagenta, brCyan, brWhite };
|
enum Border { brNone, brBlack, brRed, brGreen, brYellow, brBlue, brMagenta, brCyan, brWhite };
|
||||||
enum Where { wUp, wDown, wPageUp, wPageDown, wHome, wEnd };
|
enum Where { wUp, wDown, wPageUp, wPageDown, wHome, wEnd };
|
||||||
|
|
||||||
typedef void (*GetStringHelper)();
|
typedef void (*GetStringHelper)(const std::wstring &);
|
||||||
|
|
||||||
void InitScreen(bool);
|
void InitScreen(bool);
|
||||||
void DestroyScreen();
|
void DestroyScreen();
|
||||||
|
|||||||
Reference in New Issue
Block a user