Restore support for line wrapping info boxes

Fixes #3280
This commit is contained in:
Maxime Coste 2020-01-03 20:28:09 +11:00
parent 98c0cdedb1
commit e6b98744c6

View File

@ -1031,6 +1031,38 @@ static DisplayCoord compute_pos(DisplayCoord anchor, DisplayCoord size,
return pos;
}
static DisplayLineList wrap_lines(const DisplayLineList& lines, ColumnCount max_width)
{
DisplayLineList result;
for (auto line : lines)
{
ColumnCount column = 0;
for (auto it = line.begin(); it != line.end(); )
{
auto length = it->length();
column += length;
if (column > max_width)
{
auto content = it->content().substr(0, length - (column - max_width));
auto pos = find_if(content | reverse(), [](char c) { return not is_word(c); });
if (pos != content.rend())
content = {content.begin(), pos.base()};
if (not content.empty())
it = ++line.split(it, content.column_length());
result.push_back(AtomList(std::make_move_iterator(line.begin()),
std::make_move_iterator(it)));
it = line.erase(line.begin(), it);
column = 0;
}
else
++it;
}
result.push_back(std::move(line));
}
return result;
}
void NCursesUI::info_show(const DisplayLine& title, const DisplayLineList& content,
DisplayCoord anchor, Face face, InfoStyle style)
{
@ -1042,6 +1074,9 @@ void NCursesUI::info_show(const DisplayLine& title, const DisplayLineList& conte
m_info.face = face;
m_info.style = style;
const bool framed = style == InfoStyle::Prompt or style == InfoStyle::Modal;
const bool assisted = style == InfoStyle::Prompt and m_assistant.size() != 0;
DisplayCoord max_size = m_dimensions;
if (style == InfoStyle::MenuDoc)
max_size.column = std::max(m_dimensions.column - (m_menu.pos.column + m_menu.size.column),
@ -1049,21 +1084,32 @@ void NCursesUI::info_show(const DisplayLine& title, const DisplayLineList& conte
else if (style != InfoStyle::Modal)
max_size.line -= m_menu.size.line;
const bool framed = style == InfoStyle::Prompt or style == InfoStyle::Modal;
const bool assisted = style == InfoStyle::Prompt and m_assistant.size() != 0;
DisplayCoord size{(int)content.size(), accumulate(content, 0_col, [](ColumnCount c, const DisplayLine& l) {
return std::max(c, l.length());
})};
size.column = std::max(size.column, title.length() + (framed ? 2 : 0));
const auto max_content_width = max_size.column - (framed ? 4 : 2) - (assisted ? m_assistant[0].column_length() : 0);
if (max_content_width <= 0)
return;
auto compute_size = [](const DisplayLineList& lines) -> DisplayCoord {
return {(int)lines.size(), accumulate(lines, 0_col, [](ColumnCount c, const DisplayLine& l) { return std::max(c, l.length()); })};
};
DisplayCoord content_size = compute_size(content);
const bool wrap = content_size.column > max_content_width;
DisplayLineList wrapped_content;
if (wrap)
{
wrapped_content = wrap_lines(content, max_content_width);
content_size = compute_size(wrapped_content);
}
const auto& lines = wrap ? wrapped_content : content;
DisplayCoord size{content_size.line, std::max(content_size.column, title.length() + (framed ? 2 : 0))};
if (framed)
size += {2, 4};
if (assisted)
size = {std::max(LineCount{(int)m_assistant.size()-1}, size.line), size.column + m_assistant[0].column_length()};
size = {std::min(max_size.line, size.line), std::min(max_size.column, size.column)};
const auto content_width = size.column - (framed ? 4 : 2) - (assisted ? m_assistant[0].column_length() : 0);
if (content_width <= 0 or (framed and size.line < 3) or size.line <= 0)
if ((framed and size.line < 3) or size.line <= 0)
return;
const Rect rect = {content_line_offset(), m_dimensions};
@ -1117,30 +1163,30 @@ void NCursesUI::info_show(const DisplayLine& title, const DisplayLineList& conte
draw_atoms(assistant_line.str());
}
if (not framed)
draw_atoms(content[(int)line]);
draw_atoms(lines[(int)line]);
else if (line == 0)
{
if (title.atoms().empty() or content_width < 2)
draw_atoms("╭─" + String{dash, content_width} + "─╮");
if (title.atoms().empty() or content_size.column < 2)
draw_atoms("╭─" + String{dash, content_size.column} + "─╮");
else
{
auto trimmed_title = title;
trimmed_title.trim(0, content_width - 2);
auto dash_count = content_width - trimmed_title.length() - 2;
trimmed_title.trim(0, content_size.column - 2);
auto dash_count = content_size.column - trimmed_title.length() - 2;
String left{dash, dash_count / 2};
String right{dash, dash_count - dash_count / 2};
draw_atoms("╭─" + left + "", trimmed_title, "" + right +"─╮");
}
}
else if (line < size.line - 1 and line <= content.size())
else if (line < size.line - 1 and line <= lines.size())
{
auto info_line = content[(int)line - 1];
const bool trimmed = info_line.trim(0, content_width);
const ColumnCount padding = content_width - info_line.length();
auto info_line = lines[(int)line - 1];
const bool trimmed = info_line.trim(0, content_size.column);
const ColumnCount padding = content_size.column - info_line.length();
draw_atoms("", info_line, String{' ', padding} + (trimmed ? "…│" : ""));
}
else if (line == std::min<LineCount>((int)content.size() + 1, size.line - 1))
draw_atoms("╰─" + String(line > content.size() ? dash : dotted_dash, content_width) + "─╯");
else if (line == std::min<LineCount>((int)lines.size() + 1, size.line - 1))
draw_atoms("╰─" + String(line > lines.size() ? dash : dotted_dash, content_size.column) + "─╯");
}
m_dirty = true;
}