Rework client redrawing, delay menu/info methods until next refresh

That avoid sending lots of spurious info_hide/menu_hide, just set
a flag and wait until the client is asked to redraw.
This commit is contained in:
Maxime Coste 2016-03-07 23:11:59 +00:00
parent a15cdeae6e
commit 6c8f8fe691
3 changed files with 75 additions and 48 deletions

View File

@ -36,7 +36,7 @@ Client::Client(std::unique_ptr<UserInterface>&& ui,
m_ui->set_ui_options(m_window->options()["ui_options"].get<UserInterface::Options>()); m_ui->set_ui_options(m_window->options()["ui_options"].get<UserInterface::Options>());
m_ui->set_input_callback([this](EventMode mode) { handle_available_input(mode); }); m_ui->set_input_callback([this](EventMode mode) { handle_available_input(mode); });
m_ui_dirty = true; force_redraw();
} }
Client::~Client() Client::~Client()
@ -101,7 +101,8 @@ void Client::handle_available_input(EventMode mode)
void Client::print_status(DisplayLine status_line) void Client::print_status(DisplayLine status_line)
{ {
m_pending_status_line = std::move(status_line); m_status_line = std::move(status_line);
m_ui_pending |= StatusLine;
} }
DisplayLine Client::generate_mode_line() const DisplayLine Client::generate_mode_line() const
@ -159,7 +160,7 @@ void Client::change_buffer(Buffer& buffer)
context().selections_write_only() = std::move(ws.selections); context().selections_write_only() = std::move(ws.selections);
context().set_window(*m_window); context().set_window(*m_window);
m_window->set_dimensions(m_ui->dimensions()); m_window->set_dimensions(m_ui->dimensions());
m_ui_dirty = true; force_redraw();
m_window->hooks().run_hook("WinDisplay", buffer.name(), context()); m_window->hooks().run_hook("WinDisplay", buffer.name(), context());
} }
@ -171,56 +172,70 @@ static bool is_inline(InfoStyle style)
style == InfoStyle::InlineBelow; style == InfoStyle::InlineBelow;
} }
void Client::redraw_ifn(bool force) void Client::redraw_ifn()
{ {
Window& window = context().window(); Window& window = context().window();
if (window.needs_redraw(context()))
m_ui_pending |= Draw;
const bool needs_redraw = window.needs_redraw(context()); DisplayLine mode_line = generate_mode_line();
if (needs_redraw or force) if (mode_line.atoms() != m_mode_line.atoms())
{
m_ui_pending |= StatusLine;
m_mode_line = std::move(mode_line);
}
if (m_ui_pending == 0)
return;
if (m_ui_pending & Draw)
{ {
auto window_pos = window.position(); auto window_pos = window.position();
m_ui->draw(window.update_display_buffer(context()), get_face("Default")); m_ui->draw(window.update_display_buffer(context()), get_face("Default"));
// window moved, reanchor eventual menu and info // window moved, reanchor eventual menu and info
if (force or window_pos != window.position()) if (window_pos != window.position())
{ {
if (not m_menu.items.empty() and m_menu.style == MenuStyle::Inline) if (not m_menu.items.empty() and m_menu.style == MenuStyle::Inline)
{ m_ui_pending |= (MenuShow | MenuSelect);
m_ui->menu_show(m_menu.items, window.display_position(m_menu.anchor),
get_face("MenuForeground"), get_face("MenuBackground"), m_menu.style);
m_ui->menu_select(m_menu.selected);
}
if (not m_info.content.empty() and is_inline(m_info.style)) if (not m_info.content.empty() and is_inline(m_info.style))
m_ui->info_show(m_info.title, m_info.content, m_ui_pending |= InfoShow;
window.display_position(m_info.anchor),
get_face("Information"), m_info.style);
} }
m_ui_dirty = true;
} }
DisplayLine mode_line = generate_mode_line(); if (m_ui_pending & MenuShow)
if (force or needs_redraw or
m_status_line.atoms() != m_pending_status_line.atoms() or
mode_line.atoms() != m_mode_line.atoms())
{ {
m_mode_line = std::move(mode_line); const CharCoord ui_anchor = m_menu.style == MenuStyle::Inline ?
m_status_line = m_pending_status_line; window.display_position(m_menu.anchor) : CharCoord{};
m_ui->menu_show(m_menu.items, ui_anchor,
get_face("MenuForeground"), get_face("MenuBackground"),
m_menu.style);
}
if (m_ui_pending & MenuSelect)
m_ui->menu_select(m_menu.selected);
if (m_ui_pending & MenuHide)
m_ui->menu_hide();
if (m_ui_pending & InfoShow)
{
const CharCoord ui_anchor = is_inline(m_info.style) ?
window.display_position(m_info.anchor) : CharCoord{};
m_ui->info_show(m_info.title, m_info.content, ui_anchor,
get_face("Information"), m_info.style);
}
if (m_ui_pending & InfoHide)
m_ui->info_hide();
if (m_ui_pending & StatusLine)
m_ui->draw_status(m_status_line, m_mode_line, get_face("StatusLine")); m_ui->draw_status(m_status_line, m_mode_line, get_face("StatusLine"));
m_ui_dirty = true;
}
if (m_ui_dirty or force) m_ui->refresh(m_ui_pending | Refresh);
{ m_ui_pending = 0;
m_ui_dirty = false;
m_ui->refresh(force);
}
} }
void Client::force_redraw() void Client::force_redraw()
{ {
if (m_window) m_ui_pending |= Refresh;
m_window->force_redraw();
} }
void Client::reload_buffer() void Client::reload_buffer()
@ -310,45 +325,43 @@ void Client::on_option_changed(const Option& option)
if (option.name() == "ui_options") if (option.name() == "ui_options")
{ {
m_ui->set_ui_options(option.get<UserInterface::Options>()); m_ui->set_ui_options(option.get<UserInterface::Options>());
m_ui_dirty = true; m_ui_pending |= Draw;
} }
} }
void Client::menu_show(Vector<DisplayLine> choices, ByteCoord anchor, MenuStyle style) void Client::menu_show(Vector<DisplayLine> choices, ByteCoord anchor, MenuStyle style)
{ {
m_menu = Menu{ std::move(choices), anchor, style, -1 }; m_menu = Menu{ std::move(choices), anchor, style, -1 };
CharCoord ui_anchor = style == MenuStyle::Inline ? context().window().display_position(anchor) : CharCoord{}; m_ui_pending |= MenuShow;
m_ui->menu_show(m_menu.items, ui_anchor, get_face("MenuForeground"), get_face("MenuBackground"), style); m_ui_pending &= ~MenuHide;
m_ui_dirty = true;
} }
void Client::menu_select(int selected) void Client::menu_select(int selected)
{ {
m_menu.selected = selected; m_menu.selected = selected;
m_ui->menu_select(selected); m_ui_pending |= MenuSelect;
m_ui_dirty = true; m_ui_pending &= ~MenuHide;
} }
void Client::menu_hide() void Client::menu_hide()
{ {
m_menu = Menu{}; m_menu = Menu{};
m_ui->menu_hide(); m_ui_pending |= MenuHide;
m_ui_dirty = true; m_ui_pending &= ~(MenuShow | MenuSelect);
} }
void Client::info_show(String title, String content, ByteCoord anchor, InfoStyle style) void Client::info_show(String title, String content, ByteCoord anchor, InfoStyle style)
{ {
m_info = Info{ std::move(title), std::move(content), anchor, style }; m_info = Info{ std::move(title), std::move(content), anchor, style };
CharCoord ui_anchor = is_inline(style) ? context().window().display_position(anchor) : CharCoord{}; m_ui_pending |= InfoShow;
m_ui->info_show(m_info.title, m_info.content, ui_anchor, get_face("Information"), style); m_ui_pending &= ~InfoHide;
m_ui_dirty = true;
} }
void Client::info_hide() void Client::info_hide()
{ {
m_info = Info{}; m_info = Info{};
m_ui->info_hide(); m_ui_pending |= InfoHide;
m_ui_dirty = true; m_ui_pending &= ~InfoShow;
} }
} }

