From 539832bf29c27841490d1679c34bd956d1855a55 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Fri, 8 Jun 2018 10:54:11 +0200 Subject: [PATCH] Add position offset to Window to limit moves with search menu style Window can be resized with an "offset_pos" flag, which means that the resize took place on the top left corner of the window, leading to a change in current window position. This is treated as temporary and the position change is stored in a m_position_offset field. That allows the ncurses UI to offset the position when it displays a Search menu, so that the window does not constantly scroll when the search menu open/closes. The window will only scroll if it needs to in order to keep the main selectin visible. --- src/client.cc | 4 ++-- src/keys.hh | 5 +++-- src/ncurses_ui.cc | 33 ++++++++++++++++++++++----------- src/ncurses_ui.hh | 5 +++++ src/window.cc | 26 +++++++++++++++----------- src/window.hh | 3 ++- 6 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/client.cc b/src/client.cc index f4e371ff..850d46ac 100644 --- a/src/client.cc +++ b/src/client.cc @@ -48,9 +48,9 @@ Client::Client(std::unique_ptr&& ui, m_ui->set_on_key([this](Key key) { if (key == ctrl('c')) killpg(getpgrp(), SIGINT); - else if (key.modifiers == Key::Modifiers::Resize) + else if (key.modifiers & Key::Modifiers::Resize) { - m_window->set_dimensions(m_ui->dimensions()); + m_window->set_dimensions(key.coord(), key.modifiers & Key::Modifiers::OffsetPos); force_redraw(); } else diff --git a/src/keys.hh b/src/keys.hh index fa9549b8..f50a0f9c 100644 --- a/src/keys.hh +++ b/src/keys.hh @@ -30,7 +30,8 @@ struct Key MouseWheelDown | MouseWheelUp, Resize = 1 << 8, - MenuSelect = 1 << 9, + OffsetPos = 1 << 9, + MenuSelect = 1 << 10, }; enum NamedKey : Codepoint { @@ -112,7 +113,7 @@ constexpr Key ctrl(Key key) constexpr Codepoint encode_coord(DisplayCoord coord) { return (Codepoint)(((int)coord.line << 16) | ((int)coord.column & 0x0000FFFF)); } -constexpr Key resize(DisplayCoord dim) { return { Key::Modifiers::Resize, encode_coord(dim) }; } +constexpr Key resize(DisplayCoord dim, Key::Modifiers additional = Key::Modifiers::None) { return { Key::Modifiers::Resize | additional, encode_coord(dim) }; } constexpr size_t hash_value(const Key& key) { return hash_values(key.modifiers, key.key); } diff --git a/src/ncurses_ui.cc b/src/ncurses_ui.cc index 3f8f6845..7f2ec9f9 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -228,12 +228,6 @@ static void signal_handler(int) EventManager::instance().force_signal(0); } -static void do_ungetch(int ch) -{ - ungetch(ch); - EventManager::instance().force_signal(0); -} - static const std::initializer_list::Item> default_colors = { { Color::Default, -1 }, @@ -401,20 +395,21 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer, check_resize(); + const DisplayCoord dim = dimensions(); const LineCount line_offset = content_line_offset(); LineCount line_index = line_offset; for (const DisplayLine& line : display_buffer.lines()) { wmove(m_window, (int)line_index, 0); wclrtoeol(m_window); - draw_line(m_window, line, 0, m_dimensions.column, default_face); + draw_line(m_window, line, 0, dim.column, default_face); ++line_index; } wbkgdset(m_window, COLOR_PAIR(get_color_pair(padding_face))); set_face(m_window, padding_face, default_face); - while (line_index < m_dimensions.line + line_offset) + while (line_index < dim.line + line_offset) { wmove(m_window, (int)line_index++, 0); wclrtoeol(m_window); @@ -521,7 +516,7 @@ void NCursesUI::check_resize(bool force) if (info) info_show(m_info.title, m_info.content, m_info.anchor, m_info.face, m_info.style); - do_ungetch(KEY_RESIZE); + set_resize_pending(ResizePending::Yes); clearok(curscr, true); werase(curscr); } @@ -538,6 +533,14 @@ Optional NCursesUI::get_next_key() check_resize(); + if (m_resize_pending != ResizePending::No) + { + const auto modifiers = (m_resize_pending == ResizePending::OffsetPos) ? + Key::Modifiers::OffsetPos : Key::Modifiers::None; + m_resize_pending = ResizePending::No; + return resize(dimensions(), modifiers); + } + wtimeout(m_window, 0); const int c = wgetch(m_window); wtimeout(m_window, -1); @@ -799,7 +802,8 @@ void NCursesUI::menu_show(ConstArrayView items, m_menu.first_item = 0; if (style == MenuStyle::Search and previous_height != height) - do_ungetch(KEY_RESIZE); + set_resize_pending(m_status_on_top ? + ResizePending::OffsetPos : ResizePending::Yes); draw_menu(); @@ -838,7 +842,8 @@ void NCursesUI::menu_hide() return; if (m_menu.style == MenuStyle::Search) - do_ungetch(KEY_RESIZE); + set_resize_pending(m_status_on_top ? + ResizePending::OffsetPos : ResizePending::Yes); m_menu.items.clear(); mark_dirty(m_menu); @@ -1071,6 +1076,12 @@ LineCount NCursesUI::content_line_offset() const return (m_status_on_top ? 1 + (m_menu.style == MenuStyle::Search ? m_menu.size.line : 0) : 0); } +void NCursesUI::set_resize_pending(ResizePending resize_pending) +{ + m_resize_pending = resize_pending; + EventManager::instance().force_signal(0); +} + void NCursesUI::abort() { endwin(); diff --git a/src/ncurses_ui.hh b/src/ncurses_ui.hh index 8ac5d02f..c20e4ed0 100644 --- a/src/ncurses_ui.hh +++ b/src/ncurses_ui.hh @@ -148,6 +148,11 @@ private: bool m_change_colors = true; bool m_dirty = false; + + enum class ResizePending { No, Yes, OffsetPos }; + ResizePending m_resize_pending = ResizePending::No; + + void set_resize_pending(ResizePending resize_pending); }; } diff --git a/src/window.cc b/src/window.cc index f9c47e3d..19cde54e 100644 --- a/src/window.cc +++ b/src/window.cc @@ -90,7 +90,7 @@ Window::Setup Window::build_setup(const Context& context) const for (auto& sel : context.selections()) selections.push_back({sel.cursor(), sel.anchor()}); - return { m_position, m_dimensions, + return { m_position + m_position_offset, m_dimensions, context.buffer().timestamp(), compute_faces_hash(context.faces()), context.selections().main_index(), @@ -101,7 +101,7 @@ bool Window::needs_redraw(const Context& context) const { auto& selections = context.selections(); - if (m_position != m_last_setup.position or + if (m_position + m_position_offset != m_last_setup.position or m_dimensions != m_last_setup.dimensions or context.buffer().timestamp() != m_last_setup.timestamp or selections.main_index() != m_last_setup.main_selection or @@ -136,19 +136,16 @@ const DisplayBuffer& Window::update_display_buffer(const Context& context) kak_assert(&buffer() == &context.buffer()); const DisplaySetup setup = compute_display_setup(context); - m_position = setup.window_pos; - m_range = setup.window_range; - const int tabstop = context.options()["tabstop"].get(); - for (LineCount line = 0; line < m_range.line; ++line) + for (LineCount line = 0; line < setup.window_range.line; ++line) { - LineCount buffer_line = m_position.line + line; + LineCount buffer_line = setup.window_pos.line + line; if (buffer_line >= buffer().line_count()) break; - auto beg_byte = get_byte_to_column(buffer(), tabstop, {buffer_line, m_position.column}); + auto beg_byte = get_byte_to_column(buffer(), tabstop, {buffer_line, setup.window_pos.column}); auto end_byte = setup.full_lines ? buffer()[buffer_line].length() - : get_byte_to_column(buffer(), tabstop, {buffer_line, m_position.column + m_range.column}); + : get_byte_to_column(buffer(), tabstop, {buffer_line, setup.window_pos.column + setup.window_range.column}); // The display buffer always has at least one buffer atom, which might be empty if // beg_byte == end_byte @@ -164,6 +161,10 @@ const DisplayBuffer& Window::update_display_buffer(const Context& context) m_last_setup = build_setup(context); + m_position.line = clamp(setup.window_pos.line - m_position_offset.line, 0_line, buffer().line_count()-1); + m_position.column = std::max(0_col, setup.window_pos.column - m_position_offset.column); + m_range = setup.window_range; + if (profile and not (buffer().flags() & Buffer::Flags::Debug)) { using namespace std::chrono; @@ -181,10 +182,13 @@ void Window::set_position(DisplayCoord position) m_position.column = std::max(0_col, position.column); } -void Window::set_dimensions(DisplayCoord dimensions) +void Window::set_dimensions(DisplayCoord dimensions, bool offset_pos) { if (m_dimensions != dimensions) { + if (offset_pos) + m_position_offset += m_dimensions - dimensions; + m_dimensions = dimensions; run_hook_in_own_context("WinResize", format("{}.{}", dimensions.line, dimensions.column)); @@ -201,7 +205,7 @@ static void check_display_setup(const DisplaySetup& setup, const Window& window) DisplaySetup Window::compute_display_setup(const Context& context) const { - auto win_pos = m_position; + auto win_pos = m_position + m_position_offset; DisplayCoord offset = options()["scrolloff"].get(); offset.line = std::min(offset.line, (m_dimensions.line + 1) / 2); diff --git a/src/window.hh b/src/window.hh index c7cee384..284e82bc 100644 --- a/src/window.hh +++ b/src/window.hh @@ -25,7 +25,7 @@ public: const DisplayCoord& range() const { return m_range; } const DisplayCoord& dimensions() const { return m_dimensions; } - void set_dimensions(DisplayCoord dimensions); + void set_dimensions(DisplayCoord dimensions, bool offset_pos = false); void scroll(LineCount offset); void center_line(LineCount buffer_line); @@ -61,6 +61,7 @@ private: SafePtr m_client; DisplayCoord m_position; + DisplayCoord m_position_offset; DisplayCoord m_range; DisplayCoord m_dimensions; DisplayBuffer m_display_buffer;