From ac2763f87b62479792cef4fd560cd92577aae39d Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sun, 19 Jan 2025 21:57:32 +0100 Subject: [PATCH] radio button and tab switcher --- src/ui/ui.c | 163 +++++++++++++++++++++++++++-------------------- src/ui/ui.gen.c | 4 ++ src/ui/ui.gen.h | 3 + src/ui/ui.meta.c | 1 + 4 files changed, 103 insertions(+), 68 deletions(-) diff --git a/src/ui/ui.c b/src/ui/ui.c index 55b6002..96d82a7 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -127,6 +127,7 @@ fn ui_box_t *ui_build_box_from_id(ui_code_loc_t loc, ui_box_flags_t flags, ui_id box->flags = flags; box->text_align = ui->text_align_stack->value; box->border_thickness = ui->border_thickness_stack->value; + if (ui->background_color_stack) box->background_color = ui->background_color_stack->value; ui_push_box(ui->top, box); return box; } @@ -197,6 +198,16 @@ fn ui_signal_t ui__button(ui_code_loc_t loc, char *str, ...) { return signal; } +#define ui_radio_button(...) ui__radio_button(UILOC, __VA_ARGS__) +fn ui_signal_t ui__radio_button(ui_code_loc_t loc, i32 *value, i32 value_clicked, char *str, ...) { + S8_FMT(tcx.temp, str, string); + ui_box_t *box = ui_build_box_from_string(loc, (ui_box_flags_t){ .draw_border = true, .draw_rect = true, .draw_text = true }, string); + ui_signal_t signal = ui_signal_from_box(box); + if (signal.clicked) *value = value_clicked; + if (*value == value_clicked) box->background_color = accent1_color_global; + return signal; +} + #define ui_label_button(...) ui__label_button(UILOC, __VA_ARGS__) fn ui_signal_t ui__label_button(ui_code_loc_t loc, char *str, ...) { S8_FMT(tcx.temp, str, string); @@ -288,6 +299,7 @@ fn void ui__draw_box(app_frame_t *frame, ui_box_t *box) { r2f32_t rect = box->final_rect; v4f32_t rect_color = primary_color_global; + if (!v4f32_is_null(box->background_color)) rect_color = box->background_color; v4f32_t text_color = black_color_global; if (ui_is_hot_box(box)) { rect_color = secondary_color_global; @@ -547,89 +559,104 @@ fn void ui_demo_init(ma_arena_t *arena) { ui->box_arena = ma_push_arena(arena, mib(1)); } +gb i32 ui_g_panel = 1; gb app_event_t ui_test_event; fn void ui_demo_update(app_frame_t *frame) { ui_begin_frame(frame); for (app_event_t *ev = frame->first_event; ev; ev = ev->next) { ui_begin_build(UILOC, ev, window_rect_from_frame(frame)); - ui->top->rect = r2f32_shrinks(ui->top->rect, 200); + ui_box_t *top_box = ui_box0((ui_box_flags_t){.draw_rect = true, .clip_rect = true}); + ui_set_rect(top_box, r2f32_cut_top(&ui->top->rect, ui_em(1))); - ui_box_t *scroller_box = ui_box0((ui_box_flags_t){.draw_rect = true, .clip_rect = true}); - ui_set_rect(scroller_box, r2f32_cut_right(&ui->top->rect, ui_em(0.5f))); - - ui_box_t *item_box = ui_box0((ui_box_flags_t){.draw_rect = true, .clip_rect = true}); - ui_set_rect(item_box, r2f32_cut_left(&ui->top->rect, ui_max)); - - static f32 scroller_value; + ui_set_padding(v2f32(50, 0)) ui_set_text_align(ui_text_align_center) - ui_set_top(item_box) { - for (i32 i = 0; i < lengthof(tweak_table); i += 1) { - mt_tweak_t *tweak = tweak_table + i; - if (s8_starts_with(tweak->name, s8_lit("_"), false)) continue; + ui_set_lop(ui_lop_cut_left) + ui_set_top(top_box) { + ui_radio_button(&ui_g_panel, 1, "1"); + ui_radio_button(&ui_g_panel, 2, "2"); + } - if (tweak->type->kind == type_kind_b32) { - b32 *n = (b32 *)tweak->ptr; - if (ui_label_button("%S: %s##slider%S", tweak->name, *n ? "true" : "false", tweak->name).clicked) { - *n = !*n; - } - } else if (tweak->type->kind == type_kind_f32) { - f32 *n = (f32 *)tweak->ptr; - ui_signal_t signal = ui_label_button("%S: %f##slider%S", tweak->name, *n, tweak->name); - if (signal.dragging) { - f32 size = tweak->max - tweak->min; - v2f32_t string_size = rn_measure_string(rn_state.main_font, signal.box->string); - f32 delta = (ui->event->mouse_delta.x / string_size.x) * size; - *n = CLAMP(*n + delta, tweak->min, tweak->max); - } - } else_is_invalid; - } - ui_serial_type(&ui_test_event, type(app_event_t)); - ui_expander("app_event_t") { - for (int i = 0; i < 2; i += 1) { - ui_label("kind: app_event_kind_t##a%d", i); - ui_label("ctrl: b8##ds%d", i); - ui_label("shift: b8##f%d", i); - ui_expander("pos: v3f32_t##gg%d", i) { - ui_label("x: f64 = value##hgt%d", i); - ui_label("y: f64 = value##r%d", i); - ui_label("z: f64 = value##yr%d", i); - } - ui_expander("mouse_pos: v2f32_t##i2%d", i) { - ui_label("x: f64 = value##i3%d", i); - ui_label("y: f64 = value##i4%d", i); + ui->top->rect = r2f32_shrinks(ui->top->rect, 100); + + + if (ui_g_panel == 1) { + ui_box_t *scroller_box = ui_box0((ui_box_flags_t){.draw_rect = true, .clip_rect = true}); + ui_set_rect(scroller_box, r2f32_cut_right(&ui->top->rect, ui_em(0.5f))); + + ui_box_t *item_box = ui_box0((ui_box_flags_t){.draw_rect = true, .clip_rect = true}); + ui_set_rect(item_box, r2f32_cut_left(&ui->top->rect, ui_max)); + + static f32 scroller_value; + ui_set_text_align(ui_text_align_center) + ui_set_top(item_box) { + for (i32 i = 0; i < lengthof(tweak_table); i += 1) { + mt_tweak_t *tweak = tweak_table + i; + if (s8_starts_with(tweak->name, s8_lit("_"), false)) continue; + + if (tweak->type->kind == type_kind_b32) { + b32 *n = (b32 *)tweak->ptr; + if (ui_label_button("%S: %s##slider%S", tweak->name, *n ? "true" : "false", tweak->name).clicked) { + *n = !*n; + } + } else if (tweak->type->kind == type_kind_f32) { + f32 *n = (f32 *)tweak->ptr; + ui_signal_t signal = ui_label_button("%S: %f##slider%S", tweak->name, *n, tweak->name); + if (signal.dragging) { + f32 size = tweak->max - tweak->min; + v2f32_t string_size = rn_measure_string(rn_state.main_font, signal.box->string); + f32 delta = (ui->event->mouse_delta.x / string_size.x) * size; + *n = CLAMP(*n + delta, tweak->min, tweak->max); + } + } else_is_invalid; + } + ui_serial_type(&ui_test_event, type(app_event_t)); + ui_expander("app_event_t") { + for (int i = 0; i < 2; i += 1) { + ui_label("kind: app_event_kind_t##a%d", i); + ui_label("ctrl: b8##ds%d", i); + ui_label("shift: b8##f%d", i); + ui_expander("pos: v3f32_t##gg%d", i) { + ui_label("x: f64 = value##hgt%d", i); + ui_label("y: f64 = value##r%d", i); + ui_label("z: f64 = value##yr%d", i); + } + ui_expander("mouse_pos: v2f32_t##i2%d", i) { + ui_label("x: f64 = value##i3%d", i); + ui_label("y: f64 = value##i4%d", i); + } } } } - } - // @todo: fix scroller to match mouse - defer_block(ui_push_top(scroller_box), ui_pop_top()) { - f32 item_count = (f32)item_box->node_count; - f32 all_items_size = item_count * rn_state.main_font->size; - f32 item_box_size = r2f32_get_size(ui->top->full_rect).y; - f32 scroller_box_size = r2f32_get_size(scroller_box->full_rect).y; - f32 scroller_size = CLAMP(item_box_size / all_items_size, 0, 1.0f); - f32 scrollable_space = (1 - scroller_size); - f32 scroller_norm = scroller_value / (all_items_size); - f32 scroller_percent = scroller_norm * scrollable_space; - f32 scroller_second = scrollable_space - scroller_percent; + // @todo: fix scroller to match mouse + defer_block(ui_push_top(scroller_box), ui_pop_top()) { + f32 item_count = (f32)item_box->node_count; + f32 all_items_size = item_count * rn_state.main_font->size; + f32 item_box_size = r2f32_get_size(ui->top->full_rect).y; + f32 scroller_box_size = r2f32_get_size(scroller_box->full_rect).y; + f32 scroller_size = CLAMP(item_box_size / all_items_size, 0, 1.0f); + f32 scrollable_space = (1 - scroller_size); + f32 scroller_norm = scroller_value / (all_items_size); + f32 scroller_percent = scroller_norm * scrollable_space; + f32 scroller_second = scrollable_space - scroller_percent; - r2f32_cut_top(&ui->top->rect, scroller_percent * scroller_box_size); - ui_box_t *box = ui_build_box_from_id(UILOC, (ui_box_flags_t){.draw_border = true, .draw_rect = true}, ui_idf("slider")); - ui_set_rect(box, r2f32_cut_top(&ui->top->rect, scroller_size * scroller_box_size)); - ui_signal_t signal = ui_signal_from_box(box); - if (signal.dragging) { - scroller_value += (ev->mouse_delta.y / item_box_size * 2) * (all_items_size); - scroller_value = CLAMP(scroller_value, 0, all_items_size); - } - if (ev->kind == app_event_kind_mouse_wheel) { - scroller_value -= ev->mouse_wheel_delta.y; - scroller_value = CLAMP(scroller_value, 0, all_items_size); - } + r2f32_cut_top(&ui->top->rect, scroller_percent * scroller_box_size); + ui_box_t *box = ui_build_box_from_id(UILOC, (ui_box_flags_t){.draw_border = true, .draw_rect = true}, ui_idf("slider")); + ui_set_rect(box, r2f32_cut_top(&ui->top->rect, scroller_size * scroller_box_size)); + ui_signal_t signal = ui_signal_from_box(box); + if (signal.dragging) { + scroller_value += (ev->mouse_delta.y / item_box_size * 2) * (all_items_size); + scroller_value = CLAMP(scroller_value, 0, all_items_size); + } + if (ev->kind == app_event_kind_mouse_wheel) { + scroller_value -= ev->mouse_wheel_delta.y; + scroller_value = CLAMP(scroller_value, 0, all_items_size); + } - for (ui_box_t *it = item_box->first; it; it = it->next) { - ui_offset_box(it, v2f32(0, scroller_value)); + for (ui_box_t *it = item_box->first; it; it = it->next) { + ui_offset_box(it, v2f32(0, scroller_value)); + } } } diff --git a/src/ui/ui.gen.c b/src/ui/ui.gen.c index 2c9ca7b..d181bc8 100644 --- a/src/ui/ui.gen.c +++ b/src/ui/ui.gen.c @@ -20,6 +20,9 @@ fn void ui_pop_required_height(void) { SLLS_POP(ui->required_height_stack); } fn void ui_push_padding(v2f32_t v) { ui_v2f32_node_t *n = ma_push_type(tcx.temp, ui_v2f32_node_t); n->value = v; SLLS_PUSH(ui->padding_stack, n); } fn void ui_pop_padding(void) { SLLS_POP(ui->padding_stack); } #define ui_set_padding(x) defer_block(ui_push_padding(x), ui_pop_padding()) +fn void ui_push_background_color(v4f32_t v) { ui_v4f32_node_t *n = ma_push_type(tcx.temp, ui_v4f32_node_t); n->value = v; SLLS_PUSH(ui->background_color_stack, n); } +fn void ui_pop_background_color(void) { SLLS_POP(ui->background_color_stack); } +#define ui_set_background_color(x) defer_block(ui_push_background_color(x), ui_pop_background_color()) fn void ui_assert_stacks_are_null(void) { assert(ui->id_stack == NULL); assert(ui->lop_stack == NULL); @@ -28,4 +31,5 @@ assert(ui->text_align_stack == NULL); assert(ui->required_width_stack == NULL); assert(ui->required_height_stack == NULL); assert(ui->padding_stack == NULL); +assert(ui->background_color_stack == NULL); } \ No newline at end of file diff --git a/src/ui/ui.gen.h b/src/ui/ui.gen.h index 7927e06..a9ebc8f 100644 --- a/src/ui/ui.gen.h +++ b/src/ui/ui.gen.h @@ -4,6 +4,7 @@ typedef struct ui_lop_node_t ui_lop_node_t; struct ui_lop_node_t { ui_lop_t valu typedef struct ui_f32_node_t ui_f32_node_t; struct ui_f32_node_t { f32 value; ui_f32_node_t *next; }; typedef struct ui_text_align_node_t ui_text_align_node_t; struct ui_text_align_node_t { ui_text_align_t value; ui_text_align_node_t *next; }; typedef struct ui_v2f32_node_t ui_v2f32_node_t; struct ui_v2f32_node_t { v2f32_t value; ui_v2f32_node_t *next; }; +typedef struct ui_v4f32_node_t ui_v4f32_node_t; struct ui_v4f32_node_t { v4f32_t value; ui_v4f32_node_t *next; }; #define UI_DECL_BOX_MEMBERS \ f32 border_thickness;\ @@ -11,6 +12,7 @@ ui_text_align_t text_align;\ f32 required_width;\ f32 required_height;\ v2f32_t padding;\ +v4f32_t background_color;\ #define UI_DECL_STACKS \ ui_id_node_t *id_stack;\ @@ -20,3 +22,4 @@ ui_text_align_node_t *text_align_stack;\ ui_f32_node_t *required_width_stack;\ ui_f32_node_t *required_height_stack;\ ui_v2f32_node_t *padding_stack;\ +ui_v4f32_node_t *background_color_stack;\ diff --git a/src/ui/ui.meta.c b/src/ui/ui.meta.c index efb6099..a7f7121 100644 --- a/src/ui/ui.meta.c +++ b/src/ui/ui.meta.c @@ -17,6 +17,7 @@ void mt_ui(ma_arena_t *arena) { {s8_lit("f32") , s8_lit("required_width")} , {s8_lit("f32") , s8_lit("required_height")} , {s8_lit("v2f32_t") , s8_lit("padding")} , + {s8_lit("v4f32_t") , s8_lit("background_color")} , }; ///////////////////////////////