diff --git a/src/input_handler.cc b/src/input_handler.cc index 7b6339ff..6d712697 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -80,10 +80,47 @@ struct MouseHandler context.selections() = SelectionList{ context.buffer(), Selection{m_anchor, cursor} }; return true; } + if (key.modifiers == Key::Modifiers::MouseWheelDown) + { + wheel(context, 3); + return true; + } + if (key.modifiers == Key::Modifiers::MouseWheelUp) + { + wheel(context, -3); + return true; + } return false; } private: + void wheel(Context& context, LineCount offset) + { + Window& window = context.window(); + Buffer& buffer = context.buffer(); + + CharCoord win_pos = window.position(); + CharCoord win_dim = window.dimensions(); + + const CharCoord max_offset{(win_dim.line - 1)/2, (win_dim.column - 1)/2}; + const CharCoord scrolloff = + std::min(context.options()["scrolloff"].get(), max_offset); + + const LineCount line_count = buffer.line_count(); + win_pos.line = clamp(win_pos.line + offset, 0_line, line_count-1); + + SelectionList& selections = context.selections(); + const ByteCoord cursor = selections.main().cursor(); + + auto clamp_line = [&](LineCount line) { return clamp(line, 0_line, line_count-1); }; + auto min_coord = buffer.offset_coord(clamp_line(win_pos.line + scrolloff.line), win_pos.column); + auto max_coord = buffer.offset_coord(clamp_line(win_pos.line + win_dim.line - scrolloff.line), win_pos.column); + + selections = SelectionList{buffer, clamp(cursor, min_coord, max_coord)}; + + window.set_position(win_pos); + } + bool m_dragging = false; ByteCoord m_anchor; }; diff --git a/src/keys.hh b/src/keys.hh index 54c6e175..90a366fc 100644 --- a/src/keys.hh +++ b/src/keys.hh @@ -22,6 +22,8 @@ struct Key MousePress = 1 << 2, MouseRelease = 1 << 3, MousePos = 1 << 4, + MouseWheelDown = 1 << 5, + MouseWheelUp = 1 << 6, }; enum NamedKey : Codepoint { @@ -90,6 +92,8 @@ constexpr Codepoint encode_mouse_coord(CharCoord coord) { return (Codepoint)(((i constexpr Key mouse_press(CharCoord pos) { return { Key::Modifiers::MousePress, encode_mouse_coord(pos) }; } constexpr Key mouse_release(CharCoord pos) { return { Key::Modifiers::MouseRelease, encode_mouse_coord(pos) }; } constexpr Key mouse_pos(CharCoord pos) { return { Key::Modifiers::MousePos, encode_mouse_coord(pos) }; } +constexpr Key mouse_wheel_down(CharCoord pos) { return { Key::Modifiers::MouseWheelDown, encode_mouse_coord(pos) }; } +constexpr Key mouse_wheel_up(CharCoord pos) { return { Key::Modifiers::MouseWheelUp, encode_mouse_coord(pos) }; } inline 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 55dc3f75..44bf77a8 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -456,6 +456,8 @@ Key NCursesUI::get_key() CharCoord pos{ ev.y, ev.x }; if ((ev.bstate & BUTTON1_PRESSED) == BUTTON1_PRESSED) return mouse_press(pos); if ((ev.bstate & BUTTON1_RELEASED) == BUTTON1_RELEASED) return mouse_release(pos); + if ((ev.bstate & BUTTON2_PRESSED) == BUTTON2_PRESSED) return mouse_wheel_down(pos); + if ((ev.bstate & BUTTON4_PRESSED) == BUTTON4_PRESSED) return mouse_wheel_up(pos); else return mouse_pos(pos); } }