summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-11-27 09:40:03 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-11-27 09:40:03 -0500
commitcac24ffa13dc969244fb171b9aad565311c69f16 (patch)
tree45d8f353a5b0968ea0ea9eecc297b11749c117b6
parent370b74e5335745ea01fc7bb6d5425360d26ca0ce (diff)
scrolling working
-rw-r--r--buffer.c115
-rw-r--r--main.c31
-rw-r--r--util.c6
3 files changed, 101 insertions, 51 deletions
diff --git a/buffer.c b/buffer.c
index f98e3f3..f06ca00 100644
--- a/buffer.c
+++ b/buffer.c
@@ -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));
-}
diff --git a/main.c b/main.c
index 6831229..de72bbd 100644
--- a/main.c
+++ b/main.c
@@ -35,7 +35,7 @@ INT WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
int main(void) {
#endif
setlocale(LC_ALL, ""); // allow unicode
- SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1"); // if this program is sent a SIGTERM/SIGINT, don't turn it into a quit event
+ SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1"); // if this program is sent a SIGTERM/SIGINT, don't turn it into a quit event
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0)
die("%s", SDL_GetError());
@@ -66,12 +66,12 @@ int main(void) {
bool quit = false;
TextBuffer text_buffer;
- text_buffer_create(&text_buffer, font);
+ buffer_create(&text_buffer, font);
{
- FILE *fp = fopen("test.txt", "r");
+ FILE *fp = fopen("main.c", "r");
assert(fp);
- bool success = text_buffer_load_file(&text_buffer, fp);
+ bool success = buffer_load_file(&text_buffer, fp);
fclose(fp);
if (!success)
die("Error loading file.");
@@ -94,15 +94,15 @@ int main(void) {
// scroll with mouse wheel
Sint32 dx = event.wheel.x, dy = -event.wheel.y;
double scroll_speed = 2.5;
- text_buffer_scroll(&text_buffer, dx * scroll_speed, dy * scroll_speed);
+ 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));
+ buffer_scroll(&text_buffer, 0, -buffer_display_rows(&text_buffer));
break;
case SDLK_PAGEDOWN:
- text_buffer_scroll(&text_buffer, 0, +text_buffer_num_rows(&text_buffer));
+ buffer_scroll(&text_buffer, 0, +buffer_display_rows(&text_buffer));
break;
}
} break;
@@ -122,15 +122,16 @@ int main(void) {
if (control_key_down) {
// control + arrow keys to scroll
double scroll_speed = 20.0;
- double scroll_amount = scroll_speed * frame_dt;
+ double scroll_amount_x = scroll_speed * frame_dt * 1.5; // characters are taller than they are wide
+ double scroll_amount_y = scroll_speed * frame_dt;
if (keyboard_state[SDL_SCANCODE_UP])
- text_buffer_scroll(&text_buffer, 0, -scroll_amount);
+ buffer_scroll(&text_buffer, 0, -scroll_amount_y);
if (keyboard_state[SDL_SCANCODE_DOWN])
- text_buffer_scroll(&text_buffer, 0, +scroll_amount);
+ buffer_scroll(&text_buffer, 0, +scroll_amount_y);
if (keyboard_state[SDL_SCANCODE_LEFT])
- text_buffer_scroll(&text_buffer, -scroll_amount, 0);
+ buffer_scroll(&text_buffer, -scroll_amount_x, 0);
if (keyboard_state[SDL_SCANCODE_RIGHT])
- text_buffer_scroll(&text_buffer, +scroll_amount, 0);
+ buffer_scroll(&text_buffer, +scroll_amount_x, 0);
}
@@ -151,14 +152,14 @@ int main(void) {
{
float x1 = 50, y1 = 50, x2 = window_widthf-50, y2 = window_heightf-50;
- text_buffer_render(&text_buffer, x1, y1, x2, y2);
+ buffer_render(&text_buffer, x1, y1, x2, y2);
if (text_has_err()) {
printf("Text error: %s\n", text_get_err());
break;
}
}
- //text_buffer_print_debug(&text_buffer);
+ //buffer_print_debug(&text_buffer);
SDL_GL_SwapWindow(window);
}
@@ -166,7 +167,7 @@ int main(void) {
SDL_GL_DeleteContext(glctx);
SDL_DestroyWindow(window);
SDL_Quit();
- text_buffer_free(&text_buffer);
+ buffer_free(&text_buffer);
text_font_free(font);
return 0;
diff --git a/util.c b/util.c
index 6f252c6..c1446a8 100644
--- a/util.c
+++ b/util.c
@@ -3,11 +3,11 @@
#include "base.h"
-static uint util_popcount(u64 x) {
+static u32 util_popcount(u64 x) {
#ifdef __GNUC__
- return (uint)__builtin_popcountll(x);
+ return (u32)__builtin_popcountll(x);
#else
- uint count = 0;
+ u32 count = 0;
while (x) {
x &= x-1;
++count;