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.
This commit is contained in:
parent
60cf71bc24
commit
539832bf29
|
@ -48,9 +48,9 @@ Client::Client(std::unique_ptr<UserInterface>&& ui,
|
||||||
m_ui->set_on_key([this](Key key) {
|
m_ui->set_on_key([this](Key key) {
|
||||||
if (key == ctrl('c'))
|
if (key == ctrl('c'))
|
||||||
killpg(getpgrp(), SIGINT);
|
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();
|
force_redraw();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -30,7 +30,8 @@ struct Key
|
||||||
MouseWheelDown | MouseWheelUp,
|
MouseWheelDown | MouseWheelUp,
|
||||||
|
|
||||||
Resize = 1 << 8,
|
Resize = 1 << 8,
|
||||||
MenuSelect = 1 << 9,
|
OffsetPos = 1 << 9,
|
||||||
|
MenuSelect = 1 << 10,
|
||||||
};
|
};
|
||||||
enum NamedKey : Codepoint
|
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 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); }
|
constexpr size_t hash_value(const Key& key) { return hash_values(key.modifiers, key.key); }
|
||||||
|
|
||||||
|
|
|
@ -228,12 +228,6 @@ static void signal_handler(int)
|
||||||
EventManager::instance().force_signal(0);
|
EventManager::instance().force_signal(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_ungetch(int ch)
|
|
||||||
{
|
|
||||||
ungetch(ch);
|
|
||||||
EventManager::instance().force_signal(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::initializer_list<HashMap<Kakoune::Color, int>::Item>
|
static const std::initializer_list<HashMap<Kakoune::Color, int>::Item>
|
||||||
default_colors = {
|
default_colors = {
|
||||||
{ Color::Default, -1 },
|
{ Color::Default, -1 },
|
||||||
|
@ -401,20 +395,21 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer,
|
||||||
|
|
||||||
check_resize();
|
check_resize();
|
||||||
|
|
||||||
|
const DisplayCoord dim = dimensions();
|
||||||
const LineCount line_offset = content_line_offset();
|
const LineCount line_offset = content_line_offset();
|
||||||
LineCount line_index = line_offset;
|
LineCount line_index = line_offset;
|
||||||
for (const DisplayLine& line : display_buffer.lines())
|
for (const DisplayLine& line : display_buffer.lines())
|
||||||
{
|
{
|
||||||
wmove(m_window, (int)line_index, 0);
|
wmove(m_window, (int)line_index, 0);
|
||||||
wclrtoeol(m_window);
|
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;
|
++line_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
wbkgdset(m_window, COLOR_PAIR(get_color_pair(padding_face)));
|
wbkgdset(m_window, COLOR_PAIR(get_color_pair(padding_face)));
|
||||||
set_face(m_window, padding_face, default_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);
|
wmove(m_window, (int)line_index++, 0);
|
||||||
wclrtoeol(m_window);
|
wclrtoeol(m_window);
|
||||||
|
@ -521,7 +516,7 @@ void NCursesUI::check_resize(bool force)
|
||||||
if (info)
|
if (info)
|
||||||
info_show(m_info.title, m_info.content, m_info.anchor, m_info.face, m_info.style);
|
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);
|
clearok(curscr, true);
|
||||||
werase(curscr);
|
werase(curscr);
|
||||||
}
|
}
|
||||||
|
@ -538,6 +533,14 @@ Optional<Key> NCursesUI::get_next_key()
|
||||||
|
|
||||||
check_resize();
|
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);
|
wtimeout(m_window, 0);
|
||||||
const int c = wgetch(m_window);
|
const int c = wgetch(m_window);
|
||||||
wtimeout(m_window, -1);
|
wtimeout(m_window, -1);
|
||||||
|
@ -799,7 +802,8 @@ void NCursesUI::menu_show(ConstArrayView<DisplayLine> items,
|
||||||
m_menu.first_item = 0;
|
m_menu.first_item = 0;
|
||||||
|
|
||||||
if (style == MenuStyle::Search and previous_height != height)
|
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();
|
draw_menu();
|
||||||
|
|
||||||
|
@ -838,7 +842,8 @@ void NCursesUI::menu_hide()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_menu.style == MenuStyle::Search)
|
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();
|
m_menu.items.clear();
|
||||||
mark_dirty(m_menu);
|
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);
|
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()
|
void NCursesUI::abort()
|
||||||
{
|
{
|
||||||
endwin();
|
endwin();
|
||||||
|
|
|
@ -148,6 +148,11 @@ private:
|
||||||
bool m_change_colors = true;
|
bool m_change_colors = true;
|
||||||
|
|
||||||
bool m_dirty = false;
|
bool m_dirty = false;
|
||||||
|
|
||||||
|
enum class ResizePending { No, Yes, OffsetPos };
|
||||||
|
ResizePending m_resize_pending = ResizePending::No;
|
||||||
|
|
||||||
|
void set_resize_pending(ResizePending resize_pending);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ Window::Setup Window::build_setup(const Context& context) const
|
||||||
for (auto& sel : context.selections())
|
for (auto& sel : context.selections())
|
||||||
selections.push_back({sel.cursor(), sel.anchor()});
|
selections.push_back({sel.cursor(), sel.anchor()});
|
||||||
|
|
||||||
return { m_position, m_dimensions,
|
return { m_position + m_position_offset, m_dimensions,
|
||||||
context.buffer().timestamp(),
|
context.buffer().timestamp(),
|
||||||
compute_faces_hash(context.faces()),
|
compute_faces_hash(context.faces()),
|
||||||
context.selections().main_index(),
|
context.selections().main_index(),
|
||||||
|
@ -101,7 +101,7 @@ bool Window::needs_redraw(const Context& context) const
|
||||||
{
|
{
|
||||||
auto& selections = context.selections();
|
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
|
m_dimensions != m_last_setup.dimensions or
|
||||||
context.buffer().timestamp() != m_last_setup.timestamp or
|
context.buffer().timestamp() != m_last_setup.timestamp or
|
||||||
selections.main_index() != m_last_setup.main_selection 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());
|
kak_assert(&buffer() == &context.buffer());
|
||||||
const DisplaySetup setup = compute_display_setup(context);
|
const DisplaySetup setup = compute_display_setup(context);
|
||||||
|
|
||||||
m_position = setup.window_pos;
|
|
||||||
m_range = setup.window_range;
|
|
||||||
|
|
||||||
const int tabstop = context.options()["tabstop"].get<int>();
|
const int tabstop = context.options()["tabstop"].get<int>();
|
||||||
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())
|
if (buffer_line >= buffer().line_count())
|
||||||
break;
|
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 ?
|
auto end_byte = setup.full_lines ?
|
||||||
buffer()[buffer_line].length()
|
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
|
// The display buffer always has at least one buffer atom, which might be empty if
|
||||||
// beg_byte == end_byte
|
// beg_byte == end_byte
|
||||||
|
@ -164,6 +161,10 @@ const DisplayBuffer& Window::update_display_buffer(const Context& context)
|
||||||
|
|
||||||
m_last_setup = build_setup(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))
|
if (profile and not (buffer().flags() & Buffer::Flags::Debug))
|
||||||
{
|
{
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
@ -181,10 +182,13 @@ void Window::set_position(DisplayCoord position)
|
||||||
m_position.column = std::max(0_col, position.column);
|
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 (m_dimensions != dimensions)
|
||||||
{
|
{
|
||||||
|
if (offset_pos)
|
||||||
|
m_position_offset += m_dimensions - dimensions;
|
||||||
|
|
||||||
m_dimensions = dimensions;
|
m_dimensions = dimensions;
|
||||||
run_hook_in_own_context("WinResize", format("{}.{}", dimensions.line,
|
run_hook_in_own_context("WinResize", format("{}.{}", dimensions.line,
|
||||||
dimensions.column));
|
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
|
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<DisplayCoord>();
|
DisplayCoord offset = options()["scrolloff"].get<DisplayCoord>();
|
||||||
offset.line = std::min(offset.line, (m_dimensions.line + 1) / 2);
|
offset.line = std::min(offset.line, (m_dimensions.line + 1) / 2);
|
||||||
|
|
|
@ -25,7 +25,7 @@ public:
|
||||||
const DisplayCoord& range() const { return m_range; }
|
const DisplayCoord& range() const { return m_range; }
|
||||||
|
|
||||||
const DisplayCoord& dimensions() const { return m_dimensions; }
|
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 scroll(LineCount offset);
|
||||||
void center_line(LineCount buffer_line);
|
void center_line(LineCount buffer_line);
|
||||||
|
@ -61,6 +61,7 @@ private:
|
||||||
SafePtr<Client> m_client;
|
SafePtr<Client> m_client;
|
||||||
|
|
||||||
DisplayCoord m_position;
|
DisplayCoord m_position;
|
||||||
|
DisplayCoord m_position_offset;
|
||||||
DisplayCoord m_range;
|
DisplayCoord m_range;
|
||||||
DisplayCoord m_dimensions;
|
DisplayCoord m_dimensions;
|
||||||
DisplayBuffer m_display_buffer;
|
DisplayBuffer m_display_buffer;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user