diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-11-27 09:40:03 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-11-27 09:40:03 -0500 |
commit | cac24ffa13dc969244fb171b9aad565311c69f16 (patch) | |
tree | 45d8f353a5b0968ea0ea9eecc297b11749c117b6 /buffer.c | |
parent | 370b74e5335745ea01fc7bb6d5425360d26ca0ce (diff) |
scrolling working
Diffstat (limited to 'buffer.c')
-rw-r--r-- | buffer.c | 115 |
1 files changed, 82 insertions, 33 deletions
@@ -21,16 +21,17 @@ typedef struct { } TextBlock; 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; + u8 tab_width; float x1, y1, x2, y2; + u32 nblocks; // number of text blocks + TextBlock *blocks; } TextBuffer; // Returns a new block added at index `where`, // or NULL if there's not enough memory. -static TextBlock *text_buffer_add_block(TextBuffer *buffer, u32 where) { +static TextBlock *buffer_add_block(TextBuffer *buffer, u32 where) { // make sure we can actually allocate enough memory for the contents of the block // before doing anything char *block_contents = calloc(1, TEXT_BLOCK_MAX_SIZE); @@ -63,12 +64,13 @@ static TextBlock *text_buffer_add_block(TextBuffer *buffer, u32 where) { return block; } -void text_buffer_create(TextBuffer *buffer, Font *font) { +void buffer_create(TextBuffer *buffer, Font *font) { util_zero_memory(buffer, sizeof *buffer); buffer->font = font; + buffer->tab_width = 4; } -Status text_buffer_load_file(TextBuffer *buffer, FILE *fp) { +Status buffer_load_file(TextBuffer *buffer, FILE *fp) { char block_contents[TEXT_BLOCK_DEFAULT_SIZE]; size_t bytes_read; // @TODO: @TODO: IMPORTANT! make this work if buffer already has a file @@ -77,7 +79,7 @@ Status text_buffer_load_file(TextBuffer *buffer, FILE *fp) { do { bytes_read = fread(block_contents, 1, sizeof block_contents, fp); if (bytes_read > 0) { - TextBlock *block = text_buffer_add_block(buffer, buffer->nblocks); + TextBlock *block = buffer_add_block(buffer, buffer->nblocks); if (!block) { return false; } @@ -90,8 +92,8 @@ Status text_buffer_load_file(TextBuffer *buffer, FILE *fp) { return true; } -static void text_buffer_print_internal(TextBuffer *buffer, bool debug) { - printf("\033[2J\033[;H"); +static void buffer_print_internal(TextBuffer *buffer, bool debug) { + printf("\033[2J\033[;H"); // clear terminal screen TextBlock *blocks = buffer->blocks; u32 nblocks = buffer->nblocks; @@ -105,17 +107,17 @@ static void text_buffer_print_internal(TextBuffer *buffer, bool debug) { } // print the contents of a buffer to stdout -void text_buffer_print(TextBuffer *buffer) { - text_buffer_print_internal(buffer, false); +void buffer_print(TextBuffer *buffer) { + buffer_print_internal(buffer, false); } // print the contents of a buffer to stdout, along with debugging information -void text_buffer_print_debug(TextBuffer *buffer) { - text_buffer_print_internal(buffer, true); +void buffer_print_debug(TextBuffer *buffer) { + buffer_print_internal(buffer, true); } // Does not free the pointer `buffer` (buffer might not have even been allocated with malloc) -void text_buffer_free(TextBuffer *buffer) { +void buffer_free(TextBuffer *buffer) { TextBlock *blocks = buffer->blocks; u32 nblocks = buffer->nblocks; for (u32 i = 0; i < nblocks; ++i) { @@ -124,30 +126,87 @@ void text_buffer_free(TextBuffer *buffer) { free(blocks); } +// returns the number of lines of text in the buffer into *lines (if not NULL), +// and the number of columns of text, i.e. the length of the longest line, into *cols (if not NULL) +static void buffer_text_dimensions(TextBuffer *buffer, u64 *lines, u64 *cols) { + u64 nlines = 1; + u64 maxcol = 0; + u64 col = 0; + for (u32 i = 0; i < buffer->nblocks; ++i) { + TextBlock *block = &buffer->blocks[i]; + for (char *p = block->contents, *end = p + block->len; p != end; ++p) { + switch (*p) { + case '\n': + ++nlines; + col = 0; + break; + case '\r': break; + case '\t': + do + ++col; + while (col % buffer->tab_width); + break; + default: + ++col; + break; + } + if (col > maxcol) + maxcol = col; + } + } + if (lines) *lines = nlines; + if (cols) *cols = maxcol; +} + + +// returns the number of rows of text that can fit in the buffer, rounded down. +int buffer_display_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 buffer_display_cols(TextBuffer *buffer) { + return (int)((buffer->x2 - buffer->x1) / text_font_char_width(buffer->font)); +} // make sure we don't scroll too far -static void text_buffer_correct_scroll(TextBuffer *buffer) { +static void 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 + u64 nlines, ncols; + buffer_text_dimensions(buffer, &nlines, &ncols); + double max_scroll_x = (double)ncols - buffer_display_cols(buffer); + double max_scroll_y = (double)nlines - buffer_display_rows(buffer); + if (max_scroll_x <= 0) { + buffer->scroll_x = 0; + } else if (buffer->scroll_x > max_scroll_x) { + buffer->scroll_x = max_scroll_x; + } + + if (max_scroll_y <= 0) { + buffer->scroll_y = 0; + } else if (buffer->scroll_y > max_scroll_y) { + buffer->scroll_y = max_scroll_y; + } } -void text_buffer_scroll(TextBuffer *buffer, double dx, double dy) { +void buffer_scroll(TextBuffer *buffer, double dx, double dy) { buffer->scroll_x += dx; buffer->scroll_y += dy; - text_buffer_correct_scroll(buffer); + buffer_correct_scroll(buffer); } // Render the text buffer in the given rectangle // NOTE: also corrects scroll -void text_buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) { +void 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; + u32 nblocks = buffer->nblocks; TextBlock *blocks = buffer->blocks; - float char_height = text_font_char_height(font); + float char_width = text_font_char_width(font), + char_height = text_font_char_height(font); glColor3f(0.5f,0.5f,0.5f); glBegin(GL_LINE_STRIP); glVertex2f(x1,y1); @@ -161,7 +220,7 @@ void text_buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float text_chars_begin(font); // what x coordinate to start rendering the text from - float render_start_x = x1 - (float)buffer->scroll_x * char_height; + float render_start_x = x1 - (float)buffer->scroll_x * char_width; u32 column = 0; @@ -174,7 +233,7 @@ void text_buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float // @TODO: make this better (we should figure out where to start rendering, etc.) text_state.y -= (float)buffer->scroll_y * char_height; - for (uint block_idx = 0; block_idx < nblocks; ++block_idx) { + for (u32 block_idx = 0; block_idx < nblocks; ++block_idx) { TextBlock *block = &blocks[block_idx]; char *p = block->contents, *end = p + block->len; while (p != end) { @@ -208,7 +267,7 @@ void text_buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float do { text_render_char(font, L' ', &text_state); ++column; - } while (column % 4); + } while (column % buffer->tab_width); break; default: text_render_char(font, c, &text_state); @@ -219,13 +278,3 @@ void text_buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float } 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)); -} |