add a BufferPane class to hold logic for rendering a buffer
This commit is contained in:
parent
fa8872bcda
commit
8bffc05f09
123
src/gui/BufferPane.cc
Normal file
123
src/gui/BufferPane.cc
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#include "BufferPane.h"
|
||||||
|
|
||||||
|
BufferPane::BufferPane(std::shared_ptr<Buffer> buffer,
|
||||||
|
std::shared_ptr<Font> font,
|
||||||
|
std::shared_ptr<GL> gl)
|
||||||
|
: m_buffer(buffer), m_font(font), m_gl(gl)
|
||||||
|
{
|
||||||
|
m_cursor_row = 0;
|
||||||
|
m_scroll_offset = 5;
|
||||||
|
m_cursor = buffer->add_cursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferPane::resize(int width, int height)
|
||||||
|
{
|
||||||
|
Pane::resize(width, height);
|
||||||
|
m_columns = std::max(1, m_width / m_font->get_advance());
|
||||||
|
m_rows = std::max(1, (m_height + m_font->get_line_height() - 1) / m_font->get_line_height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferPane::update_cursor_row()
|
||||||
|
{
|
||||||
|
int so = effective_scroll_offset();
|
||||||
|
int rows_above = screen_rows_above_cursor(std::max(so, m_cursor_row));
|
||||||
|
int rows_below = screen_rows_below_cursor(std::max(so, m_rows - m_cursor_row - 1));
|
||||||
|
int min_rows_to_leave_above = std::min(rows_above, so);
|
||||||
|
int min_rows_to_leave_below = std::min(rows_below, so);
|
||||||
|
m_cursor_row = std::max(min_rows_to_leave_above, std::min(m_rows - min_rows_to_leave_below - 1, m_cursor_row));
|
||||||
|
}
|
||||||
|
|
||||||
|
int BufferPane::screen_rows_below_cursor(int stop_at)
|
||||||
|
{
|
||||||
|
GapBuffer::Cursor cursor = *m_cursor;
|
||||||
|
size_t column = cursor.column();
|
||||||
|
cursor.go_end_of_line(false);
|
||||||
|
int rows = (cursor.column() / m_columns) - (column / m_columns);
|
||||||
|
while ((rows < stop_at) && cursor.go_down(0u))
|
||||||
|
{
|
||||||
|
cursor.go_end_of_line(false);
|
||||||
|
rows += (cursor.column() / m_columns) + 1;
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BufferPane::screen_rows_above_cursor(int stop_at)
|
||||||
|
{
|
||||||
|
GapBuffer::Cursor cursor = *m_cursor;
|
||||||
|
int rows = cursor.column() / m_columns;
|
||||||
|
while ((rows < stop_at) && cursor.go_up(0u))
|
||||||
|
{
|
||||||
|
GapBuffer::Cursor cursor2 = cursor;
|
||||||
|
cursor2.go_end_of_line(false);
|
||||||
|
rows += (cursor2.column() / m_columns) + 1;
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferPane::draw()
|
||||||
|
{
|
||||||
|
update_cursor_row();
|
||||||
|
int screen_row = m_cursor_row - m_cursor->column() / m_columns;
|
||||||
|
GapBuffer::Cursor iter_cursor = *m_cursor;
|
||||||
|
iter_cursor.go_start_of_line();
|
||||||
|
while ((screen_row > 0) && iter_cursor.go_up(0u))
|
||||||
|
{
|
||||||
|
GapBuffer::Cursor cursor2 = iter_cursor;
|
||||||
|
cursor2.go_end_of_line(false);
|
||||||
|
screen_row -= (1 + cursor2.column() / m_columns);
|
||||||
|
}
|
||||||
|
while (screen_row < m_rows)
|
||||||
|
{
|
||||||
|
draw_buffer_line(screen_row, iter_cursor);
|
||||||
|
iter_cursor.go_end_of_line(false);
|
||||||
|
screen_row += (1 + iter_cursor.column() / m_columns);
|
||||||
|
if (!iter_cursor.go_down(0u))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferPane::draw_buffer_line(int screen_row, const GapBuffer::Cursor & cursor)
|
||||||
|
{
|
||||||
|
GapBuffer::Cursor iter_cursor = cursor;
|
||||||
|
while (!iter_cursor.is_end_of_line(true))
|
||||||
|
{
|
||||||
|
int draw_row = screen_row + (iter_cursor.column() / m_columns);
|
||||||
|
if (draw_row < 0)
|
||||||
|
continue;
|
||||||
|
if (draw_row >= m_rows)
|
||||||
|
break;
|
||||||
|
int draw_column = iter_cursor.column() % m_columns;
|
||||||
|
int x, y;
|
||||||
|
colrow_to_xy(draw_column, draw_row, &x, &y);
|
||||||
|
uint32_t c = *iter_cursor;
|
||||||
|
if ((c != '\t') && (c != ' '))
|
||||||
|
{
|
||||||
|
m_gl->draw_character(win_x(x), win_y(y), c, *m_font);
|
||||||
|
}
|
||||||
|
iter_cursor.go_right(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferPane::draw_buffer_character(int screen_column, int screen_row, uint32_t character)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
colrow_to_xy(screen_column, screen_row, &x, &y);
|
||||||
|
m_gl->draw_character(win_x(x), win_y(y), character, *m_font);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferPane::draw_cursor(int screen_column, int screen_row, bool insert_mode)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
colrow_to_xy(screen_column, screen_row, &x, &y);
|
||||||
|
int width = insert_mode ? 1 : m_font->get_advance();
|
||||||
|
int height = m_font->get_line_height();
|
||||||
|
m_gl->draw_rect(win_x(x), win_y(y), width, height, 1.0, 0.2, 1.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferPane::colrow_to_xy(int col, int row, int * x, int * y)
|
||||||
|
{
|
||||||
|
*x = col * m_font->get_advance();
|
||||||
|
*y = m_height - (row + 1) * m_font->get_line_height();
|
||||||
|
}
|
44
src/gui/BufferPane.h
Normal file
44
src/gui/BufferPane.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef BUFFERPANE_H
|
||||||
|
#define BUFFERPANE_H
|
||||||
|
|
||||||
|
#include "GapBuffer.h"
|
||||||
|
#include "Buffer.h"
|
||||||
|
#include "Pane.h"
|
||||||
|
#include "Font.h"
|
||||||
|
#include "GL.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class BufferPane : public Pane
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BufferPane(std::shared_ptr<Buffer> buffer,
|
||||||
|
std::shared_ptr<Font> font,
|
||||||
|
std::shared_ptr<GL> gl);
|
||||||
|
void resize(int width, int height) override;
|
||||||
|
void draw();
|
||||||
|
std::shared_ptr<GapBuffer::Cursor> cursor() { return m_cursor; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int effective_scroll_offset()
|
||||||
|
{
|
||||||
|
return std::min(m_scroll_offset, (m_rows - 1) / 2);
|
||||||
|
}
|
||||||
|
int screen_rows_below_cursor(int stop_at);
|
||||||
|
int screen_rows_above_cursor(int stop_at);
|
||||||
|
void update_cursor_row();
|
||||||
|
void draw_buffer_line(int screen_row, const GapBuffer::Cursor & cursor);
|
||||||
|
void draw_buffer_character(int screen_column, int screen_row, uint32_t character);
|
||||||
|
void draw_cursor(int screen_column, int screen_row, bool insert_mode);
|
||||||
|
void colrow_to_xy(int col, int row, int * x, int * y);
|
||||||
|
|
||||||
|
std::shared_ptr<Buffer> m_buffer;
|
||||||
|
std::shared_ptr<Font> m_font;
|
||||||
|
std::shared_ptr<GL> m_gl;
|
||||||
|
int m_rows;
|
||||||
|
int m_columns;
|
||||||
|
int m_scroll_offset;
|
||||||
|
int m_cursor_row;
|
||||||
|
std::shared_ptr<GapBuffer::Cursor> m_cursor;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
44
src/gui/Pane.h
Normal file
44
src/gui/Pane.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef PANE_H
|
||||||
|
#define PANE_H
|
||||||
|
|
||||||
|
class Pane
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Pane()
|
||||||
|
{
|
||||||
|
m_x = 0;
|
||||||
|
m_y = 0;
|
||||||
|
m_width = 0;
|
||||||
|
m_height = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void move(int x, int y)
|
||||||
|
{
|
||||||
|
m_x = x;
|
||||||
|
m_y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void resize(int width, int height)
|
||||||
|
{
|
||||||
|
m_width = width;
|
||||||
|
m_height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
int win_x(int offset)
|
||||||
|
{
|
||||||
|
return m_x + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int win_y(int offset)
|
||||||
|
{
|
||||||
|
return m_y + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int m_x;
|
||||||
|
int m_y;
|
||||||
|
int m_width;
|
||||||
|
int m_height;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -107,21 +107,20 @@ bool Window::create(std::shared_ptr<Buffer> buffer)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_font.load(font_path.c_str(), FONT_SIZE))
|
m_font = std::make_shared<Font>();
|
||||||
|
if (!m_font->load(font_path.c_str(), FONT_SIZE))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_gl = std::make_shared<GL>();
|
m_gl = std::make_shared<GL>();
|
||||||
|
|
||||||
m_buffer = buffer;
|
|
||||||
m_cursor = buffer->add_cursor();
|
|
||||||
m_cursor_row = 0;
|
|
||||||
m_scroll_offset = 5;
|
|
||||||
m_target_column = 0u; /* TODO: fix */
|
m_target_column = 0u; /* TODO: fix */
|
||||||
|
|
||||||
glClearColor (0.0, 0.0, 0.0, 0.0);
|
glClearColor (0.0, 0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
m_buffer_pane = std::make_shared<BufferPane>(buffer, m_font, m_gl);
|
||||||
|
|
||||||
resize();
|
resize();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -336,115 +335,37 @@ void Window::cursor_move(int which)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::update_cursor_row()
|
|
||||||
{
|
|
||||||
int so = effective_scroll_offset();
|
|
||||||
int rows_above = screen_rows_above_cursor(std::max(so, m_cursor_row));
|
|
||||||
int rows_below = screen_rows_below_cursor(std::max(so, m_rows - m_cursor_row - 1));
|
|
||||||
int min_rows_to_leave_above = std::min(rows_above, so);
|
|
||||||
int min_rows_to_leave_below = std::min(rows_below, so);
|
|
||||||
m_cursor_row = std::max(min_rows_to_leave_above, std::min(m_rows - min_rows_to_leave_below - 1, m_cursor_row));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::draw_buffer()
|
|
||||||
{
|
|
||||||
update_cursor_row();
|
|
||||||
int screen_row = m_cursor_row - m_cursor->column() / m_columns;
|
|
||||||
GapBuffer::Cursor iter_cursor = *m_cursor;
|
|
||||||
iter_cursor.go_start_of_line();
|
|
||||||
while ((screen_row > 0) && iter_cursor.go_up(0u))
|
|
||||||
{
|
|
||||||
GapBuffer::Cursor cursor2 = iter_cursor;
|
|
||||||
cursor2.go_end_of_line(false);
|
|
||||||
screen_row -= (1 + cursor2.column() / m_columns);
|
|
||||||
}
|
|
||||||
while (screen_row < m_rows)
|
|
||||||
{
|
|
||||||
draw_buffer_line(screen_row, iter_cursor);
|
|
||||||
iter_cursor.go_end_of_line(false);
|
|
||||||
screen_row += (1 + iter_cursor.column() / m_columns);
|
|
||||||
if (!iter_cursor.go_down(0u))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::draw_buffer_line(int screen_row, const GapBuffer::Cursor & cursor)
|
|
||||||
{
|
|
||||||
GapBuffer::Cursor iter_cursor = cursor;
|
|
||||||
while (!iter_cursor.is_end_of_line(true))
|
|
||||||
{
|
|
||||||
int draw_row = screen_row + (iter_cursor.column() / m_columns);
|
|
||||||
if (draw_row < 0)
|
|
||||||
continue;
|
|
||||||
if (draw_row >= m_rows)
|
|
||||||
break;
|
|
||||||
int draw_column = iter_cursor.column() % m_columns;
|
|
||||||
int x, y;
|
|
||||||
colrow_to_xy(draw_column, draw_row, &x, &y);
|
|
||||||
uint32_t c = *iter_cursor;
|
|
||||||
if ((c != '\t') && (c != ' '))
|
|
||||||
{
|
|
||||||
m_gl->draw_character(x, y, c, m_font);
|
|
||||||
}
|
|
||||||
iter_cursor.go_right(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::draw_buffer_character(int screen_column, int screen_row, uint32_t character)
|
|
||||||
{
|
|
||||||
int x, y;
|
|
||||||
colrow_to_xy(screen_column, screen_row, &x, &y);
|
|
||||||
m_gl->draw_character(x, y, character, m_font);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::resize()
|
void Window::resize()
|
||||||
{
|
{
|
||||||
SDL_GetWindowSize(m_window, &m_width, &m_height);
|
SDL_GetWindowSize(m_window, &m_width, &m_height);
|
||||||
glViewport(0, 0, m_width, m_height);
|
glViewport(0, 0, m_width, m_height);
|
||||||
m_gl->resize(m_width, m_height);
|
m_gl->resize(m_width, m_height);
|
||||||
m_columns = std::max(1, m_width / m_font.get_advance());
|
m_buffer_pane->move(0, m_font->get_line_height() + 1);
|
||||||
m_rows = std::max(1, (m_height - 2) / m_font.get_line_height());
|
m_buffer_pane->resize(m_width, m_height - m_font->get_line_height() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::redraw()
|
void Window::redraw()
|
||||||
{
|
{
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
draw_buffer();
|
m_buffer_pane->draw();
|
||||||
draw_status_bar();
|
draw_status_bar();
|
||||||
|
|
||||||
SDL_GL_SwapWindow(m_window);
|
SDL_GL_SwapWindow(m_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::draw_cursor(int screen_column, int screen_row, bool insert_mode)
|
|
||||||
{
|
|
||||||
int x, y;
|
|
||||||
colrow_to_xy(screen_column, screen_row, &x, &y);
|
|
||||||
int width = insert_mode ? 1 : m_font.get_advance();
|
|
||||||
int height = m_font.get_line_height();
|
|
||||||
m_gl->draw_rect(x, y, width, height, 1.0, 0.2, 1.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::colrow_to_xy(int col, int row, int * x, int * y)
|
|
||||||
{
|
|
||||||
*x = col * m_font.get_advance();
|
|
||||||
*y = m_height - (row + 1) * m_font.get_line_height();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::draw_status_bar()
|
void Window::draw_status_bar()
|
||||||
{
|
{
|
||||||
m_gl->draw_rect(0, m_font.get_line_height(), m_width, 1, 0.5, 0.5, 0.5, 1.0);
|
m_gl->draw_rect(0, m_font->get_line_height(), m_width, 1, 0.5, 0.5, 0.5, 1.0);
|
||||||
m_gl->draw_rect(0, 0, m_width, m_font.get_line_height(), 0.0, 0.0, 0.0, 1.0);
|
m_gl->draw_rect(0, 0, m_width, m_font->get_line_height(), 0.0, 0.0, 0.0, 1.0);
|
||||||
char cursor_position[20];
|
char cursor_position[20];
|
||||||
sprintf(cursor_position, "%zu, %zu", m_cursor->line() + 1, m_cursor->column() + 1u);
|
sprintf(cursor_position, "%zu, %zu", m_buffer_pane->cursor()->line() + 1, m_buffer_pane->cursor()->column() + 1u);
|
||||||
int cursor_position_length = strlen(cursor_position);
|
int cursor_position_length = strlen(cursor_position);
|
||||||
int x = m_width - m_font.get_advance() * cursor_position_length;
|
int x = m_width - m_font->get_advance() * cursor_position_length;
|
||||||
for (int i = 0; i < cursor_position_length; i++)
|
for (int i = 0; i < cursor_position_length; i++)
|
||||||
{
|
{
|
||||||
m_gl->draw_character(x, 0, cursor_position[i], m_font);
|
m_gl->draw_character(x, 0, cursor_position[i], *m_font);
|
||||||
x += m_font.get_advance();
|
x += m_font->get_advance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,30 +433,3 @@ uint32_t Window::get_shifted(uint32_t keysym)
|
|||||||
|
|
||||||
return keysym;
|
return keysym;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Window::screen_rows_below_cursor(int stop_at)
|
|
||||||
{
|
|
||||||
GapBuffer::Cursor cursor = *m_cursor;
|
|
||||||
size_t column = cursor.column();
|
|
||||||
cursor.go_end_of_line(false);
|
|
||||||
int rows = (cursor.column() / m_columns) - (column / m_columns);
|
|
||||||
while ((rows < stop_at) && cursor.go_down(0u))
|
|
||||||
{
|
|
||||||
cursor.go_end_of_line(false);
|
|
||||||
rows += (cursor.column() / m_columns) + 1;
|
|
||||||
}
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Window::screen_rows_above_cursor(int stop_at)
|
|
||||||
{
|
|
||||||
GapBuffer::Cursor cursor = *m_cursor;
|
|
||||||
int rows = cursor.column() / m_columns;
|
|
||||||
while ((rows < stop_at) && cursor.go_up(0u))
|
|
||||||
{
|
|
||||||
GapBuffer::Cursor cursor2 = cursor;
|
|
||||||
cursor2.go_end_of_line(false);
|
|
||||||
rows += (cursor2.column() / m_columns) + 1;
|
|
||||||
}
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "Font.h"
|
#include "Font.h"
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "GL.h"
|
#include "GL.h"
|
||||||
|
#include "BufferPane.h"
|
||||||
|
|
||||||
class Window
|
class Window
|
||||||
{
|
{
|
||||||
@ -35,43 +36,26 @@ protected:
|
|||||||
|
|
||||||
void resize();
|
void resize();
|
||||||
void redraw();
|
void redraw();
|
||||||
void draw_cursor(int screen_column, int screen_row, bool insert_mode);
|
|
||||||
void colrow_to_xy(int col, int row, int * x, int * y);
|
|
||||||
void handle_event(SDL_Event & event);
|
void handle_event(SDL_Event & event);
|
||||||
void handle_keysym(uint32_t keysym);
|
void handle_keysym(uint32_t keysym);
|
||||||
void handle_keyval(uint32_t keyval);
|
void handle_keyval(uint32_t keyval);
|
||||||
void cursor_move(int which);
|
void cursor_move(int which);
|
||||||
void draw_buffer();
|
|
||||||
void draw_buffer_line(int screen_row, const GapBuffer::Cursor & cursor);
|
|
||||||
void draw_buffer_character(int screen_column, int screen_row, uint32_t character);
|
|
||||||
void update_cursor_row();
|
|
||||||
void draw_status_bar();
|
void draw_status_bar();
|
||||||
uint32_t get_keyval(SDL_Keycode keysym);
|
uint32_t get_keyval(SDL_Keycode keysym);
|
||||||
uint32_t get_shifted(uint32_t keysym);
|
uint32_t get_shifted(uint32_t keysym);
|
||||||
int screen_rows_below_cursor(int stop_at);
|
|
||||||
int screen_rows_above_cursor(int stop_at);
|
|
||||||
int effective_scroll_offset()
|
|
||||||
{
|
|
||||||
return std::min(m_scroll_offset, (m_rows - 1) / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Window * m_window;
|
SDL_Window * m_window;
|
||||||
bool m_exit_requested;
|
bool m_exit_requested;
|
||||||
int m_width;
|
int m_width;
|
||||||
int m_height;
|
int m_height;
|
||||||
|
|
||||||
Font m_font;
|
std::shared_ptr<Font> m_font;
|
||||||
int m_columns;
|
|
||||||
int m_rows;
|
|
||||||
int m_cursor_row;
|
|
||||||
int m_scroll_offset;
|
|
||||||
uint32_t m_target_column;
|
uint32_t m_target_column;
|
||||||
|
|
||||||
std::shared_ptr<Buffer> m_buffer;
|
|
||||||
std::shared_ptr<GapBuffer::Cursor> m_cursor;
|
|
||||||
|
|
||||||
std::shared_ptr<GL> m_gl;
|
std::shared_ptr<GL> m_gl;
|
||||||
|
|
||||||
|
std::shared_ptr<BufferPane> m_buffer_pane;
|
||||||
|
|
||||||
Uint16 m_keymod;
|
Uint16 m_keymod;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user