280 lines
8.5 KiB
C
280 lines
8.5 KiB
C
#if 0
|
|
typedef struct ui_id_t ui_id_t;
|
|
struct ui_id_t {
|
|
u64 value;
|
|
};
|
|
ui_id_t ui_string_to_id(const char *string) { // FNV HASH (1a?)
|
|
u8 *data8 = (u8 *)string;
|
|
u64 hash = (u64)14695981039346656037ULL;
|
|
for (u64 i = 0; data8[i]; 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;
|
|
|
|
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};
|
|
{
|
|
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);
|
|
}
|
|
|
|
total_rect = ui_cut2(rc, size.x, size.y);
|
|
rect = total_rect;
|
|
if (flags.draw_checkbox) {
|
|
checkbox_rect = r2f64_cut_left(&rect, size.y);
|
|
}
|
|
}
|
|
|
|
// 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) {
|
|
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);
|
|
}
|
|
|
|
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);
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
clip(r2f64(-1000, -1000, 1000000, 1000000));
|
|
|
|
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);
|
|
{
|
|
draw_rect(window_rect, while_color_global);
|
|
}
|
|
|
|
|
|
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")) {
|
|
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
#endif
|