From 77c11183c22d640939cd8a6a7588329a5879c64c Mon Sep 17 00:00:00 2001 From: Jack Jamison Date: Sun, 26 Oct 2025 20:59:05 -0400 Subject: refactor to layout --- config.h | 2 +- graphics.c | 101 ++++++++-------------------------------------------------- input_field.c | 15 +++++---- input_field.h | 1 + keybind.c | 2 ++ layout.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ layout.h | 5 +++ state.h | 6 ++-- 8 files changed, 129 insertions(+), 99 deletions(-) diff --git a/config.h b/config.h index 8deca15..27cac24 100644 --- a/config.h +++ b/config.h @@ -8,7 +8,7 @@ typedef struct { float r,g,b,a; } color_t; -static const bool fancy_scroll = false; +static const bool fancy_scroll = true; static const uint32_t min_width = 500; static const uint32_t font_size = 16; static const color_t text_color = {0.85, 0.85, 0.85, 1.0}; diff --git a/graphics.c b/graphics.c index 638c6a7..9f66702 100644 --- a/graphics.c +++ b/graphics.c @@ -177,30 +177,27 @@ void render_frame(client_state *state) { glClearColor(background_color.r,background_color.g,background_color.b,background_color.a); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // bind shader and texture - glUseProgram(state->text_shader); - glUniform2f(state->t_screen_size_uniform, state->width, state->height); - glUniform4f(state->t_color_uniform, text_color.r,text_color.g,text_color.b,text_color.a); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, state->atlas.texture); - // calculate input buffer size - Rect input = { .x = 0, .y = state->line_height * state->lines, .dx = state->width, .dy = state->line_height }; - if (state->lines == 0 && array_size(state->filtered_items) != 0) { - input.dx = state->width / 3.0f; - } + rect_t input, options; + calculate_layout(state, &input, &options, false); // draw input buffer + glUseProgram(state->text_shader); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, state->atlas.texture); glScissor(input.x, input.y, input.dx - state->horizontal_spacing / 2.0f, input.dy); glBindVertexArray(state->input_buffer_grafix.vao); + glUniform2f(state->t_screen_size_uniform, state->width, state->height); + glUniform4f(state->t_color_uniform, text_color.r,text_color.g,text_color.b,text_color.a); glUniform2f(state->t_offset_uniform, input.x + state->horizontal_spacing / 2.0f, input.y - state->atlas.vert_shift); glDrawElements(GL_TRIANGLES, state->input_buffer_grafix.num_elements, GL_UNSIGNED_INT, 0); - // draw cursor box + // calculate cursor size float cursor_size = state->atlas.metrics['M'].bitmap_width; if (state->cursor_index != array_size(state->input_buffer)) { cursor_size = state->atlas.metrics[(int)state->input_buffer[state->cursor_index]].advance_x; } + // draw cursor glUseProgram(state->box_shader); glUniform4f(state->b_color_uniform, cursor_color.r,cursor_color.g,cursor_color.b,cursor_color.a); glUniform2f(state->b_screen_size_uniform, state->width, state->height); @@ -208,80 +205,18 @@ void render_frame(client_state *state) { glUniform2f(state->b_size_uniform, cursor_size, input.dy); glDrawArrays(GL_TRIANGLES, 0, 6); - Rect options = {0}; - float start; - // set up starting pen and scissor for options - if (state->lines) { - options.dx = state->width; - options.dy = input.y; - - start = input.y - state->line_height + state->scroll; - - if (array_size(state->filtered_items) != 0) { - // 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 { - options.x = input.x + input.dx; - options.dx = state->width - options.x; - options.dy = state->line_height; - - start = input.dx + state->scroll; - - if (array_size(state->filtered_items) != 0) { - // calc scroll - item_display_t* selected = &state->filtered_items[state->selected_filtered_item]; - float selected_len = selected->item->pixel_len + state->horizontal_spacing; - float selected_left = start + selected->offset; - float selected_right = selected_left + selected_len; - float right_diff = selected_right - state->width; - float left_diff = selected_left - input.dx; - if (selected_len > state->width - input.dx) { - state->scroll -= left_diff; - start -= left_diff; - } - else if (right_diff > 0) { - state->scroll -= right_diff; - start -= right_diff; - } - else if (left_diff < 0) { - state->scroll -= left_diff; - start -= left_diff; - } - } - } + // scissor options glScissor(options.x, options.y, options.dx, options.dy); // draw highlighted option box if (state->selected_filtered_item != -1) { item_display_t* display = &state->filtered_items[state->selected_filtered_item]; - item_t* item = display->item; - - float x,y; - if (state->lines) { - x = 0; - y = start - display->offset; - } - else { - x = start + display->offset; - y = 0; - } glUseProgram(state->box_shader); glUniform4f(state->b_color_uniform, highlight_color.r,highlight_color.g,highlight_color.b,highlight_color.a); glUniform2f(state->b_screen_size_uniform, state->width, state->height); - glUniform2f(state->b_start_uniform, x, y); - glUniform2f(state->b_size_uniform, (state->lines) ? state->width : item->pixel_len + state->horizontal_spacing, state->line_height); + glUniform2f(state->b_start_uniform, display->r.x, display->r.y); + glUniform2f(state->b_size_uniform, display->r.dx, display->r.dy); glDrawArrays(GL_TRIANGLES, 0, 6); } @@ -295,18 +230,8 @@ void render_frame(client_state *state) { item_display_t* display = &state->filtered_items[i]; item_t* item = display->item; - float x,y; - if (state->lines) { - x = 0; - y = start - display->offset; - } - else { - x = start + display->offset; - y = 0; - } - glBindVertexArray(item->text_buffer.vao); - glUniform2f(state->t_offset_uniform, x + state->horizontal_spacing / 2.0f, y - state->atlas.vert_shift); + glUniform2f(state->t_offset_uniform, display->r.x + state->horizontal_spacing / 2.0f, display->r.y - state->atlas.vert_shift); glDrawElements(GL_TRIANGLES, item->text_buffer.num_elements, GL_UNSIGNED_INT, 0); } diff --git a/input_field.c b/input_field.c index 69ddf62..dc62503 100644 --- a/input_field.c +++ b/input_field.c @@ -3,11 +3,17 @@ #include "input_field.h" #include "array.h" #include "graphics.h" +#include "layout.h" int compare(const void *a, const void *b) { return strlen(((item_display_t*)a)->item->text) > strlen(((item_display_t*)b)->item->text); } +void update_layout(client_state* state) { + rect_t input, options; + calculate_layout(state, &input, &options, true); +} + void filter_items(client_state* state) { if (!state->items) return; @@ -30,13 +36,8 @@ void filter_items(client_state* state) { 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) offset += state->line_height; - else offset += display->item->pixel_len + state->horizontal_spacing; - } + // update layout + update_layout(state); } void update_text_buffer(client_state* state) { diff --git a/input_field.h b/input_field.h index 6ec588e..b338b1f 100644 --- a/input_field.h +++ b/input_field.h @@ -8,5 +8,6 @@ key_repeat_t type_key(client_state* state, xkb_keysym_t keysym); void filter_items(client_state* state); void update_text_buffer(client_state* state); +void update_layout(client_state* state); #endif diff --git a/keybind.c b/keybind.c index 986ec4c..a24e00c 100644 --- a/keybind.c +++ b/keybind.c @@ -40,6 +40,7 @@ key_repeat_t insert_selected(client_state* state) { key_repeat_t select_next(client_state* state) { if (state->selected_filtered_item != -1) { state->selected_filtered_item = MIN(state->selected_filtered_item + 1, (int)array_size(state->filtered_items) - 1); + update_layout(state); } return KEY_REPEAT; } @@ -47,6 +48,7 @@ key_repeat_t select_next(client_state* state) { key_repeat_t select_previous(client_state* state) { if (state->selected_filtered_item != -1) { state->selected_filtered_item = MAX(state->selected_filtered_item - 1, 0); + update_layout(state); } return KEY_REPEAT; } diff --git a/layout.c b/layout.c index fb3ff4c..981210c 100644 --- a/layout.c +++ b/layout.c @@ -1,2 +1,98 @@ #include "layout.h" +#include "array.h" +#include "config.h" +void init_layout(client_state* state) { + +} + +void calculate_layout(client_state* state, rect_t* input, rect_t* options, bool recalc_options) { + + // calculate input rect + *input = (rect_t){ .x = 0, .y = state->line_height * state->lines, .dx = state->width, .dy = state->line_height }; + if (state->lines == 0 && array_size(state->filtered_items) != 0) { + input->dx = state->width / 3.0f; + } + + // calculate options rect + *options = (rect_t){0}; + if (state->lines) { + options->dx = state->width; + options->dy = input->y; + } else { + options->x = input->x + input->dx; + options->dx = state->width - options->x; + options->dy = state->line_height; + } + + if (recalc_options) { + + // calculate starting conditions + rect_t cur; + if (state->lines) { + cur = (rect_t){ .x = options->x, .y = input->y - state->line_height, .dx = options->dx, .dy = state->line_height }; + } else { + cur = (rect_t){ .x = options->x, .y = options->y, .dx = 0.0f, .dy = state->line_height }; + } + + // calculate base filtered item rects + array_for_all(item_display_t, display, state->filtered_items) { + if (!state->lines) { + cur.dx = display->item->pixel_len + state->horizontal_spacing; + } + + display->r = cur; + + if (state->lines) { + cur.y -= state->line_height; + } else { + cur.x += cur.dx; + } + } + + // calculate fancy scroll + if (fancy_scroll && array_size(state->filtered_items) != 0) { + + // calculate if we should adjust scrolling + if (state->lines) { + // calc vertical scroll + float selected_bot = state->fancy_scroll + state->filtered_items[state->selected_filtered_item].r.y; + float selected_top = selected_bot + state->filtered_items[state->selected_filtered_item].r.dy; + if (selected_bot < options->y) { + state->fancy_scroll -= selected_bot; + } + float diff = selected_top - (options->y + options->dy); + if (diff > 0) { + state->fancy_scroll -= diff; + } + } else { + // calc horizontal scroll + item_display_t* selected = &state->filtered_items[state->selected_filtered_item]; + float selected_left = state->fancy_scroll + selected->r.x; + float selected_right = selected_left + selected->r.dx; + float right_diff = selected_right - (options->x + options->dx); + float left_diff = selected_left - options->x; + + if (selected->r.dx > options->dx) { + state->fancy_scroll -= left_diff; + } + else if (right_diff > 0) { + state->fancy_scroll -= right_diff; + } + else if (left_diff < 0) { + state->fancy_scroll -= left_diff; + } + } + + // apply scroll offset + array_for_all(item_display_t, display, state->filtered_items) { + if (state->lines) { + display->r.y += state->fancy_scroll; + } else { + display->r.x += state->fancy_scroll; + } + } + + } + } +} diff --git a/layout.h b/layout.h index cd1240d..8a4dd75 100644 --- a/layout.h +++ b/layout.h @@ -1,4 +1,9 @@ #ifndef LAYOUT_H_ #define LAYOUT_H_ +#include "state.h" + +void init_layout(client_state* state); +void calculate_layout(client_state* state, rect_t* input, rect_t* options, bool recalc_options); + #endif diff --git a/state.h b/state.h index be55a11..6811c41 100644 --- a/state.h +++ b/state.h @@ -21,7 +21,7 @@ typedef struct { float x, y, dx, dy; -} Rect; +} rect_t; typedef struct { GLuint vbo, ebo, vao; @@ -52,7 +52,7 @@ typedef struct { typedef struct { item_t* item; - float offset; + rect_t r; } item_display_t; typedef struct { @@ -129,7 +129,7 @@ typedef struct { int selected_filtered_item; char* input_buffer; size_t cursor_index; - float scroll; + float fancy_scroll; } client_state; -- cgit v1.2.3