add BufferPane::walk_line() to commonize logic for laying out a line to the screen

This commit is contained in:
Josh Holtrop 2016-12-21 19:43:54 -05:00
parent 24fced221f
commit 08dab099a7
2 changed files with 67 additions and 124 deletions

View File

@ -15,36 +15,53 @@ void BufferPane::resize(int width, int height)
m_rows = std::max(1, (m_height + m_window->font()->get_line_height() - 1) / m_window->font()->get_line_height()); m_rows = std::max(1, (m_height + m_window->font()->get_line_height() - 1) / m_window->font()->get_line_height());
} }
int BufferPane::rows_in_line(const Buffer::Iterator & start_of_line) void BufferPane::walk_line(const Buffer::Iterator & start_of_line, std::function<void(int, int, int, int, const Buffer::Iterator &)> callback)
{ {
int rows = 1; int row_offset = 0;
int screen_column = 0; int screen_column = 0;
int virtual_column = 0;
Buffer::Iterator i = start_of_line; Buffer::Iterator i = start_of_line;
for (;;) for (;;)
{ {
uint32_t code_point = *i; uint32_t code_point = *i;
if ((code_point == '\n') || (!i.valid())) if ((code_point == '\n') || (!i.valid()))
{ {
callback(row_offset, screen_column, virtual_column, 0, i);
break; break;
} }
else if (code_point == '\t') int c_width;
if (code_point == '\t')
{ {
uint8_t tabstop = m_buffer->tabstop(); uint8_t tabstop = m_buffer->tabstop();
screen_column += tabstop - screen_column % tabstop; c_width = tabstop - screen_column % tabstop;
if (screen_column > m_columns) }
else
{
c_width = character_width(code_point);
}
if (((screen_column + c_width) > m_columns) &&
(screen_column > 0))
{
row_offset++;
screen_column = 0;
}
callback(row_offset, screen_column, virtual_column, c_width, i);
virtual_column += c_width;
if (code_point == '\t')
{
screen_column += c_width;
while (screen_column >= m_columns)
{ {
screen_column -= m_columns; screen_column -= m_columns;
rows++; row_offset++;
} }
} }
else else
{ {
int c_width = character_width(code_point); if ((screen_column + c_width) >= m_columns)
if (((screen_column + c_width) > m_columns) &&
(c_width <= m_columns))
{ {
rows++; row_offset++;
screen_column = c_width; screen_column = 0;
} }
else else
{ {
@ -53,63 +70,36 @@ int BufferPane::rows_in_line(const Buffer::Iterator & start_of_line)
} }
i.go_forward(); i.go_forward();
} }
return rows; }
int BufferPane::rows_in_line(const Buffer::Iterator & start_of_line)
{
int saved_row_offset;
walk_line(start_of_line, [&saved_row_offset](int row_offset, int screen_column, int virtual_column, int character_width, const Buffer::Iterator & i) {
uint32_t code_point = *i;
if ((code_point != '\n') && (code_point != 0xFFFFFFFFu))
{
saved_row_offset = row_offset;
}
});
return saved_row_offset + 1;
} }
int BufferPane::rows_in_line_with_iterator_offset(const Buffer::Iterator & start_of_line, const Buffer::Iterator & reference, int * iterator_row_offset) int BufferPane::rows_in_line_with_iterator_offset(const Buffer::Iterator & start_of_line, const Buffer::Iterator & reference, int * iterator_row_offset)
{ {
int rows = 1; int saved_row_offset;
int screen_column = 0; walk_line(start_of_line, [&saved_row_offset, &reference, &iterator_row_offset](int row_offset, int screen_column, int virtual_column, int character_width, const Buffer::Iterator & i) {
Buffer::Iterator i = start_of_line;
for (;;)
{
uint32_t code_point = *i; uint32_t code_point = *i;
if ((code_point == '\n') || (!i.valid()))
{
if (i == reference)
{
if (screen_column == m_columns)
{
*iterator_row_offset = rows;
}
else
{
*iterator_row_offset = rows - 1;
}
}
break;
}
else if (code_point == '\t')
{
uint8_t tabstop = m_buffer->tabstop();
screen_column += tabstop - screen_column % tabstop;
if (screen_column > m_columns)
{
screen_column -= m_columns;
rows++;
}
}
else
{
int c_width = character_width(code_point);
if (((screen_column + c_width) > m_columns) &&
(c_width <= m_columns))
{
rows++;
screen_column = c_width;
}
else
{
screen_column += c_width;
}
}
if (i == reference) if (i == reference)
{ {
*iterator_row_offset = rows; *iterator_row_offset = row_offset;
} }
i.go_forward(); if ((code_point != '\n') && (code_point != 0xFFFFFFFFu))
} {
return rows; saved_row_offset = row_offset;
}
});
return saved_row_offset + 1;
} }
int BufferPane::screen_rows_below_line(const Buffer::Iterator & line) int BufferPane::screen_rows_below_line(const Buffer::Iterator & line)
@ -189,81 +179,33 @@ void BufferPane::draw()
int BufferPane::draw_buffer_line(int screen_row, const Buffer::Iterator & start_of_line) int BufferPane::draw_buffer_line(int screen_row, const Buffer::Iterator & start_of_line)
{ {
int row_offset = 0; int saved_row_offset = 0;
int screen_column = 0; walk_line(start_of_line, [this, &saved_row_offset, &screen_row](int row_offset, int screen_column, int virtual_column, int character_width, const Buffer::Iterator & i) {
int virtual_column = 0;
Buffer::Iterator i = start_of_line;
for (;;)
{
uint32_t code_point = *i; uint32_t code_point = *i;
if ((code_point == '\n') || (!i.valid())) int draw_row = screen_row + row_offset;
int x = col_x(screen_column);
int y = row_y(draw_row);
if ((draw_row >= 0) && (draw_row < m_rows))
{ {
if (i == *m_iterator) if (i == *m_iterator)
{ {
if (screen_column == m_columns) /* TODO: highlight multi-column characters */
{ draw_cursor(x, y, false);
int x = col_x(0);
int y = row_y(screen_row + row_offset + 1);
draw_cursor(x, y, false);
}
else
{
int x = col_x(screen_column);
int y = row_y(screen_row + row_offset);
draw_cursor(x, y, false);
}
} }
break; if ((code_point == '\n') || (code_point == 0xFFFFFFFFu))
}
else if (code_point == '\t')
{
uint8_t tabstop = m_buffer->tabstop();
int col_increment = tabstop - screen_column % tabstop;
virtual_column += col_increment;
screen_column += col_increment;
if (screen_column > m_columns)
{ {
screen_column -= m_columns;
row_offset++;
}
}
else
{
int c_width = character_width(code_point);
virtual_column += c_width;
if (((screen_column + c_width) > m_columns) &&
(c_width <= m_columns))
{
row_offset++;
screen_column = c_width;
} }
else else
{ {
screen_column += c_width; saved_row_offset = row_offset;
if ((code_point != '\t') && (code_point != ' '))
{
m_window->gl()->draw_character(win_x(x), win_y(y), code_point, *m_window->font());
}
} }
} }
int draw_row = screen_row + row_offset; });
if (draw_row >= m_rows) return saved_row_offset + 1;
{
break;
}
if (draw_row >= 0)
{
int x = col_x(screen_column);
int y = row_y(screen_row + row_offset);
if (i == *m_iterator)
{
draw_cursor(x, y, false);
}
uint32_t c = *i;
if ((c != '\t') && (c != ' '))
{
m_window->gl()->draw_character(win_x(x), win_y(y), c, *m_window->font());
}
}
i.go_forward();
}
return row_offset + 1;
} }
int BufferPane::character_width(uint32_t character) int BufferPane::character_width(uint32_t character)

View File

@ -40,6 +40,7 @@ protected:
int screen_rows_below_line(const Buffer::Iterator & line); int screen_rows_below_line(const Buffer::Iterator & line);
int screen_rows_above_line(const Buffer::Iterator & line, std::list<std::pair<int, Buffer::Iterator>> backward_lines); int screen_rows_above_line(const Buffer::Iterator & line, std::list<std::pair<int, Buffer::Iterator>> backward_lines);
int update_cursor_row(std::list<std::pair<int, Buffer::Iterator>> backward_lines); int update_cursor_row(std::list<std::pair<int, Buffer::Iterator>> backward_lines);
void walk_line(const Buffer::Iterator & start_of_line, std::function<void(int, int, int, int, const Buffer::Iterator &)> callback);
int col_x(int col) int col_x(int col)
{ {
return col * m_window->font()->get_advance(); return col * m_window->font()->get_advance();