/* ** [x] Choosing a keying strategy from user code ** [x] Using parents ** [x] Using file and line ** [ ] Keyboard friendliness ** [x] ui_em size ** [ ] use strictness to 'solve violations' ** [ ] scrolling ** [ ] vieweing type info ** [ ] slider ** [ ] button ** [ ] pernament state */ typedef struct ui_id_t ui_id_t; struct ui_id_t { u64 value; }; typedef struct ui_code_loc_t ui_code_loc_t; struct ui_code_loc_t { char *file; int line; int counter; }; #define UI_CODE_LOC (ui_code_loc_t){.file = __FILE__, .line = __LINE__, .counter = __COUNTER__} typedef enum { ui_axis2_x, ui_axis2_y, ui_axis2_count, } ui_axis2_t; typedef enum { ui_size_kind_null, ui_size_kind_pixels, ui_size_kind_text_content, ui_size_kind_percent_of_parent, ui_size_kind_children_sum, } ui_size_kind_t; typedef struct ui_size_t ui_size_t; struct ui_size_t { ui_size_kind_t kind; f32 value; f32 strictness; }; #define flag1(flag) set_bit(flag) #define flag2(a, b) (set_bit(a) | set_bit(b)) #define flag3(a, b, c) (set_bit(a) | set_bit(b) | set_bit(c)) #define flag4(a, b, c, d) (set_bit(a) | set_bit(b) | set_bit(c) | set_bit(d)) #define is_flag_set(x, FLAG) ((x) & flag1(FLAG)) #define set_flag1(x, FLAG) ((x) |= flag1(FLAG)) typedef u32 ui_box_flag_t; enum { ui_box_flag_draw_border, ui_box_flag_draw_text, ui_box_flag_draw_rect, ui_box_flag_draw_scroller, ui_box_flag_scroll, }; typedef struct ui_box_t ui_box_t; struct ui_box_t { // recreated every frame in building code ui_box_t *next; ui_box_t *prev; ui_box_t *parent; ui_box_t *first; ui_box_t *last; ui_box_flag_t flags; s8_t string; ui_size_t semantic_size[ui_axis2_count]; ui_axis2_t grow_axis; ui_code_loc_t loc; b32 created_new; // preserving state ui_id_t id; // important position!: offset(id) used for partial zeroing u64 last_touched_event_id; ui_box_t *hash_next; ui_box_t *hash_prev; // computed by layout system every frame f32 iter_pos[ui_axis2_count]; f32 computed_rel_pos[ui_axis2_count]; f32 computed_size[ui_axis2_count]; r2f32_t rect; v2f32_t view_offset; // state b32 expanded; }; typedef struct ui_signal_t ui_signal_t; struct ui_signal_t { ui_box_t *box; b8 clicked; b8 dragging; // b8 double_clicked; // b8 right_clicked; // b8 pressed; // b8 released; // b8 dragging; // b8 hovering; }; typedef enum { ui_id_strategy_use_hierarchy, ui_id_strategy_use_code_loc, ui_id_strategy_use_string, } ui_id_strategy_t; typedef struct ui_t ui_t; struct ui_t { ma_arena_t *box_arena; // required to be only used for boxes app_event_t *event; app_frame_t *frame; i32 allocated_boxes; ui_box_t *box_array; // first item on arena ui_box_t *root; ui_box_t *top; ui_box_t *free_first; ui_box_t *hash_first; ui_box_t *hash_last; ui_id_t hot; ui_id_t active; // STACK(ui_id_t, 256) id_stack; int indent_stack; ui_id_strategy_t id_strategy; }; gb ui_t *ui = NULL; gb_read_only ui_id_t ui_null_id; gb_read_only ui_box_t ui_null_box; 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; } #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 ui_size_t ui_size(ui_size_kind_t kind, f32 value) { return (ui_size_t){.kind = kind, .value = value}; } #define ui_pixels(value) ui_size(ui_size_kind_pixels, value) #define ui_em(value) ui_size(ui_size_kind_pixels, value * get_font_size()) #define ui_text() ui_size(ui_size_kind_text_content, 0) #define ui_children_sum() ui_size(ui_size_kind_children_sum, 0) #define ui_percent(value) ui_size(ui_size_kind_percent_of_parent, value)