From 70aba6e2d427c9d547206e15496189df5b18e9a0 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 13 Sep 2017 20:08:09 -0400 Subject: [PATCH] BufferView: add scroll_view_{up,down}() --- src/core/BufferView.cc | 72 +++++++++++++++++++++++ src/core/BufferView.h | 4 ++ test/src/test_BufferView.cc | 113 ++++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) diff --git a/src/core/BufferView.cc b/src/core/BufferView.cc index 9840208..0d2a4d5 100644 --- a/src/core/BufferView.cc +++ b/src/core/BufferView.cc @@ -192,6 +192,46 @@ bool BufferView::cursor_move(CursorMovement which, bool allow_eol) return moved; } +void BufferView::scroll_view_up(int n_lines, bool allow_eol) +{ + int so = effective_scroll_offset(); + int rows_to_move_cursor = (so + n_lines) - (m_height - m_cursor_screen_row - 1); + rows_to_move_cursor = std::min(calculate_rows_above_screen(rows_to_move_cursor), rows_to_move_cursor); + int actual_lines_moved = 0; + while (rows_to_move_cursor-- > 0) + { + if (move_cursor_screen_row_up(allow_eol)) + { + actual_lines_moved++; + } + else + { + break; + } + } + m_cursor_screen_row += (n_lines - actual_lines_moved); +} + +void BufferView::scroll_view_down(int n_lines, bool allow_eol) +{ + int so = effective_scroll_offset(); + int rows_to_move_cursor = (so + n_lines) - m_cursor_screen_row; + rows_to_move_cursor = std::min(calculate_rows_below_screen(rows_to_move_cursor), rows_to_move_cursor); + int actual_lines_moved = 0; + while (rows_to_move_cursor-- > 0) + { + if (move_cursor_screen_row_down(allow_eol)) + { + actual_lines_moved++; + } + else + { + break; + } + } + m_cursor_screen_row -= (n_lines - actual_lines_moved); +} + /************************************************************************** * Internal functions *************************************************************************/ @@ -374,3 +414,35 @@ void BufferView::move_forward_to_screen_position( } } } + +int BufferView::calculate_rows_above_screen(int stop_at) +{ + if (m_lines.empty()) + return 0; + const LineDescriptor & first_line = *m_lines.begin(); + auto iterator = std::make_shared(*first_line.line); + int lines = std::max(0, -first_line.row_offset); + while (lines < stop_at) + { + if (!iterator->go_previous_line()) + break; + lines += calculate_rows_in_line(iterator); + } + return lines; +} + +int BufferView::calculate_rows_below_screen(int stop_at) +{ + if (m_lines.empty()) + return 0; + const LineDescriptor & last_line = *m_lines.rbegin(); + auto iterator = std::make_shared(*last_line.line); + int lines = std::max(0, last_line.row_offset + last_line.n_rows - m_height); + while (lines < stop_at) + { + if (!iterator->go_next_line()) + break; + lines += calculate_rows_in_line(iterator); + } + return lines; +} diff --git a/src/core/BufferView.h b/src/core/BufferView.h index 658124e..a8387b0 100644 --- a/src/core/BufferView.h +++ b/src/core/BufferView.h @@ -84,6 +84,8 @@ public: { m_cursor_screen_row = cursor_screen_row; } + void scroll_view_up(int n_lines, bool allow_eol); + void scroll_view_down(int n_lines, bool allow_eol); protected: struct LineDescriptor @@ -126,6 +128,8 @@ protected: void move_forward_to_screen_position( std::shared_ptr line, int target_row_offset, bool allow_eol); + int calculate_rows_above_screen(int stop_at); + int calculate_rows_below_screen(int stop_at); }; #endif diff --git a/test/src/test_BufferView.cc b/test/src/test_BufferView.cc index 316ab8c..456d62c 100644 --- a/test/src/test_BufferView.cc +++ b/test/src/test_BufferView.cc @@ -520,3 +520,116 @@ TEST(BufferViewTest, cursor_move_screen_row_up_and_down_returns_false_at_top_and } EXPECT_FALSE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, false)); } + +TEST(BufferViewTest, scrolls_the_view_up_and_down) +{ + auto b = buffer1(); + auto iterator = b->add_iterator(); + BufferView bv(b, iterator, Cwd); + bv.resize(40, 6); + bv.update(); + EXPECT_EQ(0, LineNumber(iterator)); + EXPECT_EQ(0, bv.cursor_screen_row()); + bv.scroll_view_down(1, false); + bv.update(); + EXPECT_EQ(1, LineNumber(iterator)); + EXPECT_EQ(0, bv.cursor_screen_row()); + bv.scroll_view_down(5, false); + bv.update(); + EXPECT_EQ(6, LineNumber(iterator)); + EXPECT_EQ(0, bv.cursor_screen_row()); + bv.scroll_view_down(1, false); + bv.update(); + EXPECT_EQ(7, LineNumber(iterator)); + EXPECT_EQ(0, bv.cursor_screen_row()); + bv.scroll_view_down(1, false); + bv.update(); + EXPECT_EQ(7, LineNumber(iterator)); + EXPECT_EQ(0, bv.cursor_screen_row()); + bv.scroll_view_down(3, false); + bv.update(); + EXPECT_EQ(7, LineNumber(iterator)); + EXPECT_EQ(0, bv.cursor_screen_row()); + + bv.scroll_view_up(1, false); + bv.update(); + EXPECT_EQ(7, LineNumber(iterator)); + EXPECT_EQ(1, bv.cursor_screen_row()); + bv.scroll_view_up(4, false); + bv.update(); + EXPECT_EQ(7, LineNumber(iterator)); + EXPECT_EQ(5, bv.cursor_screen_row()); + bv.scroll_view_up(1, false); + bv.update(); + EXPECT_EQ(6, LineNumber(iterator)); + EXPECT_EQ(5, bv.cursor_screen_row()); + bv.scroll_view_up(1, false); + bv.update(); + EXPECT_EQ(5, LineNumber(iterator)); + EXPECT_EQ(5, bv.cursor_screen_row()); + bv.scroll_view_up(1, false); + bv.update(); + EXPECT_EQ(5, LineNumber(iterator)); + EXPECT_EQ(5, bv.cursor_screen_row()); + bv.scroll_view_up(3, false); + bv.update(); + EXPECT_EQ(5, LineNumber(iterator)); + EXPECT_EQ(5, bv.cursor_screen_row()); +} + +TEST(BufferViewTest, scrolls_the_view_up_and_down_with_nonzero_scroll_offset) +{ + auto b = buffer1(); + auto iterator = b->add_iterator(); + BufferView bv(b, iterator, Cwd); + bv.resize(40, 6); + bv.set_scroll_offset(2); + bv.update(); + EXPECT_EQ(0, LineNumber(iterator)); + EXPECT_EQ(0, bv.cursor_screen_row()); + bv.scroll_view_down(1, false); + bv.update(); + EXPECT_EQ(3, LineNumber(iterator)); + EXPECT_EQ(2, bv.cursor_screen_row()); + bv.scroll_view_down(5, false); + bv.update(); + EXPECT_EQ(8, LineNumber(iterator)); + EXPECT_EQ(2, bv.cursor_screen_row()); + bv.scroll_view_down(1, false); + bv.update(); + EXPECT_EQ(9, LineNumber(iterator)); + EXPECT_EQ(2, bv.cursor_screen_row()); + bv.scroll_view_down(1, false); + bv.update(); + EXPECT_EQ(9, LineNumber(iterator)); + EXPECT_EQ(2, bv.cursor_screen_row()); + bv.scroll_view_down(3, false); + bv.update(); + EXPECT_EQ(9, LineNumber(iterator)); + EXPECT_EQ(2, bv.cursor_screen_row()); + + bv.scroll_view_up(1, false); + bv.update(); + EXPECT_EQ(9, LineNumber(iterator)); + EXPECT_EQ(3, bv.cursor_screen_row()); + bv.scroll_view_up(4, false); + bv.update(); + EXPECT_EQ(5, LineNumber(iterator)); + EXPECT_EQ(3, bv.cursor_screen_row()); + bv.scroll_view_up(1, false); + bv.update(); + EXPECT_EQ(4, LineNumber(iterator)); + EXPECT_EQ(3, bv.cursor_screen_row()); + bv.scroll_view_up(1, false); + bv.update(); + EXPECT_EQ(3, LineNumber(iterator)); + EXPECT_EQ(3, bv.cursor_screen_row()); + bv.scroll_view_up(1, false); + bv.update(); + EXPECT_EQ(3, LineNumber(iterator)); + EXPECT_EQ(3, bv.cursor_screen_row()); + bv.scroll_view_up(3, false); + bv.update(); + EXPECT_EQ(3, LineNumber(iterator)); + EXPECT_EQ(3, bv.cursor_screen_row()); +}