[Fix] Regression bugs with scrolling and auto-scrolling

This commit is contained in:
Ritchie Cunningham 2025-10-25 18:48:58 +01:00
parent 6a5515e276
commit bb8591a803
10 changed files with 77 additions and 20 deletions

View File

@ -20,7 +20,7 @@ Terminal::Terminal(GameState* game_state)
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);
}
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. */
if(event->type == SDL_EVENT_KEY_DOWN) {
switch(event->key.key) {
@ -114,10 +115,10 @@ void Terminal::handle_input(SDL_Event* event, int window_x, int window_y, int wi
}
break;
default:
if(_input_view->handle_event(event)) { _on_ret_press(); }
if(_input_view->handle_event(event, content_height)) { _on_ret_press(); }
}
} else {
if(_input_view->handle_event(event)) { _on_ret_press(); }
if(_input_view->handle_event(event, content_height)) { _on_ret_press(); }
}
}

View File

@ -17,8 +17,9 @@ public:
Terminal(GameState* game_state);
~Terminal(void);
void update(void) override;
void handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) 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,
int content_width, int content_height) override;
void render(const RenderContext& context, int x, int y_screen, int y_gl,
int width, int height) override;
void scroll(int amount, int content_height) override;

View File

@ -29,11 +29,12 @@ Editor::Editor(const std::string& filename)
Editor::~Editor(void) {}
void Editor::update(void) {
void Editor::update(int content_width, int content_height) {
/* 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;
_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. */
_pending_action = { ActionType::WRITE_FILE, _filename, _buffer.get_text() };
} 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);
context.ui_renderer->flush_shapes();
context.ui_renderer->enable_scissor(x, y_gl, width, content_height);
/* Pass 2: Main text view. */
context.ui_renderer->begin_text();
_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->disable_scissor();
/* Pass 4: Menu bar text and dropdown. */
context.ui_renderer->begin_text();
_menu_bar->render_bar_text(context.ui_renderer, x, y_screen, width);

View File

@ -25,8 +25,9 @@ public:
Editor(const std::string& filename);
~Editor(void) override;
void update(void) override;
void handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) 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,
int content_widht, int content_heigth) override;
void render(const RenderContext& context, int x, int y_screen, int y_gl,
int width, int height) override;
void scroll(int amount, int content_height) override;

View File

@ -8,8 +8,9 @@
class IWindowContent {
public:
virtual ~IWindowContent(void) = default;
virtual void update(void) = 0;
virtual void handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) = 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,
int content_width, int content_height) = 0;
virtual void render(const RenderContext& context, int x, int y_screen, int y_gl,
int width, int height) = 0;
virtual void scroll(int amount, int content_height) = 0;

View File

@ -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(event->type == SDL_EVENT_TEXT_INPUT) {
_buffer->insert_char(event->text.text[0]);
_ensure_cursor_visible(content_height);
} else if(event->type == SDL_EVENT_KEY_DOWN) {
switch(event->key.key) {
case SDLK_BACKSPACE:
_buffer->backspace();
_ensure_cursor_visible(content_height);
break;
case SDLK_RETURN:
/*
@ -43,22 +45,28 @@ bool TextView::handle_event(SDL_Event* event) {
if(_handle_ret) {
_buffer->newline();
}
_ensure_cursor_visible(content_height);
return true;
break;
case SDLK_LEFT:
_buffer->move_cursor(-1,0);
_ensure_cursor_visible(content_height);
break;
case SDLK_RIGHT:
_buffer->move_cursor(1,0);
_ensure_cursor_visible(content_height);
break;
case SDLK_UP:
_buffer->move_cursor(0,-1);
_ensure_cursor_visible(content_height);
break;
case SDLK_DOWN:
_buffer->move_cursor(0,1);
_ensure_cursor_visible(content_height);
break;
case SDLK_HOME:
_buffer->move_cursor_home();
_ensure_cursor_visible(content_height);
break;
case SDLK_END:
_buffer->move_cursor_end();
@ -77,8 +85,13 @@ void TextView::scroll(int amount, int content_height) {
_scroll_offset = 0;
}
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;
/* 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(_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
* view, we can stop rendering completely.
*/
if(current_y > y + height) {
if(current_y >= y + height) {
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);
}
}
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);
}

View File

@ -29,7 +29,7 @@ public:
TextView(TextBuffer* buffer, bool handle_ret, bool show_line_numbers, bool syntax_highlighting);
~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 render_text_content(UIRenderer* ui_renderer, const SyntaxTheme& theme,
int x, int y, int width, int height);
@ -37,6 +37,7 @@ public:
int x, int y, int width, int height);
private:
void _ensure_cursor_visible(int content_height);
std::vector<Token> _tokenize_line(const std::string& line);
TextBuffer* _buffer;

View File

@ -1,3 +1,5 @@
#include <GL/glew.h>
#include "ui_renderer.h"
#include "gfx/shape_renderer.h"
#include "gfx/txt_renderer.h"
@ -51,3 +53,12 @@ void UIRenderer::flush_shapes(void) {
TextRenderer* UIRenderer::get_text_renderer(void) {
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);
}

View File

@ -26,6 +26,9 @@ public:
/* Expose underlying text renderer for things like width calculation. */
TextRenderer* get_text_renderer(void);
void enable_scissor(int x, int y, int width, int height);
void disable_scissor(void);
private:
ShapeRenderer* _shape_renderer;
TextRenderer* _txt_renderer;

View File

@ -129,9 +129,10 @@ void UIWindow::render(const RenderContext& context) {
if(_content) {
int content_screen_y = _y + 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. */
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) {
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);
}
}