scroller work, everything improv

This commit is contained in:
Krzosa Karol
2025-01-31 09:26:23 +01:00
parent 9808d435d5
commit 644bb896ac
11 changed files with 481 additions and 386 deletions

View File

@@ -265,18 +265,6 @@ fn ui_box_t *ui_build_box_from_id(ui_code_loc_t loc, ui_box_flags_t flags, ui_id
box->border_thickness = ui_top_border_thickness();
box->string_pos_offset = ui_top_string_pos_offset();
// :ui_box_flags_t
ui_box_flags_t top_flags = ui_top_flags();
{
if(top_flags.draw_rect) box->flags.draw_rect = true;
if(top_flags.draw_border) box->flags.draw_border = true;
if(top_flags.draw_text) box->flags.draw_text = true;
if(top_flags.clip_rect) box->flags.clip_rect = true;
if(top_flags.children_sum_x) box->flags.children_sum_x = true;
if(top_flags.children_sum_y) box->flags.children_sum_y = true;
if(top_flags.keyboard_nav) box->flags.keyboard_nav = true;
}
ui_box_fill_with_colors(box);
ui_push_box(ui->top, box);
return box;
@@ -335,7 +323,6 @@ fn ui_signal_t ui_signal_from_box(ui_box_t *box) {
b32 inside = r2f32_contains(box->final_rect, ev->mouse_pos);
if (ui_is_active_box(box)) {
result.press = true;
result.dragging = true;
result.drag = ui->event->mouse_delta;
if (ev_left_up(ev)) {
@@ -357,17 +344,14 @@ fn ui_signal_t ui_signal_from_box(ui_box_t *box) {
result.drag.x -= 1;
result.dragging = true;
result.clicked = true;
result.press = true;
} else if (ev->kind == app_event_kind_key_down && ev->key == app_key_right) {
result.drag.x += 1;
result.dragging = true;
result.clicked = true;
result.press = true;
}
if (ev->kind == app_event_kind_key_down && ev->key == app_key_enter) {
result.clicked = true;
result.press = true;
}
}
@@ -430,7 +414,7 @@ fn ui_draw_compute_t ui_draw_compute(ui_box_t *box) {
}
if (ui_is_focused_box(box)) {
co.background_color = v4f32_lerp(co.background_color, ui_color_table[ui_color_focused_rect], 0.4f);
co.background_color = v4f32_lerp(co.background_color, ui_color_table[ui_color_focused_rect], 0.7f);
// co.text_color = v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.6f, 0.7f, 1.0f});
box->flags.draw_rect = true;
@@ -527,15 +511,16 @@ fn_test void ui_test_text_replace(void) {
assert(s8_are_equal(ti.string, s8_lit("qaer")));
}
#define ui_text_input(ti) ui__text_input(UILOC, ti)
fn ui_signal_t ui__text_input(ui_code_loc_t loc, ui_text_input_t *ti) {
#define ui_text_input(...) ui__text_input(UILOC, __VA_ARGS__)
fn ui_signal_t ui__text_input(ui_code_loc_t loc, ui_text_input_t *ti, b32 sim_even_if_no_focus) {
ui_box_t *box = ui_box(.loc = loc, .string = s8_lit("text_input"), .flags = { .draw_border = true, .draw_rect = true, .draw_text = true, .keyboard_nav = true });
box->text_input = ti;
box->custom_draw = ui_text_input_draw;
ui_signal_t signal = ui_signal_from_box(box);
if (ui_is_focused_box(box)) {
b32 sim = sim_even_if_no_focus || ui_is_focused_box(box);
if (sim) {
app_event_t *ev = ui->event;
i32 sel_size = r1i32_size(ti->caret.range);
if (ev->kind == app_event_kind_text) {
@@ -636,7 +621,7 @@ fn ui_box_t *ui__label(ui_code_loc_t loc, char *str, ...) {
}
fn void ui_tree_table_begin(ui_code_loc_t loc) {
ui_box_t *box = ui_box(.loc = loc, .rect = ui_next_rect(ui_top_lop(), ui_top_rectp(), v2f32_null), .flags = { .draw_border = true, .children_sum_y = true });
ui_box_t *box = ui_box(.loc = loc, .rect = ui_next_rect(ui_top_lop(), ui_top_rectp(), v2f32_null), .flags = { .draw_border = true, .children_sum_y = true, .clip_rect = true, });
ui_push_top(box);
}
@@ -649,6 +634,8 @@ fn void ui_tree_table_end(void) {
#define ui_tree_table_expandable(...) defer_if (ui_tree_table_push_expandable(UILOC, __VA_ARGS__).clicked, ui_tree_table_pop_expandable())
fn void ui_tree_table_pop_expandable(void) {
r2f32_add_left(ui_top_rectp(), ui_dm(1));
// r2f32_cut_right(ui_top_rectp(), ui_dm(0.1f));
// ui_top_rectp()[0] = r2f32_expand(ui_top_rect(), v2f32(ui_dm(1), 0));
ui_tree_table_end();
ui_pop_id();
}
@@ -664,7 +651,10 @@ fn ui_signal_t ui_tree_table_push_expandable(ui_code_loc_t loc, char *str, ...)
if (button.clicked) button.box->expanded = !button.box->expanded;
button.clicked = button.box->expanded;
// ui_top_rectp()[0] = r2f32_shrink(ui_top_rect(), v2f32(ui_dm(1), 0));
r2f32_cut_left(ui_top_rectp(), ui_dm(1));
// r2f32_cut_right(ui_top_rectp(), ui_dm(0.1f));
if (button.clicked == false) {
ui_tree_table_pop_expandable();
@@ -731,111 +721,40 @@ fn b32 ui_match_keynav(ui_box_t *box) {
return result;
}
fn void ui_begin_build(ui_code_loc_t loc, app_event_t *ev, r2f32_t window_rect) {
ui->event = ev;
for (ui_box_t *box = ui->hash_first, *next = NULL; box; box = next) {
next = box->hash_next;
if (box->id.value == 0) {
DLLQ_REMOVE_EX(ui->hash_first, ui->hash_last, box, hash_next, hash_prev);
zero_struct(box);
SLLS_PUSH(ui->free_first, box);
}
}
ui_push_init_values();
zero_struct(&ui->root);
ui->top = &ui->root;
ui->root.loc = loc;
#define ui_reverse_node_order() defer_block(ui_begin_reversal(), ui_end_reversal())
fn void ui_begin_reversal(void) {
ui->reverse_order_ref = ui->top->last;
}
fn void ui_end_build(void) {
ui_set_children_sums(&ui->root);
fn void ui_end_reversal(void) {
assert(ui->reverse_order_ref);
assert(ui->reverse_order_ref->next);
ui_box_t *first = ui->reverse_order_ref->next;
ui_box_t *last = ui->top->last;
ui->reverse_order_ref = NULL;
{
app_event_t *ev = ui->event;
ui_box_t *focus_box = ui_find_box(ui->focus);
if (focus_box == NULL) {
ui->focus = ui_get_next_box(&ui->root, ui_match_keynav)->id;
}
if (ev->kind == app_event_kind_key_down && ev->key == app_key_up) {
ui->focus = ui_get_prev_box(focus_box, ui_match_keynav)->id;
} else if (ev->kind == app_event_kind_key_down && ev->key == app_key_down) {
ui->focus = ui_get_next_box(focus_box, ui_match_keynav)->id;
b32 connected = false;
for (ui_box_t *it = first; it; it = it->next) {
if (it == last) {
connected = true;
break;
}
}
assert(ui->top == &ui->root);
ui_pop_init_values();
ui_assert_stacks_are_null();
assert(connected);
for (ui_box_t *box = ui->hash_first, *next = NULL; box; box = next) {
next = box->hash_next;
b32 touched_box_during_update = ui->event->id <= box->last_touched_event_id;
if (!touched_box_during_update) {
DLLQ_REMOVE_EX(ui->hash_first, ui->hash_last, box, hash_next, hash_prev);
zero_struct(box);
SLLS_PUSH(ui->free_first, box);
}
}
}
fn void ui__draw_box(app_frame_t *frame, ui_box_t *box) {
box->final_rect = r2f32_intersect(box->rect, ui->clip_rect);
if (box->custom_draw) {
box->custom_draw(box);
} else {
ui_default_draw_box(box);
ui_box_t *first2 = NULL;
ui_box_t *last2 = NULL;
for (ui_box_t *it = first, *next = it->next; next; it = next) {
next = it->next;
DLLQ_REMOVE(it->parent->first, it->parent->last, it);
DLLQ_APPEND(first2, last2, it);
}
r2f32_t prev_clip_rect = ui->clip_rect;
if (box->flags.clip_rect) {
ui->clip_rect = box->rect;
rn_set_clip(ui->clip_rect);
}
for (ui_box_t *it = box->first; it; it = it->next) {
ui__draw_box(frame, it);
}
if (box->flags.clip_rect) {
ui->clip_rect = prev_clip_rect;
rn_set_clip(ui->clip_rect);
}
}
fn void ui_draw(void) {
ui->clip_rect = window_rect_from_frame(ui->frame);
rn_set_clip(ui->clip_rect);
ui__draw_box(ui->frame, &ui->root);
}
fn void ui_begin_frame(app_frame_t *frame) {
ui = tcx->data[tcx_slot_ui];
ui->frame = frame;
}
fn void ui_end_frame(void) {
for (ui_box_t *box = ui->hash_first, *next = NULL; box; box = next) {
next = box->hash_next;
box->appear_t += (f32)ui->frame->delta;
if (ui_is_hot_box(box)) {
box->hot_t += (f32)ui->frame->delta;
} else {
box->hot_t = 0;
}
if (ui_is_active_box(box)) {
box->active_t += (f32)ui->frame->delta;
} else {
box->active_t = 0;
}
}
for (app_event_t *ev = ui->frame->first_event; ev; ev = ev->next) {
if (ev_left_up(ev)) {
ui->active = ui_null_id;
}
for (ui_box_t *it = last2, *prev = it->prev; prev; it = prev) {
prev = it->prev;
DLLQ_REMOVE(first2, last2, it);
DLLQ_APPEND(it->parent->first, it->parent->last, it);
}
}
@@ -1036,6 +955,248 @@ fn void ui_serial_type(ui_code_loc_t loc, void *p, type_t *type) {
ui_set_id(ui_id_from_loc(loc)) ui_serial_subtype(p, type, type->name);
}
typedef struct ui_scroller_params_t ui_scroller_params_t;
struct ui_scroller_params_t {
ui_box_t *parent;
struct {
b8 enabled;
f32 *value;
f32 max_size;
} hori;
struct {
b8 enabled;
f32 *value;
f32 item_pixels;
i32 item_count;
} verti;
};
typedef struct ui_scroller_t ui_scroller_t;
struct ui_scroller_t {
struct {
ui_box_t *box;
i32 istart;
i32 iend;
f32 item_box_pixels;
} verti;
struct {
ui_box_t *box;
} hori;
ui_scroller_params_t p;
};
fn ui_scroller_t ui_begin_scroller(ui_scroller_params_t p) {
ui_scroller_t r = {.p = p};
if (p.verti.enabled) {
r.verti.box = ui_box(.rect = r2f32_cut_right(&p.parent->rect, ui_dm(0.5f)), .flags = {.draw_rect = true});
r2f32_cut_bottom(&r.verti.box->rect, ui_dm(0.5f));
r.verti.item_box_pixels = r2f32_get_size(p.parent->rect).y;
f32 visible_item_count = f32_ceil(r.verti.item_box_pixels / p.verti.item_pixels);
f32 render_start_count = f32_floor(p.verti.value[0] / p.verti.item_pixels);
i32 istart = (i32)render_start_count;
i32 iend = (i32)render_start_count + (i32)visible_item_count;
r.verti.istart = CLAMP(istart, 0, (i32)p.verti.item_count);
r.verti.iend = CLAMP(iend, 0, (i32)p.verti.item_count);
}
if (p.hori.enabled) {
r.hori.box = ui_box(.rect = r2f32_cut_bottom(&p.parent->rect, ui_dm(0.5f)), .flags = {.draw_rect = true});
}
return r;
}
fn void ui_cut_top_scroller_offset(ui_scroller_t s) {
r2f32_cut_top_no_squash(ui_top_rectp(), (f32)s.verti.istart * s.p.verti.item_pixels);
}
fn void ui_end_scroller(ui_scroller_t s) {
if (s.p.verti.enabled) ui_set_top(s.verti.box) {
f32 scroller_rect_pixels = r2f32_get_size(s.verti.box->rect).y;
f32 all_items_size = s.p.verti.item_pixels * s.p.verti.item_count;
f32 scroller_size = f32_clamp01(s.verti.item_box_pixels / (all_items_size + s.verti.item_box_pixels));
f32 scrollable_space = (1 - scroller_size);
f32 scroller_value_norm = s.p.verti.value[0] / (all_items_size);
f32 scroller_value_n = scroller_value_norm * scrollable_space;
ui_box_t *upper_box = ui_box(r2f32_cut_top(ui_top_rectp(), scroller_value_n * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *slider_box = ui_box(r2f32_cut_top(ui_top_rectp(), scroller_size * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *down_box = ui_box(r2f32_cut_top(ui_top_rectp(), ui_max), {.draw_rect = true});
slider_box->background_color = ui_color_table[ui_color_scroller];
slider_box->bg_hot_color = ui_color_table[ui_color_scroller_hot];
slider_box->bg_active_color = ui_color_table[ui_color_scroller_active];
ui_signal_t signal = ui_signal_from_box(slider_box);
ui_signal_t upper_box_signal = ui_signal_from_box(upper_box);
ui_signal_t down_box_signal = ui_signal_from_box(down_box);
app_event_t *ev = ui->event;
f32 drag = ev->mouse_delta.y;
f32 coef = f32_safe_ratio0((all_items_size / s.verti.item_box_pixels), scrollable_space);
if (signal.dragging) {
s.p.verti.value[0] += drag * coef;
}
if (upper_box_signal.dragging || down_box_signal.dragging) {
s.p.verti.value[0] = (ev->mouse_pos.y - upper_box->rect.min.y) * coef;
s.p.verti.value[0] -= (r2f32_get_size(slider_box->rect).y / 2) * coef;
}
if (ev->kind == app_event_kind_mouse_wheel) {
s.p.verti.value[0] -= ev->mouse_wheel_delta.y;
}
s.p.verti.value[0] = CLAMP(s.p.verti.value[0], 0, all_items_size);
}
if (s.p.hori.enabled) ui_set_top(s.hori.box) {
f32 scroller_rect_pixels = r2f32_get_size(s.hori.box->rect).x;
f32 scroller_button_size_norm = f32_clamp01(scroller_rect_pixels / s.p.hori.max_size);
f32 scrollable_space = (1.f - scroller_button_size_norm);
f32 scroller_value_norm = s.p.hori.value[0] / s.p.hori.max_size;
f32 scroller_value_n = scroller_value_norm * scrollable_space;
ui_box_t *left_box = ui_box(r2f32_cut_left(ui_top_rectp(), scroller_value_n * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *slider_box = ui_box(r2f32_cut_left(ui_top_rectp(), scroller_button_size_norm * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *down_box = ui_box(r2f32_cut_left(ui_top_rectp(), ui_max), {.draw_rect = true});
slider_box->background_color = ui_color_table[ui_color_scroller];
slider_box->bg_hot_color = ui_color_table[ui_color_scroller_hot];
slider_box->bg_active_color = ui_color_table[ui_color_scroller_active];
ui_signal_t left_box_sig = ui_signal_from_box(left_box);
ui_signal_t signal = ui_signal_from_box(slider_box);
ui_signal_t right_box_sig = ui_signal_from_box(down_box);
app_event_t *ev = ui->event;
f32 coef = f32_safe_ratio0((s.p.hori.max_size / scroller_rect_pixels), scrollable_space);
if (signal.dragging) {
s.p.hori.value[0] += ev->mouse_delta.x * coef;
}
if (left_box_sig.dragging || right_box_sig.dragging) {
s.p.hori.value[0] = (ev->mouse_pos.x - left_box->rect.min.x) * coef;
s.p.hori.value[0] -= (r2f32_get_size(slider_box->rect).x / 2) * coef;
}
if (ev->kind == app_event_kind_mouse_wheel) {
s.p.hori.value[0] -= ev->mouse_wheel_delta.x;
}
s.p.hori.value[0] = CLAMP(s.p.hori.value[0], 0, s.p.hori.max_size);
}
ui_offset_children(s.p.parent, v2f32(s.p.hori.value ? s.p.hori.value[0] : 0, s.p.verti.value ? s.p.verti.value[0] : 0));
}
///////////////////////////////
// main ui control points
fn void ui_begin_build(ui_code_loc_t loc, app_event_t *ev, r2f32_t window_rect) {
ui->event = ev;
for (ui_box_t *box = ui->hash_first, *next = NULL; box; box = next) {
next = box->hash_next;
if (box->id.value == 0) {
DLLQ_REMOVE_EX(ui->hash_first, ui->hash_last, box, hash_next, hash_prev);
zero_struct(box);
SLLS_PUSH(ui->free_first, box);
}
}
ui_push_init_values();
zero_struct(&ui->root);
ui->top = &ui->root;
ui->root.loc = loc;
}
fn void ui_end_build(void) {
ui_set_children_sums(&ui->root);
{
app_event_t *ev = ui->event;
ui_box_t *focus_box = ui_find_box(ui->focus);
if (focus_box == NULL) {
ui->focus = ui_get_next_box(&ui->root, ui_match_keynav)->id;
}
if (ev->kind == app_event_kind_key_down && ev->key == app_key_up) {
ui->focus = ui_get_prev_box(focus_box, ui_match_keynav)->id;
} else if (ev->kind == app_event_kind_key_down && ev->key == app_key_down) {
ui->focus = ui_get_next_box(focus_box, ui_match_keynav)->id;
}
}
assert(ui->top == &ui->root);
ui_pop_init_values();
ui_assert_stacks_are_null();
for (ui_box_t *box = ui->hash_first, *next = NULL; box; box = next) {
next = box->hash_next;
b32 touched_box_during_update = ui->event->id <= box->last_touched_event_id;
if (!touched_box_during_update) {
DLLQ_REMOVE_EX(ui->hash_first, ui->hash_last, box, hash_next, hash_prev);
zero_struct(box);
SLLS_PUSH(ui->free_first, box);
}
}
}
fn void ui__draw_box(app_frame_t *frame, ui_box_t *box) {
box->final_rect = r2f32_intersect(box->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) {
ui->clip_rect = r2f32_intersect(ui->clip_rect, box->rect);
rn_set_clip(ui->clip_rect);
}
for (ui_box_t *it = box->first; it; it = it->next) {
ui__draw_box(frame, it);
}
if (box->flags.clip_rect) {
ui->clip_rect = prev_clip_rect;
rn_set_clip(ui->clip_rect);
}
}
fn void ui_draw(void) {
ui->clip_rect = window_rect_from_frame(ui->frame);
rn_set_clip(ui->clip_rect);
ui__draw_box(ui->frame, &ui->root);
}
fn void ui_begin_frame(app_frame_t *frame) {
ui = tcx->data[tcx_slot_ui];
ui->frame = frame;
}
fn void ui_end_frame(void) {
for (ui_box_t *box = ui->hash_first, *next = NULL; box; box = next) {
next = box->hash_next;
box->appear_t += (f32)ui->frame->delta;
if (ui_is_hot_box(box)) {
box->hot_t += (f32)ui->frame->delta;
} else {
box->hot_t = 0;
}
if (ui_is_active_box(box)) {
box->active_t += (f32)ui->frame->delta;
} else {
box->active_t = 0;
}
}
for (app_event_t *ev = ui->frame->first_event; ev; ev = ev->next) {
if (ev_left_up(ev)) {
ui->active = ui_null_id;
}
}
}
fn void ui_reload(void) {
ui_init_colors();
}
@@ -1047,95 +1208,8 @@ fn void ui_init(ma_arena_t *arena) {
ui_reload();
}
#define ui_reverse_node_order() defer_block(ui_begin_reversal(), ui_end_reversal())
fn void ui_begin_reversal(void) {
ui->reverse_order_ref = ui->top->last;
}
fn void ui_end_reversal(void) {
assert(ui->reverse_order_ref);
assert(ui->reverse_order_ref->next);
ui_box_t *first = ui->reverse_order_ref->next;
ui_box_t *last = ui->top->last;
ui->reverse_order_ref = NULL;
b32 connected = false;
for (ui_box_t *it = first; it; it = it->next) {
if (it == last) {
connected = true;
break;
}
}
assert(connected);
ui_box_t *first2 = NULL;
ui_box_t *last2 = NULL;
for (ui_box_t *it = first, *next = it->next; next; it = next) {
next = it->next;
DLLQ_REMOVE(it->parent->first, it->parent->last, it);
DLLQ_APPEND(first2, last2, it);
}
for (ui_box_t *it = last2, *prev = it->prev; prev; it = prev) {
prev = it->prev;
DLLQ_REMOVE(first2, last2, it);
DLLQ_APPEND(it->parent->first, it->parent->last, it);
}
}
gb_read_only i64 fuzzy_closer_word_begin = 5;
gb_read_only i64 fuzzy_consecutive_multiplier = 3;
fn i64 fuzzy_rate_string(s8_t string, s8_t with) {
if (with.len == 0) return 0;
i64 points = 0;
i64 consecutive = 0;
i64 with_i = 0;
for (i64 i = 0; i < string.len; i++) {
if (string.str[i] == with.str[with_i]) {
i64 closer_begin = CLAMP_BOT((i64)0, fuzzy_closer_word_begin - i);
points += closer_begin;
consecutive++;
with_i += 1;
} else {
points += consecutive * fuzzy_consecutive_multiplier;
consecutive = 0;
with_i = 0;
}
if (with_i >= with.len) with_i = 0;
}
points += consecutive * fuzzy_consecutive_multiplier;
return points;
}
typedef struct fuzzy_pair_t fuzzy_pair_t;
struct fuzzy_pair_t {
i64 index;
i64 rating;
};
fn fuzzy_pair_t *fuzzy_rate_array(ma_arena_t *arena, s8_t needle, s8_t *array, i32 len) {
fuzzy_pair_t *pairs = ma_push_array(arena, fuzzy_pair_t, len);
for (i32 i = 0; i < len; i += 1) {
pairs[i].rating = fuzzy_rate_string(array[i], needle);
pairs[i].index = i;
}
for (i32 i = 0; i < len - 1; i++) {
for (i32 j = 0; j < len - 1; j++) {
if (pairs[j].rating < pairs[j + 1].rating) {
SWAP(fuzzy_pair_t, pairs[j], pairs[j + 1]);
}
}
}
return pairs;
}
gb app_event_t ui_test_event;
gb i32 ui_g_panel = 2;
gb i32 ui_g_panel = 1;
fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_count) {
ui_begin_frame(frame);
rn_begin_frame(frame);
@@ -1169,18 +1243,10 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
ui_box_t *bottom_scroller = ui_box(r2f32_cut_bottom(ui_top_rectp(), 10 * frame->dpr), {.draw_rect = true});
ui_box_t *item_box = ui_box(r2f32_cut_left(ui_top_rectp(), ui_max), {.draw_rect = true, .clip_rect = true});
r2f32_t scroll_rect = {0};
ui_set_text_align(ui_text_align_left)
ui_set_top(item_box) {
ui_top_rectp()[0] = r2f32_shrinks(ui_top_rect(), ui_em(1));
locl char buff[128];
locl ui_text_input_t text_input;
if (text_input.str == NULL) {
text_input.str = buff;
text_input.cap = lengthof(buff);
}
ui_text_input(&text_input);
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)) {
@@ -1205,13 +1271,13 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
ui_label("allocated boxes: %d", ui->allocated_boxes);
ui_serial_type(UILOC, &ui_test_event, type(app_event_t));
ui_serial_type(UILOC, &ui_test_event, type(app_event_t));
scroll_rect = r2f32_fix(ui_top_rect());
}
locl f32 scroller_value;
ui_set_top(scroller_box) {
f32 item_count = (f32)item_box->node_count;
f32 one_item_y_size = ui_em(1);
f32 all_items_size = item_count * one_item_y_size;
f32 all_items_size = r2f32_get_size(scroll_rect).y;
f32 item_box_size = r2f32_get_size(item_box->rect).y;
f32 scroller_box_size = r2f32_get_size(scroller_box->rect).y;
f32 scroller_size = CLAMP(item_box_size / (all_items_size + frame->window_size.y), 0, 1.0f);
@@ -1233,59 +1299,21 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
f32 coef = f32_safe_ratio0(all_items_size / item_box_size, scrollable_space);
if (signal.dragging) {
scroller_value += drag * coef;
scroller_value = CLAMP(scroller_value, 0, all_items_size);
}
if (upper_box_signal.dragging || down_box_signal.dragging) {
scroller_value = (ev->mouse_pos.y - upper_box->final_rect.min.y) * coef;
scroller_value -= (slider_box_size / 2) * coef;
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);
}
scroller_value = CLAMP(scroller_value, 0, all_items_size);
}
locl f32 bottom_scroller_value;
ui_set_top(bottom_scroller) {
f32 max_size = 0;
for (ui_box_t *it = item_box->first; it; it = it->next) {
max_size = MAX(max_size, it->string_size.x);
}
f32 scroller_rect_pixels = r2f32_get_size(bottom_scroller->rect).x;
f32 scroller_button_size_norm = f32_clamp01(scroller_rect_pixels / max_size);
f32 scrollable_space = (1.f - scroller_button_size_norm);
f32 scroller_value_norm = bottom_scroller_value / max_size;
f32 scroller_value_n = scroller_value_norm * scrollable_space;
ui_box_t *left_box = ui_box(r2f32_cut_left(ui_top_rectp(), scroller_value_n * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *slider_box = ui_box(r2f32_cut_left(ui_top_rectp(), scroller_button_size_norm * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *down_box = ui_box(r2f32_cut_left(ui_top_rectp(), ui_max), {.draw_rect = true});
slider_box->background_color = ui_color_table[ui_color_scroller];
slider_box->bg_hot_color = ui_color_table[ui_color_scroller_hot];
slider_box->bg_active_color = ui_color_table[ui_color_scroller_active];
ui_signal_t left_box_sig = ui_signal_from_box(left_box);
ui_signal_t signal = ui_signal_from_box(slider_box);
ui_signal_t right_box_sig = ui_signal_from_box(down_box);
f32 coef = f32_safe_ratio0(max_size / scroller_rect_pixels, scrollable_space);
if (signal.dragging) {
bottom_scroller_value += ev->mouse_delta.x * coef;
}
if (left_box_sig.dragging || right_box_sig.dragging) {
bottom_scroller_value = (ev->mouse_pos.x - left_box->rect.min.x) * coef;
bottom_scroller_value -= (r2f32_get_size(slider_box->rect).x / 2) * coef;
}
if (ev->kind == app_event_kind_mouse_wheel) {
bottom_scroller_value -= ev->mouse_wheel_delta.x;
}
bottom_scroller_value = CLAMP(bottom_scroller_value, 0, max_size);
}
ui_offset_children(item_box, v2f32(bottom_scroller_value, scroller_value));
ui_offset_children(item_box, v2f32(0, scroller_value));
}
///////////////////////////////
@@ -1424,103 +1452,31 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
}
}
ui_box_t *right_scroller = ui_box(.rect = r2f32_cut_right(ui_top_rectp(), 10 * frame->dpr), .flags = {.draw_rect = true});
ui_box_t *bottom_scroller = ui_box(.rect = r2f32_cut_bottom(ui_top_rectp(), 10 * frame->dpr), .flags = {.draw_rect = true});
ui_box_t *item_box = ui_box(.rect = r2f32_cut_left(ui_top_rectp(), ui_max), .flags = {.draw_rect = true, .clip_rect = true});
locl f32 right_scroller_value;
locl f32 bottom_scroller_value;
ui_scroller_t scroller = ui_begin_scroller((ui_scroller_params_t){
.parent = item_box,
.verti = {
.enabled = true,
.value = &right_scroller_value,
.item_pixels = ui_em(1),
.item_count = (i32)item_count
},
.hori = { .enabled = true, .value = &bottom_scroller_value, .max_size = 2000 },
});
f32 one_item_y_size = ui_em(1);
f32 all_items_size = item_count * one_item_y_size;
f32 item_box_pixels = r2f32_get_size(item_box->rect).y;
f32 visible_item_count = f32_ceil(item_box_pixels / one_item_y_size);
f32 render_start_count = f32_floor(right_scroller_value / one_item_y_size);
i32 istart = (i32)render_start_count;
i32 iend = (i32)render_start_count + (i32)visible_item_count;
istart = CLAMP(istart, 0, (i32)item_count);
iend = CLAMP(iend, 0, (i32)item_count);
ui_set_top(item_box) {
r2f32_cut_top_no_squash(ui_top_rectp(), render_start_count * one_item_y_size);
for (i32 i = istart; i <iend ; i += 1) {
ui_cut_top_scroller_offset(scroller);
for (i32 i = scroller.verti.istart; i < scroller.verti.iend; i += 1) {
char *it = log_lines[i % lengthof(log_lines)];
ui_label("%s##log_line%d", it, i);
}
}
ui_set_top(right_scroller) {
f32 scroller_rect_pixels = r2f32_get_size(right_scroller->rect).y;
f32 scroller_size = f32_clamp01(item_box_pixels / (all_items_size + frame->window_size.y));
f32 scrollable_space = (1 - scroller_size);
f32 scroller_value_norm = right_scroller_value / (all_items_size);
f32 scroller_value_n = scroller_value_norm * scrollable_space;
ui_box_t *upper_box = ui_box(r2f32_cut_top(ui_top_rectp(), scroller_value_n * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *slider_box = ui_box(r2f32_cut_top(ui_top_rectp(), scroller_size * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *down_box = ui_box(r2f32_cut_top(ui_top_rectp(), ui_max), {.draw_rect = true});
slider_box->background_color = ui_color_table[ui_color_scroller];
slider_box->bg_hot_color = ui_color_table[ui_color_scroller_hot];
slider_box->bg_active_color = ui_color_table[ui_color_scroller_active];
ui_signal_t signal = ui_signal_from_box(slider_box);
ui_signal_t upper_box_signal = ui_signal_from_box(upper_box);
ui_signal_t down_box_signal = ui_signal_from_box(down_box);
f32 drag = ev->mouse_delta.y;
f32 coef = f32_safe_ratio0((all_items_size / item_box_pixels), scrollable_space);
if (signal.dragging) {
right_scroller_value += drag * coef;
}
if (upper_box_signal.dragging || down_box_signal.dragging) {
right_scroller_value = (ev->mouse_pos.y - upper_box->rect.min.y) * coef;
right_scroller_value -= (r2f32_get_size(slider_box->rect).y / 2) * coef;
}
if (ev->kind == app_event_kind_mouse_wheel) {
right_scroller_value -= ev->mouse_wheel_delta.y;
}
right_scroller_value = CLAMP(right_scroller_value, 0, all_items_size);
}
locl f32 bottom_scroller_value;
ui_set_top(bottom_scroller) {
f32 max_size = 0;
for (ui_box_t *it = item_box->first; it; it = it->next) {
max_size = MAX(max_size, it->string_size.x);
}
f32 scroller_rect_pixels = r2f32_get_size(bottom_scroller->rect).x;
f32 scroller_button_size_norm = f32_clamp01(scroller_rect_pixels / max_size);
f32 scrollable_space = (1.f - scroller_button_size_norm);
f32 scroller_value_norm = bottom_scroller_value / max_size;
f32 scroller_value_n = scroller_value_norm * scrollable_space;
ui_box_t *left_box = ui_box(r2f32_cut_left(ui_top_rectp(), scroller_value_n * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *slider_box = ui_box(r2f32_cut_left(ui_top_rectp(), scroller_button_size_norm * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *down_box = ui_box(r2f32_cut_left(ui_top_rectp(), ui_max), {.draw_rect = true});
slider_box->background_color = ui_color_table[ui_color_scroller];
slider_box->bg_hot_color = ui_color_table[ui_color_scroller_hot];
slider_box->bg_active_color = ui_color_table[ui_color_scroller_active];
ui_signal_t left_box_sig = ui_signal_from_box(left_box);
ui_signal_t signal = ui_signal_from_box(slider_box);
ui_signal_t right_box_sig = ui_signal_from_box(down_box);
f32 coef = f32_safe_ratio0((max_size / scroller_rect_pixels), scrollable_space);
if (signal.dragging) {
bottom_scroller_value += ev->mouse_delta.x * coef;
}
if (left_box_sig.dragging || right_box_sig.dragging) {
bottom_scroller_value = (ev->mouse_pos.x - left_box->rect.min.x) * coef;
bottom_scroller_value -= (r2f32_get_size(slider_box->rect).x / 2) * coef;
}
if (ev->kind == app_event_kind_mouse_wheel) {
bottom_scroller_value -= ev->mouse_wheel_delta.x;
}
bottom_scroller_value = CLAMP(bottom_scroller_value, 0, max_size);
}
ui_offset_children(item_box, v2f32(bottom_scroller_value, right_scroller_value));
ui_end_scroller(scroller);
}
///////////////////////////////
@@ -1580,13 +1536,58 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
if (lister_open) lister_just_opened = true;
}
s8_t cmds[] = {
s8_lit("show data tab"),
s8_lit("show log tab"),
s8_lit("show menus tab"),
s8_lit("x"),
s8_lit("x1"),
s8_lit("x2"),
s8_lit("x3"),
s8_lit("x4"),
s8_lit("x5"),
s8_lit("x6"),
s8_lit("x7"),
s8_lit("x8"),
s8_lit("x9"),
s8_lit("x0"),
s8_lit("x22"),
s8_lit("x33"),
s8_lit("x44"),
s8_lit("x55"),
s8_lit("x66"),
s8_lit("x77"),
s8_lit("x88"),
s8_lit("x99"),
s8_lit("x123"),
s8_lit("x12"),
s8_lit("x32"),
s8_lit("x42"),
s8_lit("x52"),
s8_lit("x64"),
s8_lit("x75"),
};
if (lister_open) {
v2f32_t max_size = v2f32_sub(frame->window_size, v2f32(ui_em(2), ui_em(2)));
v2f32_t _lister_size = v2f32(ui_em(50), ui_em(40));
v2f32_t _lister_size = v2f32(ui_dm(50), ui_em(25));
v2f32_t lister_size = v2f32_clamp(_lister_size, v2f32_null, max_size);
v2f32_t pos = v2f32_divs(v2f32_sub(frame->window_size, lister_size), 2.0);
pos.y *= 0.05f;
r2f32_t rect = r2f32_min_dim(pos, lister_size);
ui_box_t *lister = ui_box(.id = lister_id, .rect = rect, .flags = {.draw_rect = true, .draw_border = true, .clip_rect = true});
locl f32 verti_scroller_value;
ui_scroller_t scroller = ui_begin_scroller((ui_scroller_params_t){
.parent = lister,
.verti = {
.enabled = true,
.value = &verti_scroller_value,
.item_pixels = ui_em(1),
.item_count = (i32)lengthof(cmds),
},
});
ui_set_top(lister)
ui_set_lop(ui_lop_cut_top) {
locl char buff[128];
@@ -1595,24 +1596,27 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
text_input.str = buff;
text_input.cap = lengthof(buff);
}
ui_signal_t ti_sig = ui_text_input(&text_input);
ui->focus = ti_sig.box->id;
s8_t cmds[] = {
s8_lit("show data tab"),
s8_lit("show log tab"),
s8_lit("show menus tab"),
};
ui_signal_t ti_sig = ui_text_input(&text_input, true);
ma_temp_t scratch = ma_begin_scratch();
s8_t needle = s8(text_input.str, text_input.len);
fuzzy_pair_t *pairs = fuzzy_rate_array(scratch.arena, needle, cmds, lengthof(cmds));
ui_set_string_pos_offset(ui_dm(1))
for (i32 i = 0; i < lengthof(cmds); i += 1) {
ui_button(cmds[pairs[i].index].str);
b32 set_focus = lister_just_opened || ti_sig.text_changed;
ui_set_string_pos_offset(ui_dm(1)) {
ui_cut_top_scroller_offset(scroller);
for (i32 i = scroller.verti.istart; i < scroller.verti.iend; i += 1) {
ui_signal_t sig = ui_button(cmds[pairs[i].index].str);
if (set_focus) {
ui->focus = sig.box->id;
set_focus = false;
}
}
}
if (ti_sig.text_commit) {
fuzzy_pair_t *pair = &pairs[0];
ui_g_panel = (i32)pair->index + 1;
@@ -1622,6 +1626,9 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
ma_end_scratch(scratch);
}
ui_end_scroller(scroller);
}
ui_end_build();

View File

@@ -36,12 +36,12 @@ fn void ui_init_colors(void) {
ui_color_table[ui_color_rect] = v4f32_hsla_to_rgba((v4f32_t){0.0f, 0.2f, 0.95f, 1.0f});
ui_color_table[ui_color_rect_hot] = v4f32_hsla_to_rgba((v4f32_t){0.0f, 0.5f, 0.95f, 1.0f});
ui_color_table[ui_color_rect_active] = v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.5f, 0.95f, 1.0f});
ui_color_table[ui_color_rect_turned_on] = v4f32_hsla_to_rgba((v4f32_t){0.4f, 0.5f, 0.95f, 1.0f});
ui_color_table[ui_color_rect_turned_on] = v4f32_hsla_to_rgba((v4f32_t){0.55f, 0.5f, 0.95f, 1.0f});
ui_color_table[ui_color_border] = v4f32_hsla_to_rgba((v4f32_t){0.0f, 0.2f, 0.70f, 1.0f});
ui_color_table[ui_color_text] = v4f32_hsla_to_rgba((v4f32_t){0.0f, 0.2f, 0.70f, 1.0f});
ui_color_table[ui_color_text_hot] = v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.4f, 0.70f, 1.0f});
ui_color_table[ui_color_text_active] = v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.5f, 0.70f, 1.0f});
ui_color_table[ui_color_focused_rect] = (v4f32_t){1,1,1,1};
ui_color_table[ui_color_focused_rect] = v4f32_hsla_to_rgba((v4f32_t){0.4f, 0.5f, 0.95f, 1.0f});
ui_color_table[ui_color_scroller] = ui_color_table[ui_color_text];
ui_color_table[ui_color_scroller_hot] = v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.2f, 0.7f, 1.0f});
ui_color_table[ui_color_scroller_active] = v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.2f, 0.5f, 1.0f});
@@ -78,10 +78,6 @@ fn void ui_push_rect(r2f32_t v) { ui_r2f32_node_t *n = ma_push_type(tcx->temp, u
fn void ui_pop_rect(void) { SLLS_POP(ui->rect_stack); }
fn r2f32_t ui_top_rect(void) { return ui->rect_stack->value; }
#define ui_set_rect(x) defer_block(ui_push_rect(x), ui_pop_rect())
fn void ui_push_flags(ui_box_flags_t v) { ui_box_flags_node_t *n = ma_push_type(tcx->temp, ui_box_flags_node_t); n->value = v; SLLS_PUSH(ui->flags_stack, n); }
fn void ui_pop_flags(void) { SLLS_POP(ui->flags_stack); }
fn ui_box_flags_t ui_top_flags(void) { return ui->flags_stack->value; }
#define ui_set_flags(x) defer_block(ui_push_flags(x), ui_pop_flags())
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); }
fn v4f32_t ui_top_background_color(void) { return ui->background_color_stack->value; }
@@ -120,7 +116,6 @@ assert(ui->required_size_stack == NULL);
assert(ui->padding_stack == NULL);
assert(ui->string_pos_offset_stack == NULL);
assert(ui->rect_stack == NULL);
assert(ui->flags_stack == NULL);
assert(ui->background_color_stack == NULL);
assert(ui->bg_hot_color_stack == NULL);
assert(ui->bg_active_color_stack == NULL);
@@ -136,7 +131,6 @@ ui_push_border_thickness(1.0f);
ui_push_text_align(ui_text_align_left);
ui_push_string_pos_offset(0);
ui_push_rect(window_rect_from_frame(ui->frame));
ui_push_flags((ui_box_flags_t){0});
ui_push_background_color(ui_color_table[ui_color_rect]);
ui_push_bg_hot_color(ui_color_table[ui_color_rect_hot]);
ui_push_bg_active_color(ui_color_table[ui_color_rect_active]);
@@ -152,7 +146,6 @@ ui_pop_border_thickness();
ui_pop_text_align();
ui_pop_string_pos_offset();
ui_pop_rect();
ui_pop_flags();
ui_pop_background_color();
ui_pop_bg_hot_color();
ui_pop_bg_active_color();

View File

@@ -20,7 +20,6 @@ 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_r2f32_node_t ui_r2f32_node_t; struct ui_r2f32_node_t { r2f32_t value; ui_r2f32_node_t *next; };
typedef struct ui_box_flags_node_t ui_box_flags_node_t; struct ui_box_flags_node_t { ui_box_flags_t value; ui_box_flags_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;\
@@ -29,7 +28,6 @@ f32 required_size;\
f32 padding;\
f32 string_pos_offset;\
r2f32_t rect;\
ui_box_flags_t flags;\
v4f32_t background_color;\
v4f32_t bg_hot_color;\
v4f32_t bg_active_color;\
@@ -47,7 +45,6 @@ ui_f32_node_t *required_size_stack;\
ui_f32_node_t *padding_stack;\
ui_f32_node_t *string_pos_offset_stack;\
ui_r2f32_node_t *rect_stack;\
ui_box_flags_node_t *flags_stack;\
ui_v4f32_node_t *background_color_stack;\
ui_v4f32_node_t *bg_hot_color_stack;\
ui_v4f32_node_t *bg_active_color_stack;\

View File

@@ -12,7 +12,6 @@ struct ui_id_t {
typedef struct ui_box_flags_t ui_box_flags_t;
struct ui_box_flags_t {
// :ui_box_flags_t - change those places when modifying this
b8 draw_rect: 1;
b8 draw_border: 1;
b8 draw_text: 1;
@@ -80,6 +79,7 @@ struct ui_box_t {
s8_t string;
v2f32_t string_size;
ui_box_flags_t flags;
b8 created_new;
ui_custom_draw_t *custom_draw;
ui_lop_t lop;
@@ -107,7 +107,6 @@ struct ui_signal_t {
v2f32_t drag;
struct {
b8 clicked: 1;
b8 press: 1;
b8 dragging: 1;
b8 text_changed: 1;

View File

@@ -4,12 +4,12 @@ fn void mt_ui_colors(ma_arena_t *arena, sb8_t *c, sb8_t *h) {
{ rect `v4f32_hsla_to_rgba((v4f32_t){0.0f, 0.2f, 0.95f, 1.0f})` }
{ rect_hot `v4f32_hsla_to_rgba((v4f32_t){0.0f, 0.5f, 0.95f, 1.0f})` }
{ rect_active `v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.5f, 0.95f, 1.0f})` }
{ rect_turned_on `v4f32_hsla_to_rgba((v4f32_t){0.4f, 0.5f, 0.95f, 1.0f})` }
{ rect_turned_on `v4f32_hsla_to_rgba((v4f32_t){0.55f, 0.5f, 0.95f, 1.0f})` }
{ border `v4f32_hsla_to_rgba((v4f32_t){0.0f, 0.2f, 0.70f, 1.0f})` }
{ text `v4f32_hsla_to_rgba((v4f32_t){0.0f, 0.2f, 0.70f, 1.0f})` }
{ text_hot `v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.4f, 0.70f, 1.0f})` }
{ text_active `v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.5f, 0.70f, 1.0f})` }
{ focused_rect `(v4f32_t){1,1,1,1}` }
{ focused_rect `v4f32_hsla_to_rgba((v4f32_t){0.4f, 0.5f, 0.95f, 1.0f})` }
{ scroller `ui_color_table[ui_color_text]` }
{ scroller_hot `v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.2f, 0.7f, 1.0f})` }
{ scroller_active `v4f32_hsla_to_rgba((v4f32_t){0.1f, 0.2f, 0.5f, 1.0f})` }
@@ -42,7 +42,6 @@ fn void mt_ui_stacks(ma_arena_t *arena, sb8_t *c, sb8_t *h) {
{ f32 padding 0 x }
{ f32 string_pos_offset 0 0 }
{ r2f32_t rect 0 `window_rect_from_frame(ui->frame)` }
{ ui_box_flags_t flags 0 `(ui_box_flags_t){0}` }
{ v4f32_t background_color 0 `ui_color_table[ui_color_rect]` }
{ v4f32_t bg_hot_color 0 `ui_color_table[ui_color_rect_hot]` }
{ v4f32_t bg_active_color 0 `ui_color_table[ui_color_rect_active]` }