fn_test and ui_text_input work

This commit is contained in:
Krzosa Karol
2025-01-23 19:02:20 +01:00
parent fdbc8490c4
commit 0b6ea60fa7
9 changed files with 265 additions and 35 deletions

View File

@@ -206,38 +206,147 @@ fn ui_signal_t ui_signal_from_box(ui_box_t *box) {
}
fn void ui_text_input_draw(ui_box_t *box) {
r2f32_t rect = box->final_rect;
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);
active_t = f32_clamp01(active_t);
background_color = v4f32_lerp(background_color, box->bg_active_color, 1.0);
text_color = v4f32_lerp(text_color, box->text_active_color, active_t);
} else if (ui_is_hot_box(box)) {
f32 hot_t = f32_ease_out_n(box->hot_t, 3.f);
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});
}
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;
ui_text_input_t *ti = &box->text_input;
s8_t string = s8(ti->str, ti->len);
v2f32_t pos = ui_aligned_text_pos(box->text_align, rect, string);
rn_draw_string(rn_state.main_font, pos, text_color, string);
ti->caret = ui_caret_clamp(ti->caret, 0, (i32)ti->len);
{
s8_t string_min = s8(ti->str, ti->caret.range.min);
s8_t string_max = s8(ti->str, ti->caret.range.max);
v2f32_t size_min = rn_measure_string(rn_state.main_font, string_min);
v2f32_t size_max = rn_measure_string(rn_state.main_font, string_max);
r2f32_t selection_rect = r2f32(rect.min.x + size_min.x, rect.min.y, rect.min.x + size_max.x, rect.min.y + ui_em(1));
rn_draw_rect(selection_rect, v4f32(1,1,1,0.2f));
v2f32_t size_front = ti->caret.ifront == 0 ? size_min : size_max;
r2f32_t caret_rect = r2f32(rect.min.x + size_front.x, rect.min.y, rect.min.x + size_front.x + 1, rect.min.y + ui_em(1));
rn_draw_rect(caret_rect, text_color);
}
v2f32_t pos = v2f32_add(pos_in_rect, rect.min);
rn_draw_string(rn_state.main_font, pos, box->text_color, string);
}
fn i32 ui_text_replace(ui_text_input_t *ti, r1i32_t range, s8_t string) {
range.min = CLAMP(range.min, 0, (i32)ti->len);
range.max = CLAMP(range.max, range.min, (i32)ti->len);
assert(range.min >= 0 && range.max <= ti->len);
i32 size_to_remove = r1i32_size(range);
i32 size_to_add = (i32)string.len;
i32 change_size = size_to_add - size_to_remove;
if (ti->len + change_size > ti->cap) {
i32 rem = ((i32)ti->len + change_size) - ti->cap;
size_to_add -= rem;
change_size -= rem;
assert(change_size >= 0);
}
u8 *begin_remove = ti->str + range.min;
u8 *end_remove = begin_remove + size_to_remove;
i32 remain_len = (i32)ti->len - (range.min + size_to_remove);
u8 *begin_add = begin_remove;
u8 *end_add = begin_add + size_to_add;
memory_move(end_add, end_remove, remain_len);
memory_copy(begin_add, string.str, size_to_add);
ti->len = ti->len + change_size;
return change_size;
}
fn_test void ui_test_text_replace(void) {
ui_text_input_t ti = {0};
char buff[4] = {0};
ti.str = buff;
ti.cap = lengthof(buff);
ui_text_replace(&ti, r1i32(0,0), s8_lit("astfpo"));
assert(s8_are_equal(ti.string, s8_lit("astf")));
ui_text_replace(&ti, r1i32(0,4), s8_lit("qwer"));
assert(s8_are_equal(ti.string, s8_lit("qwer")));
ui_text_replace(&ti, r1i32(1,2), s8_lit("a"));
assert(s8_are_equal(ti.string, s8_lit("qaer")));
}
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_text_input_t *ti = &box->text_input;
ti->str = buffer;
ti->cap = buffer_size;
ui_signal_t signal = ui_signal_from_box(box);
if (ui_is_focused_box(box)) {
app_event_t *ev = ui->event;
i32 sel_size = r1i32_size(ti->caret.range);
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];
ui_text_replace(ti, ti->caret.range, ev->text);
if (sel_size) {
ti->caret = ui_carets(ti->caret.range.min);
} else {
ti->caret = ui_carets(ti->caret.range.min + 1);
}
} else if (ev->kind == app_event_kind_key_down) {
if (ev->key == app_key_backspace) {
if (sel_size) {
ui_text_replace(ti, ti->caret.range, s8_lit(""));
} else {
ui_text_replace(ti, r1i32(ti->caret.e[0] - 1, ti->caret.e[0]), s8_null);
ti->caret = ui_carets(ti->caret.range.min - 1);
}
} else if (ev->key == app_key_delete) {
if (sel_size) {
ui_text_replace(ti, ti->caret.range, s8_lit(""));
} else {
ui_text_replace(ti, r1i32(ti->caret.e[0], ti->caret.e[0] + 1), s8_null);
}
} else if (ev->key == app_key_left) {
if (ev->shift) {
ti->caret = ui_caret_set_front(ti->caret, ui_caret_front(ti->caret) - 1);
} else {
ti->caret = ui_carets(ui_caret_front(ti->caret) - 1);
}
} else if (ev->key == app_key_right) {
if (ev->shift) {
ti->caret = ui_caret_set_front(ti->caret, ui_caret_front(ti->caret) + 1);
} else {
ti->caret = ui_carets(ui_caret_front(ti->caret) + 1);
}
}
} else if (signal.dragging) {
v2f32_t size = rn_measure_string(rn_state.main_font, s8_lit("_"));
v2f32_t pos = v2f32_sub(ev->mouse_pos, box->final_rect.min);
i32 p = (i32)f32_round(pos.x / size.x);
if (ev->kind == app_event_kind_mouse_down && ev->mouse_button == app_mouse_button_left) {
ti->caret = ui_carets(p);
}
ti->caret = ui_caret_set_front(ti->caret, p);
}
ti->caret = ui_caret_clamp(ti->caret, 0, (i32)ti->len);
}
return signal;
}
@@ -336,12 +445,25 @@ fn void ui_end_build(void) {
}
}
fn v2f32_t ui_aligned_text_pos(ui_text_align_t text_align, r2f32_t rect, s8_t string) {
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 (text_align == ui_text_align_center) {
pos_in_rect = center_pos;
}
v2f32_t pos = v2f32_add(pos_in_rect, rect.min);
return pos;
}
fn void ui_default_draw_box(ui_box_t *box) {
r2f32_t rect = box->final_rect;
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);
active_t = f32_clamp01(active_t);
@@ -365,15 +487,7 @@ fn void ui_default_draw_box(ui_box_t *box) {
rn_draw_rect_border(rect, border_color, box->border_thickness);
}
if (box->flags.draw_text) {
v2f32_t string_size = rn_measure_string(rn_state.main_font, box->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);
v2f32_t pos = ui_aligned_text_pos(box->text_align, rect, box->string);
rn_draw_string(rn_state.main_font, pos, text_color, box->string);
}
}

