new feature: support for multiple tag types in one column
This commit is contained in:
17
doc/config
17
doc/config
@@ -208,12 +208,21 @@
|
|||||||
## - r - column will be right aligned
|
## - r - column will be right aligned
|
||||||
## - E - if tag is empty, empty tag marker won't be displayed
|
## - E - if tag is empty, empty tag marker won't be displayed
|
||||||
##
|
##
|
||||||
## You can also give a column custom name by putting it after
|
## You can also:
|
||||||
## attributes, separated with character ':', e.g. {lr:Length}
|
##
|
||||||
## gives you right aligned column of lengths named "Length".
|
## - give a column custom name by putting it after attributes,
|
||||||
|
## separated with character ':', e.g. {lr:Length} gives you
|
||||||
|
## right aligned column of lengths named "Length".
|
||||||
|
##
|
||||||
|
## - define sequence of tags, that have to be displayed in case
|
||||||
|
## predecessor is empty in a way similar to the one in classic
|
||||||
|
## song format, i.e. using '|' character, e.g. {a|c|p:Owner}
|
||||||
|
## creates column named "Owner" that tries to display artist
|
||||||
|
## tag and then composer and performer if previous ones are
|
||||||
|
## not available.
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
#song_columns_list_format = "(7f)[green]{l} (25)[cyan]{a} (40)[]{t} (30)[red]{b}"
|
#song_columns_list_format = "(7f)[green]{l} (25)[cyan]{a} (40)[]{t|f} (30)[red]{b}"
|
||||||
#
|
#
|
||||||
##### various settings #####
|
##### various settings #####
|
||||||
#
|
#
|
||||||
|
|||||||
207
src/display.cpp
207
src/display.cpp
@@ -28,7 +28,7 @@ std::string Display::Columns()
|
|||||||
if (Config.columns.empty())
|
if (Config.columns.empty())
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
std::basic_string<my_char_t> result, tag;
|
std::basic_string<my_char_t> result;
|
||||||
size_t where = 0;
|
size_t where = 0;
|
||||||
int width;
|
int width;
|
||||||
|
|
||||||
@@ -46,57 +46,63 @@ std::string Display::Columns()
|
|||||||
else
|
else
|
||||||
width = it->width*(it->fixed ? 1 : COLS/100.0);
|
width = it->width*(it->fixed ? 1 : COLS/100.0);
|
||||||
|
|
||||||
if (it->name.empty())
|
std::basic_string<my_char_t> tag;
|
||||||
|
if (it->type.length() >= 1 && it->name.empty())
|
||||||
{
|
{
|
||||||
switch (it->type)
|
for (size_t j = 0; j < it->type.length(); ++j)
|
||||||
{
|
{
|
||||||
case 'l':
|
switch (it->type[j])
|
||||||
tag = U("Time");
|
{
|
||||||
break;
|
case 'l':
|
||||||
case 'f':
|
tag += U("Time");
|
||||||
tag = U("Filename");
|
break;
|
||||||
break;
|
case 'f':
|
||||||
case 'D':
|
tag += U("Filename");
|
||||||
tag = U("Directory");
|
break;
|
||||||
break;
|
case 'D':
|
||||||
case 'a':
|
tag += U("Directory");
|
||||||
tag = U("Artist");
|
break;
|
||||||
break;
|
case 'a':
|
||||||
case 'A':
|
tag += U("Artist");
|
||||||
tag = U("Album Artist");
|
break;
|
||||||
break;
|
case 'A':
|
||||||
case 't':
|
tag += U("Album Artist");
|
||||||
tag = U("Title");
|
break;
|
||||||
break;
|
case 't':
|
||||||
case 'b':
|
tag += U("Title");
|
||||||
tag = U("Album");
|
break;
|
||||||
break;
|
case 'b':
|
||||||
case 'y':
|
tag += U("Album");
|
||||||
tag = U("Year");
|
break;
|
||||||
break;
|
case 'y':
|
||||||
case 'n':
|
tag += U("Year");
|
||||||
case 'N':
|
break;
|
||||||
tag = U("Track");
|
case 'n':
|
||||||
break;
|
case 'N':
|
||||||
case 'g':
|
tag += U("Track");
|
||||||
tag = U("Genre");
|
break;
|
||||||
break;
|
case 'g':
|
||||||
case 'c':
|
tag += U("Genre");
|
||||||
tag = U("Composer");
|
break;
|
||||||
break;
|
case 'c':
|
||||||
case 'p':
|
tag += U("Composer");
|
||||||
tag = U("Performer");
|
break;
|
||||||
break;
|
case 'p':
|
||||||
case 'd':
|
tag += U("Performer");
|
||||||
tag = U("Disc");
|
break;
|
||||||
break;
|
case 'd':
|
||||||
case 'C':
|
tag += U("Disc");
|
||||||
tag = U("Comment");
|
break;
|
||||||
break;
|
case 'C':
|
||||||
default:
|
tag += U("Comment");
|
||||||
tag.clear();
|
break;
|
||||||
break;
|
default:
|
||||||
|
tag += U("?");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tag += '/';
|
||||||
}
|
}
|
||||||
|
tag.resize(tag.length()-1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tag = it->name;
|
tag = it->name;
|
||||||
@@ -169,63 +175,66 @@ void Display::SongsInColumns(const MPD::Song &s, void *, Menu<MPD::Song> *menu)
|
|||||||
|
|
||||||
MPD::Song::GetFunction get = 0;
|
MPD::Song::GetFunction get = 0;
|
||||||
|
|
||||||
switch (it->type)
|
std::string tag;
|
||||||
|
for (size_t i = 0; i < it->type.length(); ++i)
|
||||||
{
|
{
|
||||||
case 'l':
|
switch (it->type[i])
|
||||||
get = &MPD::Song::GetLength;
|
{
|
||||||
break;
|
case 'l':
|
||||||
case 'D':
|
get = &MPD::Song::GetLength;
|
||||||
get = &MPD::Song::GetDirectory;
|
break;
|
||||||
break;
|
case 'D':
|
||||||
case 'f':
|
get = &MPD::Song::GetDirectory;
|
||||||
get = &MPD::Song::GetName;
|
break;
|
||||||
break;
|
case 'f':
|
||||||
case 'a':
|
|
||||||
get = &MPD::Song::GetArtist;
|
|
||||||
break;
|
|
||||||
case 'A':
|
|
||||||
get = &MPD::Song::GetAlbumArtist;
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
get = &MPD::Song::GetAlbum;
|
|
||||||
break;
|
|
||||||
case 'y':
|
|
||||||
get = &MPD::Song::GetDate;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
get = &MPD::Song::GetTrackNumber;
|
|
||||||
break;
|
|
||||||
case 'N':
|
|
||||||
get = &MPD::Song::GetTrack;
|
|
||||||
break;
|
|
||||||
case 'g':
|
|
||||||
get = &MPD::Song::GetGenre;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
get = &MPD::Song::GetComposer;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
get = &MPD::Song::GetPerformer;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
get = &MPD::Song::GetDisc;
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
get = &MPD::Song::GetComment;
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
if (!s.GetTitle().empty())
|
|
||||||
get = &MPD::Song::GetTitle;
|
|
||||||
else
|
|
||||||
get = &MPD::Song::GetName;
|
get = &MPD::Song::GetName;
|
||||||
break;
|
break;
|
||||||
default:
|
case 'a':
|
||||||
|
get = &MPD::Song::GetArtist;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
get = &MPD::Song::GetAlbumArtist;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
get = &MPD::Song::GetAlbum;
|
||||||
|
break;
|
||||||
|
case 'y':
|
||||||
|
get = &MPD::Song::GetDate;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
get = &MPD::Song::GetTrackNumber;
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
get = &MPD::Song::GetTrack;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
get = &MPD::Song::GetGenre;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
get = &MPD::Song::GetComposer;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
get = &MPD::Song::GetPerformer;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
get = &MPD::Song::GetDisc;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
get = &MPD::Song::GetComment;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
get = &MPD::Song::GetTitle;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tag = get ? s.GetTags(get) : "";
|
||||||
|
if (!tag.empty())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!discard_colors && it->color != clDefault)
|
if (!discard_colors && it->color != clDefault)
|
||||||
*menu << it->color;
|
*menu << it->color;
|
||||||
whline(menu->Raw(), 32, menu->GetWidth()-where);
|
whline(menu->Raw(), 32, menu->GetWidth()-where);
|
||||||
std::string tag = get ? s.GetTags(get) : "";
|
|
||||||
|
|
||||||
// last column might need to be shrinked to make space for np/sel suffixes
|
// last column might need to be shrinked to make space for np/sel suffixes
|
||||||
if (it == last)
|
if (it == last)
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ std::string GetLineValue(std::string &line, char a, char b, bool once)
|
|||||||
++pos[0];
|
++pos[0];
|
||||||
std::string result = pos[0] >= 0 && pos[1] >= 0 ? line.substr(pos[0], pos[1]-pos[0]) : "";
|
std::string result = pos[0] >= 0 && pos[1] >= 0 ? line.substr(pos[0], pos[1]-pos[0]) : "";
|
||||||
|
|
||||||
// replace \a and \b to a and b respectively
|
// replace \a and \b with a and b respectively
|
||||||
char r1[] = "\\ ", r2[] = " ";
|
char r1[] = "\\ ", r2[] = " ";
|
||||||
r1[1] = r2[0] = a;
|
r1[1] = r2[0] = a;
|
||||||
Replace(result, r1, r2);
|
Replace(result, r1, r2);
|
||||||
|
|||||||
@@ -415,25 +415,7 @@ std::string Playlist::SongToString(const MPD::Song &s, void *data)
|
|||||||
|
|
||||||
std::string Playlist::SongInColumnsToString(const MPD::Song &s, void *)
|
std::string Playlist::SongInColumnsToString(const MPD::Song &s, void *)
|
||||||
{
|
{
|
||||||
std::string result = "{";
|
return s.toString(Config.song_in_columns_to_string_format);
|
||||||
for (std::vector<Column>::const_iterator it = Config.columns.begin(); it != Config.columns.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->type == 't')
|
|
||||||
{
|
|
||||||
result += "{%t}|{%f}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// tags should be put in additional braces as if they are not, the
|
|
||||||
// tag that is not present within 'main' braces discards them all.
|
|
||||||
result += "{%";
|
|
||||||
result += it->type;
|
|
||||||
result += "}";
|
|
||||||
}
|
|
||||||
result += " ";
|
|
||||||
}
|
|
||||||
result += "}";
|
|
||||||
return s.toString(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Playlist::Add(const MPD::Song &s, bool in_playlist, bool play, int position)
|
bool Playlist::Add(const MPD::Song &s, bool in_playlist, bool play, int position)
|
||||||
|
|||||||
@@ -1149,13 +1149,7 @@ void NcmpcppConfig::Read()
|
|||||||
Column col;
|
Column col;
|
||||||
col.color = IntoColor(GetLineValue(song_list_columns_format, '[', ']', 1));
|
col.color = IntoColor(GetLineValue(song_list_columns_format, '[', ']', 1));
|
||||||
std::string tag_type = GetLineValue(song_list_columns_format, '{', '}', 1);
|
std::string tag_type = GetLineValue(song_list_columns_format, '{', '}', 1);
|
||||||
if (tag_type.length() > 0) // at least tag type was specified
|
|
||||||
col.type = tag_type[0];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
col.type = 0;
|
|
||||||
col.display_empty_tag = 0;
|
|
||||||
}
|
|
||||||
col.fixed = *width.rbegin() == 'f';
|
col.fixed = *width.rbegin() == 'f';
|
||||||
|
|
||||||
// alternative name
|
// alternative name
|
||||||
@@ -1166,20 +1160,51 @@ void NcmpcppConfig::Read()
|
|||||||
tag_type.resize(tag_type_colon_pos);
|
tag_type.resize(tag_type_colon_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::string::const_iterator it = tag_type.begin()+(tag_type.length() > 0); it != tag_type.end(); ++it)
|
if (!tag_type.empty())
|
||||||
{
|
{
|
||||||
switch (*it)
|
size_t i = -1;
|
||||||
|
|
||||||
|
// extract tag types in format a|b|c etc.
|
||||||
|
do
|
||||||
|
col.type += tag_type[(++i)++]; // nice one.
|
||||||
|
while (tag_type[i] == '|');
|
||||||
|
|
||||||
|
// apply attributes
|
||||||
|
for (; i < tag_type.length(); ++i)
|
||||||
{
|
{
|
||||||
case 'r':
|
switch (tag_type[i])
|
||||||
col.right_alignment = 1;
|
{
|
||||||
break;
|
case 'r':
|
||||||
case 'E':
|
col.right_alignment = 1;
|
||||||
col.display_empty_tag = 0;
|
break;
|
||||||
break;
|
case 'E':
|
||||||
|
col.display_empty_tag = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else // empty column
|
||||||
|
col.display_empty_tag = 0;
|
||||||
|
|
||||||
col.width = StrToInt(width);
|
col.width = StrToInt(width);
|
||||||
columns.push_back(col);
|
columns.push_back(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate format for converting tags in columns to string for Playlist::SongInColumnsToString()
|
||||||
|
char tag[] = "{% }|";
|
||||||
|
song_in_columns_to_string_format = "{";
|
||||||
|
for (std::vector<Column>::const_iterator it = columns.begin(); it != columns.end(); ++it)
|
||||||
|
{
|
||||||
|
for (std::string::const_iterator j = it->type.begin(); j != it->type.end(); ++j)
|
||||||
|
{
|
||||||
|
tag[2] = *j;
|
||||||
|
song_in_columns_to_string_format += tag;
|
||||||
|
}
|
||||||
|
*song_in_columns_to_string_format.rbegin() = ' ';
|
||||||
|
}
|
||||||
|
if (song_in_columns_to_string_format.length() == 1) // only '{'
|
||||||
|
song_in_columns_to_string_format += '}';
|
||||||
|
else
|
||||||
|
*song_in_columns_to_string_format.rbegin() = '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ struct Column
|
|||||||
Column() : right_alignment(0), display_empty_tag(1) { }
|
Column() : right_alignment(0), display_empty_tag(1) { }
|
||||||
|
|
||||||
std::basic_string<my_char_t> name;
|
std::basic_string<my_char_t> name;
|
||||||
|
std::string type;
|
||||||
unsigned width;
|
unsigned width;
|
||||||
Color color;
|
Color color;
|
||||||
char type;
|
|
||||||
bool fixed;
|
bool fixed;
|
||||||
bool right_alignment;
|
bool right_alignment;
|
||||||
bool display_empty_tag;
|
bool display_empty_tag;
|
||||||
@@ -157,6 +157,7 @@ struct NcmpcppConfig
|
|||||||
std::string song_window_title_format;
|
std::string song_window_title_format;
|
||||||
std::string song_library_format;
|
std::string song_library_format;
|
||||||
std::string tag_editor_album_format;
|
std::string tag_editor_album_format;
|
||||||
|
std::string song_in_columns_to_string_format;
|
||||||
std::string external_editor;
|
std::string external_editor;
|
||||||
std::string system_encoding;
|
std::string system_encoding;
|
||||||
std::string execute_on_song_change;
|
std::string execute_on_song_change;
|
||||||
|
|||||||
Reference in New Issue
Block a user