From 8bffc05f093a113242ee7ea3763a16b95666c933 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 27 Nov 2016 13:17:20 -0500 Subject: [PATCH] add a BufferPane class to hold logic for rendering a buffer --- src/gui/BufferPane.cc | 123 +++++++++++++++++++++++++++++++++++++++ src/gui/BufferPane.h | 44 ++++++++++++++ src/gui/Pane.h | 44 ++++++++++++++ src/gui/Window.cc | 132 +++++------------------------------------- src/gui/Window.h | 24 ++------ 5 files changed, 228 insertions(+), 139 deletions(-) create mode 100644 src/gui/BufferPane.cc create mode 100644 src/gui/BufferPane.h create mode 100644 src/gui/Pane.h diff --git a/src/gui/BufferPane.cc b/src/gui/BufferPane.cc new file mode 100644 index 0000000..60a7b60 --- /dev/null +++ b/src/gui/BufferPane.cc @@ -0,0 +1,123 @@ +#include "BufferPane.h" + +BufferPane::BufferPane(std::shared_ptr buffer, + std::shared_ptr font, + std::shared_ptr 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(); +} diff --git a/src/gui/BufferPane.h b/src/gui/BufferPane.h new file mode 100644 index 0000000..62413e9 --- /dev/null +++ b/src/gui/BufferPane.h @@ -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 + +class BufferPane : public Pane +{ +public: + BufferPane(std::shared_ptr buffer, + std::shared_ptr font, + std::shared_ptr gl); + void resize(int width, int height) override; + void draw(); + std::shared_ptr 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 m_buffer; + std::shared_ptr m_font; + std::shared_ptr m_gl; + int m_rows; + int m_columns; + int m_scroll_offset; + int m_cursor_row; + std::shared_ptr m_cursor; +}; + +#endif diff --git a/src/gui/Pane.h b/src/gui/Pane.h new file mode 100644 index 0000000..b3059f2 --- /dev/null +++ b/src/gui/Pane.h @@ -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 diff --git a/src/gui/Window.cc b/src/gui/Window.cc index f976dd0..028c0ce 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -107,21 +107,20 @@ bool Window::create(std::shared_ptr buffer) return false; } - if (!m_font.load(font_path.c_str(), FONT_SIZE)) + m_font = std::make_shared(); + if (!m_font->load(font_path.c_str(), FONT_SIZE)) { return false; } m_gl = std::make_shared(); - m_buffer = buffer; - m_cursor = buffer->add_cursor(); - m_cursor_row = 0; - m_scroll_offset = 5; m_target_column = 0u; /* TODO: fix */ glClearColor (0.0, 0.0, 0.0, 0.0); + m_buffer_pane = std::make_shared(buffer, m_font, m_gl); + resize(); return true; @@ -336,115 +335,37 @@ void Window::cursor_move(int which) #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() { SDL_GetWindowSize(m_window, &m_width, &m_height); glViewport(0, 0, m_width, m_height); m_gl->resize(m_width, m_height); - m_columns = std::max(1, m_width / m_font.get_advance()); - m_rows = std::max(1, (m_height - 2) / m_font.get_line_height()); + m_buffer_pane->move(0, m_font->get_line_height() + 1); + m_buffer_pane->resize(m_width, m_height - m_font->get_line_height() - 1); } void Window::redraw() { glClear(GL_COLOR_BUFFER_BIT); - draw_buffer(); + m_buffer_pane->draw(); draw_status_bar(); 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() { - 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, 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); 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 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++) { - m_gl->draw_character(x, 0, cursor_position[i], m_font); - x += m_font.get_advance(); + m_gl->draw_character(x, 0, cursor_position[i], *m_font); + x += m_font->get_advance(); } } @@ -512,30 +433,3 @@ uint32_t Window::get_shifted(uint32_t 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; -} diff --git a/src/gui/Window.h b/src/gui/Window.h index 7a5e128..37317b6 100644 --- a/src/gui/Window.h +++ b/src/gui/Window.h @@ -7,6 +7,7 @@ #include "Font.h" #include "Buffer.h" #include "GL.h" +#include "BufferPane.h" class Window { @@ -35,43 +36,26 @@ protected: void resize(); 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_keysym(uint32_t keysym); void handle_keyval(uint32_t keyval); 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(); uint32_t get_keyval(SDL_Keycode 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; bool m_exit_requested; int m_width; int m_height; - Font m_font; - int m_columns; - int m_rows; - int m_cursor_row; - int m_scroll_offset; + std::shared_ptr m_font; uint32_t m_target_column; - std::shared_ptr m_buffer; - std::shared_ptr m_cursor; - std::shared_ptr m_gl; + std::shared_ptr m_buffer_pane; + Uint16 m_keymod; };