Add cursor movement logic to BufferView

This commit is contained in:
josh committed 2017-09-11 21:10:02 -04:00
1 parent 7ad28ceb67
commit fcd198b691
3 files changed
+382 -54

No files matched your search

+129 -8
View File
@@ -1,6 +1,7 @@
#include "BufferView.h"
#include <list>
#include <utility>
#include <limits.h>
BufferView::BufferView(std::shared_ptr<Buffer> buffer,
std::shared_ptr<Buffer::Iterator> iterator,
@@ -16,6 +17,8 @@ BufferView::BufferView(std::shared_ptr<Buffer> buffer,
m_cursor_screen_column = 0;
m_cursor_virtual_column = 0;
m_cursor_row_offset = 0;
m_target_column = 0;
m_update_target_column = false;
}
void BufferView::resize(int width, int height)
@@ -42,9 +45,6 @@ void BufferView::update()
start_of_line->go_start_of_line();
int rows_in_cursor_line = calculate_rows_in_cursor_line(start_of_line);
/* Update the cursor screen row in case the cursor position changed. */
m_cursor_screen_row = determine_new_cursor_screen_row();
/* Limit the cursor screen row taking into account view dimensions,
* available buffer contents above and below the current line, and scroll
* offset. */
@@ -98,31 +98,127 @@ void BufferView::update()
}
}
bool BufferView::cursor_move(CursorMovement which, bool allow_eol)
{
bool moved = false;
switch (which)
{
case CursorMovement::LEFT:
moved = m_iterator->go_left_in_line();
m_update_target_column = true;
break;
case CursorMovement::RIGHT:
moved = m_iterator->go_right_in_line(allow_eol);
m_update_target_column = true;
break;
case CursorMovement::UP:
moved = m_iterator->go_previous_line();
break;
case CursorMovement::DOWN:
moved = m_iterator->go_next_line();
break;
case CursorMovement::SOL:
moved = m_iterator->go_start_of_line();
m_target_column = 0;
break;
case CursorMovement::EOL:
moved = m_iterator->go_end_of_line(allow_eol);
m_target_column = INT_MAX;
break;
case CursorMovement::FIRST_LINE:
{
auto it = m_buffer->begin();
if (it != *m_iterator)
{
*m_iterator = it;
moved = true;
}
}
m_target_column = 0;
break;
case CursorMovement::LAST_LINE:
{
auto it = m_buffer->end();
it.go_back();
it.go_start_of_line();
if (it != *m_iterator)
{
*m_iterator = it;
moved = true;
}
}
m_target_column = 0;
break;
case CursorMovement::SCREEN_ROW_UP:
/* TODO */
#if 0
moved = move_cursor_screen_row_up();
#endif
break;
case CursorMovement::SCREEN_ROW_DOWN:
/* TODO */
#if 0
moved = move_cursor_screen_row_down();
#endif
break;
}
if (moved)
{
switch (which)
{
case CursorMovement::LEFT:
case CursorMovement::RIGHT:
determine_new_cursor_screen_row();
break;
case CursorMovement::UP:
case CursorMovement::DOWN:
move_forward_to_column(m_target_column, allow_eol);
determine_new_cursor_screen_row();
break;
case CursorMovement::SOL:
case CursorMovement::EOL:
determine_new_cursor_screen_row();
break;
case CursorMovement::FIRST_LINE:
m_cursor_screen_row = 0;
break;
case CursorMovement::LAST_LINE:
m_cursor_screen_row = m_height - 1;
break;
}
}
return moved;
}
/**************************************************************************
* Internal functions
*************************************************************************/
int BufferView::determine_new_cursor_screen_row()
void BufferView::determine_new_cursor_screen_row()
{
if (m_lines.size() > 0)
{
if (m_iterator->line() < m_lines.begin()->line->line())
{
return 0;
m_cursor_screen_row = 0;
return;
}
if (m_iterator->line() > m_lines.rbegin()->line->line())
{
return m_height;
m_cursor_screen_row = m_height - 1;
return;
}
for (const LineDescriptor & screen_line : m_lines)
{
if (screen_line.line->line() == m_iterator->line())
{
return screen_line.row_offset + m_cursor_row_offset;
m_cursor_screen_row = screen_line.row_offset + m_cursor_row_offset;
return;
}
}
}
return 0;
}
int BufferView::calculate_rows_in_line(std::shared_ptr<Buffer::Iterator> start_of_line)
@@ -151,6 +247,10 @@ int BufferView::calculate_rows_in_cursor_line(std::shared_ptr<Buffer::Iterator>
{
m_cursor_virtual_column = it.virtual_column();
m_cursor_screen_column = it.screen_column();
if (m_update_target_column)
{
m_target_column = m_cursor_virtual_column;
}
m_cursor_row_offset = it.row_offset();
}
if (!it.is_eol())
@@ -162,6 +262,7 @@ int BufferView::calculate_rows_in_cursor_line(std::shared_ptr<Buffer::Iterator>
break;
}
}
m_update_target_column = false;
return saved_row_offset + 1;
}
@@ -190,3 +291,23 @@ int BufferView::screen_rows_above_line(
}
return rows;
}
void BufferView::move_forward_to_column(int to_column, bool allow_eol)
{
auto start_of_line = std::make_shared<Buffer::Iterator>(*m_iterator);
start_of_line->go_start_of_line();
for (auto it = horiz_iter(start_of_line); it.is_valid(); it++)
{
if (allow_eol || (!it.is_eol()))
{
if (it.virtual_column() <= to_column)
{
*m_iterator = *it.iterator();
}
else
{
break;
}
}
}
}
+35 -13
View File
@@ -14,6 +14,20 @@
class BufferView
{
public:
enum class CursorMovement : uint8_t
{
LEFT,
RIGHT,
UP,
DOWN,
SOL,
EOL,
FIRST_LINE,
LAST_LINE,
SCREEN_ROW_UP,
SCREEN_ROW_DOWN,
};
class Iterator
{
public:
@@ -62,22 +76,16 @@ public:
{
return BufferLineWalker(m_buffer, start_of_line, m_width, m_character_width_determiner);
}
bool cursor_move(CursorMovement which, bool allow_eol);
int cursor_screen_row() const { return m_cursor_screen_row; }
int cursor_screen_column() const { return m_cursor_screen_column; }
int cursor_virtual_column() const { return m_cursor_virtual_column; }
void set_cursor_screen_row(int cursor_screen_row)
{
m_cursor_screen_row = cursor_screen_row;
}
protected:
std::shared_ptr<Buffer> m_buffer;
std::shared_ptr<Buffer::Iterator> m_iterator;
int m_width;
int m_height;
int m_scroll_offset;
int m_cursor_screen_row;
int m_cursor_screen_column;
int m_cursor_virtual_column;
int m_cursor_row_offset;
CharacterWidthDeterminer & m_character_width_determiner;
struct LineDescriptor
{
int row_offset;
@@ -85,18 +93,32 @@ protected:
std::shared_ptr<Buffer::Iterator> line;
};
std::shared_ptr<Buffer> m_buffer;
std::shared_ptr<Buffer::Iterator> m_iterator;
std::vector<LineDescriptor> m_lines;
CharacterWidthDeterminer & m_character_width_determiner;
int m_width;
int m_height;
int m_scroll_offset;
int m_cursor_screen_row;
int m_cursor_screen_column;
int m_cursor_virtual_column;
int m_cursor_row_offset;
int m_target_column;
bool m_update_target_column;
int effective_scroll_offset()
{
return std::min(m_scroll_offset, (m_height - 1) / 2);
}
int determine_new_cursor_screen_row();
void determine_new_cursor_screen_row();
int calculate_rows_in_line(std::shared_ptr<Buffer::Iterator> start_of_line);
int calculate_rows_in_cursor_line(std::shared_ptr<Buffer::Iterator> start_of_line);
int screen_rows_below_line(std::shared_ptr<Buffer::Iterator> line);
int screen_rows_above_line(
std::shared_ptr<Buffer::Iterator> line,
std::list<std::pair<int, std::shared_ptr<Buffer::Iterator>>> & backward_lines);
std::vector<LineDescriptor> m_lines;
void move_forward_to_column(int to_column, bool allow_eol);
};
#endif