View File

@ -46,7 +46,7 @@ public:
CharCoord dimensions() const { return m_ui->dimensions(); } CharCoord dimensions() const { return m_ui->dimensions(); }
void force_redraw(); void force_redraw();
void redraw_ifn(bool force = false); void redraw_ifn();
void check_if_buffer_needs_reloading(); void check_if_buffer_needs_reloading();
@ -74,7 +74,6 @@ private:
DisplayLine generate_mode_line() const; DisplayLine generate_mode_line() const;
bool m_ui_dirty = false;
std::unique_ptr<UserInterface> m_ui; std::unique_ptr<UserInterface> m_ui;
std::unique_ptr<Window> m_window; std::unique_ptr<Window> m_window;
@ -83,9 +82,21 @@ private:
InputHandler m_input_handler; InputHandler m_input_handler;
DisplayLine m_status_line; DisplayLine m_status_line;
DisplayLine m_pending_status_line;
DisplayLine m_mode_line; DisplayLine m_mode_line;
enum PendingUI : int
{
MenuShow = 1 << 0,
MenuSelect = 1 << 1,
MenuHide = 1 << 2,
InfoShow = 1 << 3,
InfoHide = 1 << 4,
StatusLine = 1 << 5,
Draw = 1 << 6,
Refresh = 1 << 7,
};
int m_ui_pending = 0;
struct Menu struct Menu
{ {
Vector<DisplayLine> items; Vector<DisplayLine> items;

View File

@ -1563,7 +1563,10 @@ void ensure_forward(Context& context, NormalParams)
void force_redraw(Context& context, NormalParams) void force_redraw(Context& context, NormalParams)
{ {
if (context.has_client()) if (context.has_client())
context.client().redraw_ifn(true); {
context.client().force_redraw();
context.client().redraw_ifn();
}
} }
static NormalCmdDesc cmds[] = static NormalCmdDesc cmds[] =