NCursesUI: refactor info_show code

Show MenuDoc info on the left of the menu if necessary. Cleanup the
code.
This commit is contained in:
Maxime Coste 2018-03-19 01:23:32 +11:00
parent cf37623f1a
commit 8a7e844207

View File

@ -845,14 +845,20 @@ static DisplayCoord compute_pos(DisplayCoord anchor, DisplayCoord size,
return pos; return pos;
} }
Vector<String> make_info_box(StringView title, StringView message, ColumnCount max_width, struct InfoBox
ConstArrayView<StringView> assistant) {
DisplayCoord size;
Vector<String> contents;
};
InfoBox make_info_box(StringView title, StringView message, ColumnCount max_width,
ConstArrayView<StringView> assistant)
{ {
DisplayCoord assistant_size; DisplayCoord assistant_size;
if (not assistant.empty()) if (not assistant.empty())
assistant_size = { (int)assistant.size(), assistant[0].column_length() }; assistant_size = { (int)assistant.size(), assistant[0].column_length() };
Vector<String> result; InfoBox result{};
const ColumnCount max_bubble_width = max_width - assistant_size.column - 6; const ColumnCount max_bubble_width = max_width - assistant_size.column - 6;
if (max_bubble_width < 4) if (max_bubble_width < 4)
@ -864,8 +870,8 @@ Vector<String> make_info_box(StringView title, StringView message, ColumnCount m
for (auto& line : lines) for (auto& line : lines)
bubble_width = max(bubble_width, line.column_length()); bubble_width = max(bubble_width, line.column_length());
auto line_count = max(assistant_size.line-1, auto line_count = max(assistant_size.line-1, LineCount{(int)lines.size()} + 2);
LineCount{(int)lines.size()} + 2); result.size = DisplayCoord{line_count, bubble_width + assistant_size.column + 4};
const auto assistant_top_margin = (line_count - assistant_size.line+1) / 2; const auto assistant_top_margin = (line_count - assistant_size.line+1) / 2;
for (LineCount i = 0; i < line_count; ++i) for (LineCount i = 0; i < line_count; ++i)
{ {
@ -899,11 +905,23 @@ Vector<String> make_info_box(StringView title, StringView message, ColumnCount m
else if (i == lines.size() + 1) else if (i == lines.size() + 1)
line += "╰─" + String(dash, bubble_width) + "─╯"; line += "╰─" + String(dash, bubble_width) + "─╯";
result.push_back(std::move(line)); result.contents.push_back(std::move(line));
} }
return result; return result;
} }
InfoBox make_simple_info_box(StringView contents, ColumnCount max_width)
{
InfoBox info_box{};
for (auto& line : wrap_lines(contents, max_width))
{
++info_box.size.line;
info_box.size.column = std::max(line.column_length(), info_box.size.column);
info_box.contents.push_back(line.str());
}
return info_box;
}
void NCursesUI::info_show(StringView title, StringView content, void NCursesUI::info_show(StringView title, StringView content,
DisplayCoord anchor, Face face, InfoStyle style) DisplayCoord anchor, Face face, InfoStyle style)
{ {
@ -915,59 +933,62 @@ void NCursesUI::info_show(StringView title, StringView content,
m_info.face = face; m_info.face = face;
m_info.style = style; m_info.style = style;
Vector<String> info_box; const Rect rect = {m_status_on_top ? 1_line : 0_line, m_dimensions};
InfoBox info_box;
if (style == InfoStyle::Prompt) if (style == InfoStyle::Prompt)
{ {
info_box = make_info_box(m_info.title, m_info.content, info_box = make_info_box(m_info.title, m_info.content, m_dimensions.column, m_assistant);
m_dimensions.column, m_assistant); anchor = DisplayCoord{m_status_on_top ? 0 : m_dimensions.line, m_dimensions.column-1};
anchor = DisplayCoord{m_status_on_top ? 0 : m_dimensions.line, anchor = compute_pos(anchor, info_box.size, rect, m_menu, style == InfoStyle::InlineAbove);
m_dimensions.column-1};
} }
else if (style == InfoStyle::Modal) else if (style == InfoStyle::Modal)
info_box = make_info_box(m_info.title, m_info.content,
m_dimensions.column, {});
else
{ {
if (m_status_on_top) info_box = make_info_box(m_info.title, m_info.content, m_dimensions.column, {});
anchor.line += 1; auto half = [](const DisplayCoord& c) { return DisplayCoord{c.line / 2, c.column / 2}; };
ColumnCount col = anchor.column; anchor = rect.pos + half(rect.size) - half(info_box.size);
if (style == InfoStyle::MenuDoc and m_menu) }
col = m_menu.pos.column + m_menu.size.column; else if (style == InfoStyle::MenuDoc)
{
if (not m_menu)
return;
const ColumnCount max_width = m_dimensions.column - col; const auto right_max_width = m_dimensions.column - (m_menu.pos.column + m_menu.size.column);
const auto left_max_width = m_menu.pos.column;
const auto max_width = std::max(right_max_width, left_max_width);
if (max_width < 4) if (max_width < 4)
return; return;
for (auto& line : wrap_lines(m_info.content, max_width)) info_box = make_simple_info_box(m_info.content, max_width);
info_box.push_back(line.str()); anchor.line = m_menu.pos.line;
} if (info_box.size.column <= right_max_width or right_max_width >= left_max_width)
anchor.column = m_menu.pos.column + m_menu.size.column;
const DisplayCoord size{(int)info_box.size(), else
accumulate(info_box | transform(&String::column_length), 0_col, anchor.column = m_menu.pos.column - info_box.size.column;
[](auto&& lhs, auto&& rhs){ return std::max(lhs, rhs); })};
const Rect rect = {m_status_on_top ? 1_line : 0_line, m_dimensions};
DisplayCoord pos;
if (style == InfoStyle::MenuDoc and m_menu)
pos = m_menu.pos + DisplayCoord{0_line, m_menu.size.column};
else if (style == InfoStyle::Modal)
{
auto half = [](const DisplayCoord& c) { return DisplayCoord{c.line / 2, c.column / 2}; };
pos = rect.pos + half(rect.size) - half(size);
} }
else else
pos = compute_pos(anchor, size, rect, m_menu, style == InfoStyle::InlineAbove); {
const ColumnCount max_width = m_dimensions.column - anchor.column;
if (max_width < 4)
return;
info_box = make_simple_info_box(m_info.content, max_width);
anchor = compute_pos(anchor, info_box.size, rect, m_menu, style == InfoStyle::InlineAbove);
if (m_status_on_top)
anchor.line += 1;
}
// The info box does not fit // The info box does not fit
if (pos < rect.pos or pos + size > rect.pos + rect.size) if (anchor < rect.pos or anchor + info_box.size > rect.pos + rect.size)
return; return;
m_info.create(pos, size); m_info.create(anchor, info_box.size);
wbkgd(m_info.win, COLOR_PAIR(get_color_pair(face))); wbkgd(m_info.win, COLOR_PAIR(get_color_pair(face)));
for (size_t line = 0; line < info_box.size(); ++line) for (auto line = 0_line; line < info_box.size.line; ++line)
{ {
wmove(m_info.win, line, 0); wmove(m_info.win, (int)line, 0);
add_str(m_info.win, info_box[line]); add_str(m_info.win, info_box.contents[(int)line]);
} }
m_dirty = true; m_dirty = true;
} }