[Fix] Regression bugs with scrolling and auto-scrolling
This commit is contained in:
parent
6a5515e276
commit
bb8591a803
@ -20,7 +20,7 @@ Terminal::Terminal(GameState* game_state)
|
|||||||
|
|
||||||
Terminal::~Terminal(void) {}
|
Terminal::~Terminal(void) {}
|
||||||
|
|
||||||
void Terminal::update(void) {
|
void Terminal::update(int content_width, int content_height) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,8 @@ void Terminal::_on_ret_press(void) {
|
|||||||
_game_state->send_network_command(_session_id, command);
|
_game_state->send_network_command(_session_id, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) {
|
void Terminal::handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y,
|
||||||
|
int content_width, int content_height) {
|
||||||
/* Pass input to TextView; if true, RET was pressed. */
|
/* Pass input to TextView; if true, RET was pressed. */
|
||||||
if(event->type == SDL_EVENT_KEY_DOWN) {
|
if(event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
switch(event->key.key) {
|
switch(event->key.key) {
|
||||||
@ -114,10 +115,10 @@ void Terminal::handle_input(SDL_Event* event, int window_x, int window_y, int wi
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if(_input_view->handle_event(event)) { _on_ret_press(); }
|
if(_input_view->handle_event(event, content_height)) { _on_ret_press(); }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(_input_view->handle_event(event)) { _on_ret_press(); }
|
if(_input_view->handle_event(event, content_height)) { _on_ret_press(); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,8 +17,9 @@ public:
|
|||||||
Terminal(GameState* game_state);
|
Terminal(GameState* game_state);
|
||||||
~Terminal(void);
|
~Terminal(void);
|
||||||
|
|
||||||
void update(void) override;
|
void update(int content_width, int content_height) override;
|
||||||
void handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) override;
|
void handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y,
|
||||||
|
int content_width, int content_height) override;
|
||||||
void render(const RenderContext& context, int x, int y_screen, int y_gl,
|
void render(const RenderContext& context, int x, int y_screen, int y_gl,
|
||||||
int width, int height) override;
|
int width, int height) override;
|
||||||
void scroll(int amount, int content_height) override;
|
void scroll(int amount, int content_height) override;
|
||||||
|
|||||||
@ -29,11 +29,12 @@ Editor::Editor(const std::string& filename)
|
|||||||
|
|
||||||
Editor::~Editor(void) {}
|
Editor::~Editor(void) {}
|
||||||
|
|
||||||
void Editor::update(void) {
|
void Editor::update(int content_width, int content_height) {
|
||||||
/* Nothing to do yet. */
|
/* Nothing to do yet. */
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) {
|
void Editor::handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y,
|
||||||
|
int content_width, int content_height) {
|
||||||
if(!event) return;
|
if(!event) return;
|
||||||
|
|
||||||
_menu_bar->handle_event(event, window_x, window_y);
|
_menu_bar->handle_event(event, window_x, window_y);
|
||||||
@ -44,7 +45,7 @@ void Editor::handle_input(SDL_Event* event, int window_x, int window_y, int wind
|
|||||||
/* C-S pressed, create a save action. */
|
/* C-S pressed, create a save action. */
|
||||||
_pending_action = { ActionType::WRITE_FILE, _filename, _buffer.get_text() };
|
_pending_action = { ActionType::WRITE_FILE, _filename, _buffer.get_text() };
|
||||||
} else {
|
} else {
|
||||||
_view->handle_event(event);
|
_view->handle_event(event, content_height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +60,8 @@ void Editor::render(const RenderContext& context, int x, int y_screen, int y_gl,
|
|||||||
_menu_bar->render_bar_bg(context.ui_renderer, x, y_screen, width);
|
_menu_bar->render_bar_bg(context.ui_renderer, x, y_screen, width);
|
||||||
context.ui_renderer->flush_shapes();
|
context.ui_renderer->flush_shapes();
|
||||||
|
|
||||||
|
context.ui_renderer->enable_scissor(x, y_gl, width, content_height);
|
||||||
|
|
||||||
/* Pass 2: Main text view. */
|
/* Pass 2: Main text view. */
|
||||||
context.ui_renderer->begin_text();
|
context.ui_renderer->begin_text();
|
||||||
_view->render_text_content(context.ui_renderer, _theme, x, content_y, width, content_height);
|
_view->render_text_content(context.ui_renderer, _theme, x, content_y, width, content_height);
|
||||||
@ -71,6 +74,8 @@ void Editor::render(const RenderContext& context, int x, int y_screen, int y_gl,
|
|||||||
context.ui_renderer->flush_shapes();
|
context.ui_renderer->flush_shapes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.ui_renderer->disable_scissor();
|
||||||
|
|
||||||
/* Pass 4: Menu bar text and dropdown. */
|
/* Pass 4: Menu bar text and dropdown. */
|
||||||
context.ui_renderer->begin_text();
|
context.ui_renderer->begin_text();
|
||||||
_menu_bar->render_bar_text(context.ui_renderer, x, y_screen, width);
|
_menu_bar->render_bar_text(context.ui_renderer, x, y_screen, width);
|
||||||
|
|||||||
@ -25,8 +25,9 @@ public:
|
|||||||
Editor(const std::string& filename);
|
Editor(const std::string& filename);
|
||||||
~Editor(void) override;
|
~Editor(void) override;
|
||||||
|
|
||||||
void update(void) override;
|
void update(int content_width, int content_height) override;
|
||||||
void handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) override;
|
void handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y,
|
||||||
|
int content_widht, int content_heigth) override;
|
||||||
void render(const RenderContext& context, int x, int y_screen, int y_gl,
|
void render(const RenderContext& context, int x, int y_screen, int y_gl,
|
||||||
int width, int height) override;
|
int width, int height) override;
|
||||||
void scroll(int amount, int content_height) override;
|
void scroll(int amount, int content_height) override;
|
||||||
|
|||||||
@ -8,8 +8,9 @@
|
|||||||
class IWindowContent {
|
class IWindowContent {
|
||||||
public:
|
public:
|
||||||
virtual ~IWindowContent(void) = default;
|
virtual ~IWindowContent(void) = default;
|
||||||
virtual void update(void) = 0;
|
virtual void update(int content_width, int content_height) = 0;
|
||||||
virtual void handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) = 0;
|
virtual void handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y,
|
||||||
|
int content_width, int content_height) = 0;
|
||||||
virtual void render(const RenderContext& context, int x, int y_screen, int y_gl,
|
virtual void render(const RenderContext& context, int x, int y_screen, int y_gl,
|
||||||
int width, int height) = 0;
|
int width, int height) = 0;
|
||||||
virtual void scroll(int amount, int content_height) = 0;
|
virtual void scroll(int amount, int content_height) = 0;
|
||||||
|
|||||||
@ -22,17 +22,19 @@ TextView::TextView(TextBuffer* buffer, bool handle_ret, bool show_line_numbers,
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
TextView::~TextView(void) {}
|
TextView::~TextView(void) = default;
|
||||||
|
|
||||||
bool TextView::handle_event(SDL_Event* event) {
|
bool TextView::handle_event(SDL_Event* event, int content_height) {
|
||||||
if(!_buffer) return false;
|
if(!_buffer) return false;
|
||||||
|
|
||||||
if(event->type == SDL_EVENT_TEXT_INPUT) {
|
if(event->type == SDL_EVENT_TEXT_INPUT) {
|
||||||
_buffer->insert_char(event->text.text[0]);
|
_buffer->insert_char(event->text.text[0]);
|
||||||
|
_ensure_cursor_visible(content_height);
|
||||||
} else if(event->type == SDL_EVENT_KEY_DOWN) {
|
} else if(event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
switch(event->key.key) {
|
switch(event->key.key) {
|
||||||
case SDLK_BACKSPACE:
|
case SDLK_BACKSPACE:
|
||||||
_buffer->backspace();
|
_buffer->backspace();
|
||||||
|
_ensure_cursor_visible(content_height);
|
||||||
break;
|
break;
|
||||||
case SDLK_RETURN:
|
case SDLK_RETURN:
|
||||||
/*
|
/*
|
||||||
@ -43,22 +45,28 @@ bool TextView::handle_event(SDL_Event* event) {
|
|||||||
if(_handle_ret) {
|
if(_handle_ret) {
|
||||||
_buffer->newline();
|
_buffer->newline();
|
||||||
}
|
}
|
||||||
|
_ensure_cursor_visible(content_height);
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
case SDLK_LEFT:
|
case SDLK_LEFT:
|
||||||
_buffer->move_cursor(-1,0);
|
_buffer->move_cursor(-1,0);
|
||||||
|
_ensure_cursor_visible(content_height);
|
||||||
break;
|
break;
|
||||||
case SDLK_RIGHT:
|
case SDLK_RIGHT:
|
||||||
_buffer->move_cursor(1,0);
|
_buffer->move_cursor(1,0);
|
||||||
|
_ensure_cursor_visible(content_height);
|
||||||
break;
|
break;
|
||||||
case SDLK_UP:
|
case SDLK_UP:
|
||||||
_buffer->move_cursor(0,-1);
|
_buffer->move_cursor(0,-1);
|
||||||
|
_ensure_cursor_visible(content_height);
|
||||||
break;
|
break;
|
||||||
case SDLK_DOWN:
|
case SDLK_DOWN:
|
||||||
_buffer->move_cursor(0,1);
|
_buffer->move_cursor(0,1);
|
||||||
|
_ensure_cursor_visible(content_height);
|
||||||
break;
|
break;
|
||||||
case SDLK_HOME:
|
case SDLK_HOME:
|
||||||
_buffer->move_cursor_home();
|
_buffer->move_cursor_home();
|
||||||
|
_ensure_cursor_visible(content_height);
|
||||||
break;
|
break;
|
||||||
case SDLK_END:
|
case SDLK_END:
|
||||||
_buffer->move_cursor_end();
|
_buffer->move_cursor_end();
|
||||||
@ -77,8 +85,13 @@ void TextView::scroll(int amount, int content_height) {
|
|||||||
_scroll_offset = 0;
|
_scroll_offset = 0;
|
||||||
}
|
}
|
||||||
float line_height = 20.0f;
|
float line_height = 20.0f;
|
||||||
int visible_lines = content_height / line_height;
|
int visible_lines = static_cast<int>(content_height / line_height)-1;
|
||||||
int max_scroll = _buffer->get_line_count() - visible_lines;
|
int max_scroll = _buffer->get_line_count() - visible_lines;
|
||||||
|
/* Allow one extra scroll step if content is larger than visible area. */
|
||||||
|
if(_buffer->get_line_count() > visible_lines) max_scroll += 1;
|
||||||
|
if(max_scroll < 0) {
|
||||||
|
max_scroll = 0;
|
||||||
|
}
|
||||||
if(max_scroll < 0) max_scroll = 0;
|
if(max_scroll < 0) max_scroll = 0;
|
||||||
if(_scroll_offset > max_scroll) {
|
if(_scroll_offset > max_scroll) {
|
||||||
_scroll_offset = max_scroll;
|
_scroll_offset = max_scroll;
|
||||||
@ -168,7 +181,7 @@ void TextView::render_text_content(UIRenderer* ui_renderer, const SyntaxTheme& t
|
|||||||
* Culling: If the top of the current line is already below the bottom of the
|
* Culling: If the top of the current line is already below the bottom of the
|
||||||
* view, we can stop rendering completely.
|
* view, we can stop rendering completely.
|
||||||
*/
|
*/
|
||||||
if(current_y > y + height) {
|
if(current_y >= y + height) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,3 +231,20 @@ void TextView::render_cursor(UIRenderer* ui_renderer, const SyntaxTheme& theme,
|
|||||||
ui_renderer->draw_rect(cursor_x, cursor_y, 2, line_height, theme.normal);
|
ui_renderer->draw_rect(cursor_x, cursor_y, 2, line_height, theme.normal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextView::_ensure_cursor_visible(int content_height) {
|
||||||
|
Point cursor_pos = _buffer->get_cursor_pos();
|
||||||
|
float line_height = 20.0f;
|
||||||
|
int visible_lines = static_cast<int>(content_height / line_height)-1;
|
||||||
|
|
||||||
|
/* If cursor above current scroll view, scroll up. */
|
||||||
|
if(cursor_pos.row < _scroll_offset) {
|
||||||
|
_scroll_offset = cursor_pos.row;
|
||||||
|
} else if(cursor_pos.row >= _scroll_offset + visible_lines) {
|
||||||
|
/* Below, scroll down. */
|
||||||
|
_scroll_offset = cursor_pos.row - visible_lines+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-clamp scroll offset to ensure it's within valid bounds. */
|
||||||
|
scroll(0, content_height);
|
||||||
|
}
|
||||||
|
|||||||
@ -29,7 +29,7 @@ public:
|
|||||||
TextView(TextBuffer* buffer, bool handle_ret, bool show_line_numbers, bool syntax_highlighting);
|
TextView(TextBuffer* buffer, bool handle_ret, bool show_line_numbers, bool syntax_highlighting);
|
||||||
~TextView(void);
|
~TextView(void);
|
||||||
|
|
||||||
bool handle_event(SDL_Event* event);
|
bool handle_event(SDL_Event* event, int content_height);
|
||||||
void scroll(int amount, int content_height);
|
void scroll(int amount, int content_height);
|
||||||
void render_text_content(UIRenderer* ui_renderer, const SyntaxTheme& theme,
|
void render_text_content(UIRenderer* ui_renderer, const SyntaxTheme& theme,
|
||||||
int x, int y, int width, int height);
|
int x, int y, int width, int height);
|
||||||
@ -37,6 +37,7 @@ public:
|
|||||||
int x, int y, int width, int height);
|
int x, int y, int width, int height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void _ensure_cursor_visible(int content_height);
|
||||||
std::vector<Token> _tokenize_line(const std::string& line);
|
std::vector<Token> _tokenize_line(const std::string& line);
|
||||||
|
|
||||||
TextBuffer* _buffer;
|
TextBuffer* _buffer;
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
#include <GL/glew.h>
|
||||||
|
|
||||||
#include "ui_renderer.h"
|
#include "ui_renderer.h"
|
||||||
#include "gfx/shape_renderer.h"
|
#include "gfx/shape_renderer.h"
|
||||||
#include "gfx/txt_renderer.h"
|
#include "gfx/txt_renderer.h"
|
||||||
@ -51,3 +53,12 @@ void UIRenderer::flush_shapes(void) {
|
|||||||
TextRenderer* UIRenderer::get_text_renderer(void) {
|
TextRenderer* UIRenderer::get_text_renderer(void) {
|
||||||
return _txt_renderer;
|
return _txt_renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UIRenderer::enable_scissor(int x, int y, int width, int height) {
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
glScissor(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIRenderer::disable_scissor(void) {
|
||||||
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
}
|
||||||
|
|||||||
@ -26,6 +26,9 @@ public:
|
|||||||
/* Expose underlying text renderer for things like width calculation. */
|
/* Expose underlying text renderer for things like width calculation. */
|
||||||
TextRenderer* get_text_renderer(void);
|
TextRenderer* get_text_renderer(void);
|
||||||
|
|
||||||
|
void enable_scissor(int x, int y, int width, int height);
|
||||||
|
void disable_scissor(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ShapeRenderer* _shape_renderer;
|
ShapeRenderer* _shape_renderer;
|
||||||
TextRenderer* _txt_renderer;
|
TextRenderer* _txt_renderer;
|
||||||
|
|||||||
@ -129,9 +129,10 @@ void UIWindow::render(const RenderContext& context) {
|
|||||||
if(_content) {
|
if(_content) {
|
||||||
int content_screen_y = _y + title_bar_height;
|
int content_screen_y = _y + title_bar_height;
|
||||||
int content_height = _height - title_bar_height;
|
int content_height = _height - title_bar_height;
|
||||||
|
int content_width = _width;
|
||||||
/* Got to pass GL y-coord for scissor box to work correctly. */
|
/* Got to pass GL y-coord for scissor box to work correctly. */
|
||||||
int content_gl_y = context.screen_height - content_screen_y - content_height;
|
int content_gl_y = context.screen_height - content_screen_y - content_height;
|
||||||
_content->render(context, _x, content_screen_y, content_gl_y, _width, content_height);
|
_content->render(context, _x, content_screen_y, content_gl_y, content_width, content_height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +216,9 @@ void UIWindow::handle_event(SDL_Event* event, int screen_width,
|
|||||||
}
|
}
|
||||||
if(_content) {
|
if(_content) {
|
||||||
int y_gl = screen_height - _y - _height;
|
int y_gl = screen_height - _y - _height;
|
||||||
_content->handle_input(event, _x, _y, y_gl);
|
int content_height = _height - title_bar_height;
|
||||||
|
int content_width = _width;
|
||||||
|
_content->handle_input(event, _x, _y, y_gl, content_width, content_height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user