diff --git a/doc/config b/doc/config index bcef80e7..db914f77 100644 --- a/doc/config +++ b/doc/config @@ -208,12 +208,21 @@ ## - r - column will be right aligned ## - E - if tag is empty, empty tag marker won't be displayed ## -## You can also 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". +## You can also: +## +## - 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 ##### # diff --git a/src/display.cpp b/src/display.cpp index c934857c..8dcc6076 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -28,7 +28,7 @@ std::string Display::Columns() if (Config.columns.empty()) return ""; - std::basic_string result, tag; + std::basic_string result; size_t where = 0; int width; @@ -46,57 +46,63 @@ std::string Display::Columns() else width = it->width*(it->fixed ? 1 : COLS/100.0); - if (it->name.empty()) + std::basic_string tag; + if (it->type.length() >= 1 && it->name.empty()) { - switch (it->type) + for (size_t j = 0; j < it->type.length(); ++j) { - case 'l': - tag = U("Time"); - break; - case 'f': - tag = U("Filename"); - break; - case 'D': - tag = U("Directory"); - break; - case 'a': - tag = U("Artist"); - break; - case 'A': - tag = U("Album Artist"); - break; - case 't': - tag = U("Title"); - break; - case 'b': - tag = U("Album"); - break; - case 'y': - tag = U("Year"); - break; - case 'n': - case 'N': - tag = U("Track"); - break; - case 'g': - tag = U("Genre"); - break; - case 'c': - tag = U("Composer"); - break; - case 'p': - tag = U("Performer"); - break; - case 'd': - tag = U("Disc"); - break; - case 'C': - tag = U("Comment"); - break; - default: - tag.clear(); - break; + switch (it->type[j]) + { + case 'l': + tag += U("Time"); + break; + case 'f': + tag += U("Filename"); + break; + case 'D': + tag += U("Directory"); + break; + case 'a': + tag += U("Artist"); + break; + case 'A': + tag += U("Album Artist"); + break; + case 't': + tag += U("Title"); + break; + case 'b': + tag += U("Album"); + break; + case 'y': + tag += U("Year"); + break; + case 'n': + case 'N': + tag += U("Track"); + break; + case 'g': + tag += U("Genre"); + break; + case 'c': + tag += U("Composer"); + break; + case 'p': + tag += U("Performer"); + break; + case 'd': + tag += U("Disc"); + break; + case 'C': + tag += U("Comment"); + break; + default: + tag += U("?"); + break; + } + tag += '/'; } + tag.resize(tag.length()-1); } else tag = it->name; @@ -169,63 +175,66 @@ void Display::SongsInColumns(const MPD::Song &s, void *, Menu *menu) MPD::Song::GetFunction get = 0; - switch (it->type) + std::string tag; + for (size_t i = 0; i < it->type.length(); ++i) { - case 'l': - get = &MPD::Song::GetLength; - break; - case 'D': - get = &MPD::Song::GetDirectory; - break; - case 'f': - get = &MPD::Song::GetName; - break; - 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 + switch (it->type[i]) + { + case 'l': + get = &MPD::Song::GetLength; + break; + case 'D': + get = &MPD::Song::GetDirectory; + break; + case 'f': get = &MPD::Song::GetName; - break; - default: + break; + 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; } if (!discard_colors && it->color != clDefault) *menu << it->color; 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 if (it == last) diff --git a/src/helpers.cpp b/src/helpers.cpp index 9e1893d5..56a5a412 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -356,7 +356,7 @@ std::string GetLineValue(std::string &line, char a, char b, bool once) ++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[] = " "; r1[1] = r2[0] = a; Replace(result, r1, r2); diff --git a/src/playlist.cpp b/src/playlist.cpp index ebf9d9fc..8806a630 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -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 result = "{"; - for (std::vector::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); + return s.toString(Config.song_in_columns_to_string_format); } bool Playlist::Add(const MPD::Song &s, bool in_playlist, bool play, int position) diff --git a/src/settings.cpp b/src/settings.cpp index 7e23eadb..12598d24 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1149,13 +1149,7 @@ void NcmpcppConfig::Read() Column col; col.color = IntoColor(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'; // alternative name @@ -1166,20 +1160,51 @@ void NcmpcppConfig::Read() 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) - { - case 'r': - col.right_alignment = 1; - break; - case 'E': - col.display_empty_tag = 0; - break; + 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) + { + switch (tag_type[i]) + { + case 'r': + col.right_alignment = 1; + break; + case 'E': + col.display_empty_tag = 0; + break; + } } } + else // empty column + col.display_empty_tag = 0; + col.width = StrToInt(width); 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::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() = '}'; } diff --git a/src/settings.h b/src/settings.h index f9264f6e..bf078b88 100644 --- a/src/settings.h +++ b/src/settings.h @@ -43,9 +43,9 @@ struct Column Column() : right_alignment(0), display_empty_tag(1) { } std::basic_string name; + std::string type; unsigned width; Color color; - char type; bool fixed; bool right_alignment; bool display_empty_tag; @@ -157,6 +157,7 @@ struct NcmpcppConfig std::string song_window_title_format; std::string song_library_format; std::string tag_editor_album_format; + std::string song_in_columns_to_string_format; std::string external_editor; std::string system_encoding; std::string execute_on_song_change;