From fdbc8490c43ee205362928fb88aa3ee6f5402a12 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Thu, 23 Jan 2025 09:51:16 +0100 Subject: [PATCH] ui begin text box --- src/app/app_win32.c | 2 +- src/ui/ui.c | 62 ++++++++++++++++++++++++++++++++++++++++----- src/ui/ui.h | 10 ++++++++ todo.txt | 24 +++++------------- 4 files changed, 73 insertions(+), 25 deletions(-) diff --git a/src/app/app_win32.c b/src/app/app_win32.c index 0376549..ea96036 100644 --- a/src/app/app_win32.c +++ b/src/app/app_win32.c @@ -81,7 +81,7 @@ fn void w32_push_event(app_frame_t *frame, app_event_t event) { } fn void w32_push_wm_char_event(WPARAM wparam) { - if (wparam >= 32 || wparam == 127) return; + if (wparam <= 32 || wparam == 127) return; s8_t string = s8_lit("?"); utf32_result_t encode = utf16_to_utf32((u16 *)&wparam, 1); diff --git a/src/ui/ui.c b/src/ui/ui.c index 2f72df3..452dac6 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -193,6 +193,7 @@ fn ui_signal_t ui_signal_from_box(ui_box_t *box) { } } else if (ui_is_hot_box(box) && ev_left_down(ev)) { ui->active = box->id; + ui->focus = box->id; } if (inside) { @@ -204,6 +205,43 @@ fn ui_signal_t ui_signal_from_box(ui_box_t *box) { return result; } +fn void ui_text_input_draw(ui_box_t *box) { + v4f32_t background_color = box->background_color; + v4f32_t border_color = box->border_color; + r2f32_t rect = box->final_rect; // @todo: this or clipped? + rn_draw_rect(rect, background_color); + rn_draw_rect_border(rect, border_color, box->border_thickness); + + s8_t string = s8(box->ti_buffer, box->ti_buffer_len); + v2f32_t string_size = rn_measure_string(rn_state.main_font, string); + v2f32_t rect_size = r2f32_get_size(rect); + v2f32_t rect_string_diff = v2f32_sub(rect_size, string_size); + v2f32_t center_pos = v2f32_divs(rect_string_diff, 2); + v2f32_t pos_in_rect = v2f32(0, center_pos.y); + if (box->text_align == ui_text_align_center) { + pos_in_rect = center_pos; + } + v2f32_t pos = v2f32_add(pos_in_rect, rect.min); + rn_draw_string(rn_state.main_font, pos, box->text_color, string); +} + +fn ui_signal_t ui_text_input(ui_code_loc_t loc, char *buffer, i32 buffer_size) { + ui_box_t *box = ui_build_box_from_string(loc, (ui_box_flags_t){ .draw_border = true, .draw_rect = true, .draw_text = true }, s8_lit("text_input")); + box->custom_draw = ui_text_input_draw; + box->ti_buffer = buffer; + box->ti_buffer_cap = buffer_size; + ui_signal_t signal = ui_signal_from_box(box); + if (ui_is_focused_box(box)) { + app_event_t *ev = ui->event; + if (ev->kind == app_event_kind_text) { + for (i64 i = 0; i < ev->text.len; i += 1) { + box->ti_buffer[box->ti_buffer_len++] = ev->text.str[i]; + } + } + } + return signal; +} + #define ui_button(...) ui__button(UILOC, __VA_ARGS__) fn ui_signal_t ui__button(ui_code_loc_t loc, char *str, ...) { S8_FMT(tcx.temp, str, string); @@ -298,14 +336,11 @@ fn void ui_end_build(void) { } } -fn void ui__draw_box(app_frame_t *frame, ui_box_t *box) { - r2f32_t rect = box->full_rect; - box->final_rect = r2f32_intersect(box->full_rect, ui->clip_rect); - +fn void ui_default_draw_box(ui_box_t *box) { v4f32_t background_color = box->background_color; v4f32_t text_color = box->text_color; - v4f32_t border_color = box->border_color; + r2f32_t rect = box->final_rect; // @todo: this or clipped? if (ui_is_active_box(box)) { f32 active_t = f32_ease_out_n(box->active_t, 50.f); @@ -317,6 +352,9 @@ fn void ui__draw_box(app_frame_t *frame, ui_box_t *box) { hot_t = f32_clamp01(hot_t); background_color = v4f32_lerp(background_color, box->bg_hot_color, hot_t); text_color = v4f32_lerp(background_color, box->text_hot_color, hot_t); + } else if (ui_is_focused_box(box)) { + background_color = v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.6f, 0.95f, 1.0f}); + text_color = v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.6f, 0.7f, 1.0f}); } @@ -338,6 +376,15 @@ fn void ui__draw_box(app_frame_t *frame, ui_box_t *box) { v2f32_t pos = v2f32_add(pos_in_rect, rect.min); rn_draw_string(rn_state.main_font, pos, text_color, box->string); } +} + +fn void ui__draw_box(app_frame_t *frame, ui_box_t *box) { + box->final_rect = r2f32_intersect(box->full_rect, ui->clip_rect); + if (box->custom_draw) { + box->custom_draw(box); + } else { + ui_default_draw_box(box); + } r2f32_t prev_clip_rect = ui->clip_rect; if (box->flags.clip_rect) { @@ -616,6 +663,9 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co ui_set_text_align(ui_text_align_left) ui_set_top(item_box) { + static char buff[128]; + ui_text_input(UILOC, buff, sizeof(buff)); + for (i32 i = 0; i < tweak_count; i += 1) { mt_tweak_t *tweak = tweak_table + i; if (s8_starts_with(tweak->name, s8_lit("_"), false)) { @@ -638,6 +688,7 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co } } else_is_invalid; } + ui_label("allocated boxes: %d", ui->allocated_boxes); ui_serial_type(&ui_test_event, type(app_event_t)); } @@ -679,7 +730,6 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co rn_begin(frame, white_color); ui_draw(); - rn_draw_stringf(rn_state.main_font, v2f32(0, frame->window_size.y - rn_state.main_font->size), v4f32(0,0,0,1), "boxes: %d", ui->allocated_boxes); rn_end(); ui_end_frame(); diff --git a/src/ui/ui.h b/src/ui/ui.h index a361ab6..186b9d4 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -1,3 +1,5 @@ +typedef void ui_custom_draw_t(struct ui_box_t *box); + typedef struct ui_code_loc_t ui_code_loc_t; struct ui_code_loc_t { char *file; @@ -54,6 +56,7 @@ struct ui_box_t { ui_box_flags_t flags; b8 created_new; + ui_custom_draw_t *custom_draw; UI_DECL_BOX_MEMBERS r2f32_t full_rect; @@ -70,6 +73,11 @@ struct ui_box_t { r2f32_t final_rect; b32 expanded; + + i32 ti_cursor; + char *ti_buffer; + i32 ti_buffer_len; + i32 ti_buffer_cap; }; typedef struct ui_signal_t ui_signal_t; @@ -100,6 +108,7 @@ struct ui_t { // interaction ui_id_t hot; ui_id_t active; + ui_id_t focus; // drawing r2f32_t clip_rect; @@ -115,6 +124,7 @@ fn b32 ui_is_null_id(ui_id_t id) { return id.value == 0; } fn b32 ui_is_null_box(ui_box_t *box) { return box->id.value == 0; } fn b32 ui_is_hot_box(ui_box_t *box) { return !ui_is_null_box(box) && box->id.value == ui->hot.value; } fn b32 ui_is_active_box(ui_box_t *box) { return !ui_is_null_box(box) && box->id.value == ui->active.value; } +fn b32 ui_is_focused_box(ui_box_t *box) { return !ui_is_null_box(box) && box->id.value == ui->focus.value; } #define ev_left(ev) ((ev)->mouse_button == app_mouse_button_left) #define ev_left_up(ev) ((ev)->kind == app_event_kind_mouse_up && ev_left(ev)) diff --git a/todo.txt b/todo.txt index 104e46c..8582006 100644 --- a/todo.txt +++ b/todo.txt @@ -24,31 +24,19 @@ [ ] ui [ ] text input [ ] everything lister (with edits etc.) + [ ] push pop flag + [ ] how to do colors? + - css like based on ids and pre built palettes + - fat box with stacks (now) + - [ ] demo style, with different buttons and controls, headings [x] palette idea, also push pop palette - [ ] push pop flag [x] replace padding with something more 'real' + [ ] color picker [ ] slider [ ] draw image in box ui - -- maybe remove radio_color in ui and do a 2 tier color scheme (ui as separate from the theme ui) - - but then how do we pass color to ui_radio_button? -float COLOR_Tint = 0.0; -Vec4 COLOR_Caret = HSLToRGB({COLOR_Tint, 0.4f, 0.60f, 1.0f}); -Vec4 COLOR_white = {1, 1, 1, 1}; -Vec4 COLOR_plot_lines = COLOR_white; -Vec4 COLOR_on_hover_rect = HSLToRGB({COLOR_Tint, 0.2f, 0.96f, 1.0f}); -Vec4 COLOR_cell_outline = COLOR_white; -Vec4 COLOR_background_plot = HSLToRGB({COLOR_Tint, 0.2f, 0.95f, 1.0f}); -Vec4 COLOR_spreadsheet_background = COLOR_background_plot; -Vec4 COLOR_text = HSLToRGB({COLOR_Tint, 0.2f, 0.7f, 1.0f}); -Vec4 COLOR_highlighted_text = HSLToRGB({COLOR_Tint, 0.4f, 0.9f, 1.0f}); -Vec4 COLOR_data_point = HSLToRGB({COLOR_Tint, 0.4f, 0.60f, 1.0f}); -Vec4 COLOR_highlighted_data_point = HSLToRGB({COLOR_Tint, 0.4f, 0.90f, 1.0f}); -Vec4 COLOR_on_hover_outline_rect = COLOR_text; - [ ] core [ ] ast [ ] move to core layer at some point as the abstract format for different types of serialization