diff --git a/src/app/app_wasm.c b/src/app/app_wasm.c index 81df724..caf400b 100644 --- a/src/app/app_wasm.c +++ b/src/app/app_wasm.c @@ -1,16 +1,8 @@ -fn_wasm_import void wasm_clear(void); -fn_wasm_import void wasm_draw_text(isize str, i32 len, f64 x, f64 y, isize font_str, i32 font_len, i32 font_size, f32 r, f32 g, f32 b, f32 a); -fn_wasm_import void wasm_draw_rect(f64 x, f64 y, f64 w, f64 h, f32 r, f32 g, f32 b, f32 a); -fn_wasm_import f64 wasm_measure_text(isize str, i32 len, isize font_str, i32 font_len, i32 font_size); -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); - glb_wasm_export char wasm_temp_buff1[128] = {[127] = 0x13}; glb_wasm_export i32 wasm_temp_buff1_len = 127; glb_wasm_export char wasm_temp_buff2[128] = {[127] = 0x13}; glb_wasm_export i32 wasm_temp_buff2_len = 127; -glb s8_t font_face = s8_const_lit("open_sans_regular"); glb f64 wasm_dpr; glb ma_arena_t *wasm_input_text_arena; glb STACK(app_event_t, 64) wasm_events; @@ -24,40 +16,7 @@ struct wasm_cached_t { } wasm_cached; fn void app_update(app_event_t *events, i32 event_count); - -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)); -} - -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(char *str) { - return measure_text_ex(str, str_len(str)); -} - -fn void draw_text(v2f64_t pos, v4f32_t color, s8_t string) { - wasm_draw_text((isize)string.str, string.len, wasm_dpr * pos.x, wasm_dpr * pos.y, (isize) font_face.str, font_face.len, 20*wasm_dpr, color.r * 255.f, color.g * 255.f, color.b * 255.f, color.a); -} - -fn void draw_textf(v2f64_t pos, char *str, ...) { - char buff[1024]; - va_list args; - va_start(args, str); - i32 len = stbsp_vsnprintf(buff, sizeof(buff), str, args); - va_end(args); - - wasm_draw_text((isize)buff, len, wasm_dpr * pos.x, wasm_dpr * pos.y, (isize) font_face.str, font_face.len, 20*wasm_dpr, 0, 0, 0, 1); -} - -fn void draw_rect(r2f64_t rect, v4f32_t color) { - wasm_draw_rect(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), color.r * 255.f, color.g * 255.f, color.b * 255.f, color.a); -} +fn void app_init(void); fn void wasm_add_event(app_event_t event) { if (wasm_events.len < lengthof(wasm_events.data)) { @@ -206,8 +165,6 @@ fn_wasm_export void wasm_update(f64 time, f64 width, f64 height, f64 dpr) { } wasm_dpr = dpr; - wasm_clear(); - draw_rect(r2f64(0, 0, window_size.x, window_size.y), white_color_global); app_update(wasm_events.data, wasm_events.len); wasm_events.len = 0; @@ -218,4 +175,5 @@ fn_wasm_export void wasm_update(f64 time, f64 width, f64 height, f64 dpr) { fn_wasm_export void wasm_init(void) { core_init(); wasm_input_text_arena = ma_push_arena(&tcx.perm, kib(1)); + app_init(); } \ No newline at end of file diff --git a/src/core/core_ctx.h b/src/core/core_ctx.h index 266562c..9cb523d 100644 --- a/src/core/core_ctx.h +++ b/src/core/core_ctx.h @@ -2,6 +2,7 @@ typedef struct thread_ctx_t thread_ctx_t; struct thread_ctx_t { ma_arena_t scratch[3]; ma_arena_t perm; + ma_arena_t *temp; // application specific arena logger_t log; }; diff --git a/src/gfx2d/gfx2d.c b/src/gfx2d/gfx2d.c new file mode 100644 index 0000000..c390aea --- /dev/null +++ b/src/gfx2d/gfx2d.c @@ -0,0 +1,142 @@ +fn_wasm_import void wasm_clear(void); +fn_wasm_import void wasm_draw_text(isize str, i32 len, f64 x, f64 y, isize font_str, i32 font_len, i32 font_size, f32 r, f32 g, f32 b, f32 a); +fn_wasm_import void wasm_draw_rect(f64 x, f64 y, f64 w, f64 h, f32 r, f32 g, f32 b, f32 a); +fn_wasm_import f64 wasm_measure_text(isize str, i32 len, isize font_str, i32 font_len, i32 font_size); +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); + +glb s8_t font_face = s8_const_lit("open_sans_regular"); + + +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)); +} + +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(char *str) { + return measure_text_ex(str, str_len(str)); +} + +fn void draw_text(v2f64_t pos, v4f32_t color, s8_t string) { + wasm_draw_text((isize)string.str, string.len, wasm_dpr * pos.x, wasm_dpr * pos.y, (isize) font_face.str, font_face.len, 20*wasm_dpr, color.r * 255.f, color.g * 255.f, color.b * 255.f, color.a); +} + +fn void draw_textf(v2f64_t pos, char *str, ...) { + char buff[1024]; + va_list args; + va_start(args, str); + i32 len = stbsp_vsnprintf(buff, sizeof(buff), str, args); + va_end(args); + + wasm_draw_text((isize)buff, len, wasm_dpr * pos.x, wasm_dpr * pos.y, (isize) font_face.str, font_face.len, 20*wasm_dpr, 0, 0, 0, 1); +} + +fn void draw_rect(r2f64_t rect, v4f32_t color) { + wasm_draw_rect(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), color.r * 255.f, color.g * 255.f, color.b * 255.f, color.a); +} + +typedef enum { + gfx2d_kind_null, + gfx2d_kind_clear, + gfx2d_kind_draw_rect, + gfx2d_kind_draw_text, + gfx2d_kind_set_clip, +} gfx2d_kind_t; + +typedef struct gfx2d_cmd_t gfx2d_cmd_t; +struct gfx2d_cmd_t { + gfx2d_kind_t kind; + r2f64_t rect; + v4f32_t color; + s8_t text; +}; + +typedef struct gfx2d_t gfx2d_t; +struct gfx2d_t { + ma_arena_t *ma; + gfx2d_cmd_t *cmds; + i32 cmds_len; + app_event_t *ev; +}; + +void gfx2d_begin(gfx2d_t *gfx, app_event_t *ev) { + gfx->ev = ev; +} + +void gfx2d_end(gfx2d_t *gfx) { + app_event_t *ev = gfx->ev; + r2f64_t window = (r2f64_t){0, 0, ev->window_size.x, ev->window_size.y}; + for (i32 i = 0; i < gfx->cmds_len; i += 1) { + gfx2d_cmd_t *cmd = gfx->cmds + i; + + if (cmd->kind == gfx2d_kind_clear) { + wasm_clear(); + draw_rect(window, cmd->color); + } else if (cmd->kind == gfx2d_kind_draw_rect) { + draw_rect(cmd->rect, cmd->color); + } else if (cmd->kind == gfx2d_kind_draw_text) { + draw_text(cmd->rect.min, cmd->color, cmd->text); + } else if (cmd->kind == gfx2d_kind_set_clip) { + set_clip(cmd->rect); + } else { + invalid_codepath; + } + } + + gfx->cmds_len = 0; + ma_set0(gfx->ma); +} + +void gfx2d_add_cmd(gfx2d_t *gfx, gfx2d_cmd_t cmd) { + gfx2d_cmd_t *c = ma_push_type(gfx->ma, gfx2d_cmd_t); + *c = cmd; + if (gfx->cmds_len == 0) gfx->cmds = c; + gfx->cmds_len += 1; +} + +void gfx2d_clear(gfx2d_t *gfx, v4f32_t color) { + gfx2d_add_cmd(gfx, (gfx2d_cmd_t){ + .kind = gfx2d_kind_clear, + .color = color, + }); +} + +void gfx2d_rect(gfx2d_t *gfx, r2f64_t rect, v4f32_t color) { + gfx2d_add_cmd(gfx, (gfx2d_cmd_t){ + .kind = gfx2d_kind_draw_rect, + .color = color, + .rect = rect, + }); +} + +void gfx2d_set_clip(gfx2d_t *gfx, r2f64_t rect) { + gfx2d_add_cmd(gfx, (gfx2d_cmd_t){ + .kind = gfx2d_kind_set_clip, + .rect = rect, + }); +} + +void gfx2d_text(gfx2d_t *gfx, v2f64_t pos, v4f32_t color, s8_t string) { + gfx2d_add_cmd(gfx, (gfx2d_cmd_t){ + .kind = gfx2d_kind_draw_text, + .text = s8_copy(tcx.temp, string), + .color = color, + .rect.min = pos, + }); +} +void gfx2d_textf(gfx2d_t *gfx, v2f64_t pos, v4f32_t color, char *str, ...) { + S8_FMT(tcx.temp, str, text); + gfx2d_add_cmd(gfx, (gfx2d_cmd_t){ + .kind = gfx2d_kind_draw_text, + .text = text, + .color = color, + .rect.min = pos, + }); +} \ No newline at end of file diff --git a/src/wasm_app/main.c b/src/wasm_app/main.c index 83e12a4..47b71d9 100644 --- a/src/wasm_app/main.c +++ b/src/wasm_app/main.c @@ -2,19 +2,37 @@ #include "core/core_inc.c" #include "app/app.h" #include "app/app.c" -// #include "debug.c" -#include "ui2.c" +#include "gfx2d/gfx2d.c" +#include "ui.c" + +gfx2d_t *gfx2d = NULL; +void app_init(void) { + tcx.temp = ma_push_arena(&tcx.perm, mib(1)); + gfx2d = ma_push_type(&tcx.perm, gfx2d_t); + gfx2d->ma = ma_push_arena(&tcx.perm, mib(2)); +} -f64 delta_time; void app_update(app_event_t *events, i32 event_count) { - if (event_count) delta_time = events[0].delta_time; - draw_textf(v2f64(0,0), "delta time: %f", delta_time); - - for (i32 i = 0; i < event_count; i += 1) { - ui_demo(events + i); + // @todo: record render commands and replay + // @todo: ignore render commands + for (i32 i = 0; i < event_count - 1; i += 1) { + ui_demo(gfx2d, events + i); + gfx2d->cmds_len = 0; + ma_set0(gfx2d->ma); } + { + app_event_t *ev = &events[event_count - 1]; + + gfx2d_begin(gfx2d, ev); + gfx2d_clear(gfx2d, white_color_global); + ui_demo(gfx2d, ev); + // gfx2d_textf(gfx2d, v2f64(0,0), black_color_global, "delta time: %f", ev->delta_time); + gfx2d_end(gfx2d); + } + ma_set0(tcx.temp); + #if 0 ma_scratch_scope(temp) { @@ -32,5 +50,4 @@ void app_update(app_event_t *events, i32 event_count) { } } #endif - } diff --git a/src/wasm_app/ui.c b/src/wasm_app/ui.c index 0ae7cad..5c51aaf 100644 --- a/src/wasm_app/ui.c +++ b/src/wasm_app/ui.c @@ -1,280 +1,195 @@ -#if 0 -typedef struct ui_id_t ui_id_t; -struct ui_id_t { - u64 value; +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; }; -ui_id_t ui_string_to_id(const char *string) { // FNV HASH (1a?) + +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; +} + +b32 ui_button(gfx2d_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); + + v4f32_t rect_color = secondary_color_global; + v4f32_t text_color = black_color_global; + if (sig.overlapping) { + rect_color = primary_color_global; + } + + gfx2d_set_clip(gfx, rect); + gfx2d_rect(gfx, rect, rect_color); + gfx2d_text(gfx, text_pos, text_color, s8_from_char(title)); + gfx2d_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000)); + + return sig.pressed; +} + +b32 ui_checkbox(gfx2d_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; + + 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); + } + + gfx2d_set_clip(gfx, rect); + gfx2d_rect(gfx, rect, rect_color); + gfx2d_text(gfx, text_pos, text_color, s8_from_char(title)); + gfx2d_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000)); + + return *value; +} + +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; data8[i]; i++) { + 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) -ui_id_t ui_element_pressed; +#define ui_location_id() ui_string_to_id(FILE_AND_LINE, sizeof(FILE_AND_LINE) - 1) +ui_id_t ui_active_element = {0}; -typedef enum { - cut_left, - cut_right, - cut_bottom, - cut_top, -} cut_t; - -typedef struct rcut_t rcut_t; -struct rcut_t { - r2f64_t *rect; - cut_t cut; -}; - -rcut_t rcut(r2f64_t *rect, cut_t cut) { - return (rcut_t){rect, cut}; -} - -r2f64_t ui_cut(r2f64_t *rect, f64 value, cut_t cut) { - if (cut == cut_left) return r2f64_cut_left(rect, value); - else if (cut == cut_right) return r2f64_cut_right(rect, value); - else if (cut == cut_bottom) return r2f64_cut_bottom(rect, value); - else if (cut == cut_top) return r2f64_cut_top(rect, value); - else assert(!"invalid codepath"); - return (r2f64_t){0}; -} - -r2f64_t ui_cut2(rcut_t rc, f64 x, f64 y) { - f64 cut_value = 0; - if (rc.cut == cut_left || rc.cut == cut_right) cut_value = x; - else cut_value = y; - r2f64_t result = ui_cut(rc.rect, cut_value, rc.cut); - return result; -} - -typedef struct ui_flags_t ui_flags_t; -struct ui_flags_t { - b32 draw_text : 1; - b32 text_centered : 1; - b32 text_y_centered; - - b32 draw_rect : 1; - - b32 checkable : 1; - b32 draw_checkbox : 1; - b32 draw_checked; - - b32 clickable : 1; - b32 slider : 1; -}; - -typedef struct ui_signal_t ui_signal_t; -struct ui_signal_t { - b32 pressed : 1; - b32 overlapping : 1; - b32 interacting : 1; -}; - -// TODO(Karol): Don't use inputs as flags! Use only flags. -typedef struct ui_input_t ui_input_t; -struct ui_input_t { - char *title; - b32 *value_b32; - f64 *value_f64; - ui_id_t id; -}; - -v2f64_t style_padding = {50, 10}; -ui_signal_t ui_widget(rcut_t rc, ui_input_t input, ui_flags_t flags) { - // Calculate rectangles - r2f64_t total_rect = {0}; - r2f64_t rect = {0}; - r2f64_t checkbox_rect = {0}; +void ui_slider(gfx2d_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; { - v2f64_t size = style_padding; - f64 font_height = get_font_height(); - - size.y += font_height; - if (flags.draw_text) { - size.x += measure_text(input.title); + if (sig.pressed) { + ui_active_element = id; } - - total_rect = ui_cut2(rc, size.x, size.y); - rect = total_rect; - if (flags.draw_checkbox) { - checkbox_rect = r2f64_cut_left(&rect, size.y); + if (id.value == ui_active_element.value) { + interacting = true; } } - // Solve interactions - ui_signal_t result = {0}; - { - if (r2f64_contains(total_rect, mouse_pos_g)) { - result.overlapping = true; - if (mouse_button_press_g[app_mouse_button_left]) { - ui_element_pressed = input.id; - result.pressed = true; - } - } - - if (ui_element_pressed.value == input.id.value && mouse_button_down_g[app_mouse_button_left]) { - result.interacting = true; - } - - if (flags.checkable && result.pressed) { - *input.value_b32 = !*input.value_b32; - } - - if (flags.slider && result.interacting) { - f64 mouse_pos = mouse_pos_g.x; - v2f64_t rect_size = r2f64_get_size(rect); - *input.value_f64 = (mouse_pos - rect.min.x) / rect_size.x; - *input.value_f64 = CLAMP(*input.value_f64, 0, 1.0); - } - } - - clip(total_rect); - - // Draw - if (flags.draw_rect) { - v4f32_t color = primary_color_global; - if (flags.clickable) { - if (result.overlapping) color = secondary_color_global; - if (flags.draw_checked && input.value_b32[0]) color = accent1_color_global; - } - draw_rect(rect, color); - } - - if (flags.slider) { + if (interacting) { + f64 mouse_pos = ev->mouse_pos.x; v2f64_t rect_size = r2f64_get_size(rect); - r2f64_t rect_split = r2f64_get_left(&rect, rect_size.x * input.value_f64[0]); - draw_rect(rect_split, accent1_color_global); + *value = (mouse_pos - rect.min.x) / rect_size.x; + *value = CLAMP(*value, 0, 1.0); } - if (flags.draw_text) { - v2f64_t text_pos = rect.min; - f64 text_width = measure_text(input.title); - f64 font_height = get_font_height(); + v2f64_t rect_size = r2f64_get_size(rect); + r2f64_t slider_rect = r2f64_get_left(&rect, rect_size.x * value[0]); - 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}; - if (flags.text_y_centered) { - text_pos.y += offset_to_center.y; - } - if (flags.text_centered) { - text_pos = v2f64_add(text_pos, offset_to_center); - } - draw_text(text_pos, input.title); + 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; + + gfx2d_set_clip(gfx, rect); + gfx2d_rect(gfx, rect, rect_color); + gfx2d_rect(gfx, slider_rect, slider_color); + gfx2d_text(gfx, text_pos, text_color, s8_from_char(title)); + gfx2d_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000)); +} + +void ui_demo(gfx2d_t *gfx, app_event_t *ev) { + if (ev->kind == app_event_kind_mouse_up) { + ui_active_element = (ui_id_t){0}; } - if (flags.draw_checkbox) { - v4f32_t color = accent1_color_global; - if (flags.checkable) { - if (input.value_b32[0]) { - color = accent2_color_global; - } - } - if ((flags.checkable || flags.clickable) && result.overlapping) { - color = v4f32_lerp(color, v4f32(1,1,1,1), 0.25); - } - draw_rect(checkbox_rect, color); - } + 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); + gfx2d_rect(gfx, window_rect, primary_color_global); - clip(r2f64(-1000, -1000, 1000000, 1000000)); + f64 padding = 50; + gfx2d_rect(gfx, top_bar_rect, secondary_color_global); - return result; -} - -b32 ui_button(rcut_t rc, char *title) { - ui_signal_t sig = ui_widget(rc, (ui_input_t){.title = title}, (ui_flags_t){.draw_text = true, .text_centered = true, .draw_rect = true, .clickable = true}); - return sig.pressed; -} - -b32 ui_checked_button(b32 *value, rcut_t rc, char *title) { - ui_widget(rc, (ui_input_t){.title = title, .value_b32 = value}, (ui_flags_t){.draw_rect = true, .draw_text = true, .text_centered = true, .clickable = true, .checkable = true, .draw_checked = true}); - return *value; -} - -b32 ui_checkbox(rcut_t rc, b32 *value, char *title) { - ui_widget(rc, (ui_input_t){.value_b32 = value, .title = title}, (ui_flags_t){.draw_checkbox = true, .draw_text = true, .text_y_centered = true, .draw_rect = true, .checkable = true}); - return *value; -} - -void ui_label(rcut_t rc, char *title) { - ui_widget(rc, (ui_input_t){.title = title}, (ui_flags_t){.draw_text = true, .text_centered = true, .draw_rect = true}); -} - -void ui_slider(rcut_t rc, ui_id_t id, f64 *value, char *title) { - ui_widget(rc, (ui_input_t){.title = title, .value_f64 = value, .id = id}, (ui_flags_t){.draw_text = true, .text_centered = true, .slider = true, .draw_rect = true, .clickable = true}); -} - -void ui_begin_frame(void) { - if (mouse_button_release_g[app_mouse_button_left]) { - ui_element_pressed = (ui_id_t){0}; - } -} - -void ui_demo(void) { - ui_begin_frame(); - f64 font_height = get_font_height(); - r2f64_t window_rect = r2f64(0, 0, window_size_g.x, window_size_g.y); + static b32 open_file_panel; + f64 open_file_panel_xsize = 0; { - draw_rect(window_rect, while_color_global); + // ▼▲▶◀ + 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)) { + } + r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1); + gfx2d_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); + + { + 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); + // } } - static b32 panel_open = true; - static b32 cool_rect = false; { - r2f64_t top_rect = r2f64_cut_top(&window_rect, font_height*2); - draw_rect(top_rect, primary_color_global); - - if (ui_checked_button(&cool_rect, rcut(&top_rect, cut_left), "file")) { - draw_rect(window_rect, v4f32(0.5, 0.1, 0.1, 1.0)); - } - if (ui_button(rcut(&top_rect, cut_left), "edit")) {} - if (ui_button(rcut(&top_rect, cut_left), "view")) {} - if (ui_checked_button(&panel_open, rcut(&top_rect, cut_left), "open panel")) { - + 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); + gfx2d_rect(gfx, gap_rect, black_color_global); } - if (panel_open) { - r2f64_t panel_rect = r2f64_cut_left(&window_rect, measure_text("1234567890")*2); - { - v4f32_t color = primary_color_global; color.a = 0.3f; - draw_rect(panel_rect, color); + { + char *title = "view"; + r2f64_t rect = r2f64_cut_left(&top_bar_rect, measure_text(title) + padding*2); + if (ui_button(gfx, ev, rect, title)) { } - - - - static f64 value = 0.2f; - ui_slider(rcut(&panel_rect, cut_top), ui_location_id(), &value, "value"); - - ui_widget(rcut(&panel_rect, cut_top), (ui_input_t){.title = "non centered label"}, (ui_flags_t){.draw_rect = true, .draw_text = true}); - - static b32 checkbox_memes; - ui_checkbox(rcut(&panel_rect, cut_top), &checkbox_memes, "checkbox"); - - - // TODO(Krzosa): Draw arrows / triangles - { - f64 font_height = get_font_height(); - f64 cut_size = font_height + style_padding.y; - r2f64_t rect = r2f64_cut_top(&panel_rect, cut_size); - - static int counter; - - if (ui_widget(rcut(&rect, cut_left), (ui_input_t){0}, (ui_flags_t){.draw_checkbox = true, .clickable = true}).pressed) { - counter -= 1; - } - char buff[256]; - stbsp_snprintf(buff, sizeof(buff), "counter: %d", counter); - ui_label(rcut(&rect, cut_left), buff); - if (ui_widget(rcut(&rect, cut_left), (ui_input_t){0}, (ui_flags_t){.draw_checkbox = true, .clickable = true}).pressed) { - counter += 1; - } - - } - + r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1); + gfx2d_rect(gfx, gap_rect, black_color_global); } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/wasm_app/ui2.c b/src/wasm_app/ui2.c deleted file mode 100644 index 083f4ab..0000000 --- a/src/wasm_app/ui2.c +++ /dev/null @@ -1,195 +0,0 @@ -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; -}; - -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; -} - -b32 ui_button(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); - - v4f32_t rect_color = secondary_color_global; - v4f32_t text_color = black_color_global; - if (sig.overlapping) { - rect_color = primary_color_global; - } - - set_clip(rect); - draw_rect(rect, rect_color); - draw_text(text_pos, text_color, s8_from_char(title)); - set_clip(r2f64(-1000, -1000, 1000000, 1000000)); - - return sig.pressed; -} - -b32 ui_checkbox(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; - - 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); - } - - set_clip(rect); - draw_rect(rect, rect_color); - draw_text(text_pos, text_color, s8_from_char(title)); - set_clip(r2f64(-1000, -1000, 1000000, 1000000)); - - return *value; -} - -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(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; - { - if (sig.pressed) { - ui_active_element = id; - } - if (id.value == ui_active_element.value) { - interacting = true; - } - } - - 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; - - set_clip(rect); - draw_rect(rect, rect_color); - draw_rect(slider_rect, slider_color); - draw_text(text_pos, text_color, s8_from_char(title)); - set_clip(r2f64(-1000, -1000, 1000000, 1000000)); -} - -void ui_demo(app_event_t *ev) { - if (ev->kind == app_event_kind_mouse_up) { - ui_active_element = (ui_id_t){0}; - } - - 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); - draw_rect(window_rect, primary_color_global); - - f64 padding = 50; - draw_rect(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(ev, rect, &open_file_panel, title)) { - } - r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1); - draw_rect(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); - - { - 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(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); - // } - } - - - { - char *title = "edit"; - r2f64_t rect = r2f64_cut_left(&top_bar_rect, measure_text(title) + padding*2); - if (ui_button(ev, rect, title)) { - } - r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1); - draw_rect(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(ev, rect, title)) { - } - r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1); - draw_rect(gap_rect, black_color_global); - } - -} \ No newline at end of file