typedef void ui_custom_draw_t(struct ui_box_t *box); typedef struct ui_code_loc_t ui_code_loc_t; struct ui_code_loc_t { char *file; int line; int counter; }; typedef struct ui_id_t ui_id_t; struct ui_id_t { u64 value; }; typedef struct ui_box_flags_t ui_box_flags_t; struct ui_box_flags_t { b8 draw_rect: 1; b8 draw_border: 1; b8 draw_text: 1; b8 clip_rect : 1; }; typedef enum { ui_text_align_left, ui_text_align_center, } ui_text_align_t; typedef enum { ui_axis2_invalid = -1, ui_axis2_x, ui_axis2_y, ui_axis2_count, } ui_axis2_t; typedef enum { ui_lop_cut_top, ui_lop_cut_bottom, ui_lop_cut_left, ui_lop_cut_right, ui_lop_idle, } ui_lop_t; #include "ui.gen.h" typedef struct ui_caret_t ui_caret_t; struct ui_caret_t { union { i32 e[2]; struct { r1i32_t range; }; }; i32 ifront; }; fn ui_caret_t ui_caret_clamp(ui_caret_t c, i32 min, i32 max) { return (ui_caret_t){CLAMP(c.e[0],min,max), CLAMP(c.e[1],min,max), c.ifront}; } fn i32 ui_caret_front(ui_caret_t c) { return c.e[c.ifront]; } fn i32 ui_caret_back(ui_caret_t c) { return c.e[c.ifront ? 0 : 1]; } ui_caret_t ui_caret(i32 front, i32 back) { ui_caret_t result = {0}; if (front >= back) { result.range.min = back; result.range.max = front; result.ifront = 1; } else { result.range.min = front; result.range.max = back; result.ifront = 0; } return result; } ui_caret_t ui_caret_set_back(ui_caret_t caret, i32 back) { i32 front = ui_caret_front(caret); ui_caret_t result = ui_caret(front, back); return result; } ui_caret_t ui_caret_set_front(ui_caret_t caret, i32 front) { i32 back = ui_caret_back(caret); ui_caret_t result = ui_caret(front, back); return result; } fn ui_caret_t ui_carets(i32 x) { return ui_caret(x, x); } typedef struct ui_text_input_t ui_text_input_t; struct ui_text_input_t { union { struct { char *str; i64 len; }; s8_t string; }; i32 cap; ui_caret_t caret; }; typedef struct ui_box_t ui_box_t; struct ui_box_t { ui_box_t *next; ui_box_t *prev; ui_box_t *first; ui_box_t *last; ui_box_t *parent; i32 node_count; ui_code_loc_t loc; s8_t string; ui_box_flags_t flags; b8 created_new; ui_custom_draw_t *custom_draw; UI_DECL_BOX_MEMBERS r2f32_t full_rect; r2f32_t rect; // state ui_id_t id; ui_box_t *hash_next; ui_box_t *hash_prev; u64 last_touched_event_id; f32 hot_t; f32 active_t; r2f32_t final_rect; b32 expanded; ui_text_input_t text_input; }; typedef struct ui_signal_t ui_signal_t; struct ui_signal_t { ui_box_t *box; b8 clicked; b8 dragging; }; typedef struct ui_t ui_t; struct ui_t { app_frame_t *frame; // building ui_box_t root; ui_box_t *top; app_event_t *event; UI_DECL_STACKS // allocation ma_arena_t *box_arena; i32 allocated_boxes; ui_box_t *free_first; ui_box_t *hash_first; ui_box_t *hash_last; // interaction ui_id_t hot; ui_id_t active; ui_id_t focus; // drawing r2f32_t clip_rect; }; ui_t *ui; gb_read_only ui_id_t ui_null_id; gb_read_only ui_box_t ui_null_box; gb_read_only ui_box_flags_t ui_null_flags; fn b32 ui_is_null_id(ui_id_t id) { return id.value == 0; } fn b32 ui_is_null_box(ui_box_t *box) { return box->id.value == 0; } fn b32 ui_is_hot_box(ui_box_t *box) { return !ui_is_null_box(box) && box->id.value == ui->hot.value; } fn b32 ui_is_active_box(ui_box_t *box) { return !ui_is_null_box(box) && box->id.value == ui->active.value; } fn b32 ui_is_focused_box(ui_box_t *box) { return !ui_is_null_box(box) && box->id.value == ui->focus.value; } #define ev_left(ev) ((ev)->mouse_button == app_mouse_button_left) #define ev_left_up(ev) ((ev)->kind == app_event_kind_mouse_up && ev_left(ev)) #define ev_left_down(ev) ((ev)->kind == app_event_kind_mouse_down && ev_left(ev)) fn void ui_set_rect(ui_box_t *box, r2f32_t rect) { box->rect = box->full_rect = rect; } #define UILOC (ui_code_loc_t){.file = __FILE__, .line = __LINE__, .counter = __COUNTER__} #define ui_em(x) ((x) * rn_state.main_font->size) #define ui_max 200000000.f #define ui_box_flags(...) (ui_box_flag_t){__VA_ARGS__} fn ui_id_t ui_id(s8_t string); fn ui_id_t ui_idf(char *str, ...); fn v2f32_t ui_aligned_text_pos(ui_text_align_t text_align, r2f32_t rect, s8_t string);