From 346acd202547c3ecb315ff7980f505643bacc77e Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Wed, 25 Nov 2020 22:02:43 -0500 Subject: more scrolling --- buffer.c | 43 +++++++++++++++++++++++++++++++++++++------ main.c | 17 +++++++++++++---- text.c | 12 ++++++++++++ text.h | 3 +++ 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/buffer.c b/buffer.c index cd6c353..0a19aa5 100644 --- a/buffer.c +++ b/buffer.c @@ -24,6 +24,8 @@ typedef struct { u32 nblocks; // number of text blocks double scroll_x, scroll_y; // number of characters scrolled in the x/y direction TextBlock *blocks; + Font *font; + float x1, y1, x2, y2; } TextBuffer; // Returns a new block added at index `where`, @@ -61,11 +63,15 @@ static TextBlock *text_buffer_add_block(TextBuffer *buffer, u32 where) { return block; } +void text_buffer_create(TextBuffer *buffer, Font *font) { + util_zero_memory(buffer, sizeof *buffer); + buffer->font = font; +} + Status text_buffer_load_file(TextBuffer *buffer, FILE *fp) { char block_contents[TEXT_BLOCK_DEFAULT_SIZE]; size_t bytes_read; - - util_zero_memory(buffer, sizeof *buffer); + // @TODO: @TODO: IMPORTANT! make this work if buffer already has a file // read file one block at a time do { @@ -118,13 +124,26 @@ void text_buffer_free(TextBuffer *buffer) { free(blocks); } +// make sure we don't scroll too far +static void text_buffer_correct_scroll(TextBuffer *buffer) { + if (buffer->scroll_x < 0) + buffer->scroll_x = 0; + if (buffer->scroll_y < 0) + buffer->scroll_y = 0; + // @TODO: maximum scroll_x and scroll_y +} + void text_buffer_scroll(TextBuffer *buffer, double dx, double dy) { buffer->scroll_x += dx; buffer->scroll_y += dy; + text_buffer_correct_scroll(buffer); } // Render the text buffer in the given rectangle -void text_buffer_render(TextBuffer *buffer, Font *font, float x1, float y1, float x2, float y2) { +// NOTE: also corrects scroll +void text_buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) { + buffer->x1 = x1; buffer->y1 = y1; buffer->x2 = x2; buffer->y2 = y2; + Font *font = buffer->font; mbstate_t mbstate = {0}; uint nblocks = buffer->nblocks; TextBlock *blocks = buffer->blocks; @@ -140,14 +159,17 @@ void text_buffer_render(TextBuffer *buffer, Font *font, float x1, float y1, floa glColor3f(1,1,1); text_chars_begin(font); + + // what x coordinate to start rendering the text from + float render_start_x = x1 - (float)buffer->scroll_x * char_height; + TextRenderState text_state = { - .x = x1, .y = y1 + text_font_char_height(font), + .x = render_start_x, .y = y1 + text_font_char_height(font), .min_x = x1, .min_y = y1, .max_x = x2, .max_y = y2 }; // @TODO: make this better (we should figure out where to start rendering, etc.) - text_state.x -= (float)buffer->scroll_x * char_height; text_state.y -= (float)buffer->scroll_y * char_height; for (uint block_idx = 0; block_idx < nblocks; ++block_idx) { @@ -175,7 +197,7 @@ void text_buffer_render(TextBuffer *buffer, Font *font, float x1, float y1, floa } switch (c) { case L'\n': - text_state.x = x1; + text_state.x = render_start_x; text_state.y += text_font_char_height(font); break; case L'\r': break; // for CRLF line endings @@ -192,3 +214,12 @@ void text_buffer_render(TextBuffer *buffer, Font *font, float x1, float y1, floa text_chars_end(font); } +// returns the number of rows of text that can fit in the buffer, rounded down. +int text_buffer_num_rows(TextBuffer *buffer) { + return (int)((buffer->y2 - buffer->y1) / text_font_char_height(buffer->font)); +} + +// returns the number of columns of text that can fit in the buffer, rounded down. +int text_buffer_num_cols(TextBuffer *buffer) { + return (int)((buffer->x2 - buffer->x1) / text_font_char_width(buffer->font)); +} diff --git a/main.c b/main.c index feb526a..3544919 100644 --- a/main.c +++ b/main.c @@ -66,6 +66,7 @@ int main(void) { bool quit = false; TextBuffer text_buffer; + text_buffer_create(&text_buffer, font); { FILE *fp = fopen("main.c", "r"); @@ -84,6 +85,7 @@ int main(void) { while (SDL_PollEvent(&event)) { + // @TODO: make a function to handle text buffer events switch (event.type) { case SDL_QUIT: quit = true; @@ -94,6 +96,16 @@ int main(void) { double scroll_speed = 2.5; text_buffer_scroll(&text_buffer, dx * scroll_speed, dy * scroll_speed); } break; + case SDL_KEYDOWN: { + switch (event.key.keysym.sym) { + case SDLK_PAGEUP: + text_buffer_scroll(&text_buffer, 0, -text_buffer_num_rows(&text_buffer)); + break; + case SDLK_PAGEDOWN: + text_buffer_scroll(&text_buffer, 0, +text_buffer_num_rows(&text_buffer)); + break; + } + } break; } } @@ -115,13 +127,10 @@ int main(void) { text_buffer_scroll(&text_buffer, 0, -scroll_amount); if (keyboard_state[SDL_SCANCODE_DOWN]) text_buffer_scroll(&text_buffer, 0, +scroll_amount); - // @TODO: get this to work - #if 0 if (keyboard_state[SDL_SCANCODE_LEFT]) text_buffer_scroll(&text_buffer, -scroll_amount, 0); if (keyboard_state[SDL_SCANCODE_RIGHT]) text_buffer_scroll(&text_buffer, +scroll_amount, 0); - #endif } @@ -142,7 +151,7 @@ int main(void) { { float x1 = 50, y1 = 50, x2 = window_widthf-50, y2 = window_heightf-50; - text_buffer_render(&text_buffer, font, x1, y1, x2, y2); + text_buffer_render(&text_buffer, x1, y1, x2, y2); if (text_has_err()) { printf("Text error: %s\n", text_get_err()); break; diff --git a/text.c b/text.c index 5906e5c..1913bfc 100644 --- a/text.c +++ b/text.c @@ -15,6 +15,7 @@ no_warn_end #define CHAR_PAGE_COUNT UNICODE_CODE_POINTS / CHAR_PAGE_SIZE struct Font { + float char_width; // width of the character 'a'. calculated when font is loaded. float char_height; GLuint textures[CHAR_PAGE_COUNT]; int tex_widths[CHAR_PAGE_COUNT], tex_heights[CHAR_PAGE_COUNT]; @@ -114,6 +115,13 @@ Font *text_font_load(char const *ttf_filename, float font_size) { font->char_height = font_size; font->ttf_data = file_data; text_load_char_page(font, 0); // load page with Latin text, etc. + { // calculate width of the character 'a' + stbtt_aligned_quad q = {0}; + float x = 0, y = 0; + stbtt_GetBakedQuad(font->char_pages[0], font->tex_widths[0], font->tex_heights[0], + 'a', &x, &y, &q, 1); + font->char_width = x; + } font->curr_page = -1; } else { text_set_err("Couldn't read font file."); @@ -140,6 +148,10 @@ float text_font_char_height(Font *font) { return font->char_height; } +float text_font_char_width(Font *font) { + return font->char_width; +} + static void text_render_with_page(Font *font, int page) { if (font->curr_page != page) { if (font->curr_page != -1) { diff --git a/text.h b/text.h index 9f0d351..25c5e49 100644 --- a/text.h +++ b/text.h @@ -25,6 +25,9 @@ extern void text_clear_err(void); extern Font *text_font_load(char const *ttf_filename, float font_size); // Height of a character of this font in pixels. extern float text_font_char_height(Font *font); +// Width of the character 'a' of this font in pixels. +// This is meant to be only used for monospace fonts. +extern float text_font_char_width(Font *font); // Render some UTF-8 text to the screen (simple interface). extern void text_render(Font *font, char const *text, float x, float y); // Get the dimensions of some text. -- cgit v1.2.3