View File

@@ -42,6 +42,63 @@ typedef enum {
} ui_lop_t;
#include "ui.gen.h"
typedef struct ui_caret_t ui_caret_t;
struct ui_caret_t {
union {
i32 e[2];
struct { r1i32_t range; };
};
i32 ifront;
};
fn ui_caret_t ui_caret_clamp(ui_caret_t c, i32 min, i32 max) {
return (ui_caret_t){CLAMP(c.e[0],min,max), CLAMP(c.e[1],min,max), c.ifront};
}
fn i32 ui_caret_front(ui_caret_t c) { return c.e[c.ifront]; }
fn i32 ui_caret_back(ui_caret_t c) { return c.e[c.ifront ? 0 : 1]; }
ui_caret_t ui_caret(i32 front, i32 back) {
ui_caret_t result = {0};
if (front >= back) {
result.range.min = back;
result.range.max = front;
result.ifront = 1;
} else {
result.range.min = front;
result.range.max = back;
result.ifront = 0;
}
return result;
}
ui_caret_t ui_caret_set_back(ui_caret_t caret, i32 back) {
i32 front = ui_caret_front(caret);
ui_caret_t result = ui_caret(front, back);
return result;
}
ui_caret_t ui_caret_set_front(ui_caret_t caret, i32 front) {
i32 back = ui_caret_back(caret);
ui_caret_t result = ui_caret(front, back);
return result;
}
fn ui_caret_t ui_carets(i32 x) {
return ui_caret(x, x);
}
typedef struct ui_text_input_t ui_text_input_t;
struct ui_text_input_t {
union {
struct { char *str; i64 len; };
s8_t string;
};
i32 cap;
ui_caret_t caret;
};
typedef struct ui_box_t ui_box_t;
struct ui_box_t {
ui_box_t *next;
@@ -74,10 +131,7 @@ struct ui_box_t {
r2f32_t final_rect;
b32 expanded;
i32 ti_cursor;
char *ti_buffer;
i32 ti_buffer_len;
i32 ti_buffer_cap;
ui_text_input_t text_input;
};
typedef struct ui_signal_t ui_signal_t;
@@ -138,4 +192,5 @@ fn void ui_set_rect(ui_box_t *box, r2f32_t rect) { box->rect = box->full_rect =
#define ui_box_flags(...) (ui_box_flag_t){__VA_ARGS__}
fn ui_id_t ui_id(s8_t string);
fn ui_id_t ui_idf(char *str, ...);
fn ui_id_t ui_idf(char *str, ...);
fn v2f32_t ui_aligned_text_pos(ui_text_align_t text_align, r2f32_t rect, s8_t string);