This commit is contained in:
Krzosa Karol
2025-01-06 21:33:15 +01:00
parent 1710bc232d
commit 83c28e27d0
5 changed files with 300 additions and 221 deletions

View File

@@ -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 execute_python_snippets = true; // make sure to not abuse just for quick maths
bool run_server = false; bool run_server = false;
bool core_test_target = true; bool core_test_target = false;
bool win32_target = false; bool win32_target = false;
bool wasm_target = false; bool wasm_target = true;
if (execute_python_snippets) { if (execute_python_snippets) {
sb8_t *sb = sb8_serial_begin(arena); sb8_t *sb = sb8_serial_begin(arena);

View File

@@ -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 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); 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) { 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)); 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; 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) { fn f64 measure_text_ex(s8_t string) {
return wasm_measure_text((isize)str, len, (isize) font_face.str, font_face.len, 20*wasm_dpr) / wasm_dpr; 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) { 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) { fn void draw_text(v2f64_t pos, v4f32_t color, s8_t string) {
@@ -65,6 +67,13 @@ struct gfx_t {
app_event_t *ev; 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) { void gfx_begin(gfx_t *gfx, app_event_t *ev) {
gfx->ev = ev; gfx->ev = ev;
} }

View File

@@ -5174,7 +5174,7 @@ int main(int argument_count, char **arguments) {
exe_name = OS_GetAbsolutePath(&Perm, exe_name); exe_name = OS_GetAbsolutePath(&Perm, exe_name);
int result = os_systemf("%.*s %.*s", S8_Expand(exe_name), S8_Expand(cmd_args_merged)); int result = os_systemf("%.*s %.*s", S8_Expand(exe_name), S8_Expand(cmd_args_merged));
if (result != 0) { 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")); os_delete_file(S8_Lit("build_tool.cache"));
return 1; return 1;
} }

View File

@@ -5,61 +5,58 @@
#include "app/app.c" #include "app/app.c"
#include "gfx2d/gfx2d.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 fn void app_init(void) {
b8 left_press; ui_test_iterators();
b8 left_unpress;
b8 left_down;
v2f64_t mouse_pos;
v2f64_t window_size;
//
};
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; 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) { 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!! // These steps should be totally optional!!
@@ -67,13 +64,31 @@ b32 app_update(app_event_list_t events) {
app_event_t *ev = events.last; app_event_t *ev = events.last;
f64 delta = app_get_anim_delta_time(); f64 delta = app_get_anim_delta_time();
f64 time = app_get_anim_time(); f64 time = app_get_anim_time();
f64 font_height = get_font_height();
// animate // animate
// render // render
gfx_begin(gfx, ev); gfx_begin(globals->gfx, ev);
gfx_clear(gfx, white_color_global); gfx_clear(globals->gfx, white_color_global);
gfx_textf(gfx, (v2f64_t){0,0}, black_color_global, "delta: %f, time: %f", delta, time); gfx_textf(globals->gfx, (v2f64_t){0,ev->window_size.y - font_height}, black_color_global, "delta: %f, time: %f", delta, time);
gfx_end(gfx);
// ►
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; return false;

View File

@@ -1,195 +1,250 @@
v2f64_t ui_calc_text_pos(r2f64_t rect, char *title) { typedef struct ui_id_t ui_id_t;
f64 font_height = get_font_height(); struct ui_id_t {
f64 text_width = measure_text(title); u64 value;
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) { typedef struct ui_box_t ui_box_t;
ui_signal_t sig = {0}; struct ui_box_t {
if (r2f64_contains(rect, ev->mouse_pos)) { ui_id_t id;
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(gfx_t *gfx, app_event_t *ev, r2f64_t rect, char *title) { ui_box_t *next;
v2f64_t text_pos = ui_calc_text_pos(rect, title); ui_box_t *prev;
ui_signal_t sig = ui_interact(ev, rect); ui_box_t *parent;
ui_box_t *first;
ui_box_t *last;
v4f32_t rect_color = secondary_color_global; ui_box_t *iter_next; // for iterator
v4f32_t text_color = black_color_global;
if (sig.overlapping) {
rect_color = primary_color_global;
}
gfx_set_clip(gfx, rect); s8_t string;
gfx_rect(gfx, rect, rect_color); b32 expanded;
gfx_text(gfx, text_pos, text_color, s8_from_char(title)); };
gfx_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000));
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) { i32 active_box_count;
v2f64_t text_pos = ui_calc_text_pos(rect, title); ui_box_t *root;
ui_signal_t sig = ui_interact(ev, rect); ui_box_t *top;
if (sig.pressed) *value = !*value;
v4f32_t rect_color = secondary_color_global; ui_box_t *first_free;
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);
}
gfx_set_clip(gfx, rect); ui_t *ui = NULL;
gfx_rect(gfx, rect, rect_color); ui_id_t ui_null_id;
gfx_text(gfx, text_pos, text_color, s8_from_char(title));
gfx_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000));
return *value; #if 0
} ui_begin_expander("app_event_t");
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;
{ {
if (sig.pressed) { ui_edit_enum("kind: app_event_kind_t = %S");
ui_active_element = id;
}
if (id.value == ui_active_element.value) {
interacting = true;
}
}
if (interacting) { ui_begin_expander("mouse_wheel_delta: v3f64_t");
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_demo(gfx_t *gfx, 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);
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;
{ {
// ▼▲▶◀ ui_edit_f64(&x, "x: %f", x);
char *title = "▶ file"; ui_edit_f64(&y, "y: %f", y);
if (open_file_panel) title = "▼ file"; ui_edit_f64(&z, "z: %f", z);
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); ui_end_expander();
gfx_rect(gfx, gap_rect, black_color_global); }
ui_end_expander();
#endif
void ui_init(ma_arena_t *arena) {
ui = ma_push_type(arena, ui_t);
ui->arena = arena;
} }
if (open_file_panel) { ui_box_t *ui_alloc_box(ui_id_t id) {
f64 item_count = 20; ui_box_t *result = ui->first_free;
f64 item_size = get_font_height() + 20; if (!result) result = ma_push_type(ui->arena, ui_box_t);
r2f64_t panel_rect = r2f64_get_top(&window_rect, item_count * item_size); result->id = id;
panel_rect = r2f64_get_left(&panel_rect, open_file_panel_xsize); 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;
}
while (iter->box) {
if (iter->box->next) {
iter->box = iter->box->next;
break;
} else {
iter->box = iter->box->parent;
}
}
}
typedef struct ui_postorder_iter_t ui_postorder_iter_t;
struct ui_postorder_iter_t { ui_box_t *box; };
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");
}
}
{ {
static f64 slider_value; sb8_t *sb = sb8_serial_begin(scratch.arena);
char buff[64]; ui_test_stringify_preorder(sb, ui->root);
stbsp_snprintf(buff, sizeof(buff), "%f", slider_value); s8_t recursive_string = sb8_serial_end(scratch.arena, sb);
r2f64_t rect = r2f64_cut_top(&panel_rect, item_size);
ui_slider(gfx, ev, rect, ui_location_id(), &slider_value, buff); 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);
}
s8_t iter_string = sb8_serial_end(scratch.arena, sb);
assert(s8_equal(iter_string, recursive_string));
} }
// { {
// static char buff[64]; sb8_t *sb = sb8_serial_begin(scratch.arena);
// static ui_input_state input; ui_test_stringify_postorder(sb, ui->root);
// if (input.buff == NULL) { s8_t recursive_string = sb8_serial_end(scratch.arena, sb);
// input.buff = buff;
// input.cap = sizeof(buff); 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) {
// } // }
// 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(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)) {
}
r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1);
gfx_rect(gfx, gap_rect, black_color_global);
}
}