horiscroller

This commit is contained in:
Krzosa Karol
2025-01-28 11:08:19 +01:00
parent f8a04a251d
commit 6f3ffc76ff
3 changed files with 145 additions and 77 deletions

View File

@@ -194,6 +194,7 @@ fn ui_box_t *ui_build_box_from_id(ui_code_loc_t loc, ui_box_flags_t flags, ui_id
fn void ui_box_auto_rect(ui_box_t *box) {
v2f32_t string_size = rn_measure_string(rn->main_font, box->string);
box->string_size = string_size;
ui_axis2_t axis = ui_axis_from_lop(ui_top_lop());
if (ui->required_size_stack && (axis == ui_axis2_x || axis == ui_axis2_y)) {
string_size.e[axis] = ui_top_required_size();
@@ -201,18 +202,8 @@ fn void ui_box_auto_rect(ui_box_t *box) {
if (ui->padding_stack && (axis == ui_axis2_x || axis == ui_axis2_y)) {
string_size.e[axis] += ui_top_padding();
}
if (box->flags.dont_compute_rect == false) {
r2f32_t rect = ui_next_rect(ui_top_lop(), &ui->top->rect, string_size);
ui_set_rect(box, rect);
}
}
fn ui_box_t *ui_build_box_from_string(ui_code_loc_t loc, ui_box_flags_t flags, s8_t string) {
ui_id_t id = ui_id(string);
ui_box_t *box = ui_build_box_from_id(loc, flags, id);
box->string = ui_get_display_string(string);
ui_box_auto_rect(box);
return box;
r2f32_t rect = ui_next_rect(ui_top_lop(), &ui->top->rect, string_size);
ui_set_rect(box, rect);
}
typedef struct ui_box_params_t ui_box_params_t;
@@ -308,8 +299,7 @@ fn void ui_set_to_be_determined(ui_box_t *box, ui_axis2_t axis) {
} else_is_invalid;
}
fn v2f32_t ui_aligned_text_pos(f32 offset, ui_text_align_t text_align, r2f32_t rect, s8_t string) {
v2f32_t string_size = rn_measure_string(rn->main_font, string);
fn v2f32_t ui_aligned_text_pos(f32 offset, ui_text_align_t text_align, r2f32_t rect, s8_t string, v2f32_t string_size) {
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);
@@ -375,7 +365,7 @@ fn void ui_text_input_draw(ui_box_t *box) {
ui_text_input_t *ti = box->text_input;
s8_t string = s8(ti->str, ti->len);
v2f32_t pos = ui_aligned_text_pos(box->string_pos_offset, box->text_align, co.rect, string);
v2f32_t pos = ui_aligned_text_pos(box->string_pos_offset, box->text_align, co.rect, string, rn_measure_string(rn->main_font, string));
rn_draw_string(rn->main_font, pos, co.text_color, string);
ti->caret = ui_caret_clamp(ti->caret, 0, (i32)ti->len);
@@ -406,7 +396,7 @@ fn void ui_default_draw_box(ui_box_t *box) {
rn_draw_rect_border(co.rect, co.border_color, box->border_thickness);
}
if (box->flags.draw_text) {
v2f32_t text_pos = ui_aligned_text_pos(box->string_pos_offset, box->text_align, co.rect, box->string);
v2f32_t text_pos = ui_aligned_text_pos(box->string_pos_offset, box->text_align, co.rect, box->string, box->string_size);
rn_draw_string(rn->main_font, text_pos, co.text_color, box->string);
}
}
@@ -526,7 +516,6 @@ fn ui_signal_t ui__radio_button(ui_code_loc_t loc, i32 *value, i32 value_clicked
ui_box_t *box = ui_box(.loc = loc, .string = string, .flags = { .draw_border = true, .draw_rect = true, .draw_text = true, .keyboard_nav = true });
ui_signal_t signal = ui_signal_from_box(box);
if (signal.clicked) *value = value_clicked;
// @todo?
if (*value == value_clicked) box->background_color = ui_color_table[ui_color_rect_turned_on];
return signal;
}
@@ -569,26 +558,6 @@ fn void ui_end_expander(void) {
ui_pop_id();
}
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->root.full_rect = ui->root.rect = window_rect;
ui->top = &ui->root;
ui->root.loc = loc;
}
fn ui_box_t *ui_get_prev_box(ui_box_t *box, b32 (*match)(ui_box_t *)) {
for (ui_box_t *it = box; it;) {
if (it->last) {
@@ -627,24 +596,30 @@ fn ui_box_t *ui_get_next_box(ui_box_t *box, b32 (*match)(ui_box_t *)) {
return box;
}
fn b32 ui_match_axis(ui_box_t *box, ui_axis2_t axis) {
ui_axis2_t box_axis = ui_axis_from_lop(box->lop);
b32 result = box_axis == axis;
return result;
}
fn b32 ui_match_keynav(ui_box_t *box) {
b32 result = box->flags.keyboard_nav;
return result;
}
fn b32 ui_match_keynav_xaxis(ui_box_t *box) {
b32 result = box->flags.keyboard_nav && ui_match_axis(box, ui_axis2_x);
return result;
}
fn void ui_begin_build(ui_code_loc_t loc, app_event_t *ev, r2f32_t window_rect) {
ui->event = ev;
fn ui_box_t *ui_get_right_box(ui_box_t *box) { return ui_get_next_box(box, ui_match_keynav_xaxis); }
fn ui_box_t *ui_get_left_box(ui_box_t *box) { return ui_get_prev_box(box, ui_match_keynav_xaxis); }
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->root.full_rect = ui->root.rect = window_rect;
ui->top = &ui->root;
ui->root.loc = loc;
}
fn void ui_end_build(void) {
{
@@ -980,7 +955,7 @@ fn void ui_end_reversal(void) {
gb app_event_t ui_test_event;
gb i32 ui_g_panel = 3;
gb i32 ui_g_panel = 2;
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);
@@ -1008,12 +983,14 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
ui->top->rect = r2f32_shrinks(ui->top->rect, ui_em(1));
///////////////////////////////
// First list panel
// Data panel
if (ui_g_panel == 1) {
ui_box_t *scroller_box = ui_box(r2f32_cut_right(&ui->top->rect, 10 * frame->dpr), {.draw_rect = true, .clip_rect = true});
ui_box_t *scroller_box = ui_box(r2f32_cut_right(&ui->top->rect, 10 * frame->dpr), {.draw_rect = true});
ui_box_t *bottom_scroller = ui_box(r2f32_cut_bottom(&ui->top->rect, 10 * frame->dpr), {.draw_rect = true});
ui_box_t *item_box = ui_box(r2f32_cut_left(&ui->top->rect, ui_max), {.draw_rect = true, .clip_rect = true});
item_box->rect = r2f32_shrinks(item_box->rect, ui_em(1));
ui_set_text_align(ui_text_align_left)
ui_set_top(item_box) {
locl char buff[128];
@@ -1040,8 +1017,7 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
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->main_font, signal.box->string);
f32 delta = (signal.drag.x / string_size.x) * size;
f32 delta = (signal.drag.x / signal.box->string_size.x) * size;
*n = CLAMP(*n + delta, tweak->min, tweak->max);
}
} else_is_invalid;
@@ -1054,7 +1030,7 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
}
locl f32 scroller_value;
defer_block(ui_push_top(scroller_box), ui_pop_top()) {
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;
@@ -1088,10 +1064,50 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
scroller_value -= ev->mouse_wheel_delta.y;
}
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) {
ui_offset_box(it, v2f32(0, scroller_value));
max_size = MAX(max_size, it->string_size.x);
}
f32 scroller_rect_pixels = r2f32_get_size(bottom_scroller->full_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->rect, scroller_value_n * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *slider_box = ui_box(r2f32_cut_left(&ui->top->rect, scroller_button_size_norm * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *down_box = ui_box(r2f32_cut_left(&ui->top->rect, 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 = (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->full_rect.min.x) * coef;
bottom_scroller_value -= (r2f32_get_size(slider_box->full_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);
}
for (ui_box_t *it = item_box->first; it; it = it->next) {
ui_offset_box(it, v2f32(bottom_scroller_value, scroller_value));
}
}
@@ -1231,16 +1247,17 @@ 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->rect, 10 * frame->dpr), .flags = {.draw_rect = true, .clip_rect = true});
ui_box_t *right_scroller = ui_box(.rect = r2f32_cut_right(&ui->top->rect, 10 * frame->dpr), .flags = {.draw_rect = true});
ui_box_t *bottom_scroller = ui_box(.rect = r2f32_cut_bottom(&ui->top->rect, 10 * frame->dpr), .flags = {.draw_rect = true});
ui_box_t *item_box = ui_box(.rect = r2f32_cut_left(&ui->top->rect, ui_max), .flags = {.draw_rect = true, .clip_rect = true});
locl f32 scroller_value;
locl f32 right_scroller_value;
f32 one_item_y_size = ui_em(1);
f32 all_items_size = item_count * one_item_y_size;
f32 item_box_size = r2f32_get_size(item_box->full_rect).y;
f32 visible_item_count = f32_ceil(item_box_size / one_item_y_size);
f32 render_start_count = f32_floor(scroller_value / one_item_y_size);
f32 item_box_pixels = r2f32_get_size(item_box->full_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;
@@ -1255,15 +1272,15 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
}
}
defer_block(ui_push_top(right_scroller), ui_pop_top()) {
f32 right_scroller_size = r2f32_get_size(right_scroller->full_rect).y;
f32 scroller_size = CLAMP(item_box_size / (all_items_size + frame->window_size.y), 0, 1.0f);
ui_set_top(right_scroller) {
f32 scroller_rect_pixels = r2f32_get_size(right_scroller->full_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_norm = scroller_value / (all_items_size);
f32 scroller_percent = scroller_norm * scrollable_space;
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->rect, scroller_percent * right_scroller_size), {.draw_rect = true});
ui_box_t *slider_box = ui_box(r2f32_cut_top(&ui->top->rect, scroller_size * right_scroller_size), {.draw_rect = true});
ui_box_t *upper_box = ui_box(r2f32_cut_top(&ui->top->rect, scroller_value_n * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *slider_box = ui_box(r2f32_cut_top(&ui->top->rect, scroller_size * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *down_box = ui_box(r2f32_cut_top(&ui->top->rect, 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];
@@ -1272,25 +1289,67 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
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 = (all_items_size / item_box_size) / scrollable_space;
f32 coef = (all_items_size / item_box_pixels) / scrollable_space;
if (signal.dragging) {
scroller_value += drag * coef;
right_scroller_value += drag * coef;
}
if (upper_box_signal.dragging || down_box_signal.dragging) {
scroller_value = (ev->mouse_pos.y - upper_box->full_rect.min.y) * coef;
scroller_value -= (r2f32_get_size(slider_box->full_rect).y / 2) * coef;
right_scroller_value = (ev->mouse_pos.y - upper_box->full_rect.min.y) * coef;
right_scroller_value -= (r2f32_get_size(slider_box->full_rect).y / 2) * coef;
}
if (ev->kind == app_event_kind_mouse_wheel) {
scroller_value -= ev->mouse_wheel_delta.y;
right_scroller_value -= ev->mouse_wheel_delta.y;
}
scroller_value = CLAMP(scroller_value, 0, all_items_size);
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) {
ui_offset_box(it, v2f32(0, scroller_value));
max_size = MAX(max_size, it->string_size.x);
}
f32 scroller_rect_pixels = r2f32_get_size(bottom_scroller->full_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->rect, scroller_value_n * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *slider_box = ui_box(r2f32_cut_left(&ui->top->rect, scroller_button_size_norm * scroller_rect_pixels), {.draw_rect = true});
ui_box_t *down_box = ui_box(r2f32_cut_left(&ui->top->rect, 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 = (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->full_rect.min.x) * coef;
bottom_scroller_value -= (r2f32_get_size(slider_box->full_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);
}
for (ui_box_t *it = item_box->first; it; it = it->next) {
ui_offset_box(it, v2f32(bottom_scroller_value, right_scroller_value));
}
}
///////////////////////////////
// Menus panel
if (ui_g_panel == 3) {
ui_box_t *item_box = ui_box(.rect = r2f32_cut_left(&ui->top->rect, ui_max), .flags = {.draw_rect = true, .clip_rect = true});
ui_set_top(item_box) {
@@ -1334,6 +1393,8 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co
}
///////////////////////////////
// Everything lister
ui_id_t lister_id = ui_id_from_loc(UILOC);
locl b32 lister_open;
b32 lister_just_opened = false;