From 25f0c213ed8d9d0912c0de8c2506d0820939aafd Mon Sep 17 00:00:00 2001 From: Jack Jamison Date: Sun, 19 Oct 2025 17:02:36 -0400 Subject: scrolling --- font.c | 4 +++- graphics.c | 71 +++++++++++++++++++++++++++++++++++++++++------------------ input_field.c | 8 +++++++ main.c | 2 +- state.h | 3 +++ 5 files changed, 64 insertions(+), 24 deletions(-) diff --git a/font.c b/font.c index aff5a30..c67e427 100644 --- a/font.c +++ b/font.c @@ -66,6 +66,8 @@ bool freetype_init(client_state* state, const char* file) { } state->load_flags = FT_LOAD_RENDER; state->line_height = state->ft_face->size->metrics.height >> 6; + state->horizontal_spacing = state->line_height / 2.0f; + return true; } @@ -154,7 +156,7 @@ void atlas_calc_item_widths(client_state* state) { if (state->items) { array_for_all(item_t, item, state->items) { item->pixel_len = atlas_get_strwidth(state, item->text); - state->required_width = MAX(state->required_width, item->pixel_len + state->line_height / 2.0f); + state->required_width = MAX(state->required_width, item->pixel_len + state->horizontal_spacing); } } } diff --git a/graphics.c b/graphics.c index c6b0650..448b225 100644 --- a/graphics.c +++ b/graphics.c @@ -148,48 +148,75 @@ void render_frame(client_state *state) { glBindTexture(GL_TEXTURE_2D, state->atlas.texture); // calculate input buffer - float horizontal_spacing = state->line_height / 2.0f; float input_y = state->line_height * state->lines; float input_width; if (state->lines > 0) { input_width = state->width; } else { input_width = state->width / 3.0f; } // draw input buffer - glScissor(0, input_y, input_width - horizontal_spacing / 2.0f, state->line_height); + glScissor(0, input_y, input_width - state->horizontal_spacing / 2.0f, state->line_height); glBindVertexArray(state->input_buffer_grafix.vao); - glUniform2f(state->offset_uniform, horizontal_spacing / 2.0f, input_y - state->atlas.vert_shift); + glUniform2f(state->offset_uniform, state->horizontal_spacing / 2.0f, input_y - state->atlas.vert_shift); glDrawElements(GL_TRIANGLES, state->input_buffer_grafix.num_elements, GL_UNSIGNED_INT, 0); - float pen_x = 0.0f; - float pen_y = input_y; - + float start; // set up starting pen and scissor for options if (state->lines > 0) { - glScissor(0, 0, state->width, pen_y); - pen_y -= state->line_height; - } - else { - pen_x = input_width; - glScissor(pen_x, 0, state->width, state->line_height); + glScissor(0, 0, state->width, input_y); + start = input_y - state->line_height + state->scroll; + + // calc scroll + float selected_bot = start - state->filtered_items[state->selected_filtered_item].offset; + float selected_top = selected_bot + state->line_height; + if (selected_bot < 0) { + state->scroll -= selected_bot; + start -= selected_bot; + } + float diff = selected_top - input_y; + if (diff > 0) { + state->scroll -= diff; + start -= diff; + } + } else { + glScissor(input_width, 0, state->width, state->line_height); + start = input_width + state->scroll; + + // calc scroll + item_display_t* selected = &state->filtered_items[state->selected_filtered_item]; + float selected_left = start + selected->offset; + float selected_right = selected_left + selected->item->pixel_len + state->horizontal_spacing; + float diff = selected_right - state->width; + if (diff > 0) { + state->scroll -= diff; + start -= diff; + } + diff = selected_left - input_width; + if (diff < 0) { + state->scroll -= diff; + start -= diff; + } } // draw options for (uint32_t i = 0; i < array_size(state->filtered_items); ++i) { - item_t* item = state->filtered_items[i].item; - - glBindVertexArray(item->text_buffer.vao); - glUniform2f(state->offset_uniform, pen_x + horizontal_spacing / 2.0f, pen_y - state->atlas.vert_shift); - if (i == state->selected_filtered_item) glUniform3f(state->color_uniform, 0.0f, 0.4f, 0.8f); - glDrawElements(GL_TRIANGLES, item->text_buffer.num_elements, GL_UNSIGNED_INT, 0); - if (i == state->selected_filtered_item) glUniform3f(state->color_uniform, 1.0f, 1.0f, 1.0f); + item_display_t* display = &state->filtered_items[i]; + item_t* item = display->item; - // shift pen + float x,y; if (state->lines > 0) { - pen_y -= state->line_height; + x = 0; + y = start - display->offset; } else { - pen_x += item->pixel_len + horizontal_spacing; + x = start + display->offset; + y = 0; } + + glBindVertexArray(item->text_buffer.vao); + glUniform2f(state->offset_uniform, x + state->horizontal_spacing / 2.0f, y - state->atlas.vert_shift); + if (i == state->selected_filtered_item) glUniform3f(state->color_uniform, 0.0f, 0.4f, 0.8f); + glDrawElements(GL_TRIANGLES, item->text_buffer.num_elements, GL_UNSIGNED_INT, 0); + if (i == state->selected_filtered_item) glUniform3f(state->color_uniform, 1.0f, 1.0f, 1.0f); } // present screen diff --git a/input_field.c b/input_field.c index 3e0a3e2..34f3fc2 100644 --- a/input_field.c +++ b/input_field.c @@ -24,6 +24,14 @@ void filter_items(client_state* state) { // select item if (array_size(state->filtered_items) > 0) state->selected_filtered_item = 0; else state->selected_filtered_item = -1; + + // lay out items + float offset = 0; + array_for_all(item_display_t, display, state->filtered_items) { + display->offset = offset; + if (state->lines > 0) offset += state->line_height; + else offset += display->item->pixel_len + state->horizontal_spacing; + } } void update_text_buffer(client_state* state) { diff --git a/main.c b/main.c index b2d847e..e334a8f 100644 --- a/main.c +++ b/main.c @@ -40,7 +40,6 @@ int main(int argc, char* argv[]) { // read input parse_args(&state, argc, argv); read_stdin(&state); - filter_items(&state); // find font char* font = get_font("Monospace"); @@ -83,6 +82,7 @@ int main(int argc, char* argv[]) { array_for_all(item_t, item, state.items) { init_text_buffer(&state, &item->text_buffer, item->text, strlen(item->text)); } + filter_items(&state); // event loop while (state.running) { diff --git a/state.h b/state.h index 1eb9e22..baec931 100644 --- a/state.h +++ b/state.h @@ -48,6 +48,7 @@ typedef struct { typedef struct { item_t* item; + float offset; } item_display_t; typedef struct { @@ -95,6 +96,7 @@ typedef struct { uint32_t line_height; uint32_t required_width; + float horizontal_spacing; // arguments int lines; @@ -104,6 +106,7 @@ typedef struct { // state char* input_buffer; + float scroll; int selected_filtered_item; uint32_t width, height; item_t* items; -- cgit v1.2.3