diff --git a/build_file.c b/build_file.c index 2bceba9..27310c1 100644 --- a/build_file.c +++ b/build_file.c @@ -27,9 +27,9 @@ int main(int argc, char **argv) { bool execute_python_snippets = true; // make sure to not abuse just for quick maths bool run_server = false; - bool core_test_target = true; + bool core_test_target = false; bool win32_target = false; - bool wasm_target = false; + bool wasm_target = true; if (execute_python_snippets) { sb8_t *sb = sb8_serial_begin(arena); diff --git a/src/gfx2d/gfx2d.c b/src/gfx2d/gfx2d.c index 9b7c3c4..263c7a4 100644 --- a/src/gfx2d/gfx2d.c +++ b/src/gfx2d/gfx2d.c @@ -5,7 +5,9 @@ fn_wasm_import f64 wasm_measure_text(isize str, i32 len, isize font_str, i32 fo fn_wasm_import f64 wasm_get_font_height(isize font_str, i32 font_len, i32 font_size); fn_wasm_import void wasm_set_clip(f64 x, f64 y, f64 w, f64 h); -gb_read_only s8_t font_face = s8_const_lit("open_sans_regular"); + +// gb_read_only s8_t font_face = s8_const_lit("open_sans_regular"); +gb_read_only s8_t font_face = s8_const_lit("consolas"); fn void set_clip(r2f64_t rect) { wasm_set_clip(wasm_dpr * rect.min.x, wasm_dpr * rect.min.y, wasm_dpr * (rect.max.x - rect.min.x), wasm_dpr * (rect.max.y - rect.min.y)); @@ -15,12 +17,12 @@ fn f64 get_font_height(void) { return wasm_get_font_height((isize) font_face.str, font_face.len, 20*wasm_dpr) / wasm_dpr; } -fn f64 measure_text_ex(char *str, i32 len) { - return wasm_measure_text((isize)str, len, (isize) font_face.str, font_face.len, 20*wasm_dpr) / wasm_dpr; +fn f64 measure_text_ex(s8_t string) { + return wasm_measure_text((isize)string.str, string.len, (isize) font_face.str, font_face.len, 20*wasm_dpr) / wasm_dpr; } fn f64 measure_text(char *str) { - return measure_text_ex(str, str_len(str)); + return measure_text_ex(s8_from_char(str)); } fn void draw_text(v2f64_t pos, v4f32_t color, s8_t string) { @@ -65,6 +67,13 @@ struct gfx_t { app_event_t *ev; }; +// @todo: +typedef struct gfx_group_t gfx_group_t; +struct gfx_group_t { + gfx_cmd_t *first; + gfx_cmd_t *last; +}; + void gfx_begin(gfx_t *gfx, app_event_t *ev) { gfx->ev = ev; } diff --git a/src/meta/build_tool.c b/src/meta/build_tool.c index 1b42795..b5c91a6 100644 --- a/src/meta/build_tool.c +++ b/src/meta/build_tool.c @@ -5174,7 +5174,7 @@ int main(int argument_count, char **arguments) { exe_name = OS_GetAbsolutePath(&Perm, exe_name); int result = os_systemf("%.*s %.*s", S8_Expand(exe_name), S8_Expand(cmd_args_merged)); if (result != 0) { - IO_Printf("ERROR: failed to run build_file: %.*s, exitcode(%d), %f, deleting cache\n", S8_Expand(build_file), result, OS_GetTime() - time); + IO_Printf("ERROR: error during build_file execution: %.*s, exitcode(%d), %f, deleting cache\n", S8_Expand(build_file), result, OS_GetTime() - time); os_delete_file(S8_Lit("build_tool.cache")); return 1; } diff --git a/src/wasm_app/main.c b/src/wasm_app/main.c index 7f246db..6f53595 100644 --- a/src/wasm_app/main.c +++ b/src/wasm_app/main.c @@ -5,61 +5,58 @@ #include "app/app.c" #include "gfx2d/gfx2d.c" -// #include "ui.c" +#include "ui.c" -typedef struct ui_widget_t ui_widget_t; -struct ui_widget_t { +/* +** UI Design: +** - keyboard friendly (not in the windows sense, more console sense) +** +** +** [ ] +** +** +*/ + +typedef struct globals_t globals_t; +struct globals_t { + gfx_t *gfx; + app_event_t event; }; +gb globals_t *globals; -typedef struct ui_t ui_t; -struct ui_t { - // update cycle data - b8 left_press; - b8 left_unpress; - b8 left_down; - v2f64_t mouse_pos; - v2f64_t window_size; +fn void app_init(void) { + ui_test_iterators(); - // - -}; - -gb ui_t gb_ui = {0}; -gb gfx_t *gfx = NULL; - -gb i32 config_indent = 4; - -void ui_begin_interaction(ui_t *ui, app_event_t *ev) { - ui->mouse_pos = ev->mouse_pos; - ui->window_size = ev->window_size; - ui->left_press = false; - ui->left_unpress = false; - if (ev->kind == app_event_kind_mouse_down && ev->mouse_button == app_mouse_button_left) { - ui->left_press = true; - ui->left_down = true; - } - if (ev->kind == app_event_kind_mouse_up && ev->mouse_button == app_mouse_button_left) { - ui->left_unpress = true; - ui->left_down = false; - } -} - -void app_handle_event(app_event_t *ev) { - ui_t *ui = &gb_ui; - ui_begin_interaction(ui, ev); -} - -void app_init(void) { ma_arena_t *perm = &tcx._perm; - gfx = ma_push_type(perm, gfx_t); - - + globals = ma_push_type(perm, globals_t); + globals->gfx = ma_push_type(perm, gfx_t); + ui_init(perm); } -b32 app_update(app_event_list_t events) { + +fn b32 app_update(app_event_list_t events) { for (app_event_t *ev = events.first; ev; ev = ev->next) { - app_handle_event(ev); + if (globals->event.kind == app_event_kind_null) { + globals->event = *ev; + } + + #if 0 + // ui_struct() + type_t *ti = type(app_event_t); + + ui_push_list("▼ %S: struct", ti->name); + for (type_member_t *tm = ti->members; tm < ti->members + ti->count; tm += 1) { + if (tm->kind == type_kind_struct) { + ui_list_struct(tm->type, ti_get_member_offset(tm, p) + } else { + ui_list_item("%-20S: %S = %S", tm->name, ti_serial_type(tcx.temp, tm->type), ti_serial_data(p, type)); + } + } + ui_pop_list(); + + #endif + } // These steps should be totally optional!! @@ -67,13 +64,31 @@ b32 app_update(app_event_list_t events) { app_event_t *ev = events.last; f64 delta = app_get_anim_delta_time(); f64 time = app_get_anim_time(); + f64 font_height = get_font_height(); // animate // render - gfx_begin(gfx, ev); - gfx_clear(gfx, white_color_global); - gfx_textf(gfx, (v2f64_t){0,0}, black_color_global, "delta: %f, time: %f", delta, time); - gfx_end(gfx); + gfx_begin(globals->gfx, ev); + gfx_clear(globals->gfx, white_color_global); + gfx_textf(globals->gfx, (v2f64_t){0,ev->window_size.y - font_height}, black_color_global, "delta: %f, time: %f", delta, time); + + + // ► + type_t *ti = type(app_event_t); + f64 xoffset = measure_text("--"); + + + v2f64_t p = {0, 0}; + gfx_textf(globals->gfx, p, black_color_global, "▼ %S: struct", ti->name); + p.x += xoffset; p.y += font_height + 5; + + for (type_member_t *tm = ti->members; tm < ti->members + ti->count; tm += 1) { + s8_t value = ti__serial_data(tcx.temp, ti_extract_member(&globals->event, tm), tm->type); + gfx_textf(globals->gfx, p, black_color_global, "%-20S: %-20S = %S", tm->name, ti_serial_type(tcx.temp, tm->type), value); + p.y += font_height + 5; + } + + gfx_end(globals->gfx); } return false; diff --git a/src/wasm_app/ui.c b/src/wasm_app/ui.c index 6a0cc71..2a8af22 100644 --- a/src/wasm_app/ui.c +++ b/src/wasm_app/ui.c @@ -1,195 +1,250 @@ -v2f64_t ui_calc_text_pos(r2f64_t rect, char *title) { - f64 font_height = get_font_height(); - f64 text_width = measure_text(title); - - v2f64_t text_pos = rect.min; - { - v2f64_t rect_size = r2f64_get_size(rect); - v2f64_t offset_to_center = {(rect_size.x - text_width) / 2, (rect_size.y - font_height) / 2}; - text_pos = v2f64_add(text_pos, offset_to_center); - } - - return text_pos; -} - -typedef struct ui_signal_t ui_signal_t; -struct ui_signal_t { - b8 pressed; - b8 overlapping; +typedef struct ui_id_t ui_id_t; +struct ui_id_t { + u64 value; }; -ui_signal_t ui_interact(app_event_t *ev, r2f64_t rect) { - ui_signal_t sig = {0}; - if (r2f64_contains(rect, ev->mouse_pos)) { - sig.overlapping = true; - if (ev->kind == app_event_kind_mouse_down && ev->mouse_button == app_mouse_button_left) { - sig.pressed = true; - } - } - return sig; -} +typedef struct ui_box_t ui_box_t; +struct ui_box_t { + ui_id_t id; -b32 ui_button(gfx_t *gfx, app_event_t *ev, r2f64_t rect, char *title) { - v2f64_t text_pos = ui_calc_text_pos(rect, title); - ui_signal_t sig = ui_interact(ev, rect); + ui_box_t *next; + ui_box_t *prev; + ui_box_t *parent; + ui_box_t *first; + ui_box_t *last; - v4f32_t rect_color = secondary_color_global; - v4f32_t text_color = black_color_global; - if (sig.overlapping) { - rect_color = primary_color_global; - } + ui_box_t *iter_next; // for iterator - gfx_set_clip(gfx, rect); - gfx_rect(gfx, rect, rect_color); - gfx_text(gfx, text_pos, text_color, s8_from_char(title)); - gfx_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000)); + s8_t string; + b32 expanded; +}; - return sig.pressed; -} +typedef struct ui_t ui_t; +struct ui_t { + ma_arena_t *arena; -b32 ui_checkbox(gfx_t *gfx, app_event_t *ev, r2f64_t rect, b32 *value, char *title) { - v2f64_t text_pos = ui_calc_text_pos(rect, title); - ui_signal_t sig = ui_interact(ev, rect); - if (sig.pressed) *value = !*value; + i32 active_box_count; + ui_box_t *root; + ui_box_t *top; - v4f32_t rect_color = secondary_color_global; - v4f32_t text_color = black_color_global; - if (sig.overlapping) { - rect_color = primary_color_global; - } - if (*value) { - rect_color = v4f32_lerp(rect_color, accent2_color_global, 0.5); - } + ui_box_t *first_free; +}; - gfx_set_clip(gfx, rect); - gfx_rect(gfx, rect, rect_color); - gfx_text(gfx, text_pos, text_color, s8_from_char(title)); - gfx_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000)); +ui_t *ui = NULL; +ui_id_t ui_null_id; - return *value; -} +#if 0 +ui_begin_expander("app_event_t"); +{ + ui_edit_enum("kind: app_event_kind_t = %S"); -typedef struct ui_id_t ui_id_t; -struct ui_id_t { u64 value; }; - -ui_id_t ui_string_to_id(const char *string, i32 len) { // FNV HASH (1a?) - u8 *data8 = (u8 *)string; - u64 hash = (u64)14695981039346656037ULL; - for (u64 i = 0; i < len; i++) { - hash = hash ^ (u64)(data8[i]); - hash = hash * (u64)1099511628211ULL; - } - return (ui_id_t){ .value = hash }; -} -#define ui_location_id() ui_string_to_id(FILE_AND_LINE, sizeof(FILE_AND_LINE) - 1) -ui_id_t ui_active_element = {0}; - -void ui_slider(gfx_t *gfx, app_event_t *ev, r2f64_t rect, ui_id_t id, f64 *value, char *title) { - v2f64_t text_pos = ui_calc_text_pos(rect, title); - ui_signal_t sig = ui_interact(ev, rect); - b32 interacting = false; + ui_begin_expander("mouse_wheel_delta: v3f64_t"); { - if (sig.pressed) { - ui_active_element = id; - } - if (id.value == ui_active_element.value) { - interacting = true; - } + ui_edit_f64(&x, "x: %f", x); + ui_edit_f64(&y, "y: %f", y); + ui_edit_f64(&z, "z: %f", z); } + ui_end_expander(); +} +ui_end_expander(); +#endif - if (interacting) { - f64 mouse_pos = ev->mouse_pos.x; - v2f64_t rect_size = r2f64_get_size(rect); - *value = (mouse_pos - rect.min.x) / rect_size.x; - *value = CLAMP(*value, 0, 1.0); - } - - v2f64_t rect_size = r2f64_get_size(rect); - r2f64_t slider_rect = r2f64_get_left(&rect, rect_size.x * value[0]); - - v4f32_t rect_color = secondary_color_global; - if (sig.overlapping) rect_color = v4f32_lerp(rect_color, accent2_color_global, 0.2); - v4f32_t slider_color = accent2_color_global; - if (sig.overlapping) slider_color = v4f32_lerp(slider_color, accent2_color_global, 0.2); - v4f32_t text_color = black_color_global; - - gfx_set_clip(gfx, rect); - gfx_rect(gfx, rect, rect_color); - gfx_rect(gfx, slider_rect, slider_color); - gfx_text(gfx, text_pos, text_color, s8_from_char(title)); - gfx_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000)); +void ui_init(ma_arena_t *arena) { + ui = ma_push_type(arena, ui_t); + ui->arena = arena; } -void ui_demo(gfx_t *gfx, app_event_t *ev) { - if (ev->kind == app_event_kind_mouse_up) { - ui_active_element = (ui_id_t){0}; +ui_box_t *ui_alloc_box(ui_id_t id) { + ui_box_t *result = ui->first_free; + if (!result) result = ma_push_type(ui->arena, ui_box_t); + result->id = id; + ui->active_box_count += 1; + return result; +} + +void ui_begin_build(void) { + ui->root = ui_alloc_box(ui_null_id); + ui->top = ui->root; +} + +void ui_end_build(void) { + +} + +ui_id_t ui_id_from_string(s8_t string) { + u64 value = ht_hash_data(string); + ui_id_t id = {value}; + return id; +} + +void ui_push_box(ui_box_t *box) { + box->parent = ui->top; + DLLQ_APPEND(ui->top->first, ui->top->last, box); +} + +void ui_push_parent(ui_box_t *box) { + ui_push_box(box); + ui->top = box; +} + +ui_box_t *ui_pop_parent(void) { + ui_box_t *top = ui->top; + ui->top = ui->top->parent; + return top; +} + +ui_box_t *ui_push_expander(char *cstring) { + s8_t string = s8_from_char(cstring); + ui_id_t id = ui_id_from_string(string); + ui_box_t *box = ui_alloc_box(id); + ui_push_parent(box); + box->string = string; + box->expanded = true; + return box; +} + +ui_box_t *ui_label(char *cstring) { + s8_t string = s8_from_char(cstring); + ui_id_t id = ui_id_from_string(string); + ui_box_t *box = ui_alloc_box(id); + box->string = string; + ui_push_box(box); + return box; +} + +typedef struct ui_preorder_iter_t ui_preorder_iter_t; +struct ui_preorder_iter_t { ui_box_t *box; }; + +ui_preorder_iter_t ui_iterate_preorder(ui_box_t *box) { + ui_preorder_iter_t iter = {box}; + return iter; +} + +b32 ui_preorder_iter_is_valid(ui_preorder_iter_t iter) { + b32 result = iter.box != NULL; + return result; +} + +void ui_iter_advance_preorder(ui_preorder_iter_t *iter) { + if (iter->box->first) { + iter->box = iter->box->first; + return; } - - r2f64_t window_rect = (r2f64_t){(v2f64_t){0}, ev->window_size}; - r2f64_t top_bar_rect = r2f64_cut_top(&window_rect, get_font_height() + 20); - gfx_rect(gfx, window_rect, primary_color_global); - - f64 padding = 50; - gfx_rect(gfx, top_bar_rect, secondary_color_global); - - static b32 open_file_panel; - f64 open_file_panel_xsize = 0; - { - // ▼▲▶◀ - char *title = "▶ file"; - if (open_file_panel) title = "▼ file"; - open_file_panel_xsize = measure_text(title) + padding*2; - r2f64_t rect = r2f64_cut_left(&top_bar_rect, open_file_panel_xsize); - if (ui_checkbox(gfx, ev, rect, &open_file_panel, title)) { + while (iter->box) { + if (iter->box->next) { + iter->box = iter->box->next; + break; + } else { + iter->box = iter->box->parent; } - r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1); - gfx_rect(gfx, gap_rect, black_color_global); } +} - if (open_file_panel) { - f64 item_count = 20; - f64 item_size = get_font_height() + 20; - r2f64_t panel_rect = r2f64_get_top(&window_rect, item_count * item_size); - panel_rect = r2f64_get_left(&panel_rect, open_file_panel_xsize); +typedef struct ui_postorder_iter_t ui_postorder_iter_t; +struct ui_postorder_iter_t { ui_box_t *box; }; - { - static f64 slider_value; - char buff[64]; - stbsp_snprintf(buff, sizeof(buff), "%f", slider_value); - r2f64_t rect = r2f64_cut_top(&panel_rect, item_size); - ui_slider(gfx, ev, rect, ui_location_id(), &slider_value, buff); - } - - // { - // static char buff[64]; - // static ui_input_state input; - // if (input.buff == NULL) { - // input.buff = buff; - // input.cap = sizeof(buff); - // } - - // r2f64_t rect = r2f64_cut_top(&panel_rect, item_size); - // ui_input_text(rect, &input); - // } +ui_postorder_iter_t ui_iterate_postorder(ui_box_t *box) { + while (box->first) { + box = box->first; } + ui_postorder_iter_t iter = {box}; + return iter; +} +b32 ui_postorder_iter_is_valid(ui_postorder_iter_t iter) { + b32 result = iter.box != NULL; + return result; +} + +void ui_iter_advance_postorder(ui_postorder_iter_t *iter) { + while (iter->box) { + if (iter->box->next) { + iter->box = iter->box->next; + while (iter->box->first) { + iter->box = iter->box->first; + } + break; + } else { + iter->box = iter->box->parent; + break; + } + } +} + +void ui_test_stringify_preorder(sb8_t *sb, ui_box_t *box) { + sb8_printf(sb, "%S", box->string); + for (ui_box_t *it = box->first; it; it = it->next) { + ui_test_stringify_preorder(sb, it); + } +} + +void ui_test_stringify_postorder(sb8_t *sb, ui_box_t *box) { + for (ui_box_t *it = box->first; it; it = it->next) { + ui_test_stringify_postorder(sb, it); + } + sb8_printf(sb, "%S", box->string); +} + +void ui_test_iterators(void) { + ma_temp_t scratch = ma_begin_scratch(); + ui_init(scratch.arena); + + defer_block(ui_begin_build(), ui_end_build()) { + defer_block(ui_push_expander("app_event_t"), ui_pop_parent()) { + defer_block(ui_push_expander("mouse_wheel_delta: v3f64_t"), ui_pop_parent()) { + ui_label("x: f64 = value"); + ui_label("y: f64 = value"); + ui_label("z: f64 = value"); + } + ui_label("kind: app_event_kind_t = value"); + ui_label("ctrl: b8 = value"); + ui_label("shift: b8 = value"); + defer_block(ui_push_expander("pos: v2f64_t"), ui_pop_parent()) { + ui_label("x: f64 = value"); + ui_label("y: f64 = value"); + defer_block(ui_push_expander("inner_pos: v2f64_t"), ui_pop_parent()) { + ui_label("x: f64 = value"); + ui_label("y: f64 = value"); + } + } + ui_label("alt: b8 = value"); + ui_label("meta: b8 = value"); - { - char *title = "edit"; - r2f64_t rect = r2f64_cut_left(&top_bar_rect, measure_text(title) + padding*2); - if (ui_button(gfx, ev, rect, title)) { } - r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1); - gfx_rect(gfx, gap_rect, black_color_global); } { - char *title = "view"; - r2f64_t rect = r2f64_cut_left(&top_bar_rect, measure_text(title) + padding*2); - if (ui_button(gfx, ev, rect, title)) { + sb8_t *sb = sb8_serial_begin(scratch.arena); + ui_test_stringify_preorder(sb, ui->root); + s8_t recursive_string = sb8_serial_end(scratch.arena, sb); + + sb = sb8_serial_begin(scratch.arena); + for (ui_preorder_iter_t it = ui_iterate_preorder(ui->root); ui_preorder_iter_is_valid(it); ui_iter_advance_preorder(&it)) { + sb8_printf(sb, "%S", it.box->string); } - r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1); - gfx_rect(gfx, gap_rect, black_color_global); + s8_t iter_string = sb8_serial_end(scratch.arena, sb); + assert(s8_equal(iter_string, recursive_string)); } -} \ No newline at end of file + { + sb8_t *sb = sb8_serial_begin(scratch.arena); + ui_test_stringify_postorder(sb, ui->root); + s8_t recursive_string = sb8_serial_end(scratch.arena, sb); + + sb = sb8_serial_begin(scratch.arena); + for (ui_postorder_iter_t it = ui_iterate_postorder(ui->root); ui_postorder_iter_is_valid(it); ui_iter_advance_postorder(&it)) { + sb8_printf(sb, "%S", it.box->string); + } + s8_t iter_string = sb8_serial_end(scratch.arena, sb); + assert(s8_equal(iter_string, recursive_string)); + } + + ui = NULL; + ma_end_scratch(scratch); +} + + +// void ui_end_build(ui_t *ui) { + +// } +