Configurable Column Widths (#360)

* add configurable column widths

* reorder to match config file

* fix possibly misleading documentation

* fix crash when integer out of bounds

* parse config string during initial processing

* use std::bind with length of list

* fix division by zero error

* use list_of

* change escaped_list_separator variable names
This commit is contained in:
Jinwoo Park
2021-04-26 03:42:56 +10:00
committed by GitHub
parent 22fd919ce4
commit f47cf7f37c
8 changed files with 93 additions and 15 deletions

View File

@@ -465,6 +465,20 @@
# #
#ask_for_locked_screen_width_part = yes #ask_for_locked_screen_width_part = yes
# #
##
## Width of media_library screen columns
##
#
#media_library_column_width_ratio_two = 1:1
#
#media_library_column_width_ratio_three = 1:1:1
#
##
## Width of playlist_editor screen columns
##
#
#playlist_editor_column_width_ratio = 1:2
#
#jump_to_now_playing_song_at_start = yes #jump_to_now_playing_song_at_start = yes
# #
#ask_before_clearing_playlists = yes #ask_before_clearing_playlists = yes

View File

@@ -335,6 +335,15 @@ If you want to lock a screen, ncmpcpp asks for % of locked screen's width to be
.B ask_for_locked_screen_width_part = yes/no .B ask_for_locked_screen_width_part = yes/no
If enabled, ncmpcpp will ask for % of locked screen's width each time you want to lock a screen. If you disable that, it'll silently attempt to use default value. If enabled, ncmpcpp will ask for % of locked screen's width each time you want to lock a screen. If you disable that, it'll silently attempt to use default value.
.TP .TP
.B media_library_column_width_ratio_two = a:b
The ratio of the column widths in the media library, when there are two columns.
.TP
.B media_library_column_width_ratio_three = a:b:c
The ratio of the column widths in the media library, when there are three columns.
.TP
.B playlist_editor_column_width_ratio = a:b
The ratio of the column widths in the playlist editor.
.TP
.B jump_to_now_playing_song_at_start = yes/no .B jump_to_now_playing_song_at_start = yes/no
If enabled, ncmpcpp will jump at start to now playing song if mpd is playing or paused. If enabled, ncmpcpp will jump at start to now playing song if mpd is playing or paused.
.TP .TP

View File

@@ -191,11 +191,16 @@ MediaLibrary::MediaLibrary()
{ {
hasTwoColumns = 0; hasTwoColumns = 0;
isAlbumOnly = 0; isAlbumOnly = 0;
itsLeftColWidth = COLS/3-1;
itsMiddleColWidth = COLS/3; size_t ra = Config.media_library_column_width_ratio_three[0];
size_t rb = Config.media_library_column_width_ratio_three[1];
size_t rc = Config.media_library_column_width_ratio_three[2];
itsLeftColWidth = COLS*ra/(ra+rb+rc)-1;
itsMiddleColStartX = itsLeftColWidth+1; itsMiddleColStartX = itsLeftColWidth+1;
itsRightColWidth = COLS-COLS/3*2-1; itsMiddleColWidth = COLS*rb/(ra+rb+rc);
itsRightColStartX = itsLeftColWidth+itsMiddleColWidth+2; itsRightColStartX = itsMiddleColStartX+itsMiddleColWidth+1;
itsRightColWidth = COLS-itsLeftColWidth-itsMiddleColWidth-2;
Tags = NC::Menu<PrimaryTag>(0, MainStartY, itsLeftColWidth, MainHeight, Config.titles_visibility ? tagTypeToString(Config.media_lib_primary_tag) + "s" : "", Config.main_color, NC::Border()); Tags = NC::Menu<PrimaryTag>(0, MainStartY, itsLeftColWidth, MainHeight, Config.titles_visibility ? tagTypeToString(Config.media_lib_primary_tag) + "s" : "", Config.main_color, NC::Border());
setHighlightFixes(Tags); setHighlightFixes(Tags);
@@ -240,18 +245,25 @@ void MediaLibrary::resize()
getWindowResizeParams(x_offset, width); getWindowResizeParams(x_offset, width);
if (!hasTwoColumns) if (!hasTwoColumns)
{ {
size_t ra = Config.media_library_column_width_ratio_three[0];
size_t rb = Config.media_library_column_width_ratio_three[1];
size_t rc = Config.media_library_column_width_ratio_three[2];
itsLeftColStartX = x_offset; itsLeftColStartX = x_offset;
itsLeftColWidth = width/3-1; itsLeftColWidth = width*ra/(ra+rb+rc)-1;
itsMiddleColStartX = itsLeftColStartX+itsLeftColWidth+1; itsMiddleColStartX = itsLeftColStartX+itsLeftColWidth+1;
itsMiddleColWidth = width/3; itsMiddleColWidth = width*rb/(ra+rb+rc);
itsRightColStartX = itsMiddleColStartX+itsMiddleColWidth+1; itsRightColStartX = itsMiddleColStartX+itsMiddleColWidth+1;
itsRightColWidth = width-width/3*2-1; itsRightColWidth = width-itsLeftColWidth-itsMiddleColWidth-2;
} }
else else
{ {
size_t ra = Config.media_library_column_width_ratio_two[0];
size_t rb = Config.media_library_column_width_ratio_two[1];
itsMiddleColStartX = x_offset; itsMiddleColStartX = x_offset;
itsMiddleColWidth = width/2; itsMiddleColWidth = width*ra/(ra+rb);
itsRightColStartX = x_offset+itsMiddleColWidth+1; itsRightColStartX = itsMiddleColStartX+itsMiddleColWidth+1;
itsRightColWidth = width-itsMiddleColWidth-1; itsRightColWidth = width-itsMiddleColWidth-1;
} }

View File

@@ -66,10 +66,14 @@ PlaylistEditor::PlaylistEditor()
, m_window_timeout(Config.data_fetching_delay ? 250 : BaseScreen::defaultWindowTimeout) , m_window_timeout(Config.data_fetching_delay ? 250 : BaseScreen::defaultWindowTimeout)
, m_fetching_delay(boost::posix_time::milliseconds(Config.data_fetching_delay ? 250 : -1)) , m_fetching_delay(boost::posix_time::milliseconds(Config.data_fetching_delay ? 250 : -1))
{ {
LeftColumnWidth = COLS/3-1; size_t ra = Config.playlist_editor_column_width_ratio[0];
size_t rb = Config.playlist_editor_column_width_ratio[1];
LeftColumnWidth = COLS*ra/(ra+rb)-1;
RightColumnStartX = LeftColumnWidth+1; RightColumnStartX = LeftColumnWidth+1;
RightColumnWidth = COLS-LeftColumnWidth-1; RightColumnWidth = COLS-LeftColumnWidth-1;
Playlists = NC::Menu<MPD::Playlist>(0, MainStartY, LeftColumnWidth, MainHeight, Config.titles_visibility ? "Playlists" : "", Config.main_color, NC::Border()); Playlists = NC::Menu<MPD::Playlist>(0, MainStartY, LeftColumnWidth, MainHeight, Config.titles_visibility ? "Playlists" : "", Config.main_color, NC::Border());
setHighlightFixes(Playlists); setHighlightFixes(Playlists);
Playlists.cyclicScrolling(Config.use_cyclic_scrolling); Playlists.cyclicScrolling(Config.use_cyclic_scrolling);
@@ -108,11 +112,14 @@ void PlaylistEditor::resize()
size_t x_offset, width; size_t x_offset, width;
getWindowResizeParams(x_offset, width); getWindowResizeParams(x_offset, width);
size_t ra = Config.playlist_editor_column_width_ratio[0];
size_t rb = Config.playlist_editor_column_width_ratio[1];
LeftColumnStartX = x_offset; LeftColumnStartX = x_offset;
LeftColumnWidth = width/3-1; LeftColumnWidth = width*ra/(ra+rb)-1;
RightColumnStartX = LeftColumnStartX+LeftColumnWidth+1; RightColumnStartX = LeftColumnStartX+LeftColumnWidth+1;
RightColumnWidth = width-LeftColumnWidth-1; RightColumnWidth = width-LeftColumnWidth-1;
Playlists.resize(LeftColumnWidth, MainHeight); Playlists.resize(LeftColumnWidth, MainHeight);
Content.resize(RightColumnWidth, MainHeight); Content.resize(RightColumnWidth, MainHeight);

View File

@@ -534,6 +534,12 @@ bool Configuration::read(const std::vector<std::string> &config_paths, bool igno
}); });
p.add("ask_for_locked_screen_width_part", &ask_for_locked_screen_width_part, p.add("ask_for_locked_screen_width_part", &ask_for_locked_screen_width_part,
"yes", yes_no); "yes", yes_no);
p.add("media_library_column_width_ratio_two", &media_library_column_width_ratio_two,
"1:1", std::bind(parse_ratio, ph::_1, 2));
p.add("media_library_column_width_ratio_three", &media_library_column_width_ratio_three,
"1:1:1", std::bind(parse_ratio, ph::_1, 3));
p.add("playlist_editor_column_width_ratio", &playlist_editor_column_width_ratio,
"1:2", std::bind(parse_ratio, ph::_1, 2));
p.add("jump_to_now_playing_song_at_start", &jump_to_now_playing_song_at_start, p.add("jump_to_now_playing_song_at_start", &jump_to_now_playing_song_at_start,
"yes", yes_no); "yes", yes_no);
p.add("ask_before_clearing_playlists", &ask_before_clearing_playlists, p.add("ask_before_clearing_playlists", &ask_before_clearing_playlists,
@@ -549,6 +555,7 @@ bool Configuration::read(const std::vector<std::string> &config_paths, bool igno
return boost::regex::icase | boost::regex::literal; return boost::regex::icase | boost::regex::literal;
else if (v == "basic") else if (v == "basic")
return boost::regex::icase | boost::regex::basic; return boost::regex::icase | boost::regex::basic;
else if (v == "extended") else if (v == "extended")
return boost::regex::icase | boost::regex::extended; return boost::regex::icase | boost::regex::extended;
else if (v == "perl") else if (v == "perl")

View File

@@ -93,6 +93,10 @@ struct Configuration
std::string pattern; std::string pattern;
std::vector<size_t> playlist_editor_column_width_ratio;
std::vector<size_t> media_library_column_width_ratio_two;
std::vector<size_t> media_library_column_width_ratio_three;
std::vector<Column> columns; std::vector<Column> columns;
DisplayMode playlist_display_mode; DisplayMode playlist_display_mode;

View File

@@ -45,6 +45,20 @@ bool yes_no(const std::string &v)
invalid_value(v); invalid_value(v);
} }
std::vector<size_t> parse_ratio(const std::string &v, const std::vector<size_t>::size_type length)
{
std::vector<size_t> ret = list_of<size_t>(v, verbose_lexical_cast<size_t>, length, "", ":", "");
size_t total = 0;
for (auto i : ret)
total += i;
if (total == 0)
invalid_value(v);
return ret;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool option_parser::run(std::istream &is, bool ignore_errors) bool option_parser::run(std::istream &is, bool ignore_errors)

View File

@@ -56,17 +56,26 @@ DestT verbose_lexical_cast(const std::string &v)
} }
template <typename ValueT, typename ConvertT> template <typename ValueT, typename ConvertT>
std::vector<ValueT> list_of(const std::string &v, ConvertT convert) std::vector<ValueT> list_of(const std::string &v, ConvertT convert, const typename std::vector<ValueT>::size_type length, const std::string &escape, const std::string &sep, const std::string &quote)
{ {
std::vector<ValueT> result; std::vector<ValueT> result;
boost::tokenizer<boost::escaped_list_separator<char>> elems(v); boost::escaped_list_separator<char> esq(escape, sep, quote);
boost::tokenizer<boost::escaped_list_separator<char>> elems(v, esq);
for (auto &value : elems) for (auto &value : elems)
result.push_back(convert(boost::trim_copy(value))); result.push_back(convert(boost::trim_copy(value)));
if (result.empty()) if (result.empty())
throw std::runtime_error("empty list"); throw std::runtime_error("empty list");
if (length > 0 && result.size() != length)
throw std::runtime_error("invalid list length");
return result; return result;
} }
template <typename ValueT, typename ConvertT>
std::vector<ValueT> list_of(const std::string &v, ConvertT convert)
{
return list_of<ValueT>(v, convert, 0, "\\", ",", "\"");
}
template <typename ValueT> template <typename ValueT>
std::vector<ValueT> list_of(const std::string &v) std::vector<ValueT> list_of(const std::string &v)
{ {
@@ -75,6 +84,8 @@ std::vector<ValueT> list_of(const std::string &v)
bool yes_no(const std::string &v); bool yes_no(const std::string &v);
std::vector<size_t> parse_ratio(const std::string &v, const std::vector<size_t>::size_type length);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
class option_parser class option_parser