[ui, styling] revisiting layout/sizing
This commit is contained in:
parent
d3a8a651e5
commit
8032c7340b
|
@ -31,6 +31,14 @@ void debug_print_rule(ui_style_rule* rule)
|
|||
{
|
||||
switch(selector->kind)
|
||||
{
|
||||
case UI_SEL_ANY:
|
||||
printf("any: ");
|
||||
break;
|
||||
|
||||
case UI_SEL_OWNER:
|
||||
printf("owner: ");
|
||||
break;
|
||||
|
||||
case UI_SEL_TEXT:
|
||||
printf("text='%.*s': ", (int)selector->text.len, selector->text.ptr);
|
||||
break;
|
||||
|
@ -39,6 +47,26 @@ void debug_print_rule(ui_style_rule* rule)
|
|||
printf("tag=0x%llx: ", selector->tag.hash);
|
||||
break;
|
||||
|
||||
case UI_SEL_STATUS:
|
||||
{
|
||||
if(selector->status & UI_HOVER)
|
||||
{
|
||||
printf("hover: ");
|
||||
}
|
||||
if(selector->status & UI_ACTIVE)
|
||||
{
|
||||
printf("active: ");
|
||||
}
|
||||
if(selector->status & UI_DRAGGING)
|
||||
{
|
||||
printf("dragging: ");
|
||||
}
|
||||
} break;
|
||||
|
||||
case UI_SEL_KEY:
|
||||
printf("key=0x%llx: ", selector->key.hash);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("unknown: ");
|
||||
break;
|
||||
|
@ -46,6 +74,30 @@ void debug_print_rule(ui_style_rule* rule)
|
|||
}
|
||||
printf("=> font size = %f\n", rule->style->fontSize);
|
||||
}
|
||||
void debug_print_size(ui_box* box, ui_axis axis, int indent)
|
||||
{
|
||||
debug_print_indent(indent);
|
||||
printf("size %s: ", axis == UI_AXIS_X ? "x" : "y");
|
||||
switch(box->targetStyle->size.s[axis].kind)
|
||||
{
|
||||
case UI_SIZE_TEXT:
|
||||
printf("text\n");
|
||||
break;
|
||||
|
||||
case UI_SIZE_CHILDREN:
|
||||
printf("children\n");
|
||||
break;
|
||||
|
||||
case UI_SIZE_PARENT:
|
||||
printf("parent\n");
|
||||
break;
|
||||
|
||||
case UI_SIZE_PIXELS:
|
||||
printf("pixels\n");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void debug_print_styles(ui_box* box, int indent)
|
||||
{
|
||||
|
@ -56,6 +108,9 @@ void debug_print_styles(ui_box* box, int indent)
|
|||
debug_print_indent(indent);
|
||||
printf("font size: %f\n", box->targetStyle->fontSize);
|
||||
|
||||
debug_print_size(box, UI_AXIS_X, indent);
|
||||
debug_print_size(box, UI_AXIS_Y, indent);
|
||||
|
||||
if(!ListEmpty(&box->beforeRules))
|
||||
{
|
||||
debug_print_indent(indent);
|
||||
|
@ -90,6 +145,38 @@ void debug_print_styles(ui_box* box, int indent)
|
|||
}
|
||||
}
|
||||
|
||||
mg_font create_font()
|
||||
{
|
||||
//NOTE(martin): create font
|
||||
str8 fontPath = mp_app_get_resource_path(mem_scratch(), "../resources/OpenSansLatinSubset.ttf");
|
||||
char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath);
|
||||
|
||||
FILE* fontFile = fopen(fontPathCString, "r");
|
||||
if(!fontFile)
|
||||
{
|
||||
LOG_ERROR("Could not load font file '%s': %s\n", fontPathCString, strerror(errno));
|
||||
return(mg_font_nil());
|
||||
}
|
||||
unsigned char* fontData = 0;
|
||||
fseek(fontFile, 0, SEEK_END);
|
||||
u32 fontDataSize = ftell(fontFile);
|
||||
rewind(fontFile);
|
||||
fontData = (unsigned char*)malloc(fontDataSize);
|
||||
fread(fontData, 1, fontDataSize, fontFile);
|
||||
fclose(fontFile);
|
||||
|
||||
unicode_range ranges[5] = {UNICODE_RANGE_BASIC_LATIN,
|
||||
UNICODE_RANGE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT,
|
||||
UNICODE_RANGE_LATIN_EXTENDED_A,
|
||||
UNICODE_RANGE_LATIN_EXTENDED_B,
|
||||
UNICODE_RANGE_SPECIALS};
|
||||
|
||||
mg_font font = mg_font_create_from_memory(fontDataSize, fontData, 5, ranges);
|
||||
free(fontData);
|
||||
|
||||
return(font);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
LogLevel(LOG_LEVEL_WARNING);
|
||||
|
@ -117,59 +204,184 @@ int main()
|
|||
return(-1);
|
||||
}
|
||||
|
||||
mg_font font = create_font();
|
||||
|
||||
// start app
|
||||
mp_window_bring_to_front(window);
|
||||
mp_window_focus(window);
|
||||
|
||||
while(!mp_should_quit())
|
||||
{
|
||||
bool printDebugStyle = false;
|
||||
|
||||
f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC);
|
||||
|
||||
mp_pump_events(0);
|
||||
mp_event event = {0};
|
||||
while(mp_next_event(&event))
|
||||
{
|
||||
switch(event.type)
|
||||
{
|
||||
case MP_EVENT_WINDOW_CLOSE:
|
||||
{
|
||||
mp_request_quit();
|
||||
} break;
|
||||
|
||||
|
||||
case MP_EVENT_KEYBOARD_KEY:
|
||||
{
|
||||
if(event.key.action == MP_KEY_PRESS && event.key.code == MP_KEY_P)
|
||||
{
|
||||
printDebugStyle = true;
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//TEST UI
|
||||
ui_style defaultStyle = {.bgColor = {0.9, 0.9, 0.9, 1},
|
||||
ui_style defaultStyle = {.size.width = {UI_SIZE_CHILDREN},
|
||||
.size.height = {UI_SIZE_CHILDREN},
|
||||
.layout.axis = UI_AXIS_Y,
|
||||
.layout.spacing = 10,
|
||||
.layout.margin.x = 10,
|
||||
.layout.margin.y = 10,
|
||||
.bgColor = {0.9, 0.9, 0.9, 1},
|
||||
.borderSize = 2,
|
||||
.borderColor = {0, 0, 1, 1},
|
||||
.color = {0, 0, 0, 1},
|
||||
.font = font,
|
||||
.fontSize = 32};
|
||||
|
||||
ui_flags defaultFlags = UI_FLAG_DRAW_BORDER;
|
||||
|
||||
ui_box* root = 0;
|
||||
ui_frame(800, 800, defaultStyle)
|
||||
ui_frame(800, 610, defaultStyle)
|
||||
{
|
||||
root = ui_box_top();
|
||||
|
||||
// ui_label("Hello, world!");
|
||||
|
||||
|
||||
ui_pattern pattern = {0};
|
||||
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TEXT, .text = str8_lit("b")});
|
||||
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TAG, .tag = ui_tag_make(str8_lit("foo"))});
|
||||
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TAG, .tag = ui_tag_make("foo")});
|
||||
ui_style_next(pattern,
|
||||
&(ui_style){.fontSize = 12},
|
||||
&(ui_style){.fontSize = 36},
|
||||
UI_STYLE_FONT_SIZE);
|
||||
|
||||
ui_container("a", 0)
|
||||
ui_style_next(ui_pattern_all(), &defaultStyle, UI_STYLE_BORDER_SIZE|UI_STYLE_BORDER_COLOR|UI_STYLE_SIZE_X|UI_STYLE_SIZE_Y|UI_STYLE_LAYOUT);
|
||||
|
||||
ui_container("a", defaultFlags)
|
||||
{
|
||||
ui_pattern pattern = {0};
|
||||
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TEXT, .text = str8_lit("b")});
|
||||
ui_style_next(pattern,
|
||||
&(ui_style){.fontSize = 20},
|
||||
&(ui_style){.fontSize = 22},
|
||||
UI_STYLE_FONT_SIZE);
|
||||
|
||||
ui_container("b", 0)
|
||||
ui_container("b", defaultFlags)
|
||||
{
|
||||
ui_container("c", 0)
|
||||
ui_container("c", defaultFlags)
|
||||
{
|
||||
ui_box_make("d", 0);
|
||||
if(ui_button("button d").clicked)
|
||||
{
|
||||
printf("clicked button d\n");
|
||||
}
|
||||
}
|
||||
|
||||
ui_container("e", 0)
|
||||
ui_container("e", defaultFlags)
|
||||
{
|
||||
ui_tag_next(str8_lit("foo"));
|
||||
ui_box_make("f", 0);
|
||||
ui_tag_next("foo");
|
||||
if(ui_button("button f").clicked)
|
||||
{
|
||||
printf("clicked button f\n");
|
||||
}
|
||||
|
||||
ui_style_next(ui_pattern_owner(),
|
||||
&(ui_style){.size.width = {UI_SIZE_PIXELS, 200, 0},
|
||||
.size.height = {UI_SIZE_PIXELS, 20, 0}},
|
||||
UI_STYLE_SIZE_X|UI_STYLE_SIZE_Y);
|
||||
static f32 slider1 = 0;
|
||||
ui_slider("slider1", 0.3, &slider1);
|
||||
|
||||
|
||||
ui_style_next(ui_pattern_owner(),
|
||||
&(ui_style){.size.width = {UI_SIZE_PIXELS, 200, 0},
|
||||
.size.height = {UI_SIZE_PIXELS, 20, 0}},
|
||||
UI_STYLE_SIZE_X|UI_STYLE_SIZE_Y);
|
||||
static f32 slider2 = 0;
|
||||
ui_slider("slider2", 0.3, &slider2);
|
||||
|
||||
ui_style_next(ui_pattern_owner(),
|
||||
&(ui_style){.size.width = {UI_SIZE_PIXELS, 200, 0},
|
||||
.size.height = {UI_SIZE_PIXELS, 20, 0}},
|
||||
UI_STYLE_SIZE_X|UI_STYLE_SIZE_Y);
|
||||
static f32 slider3 = 0;
|
||||
ui_slider("slider3", 0.3, &slider3);
|
||||
|
||||
}
|
||||
}
|
||||
ui_tag_next(str8_lit("foo"));
|
||||
ui_box_make("d", 0);
|
||||
ui_tag_next("foo");
|
||||
ui_label("label d");
|
||||
}
|
||||
|
||||
pattern = (ui_pattern){0};
|
||||
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TEXT, .text = str8_lit("c")});
|
||||
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TEXT, .text = str8_lit("d")});
|
||||
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TAG, .tag = ui_tag_make("button")});
|
||||
ui_style_prev(pattern,
|
||||
&(ui_style){.fontSize = 30},
|
||||
UI_STYLE_FONT_SIZE);
|
||||
&(ui_style){.bgColor = {1, 0.5, 0.5, 1}},
|
||||
UI_STYLE_BG_COLOR);
|
||||
|
||||
pattern = (ui_pattern){0};
|
||||
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TEXT, .text = str8_lit("c")});
|
||||
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TAG, .tag = ui_tag_make("button")});
|
||||
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_STATUS, .op = UI_SEL_AND, .status = UI_ACTIVE|UI_HOVER});
|
||||
ui_style_prev(pattern,
|
||||
&(ui_style){.bgColor = {0.5, 1, 0.5, 1}},
|
||||
UI_STYLE_BG_COLOR);
|
||||
|
||||
}
|
||||
if(printDebugStyle)
|
||||
{
|
||||
debug_print_styles(root, 0);
|
||||
}
|
||||
|
||||
mg_surface_prepare(surface);
|
||||
|
||||
// mg_set_color_rgba(1, 0, 0, 1);
|
||||
// mg_rectangle_fill(100, 100, 400, 200);
|
||||
|
||||
ui_draw();
|
||||
|
||||
/*
|
||||
mg_mat2x3 transform = {1, 0, 0,
|
||||
0, -1, 800};
|
||||
|
||||
bool oldTextFlip = mg_get_text_flip();
|
||||
mg_set_text_flip(true);
|
||||
|
||||
mg_matrix_push(transform);
|
||||
|
||||
mg_set_font(font);
|
||||
mg_set_font_size(20);
|
||||
mg_set_color_rgba(0, 0, 0, 1);
|
||||
|
||||
mg_move_to(0, 38);
|
||||
mg_text_outlines(str8_lit("hello, world"));
|
||||
mg_fill();
|
||||
|
||||
mg_matrix_pop();
|
||||
|
||||
mg_set_text_flip(oldTextFlip);
|
||||
*/
|
||||
mg_flush();
|
||||
mg_surface_present(surface);
|
||||
|
||||
mem_arena_clear(mem_scratch());
|
||||
}
|
||||
|
||||
mp_terminate();
|
||||
|
||||
|
|
490
src/ui.c
490
src/ui.c
|
@ -13,6 +13,22 @@
|
|||
|
||||
#define LOG_SUBSYSTEM "UI"
|
||||
|
||||
|
||||
static ui_style UI_STYLE_DEFAULTS =
|
||||
{
|
||||
.size.width = {.kind = UI_SIZE_CHILDREN,
|
||||
.value = 0,
|
||||
.strictness = 0},
|
||||
.size.height = {.kind = UI_SIZE_CHILDREN,
|
||||
.value = 0,
|
||||
.strictness = 0},
|
||||
|
||||
.layout = {.axis = UI_AXIS_Y,
|
||||
.align = {UI_ALIGN_START,
|
||||
UI_ALIGN_START}},
|
||||
.color = {0, 0, 0, 1},
|
||||
.fontSize = 16,
|
||||
};
|
||||
//-----------------------------------------------------------------------------
|
||||
// context
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -193,32 +209,32 @@ void ui_box_pop(void)
|
|||
// tagging
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ui_tag ui_tag_make(str8 string)
|
||||
ui_tag ui_tag_make_str8(str8 string)
|
||||
{
|
||||
ui_tag tag = {.hash = mp_hash_aes_string(string)};
|
||||
return(tag);
|
||||
}
|
||||
|
||||
void ui_tag_box(ui_box* box, str8 string)
|
||||
void ui_tag_box_str8(ui_box* box, str8 string)
|
||||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
ui_tag_elt* elt = mem_arena_alloc_type(&ui->frameArena, ui_tag_elt);
|
||||
elt->tag = ui_tag_make(string);
|
||||
elt->tag = ui_tag_make_str8(string);
|
||||
ListAppend(&box->tags, &elt->listElt);
|
||||
}
|
||||
|
||||
void ui_tag_next(str8 string)
|
||||
void ui_tag_next_str8(str8 string)
|
||||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
ui_tag_elt* elt = mem_arena_alloc_type(&ui->frameArena, ui_tag_elt);
|
||||
elt->tag = ui_tag_make(string);
|
||||
elt->tag = ui_tag_make_str8(string);
|
||||
ListAppend(&ui->nextBoxTags, &elt->listElt);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// key hashing and caching
|
||||
//-----------------------------------------------------------------------------
|
||||
ui_key ui_key_from_string(str8 string)
|
||||
ui_key ui_key_make_str8(str8 string)
|
||||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
u64 seed = 0;
|
||||
|
@ -233,6 +249,23 @@ ui_key ui_key_from_string(str8 string)
|
|||
return(key);
|
||||
}
|
||||
|
||||
ui_key ui_key_make_path(str8_list path)
|
||||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
u64 seed = 0;
|
||||
ui_box* parent = ui_box_top();
|
||||
if(parent)
|
||||
{
|
||||
seed = parent->key.hash;
|
||||
}
|
||||
for_each_in_list(&path.list, elt, str8_elt, listElt)
|
||||
{
|
||||
seed = mp_hash_aes_string_seed(elt->string, seed);
|
||||
}
|
||||
ui_key key = {seed};
|
||||
return(key);
|
||||
}
|
||||
|
||||
bool ui_key_equal(ui_key a, ui_key b)
|
||||
{
|
||||
return(a.hash == b.hash);
|
||||
|
@ -244,8 +277,9 @@ void ui_box_cache(ui_context* ui, ui_box* box)
|
|||
ListAppend(&(ui->boxMap[index]), &box->bucketElt);
|
||||
}
|
||||
|
||||
ui_box* ui_box_lookup_with_key(ui_context* ui, ui_key key)
|
||||
ui_box* ui_box_lookup_key(ui_key key)
|
||||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
u64 index = key.hash & (UI_BOX_MAP_BUCKET_COUNT-1);
|
||||
|
||||
for_each_in_list(&ui->boxMap[index], box, ui_box, bucketElt)
|
||||
|
@ -260,14 +294,8 @@ ui_box* ui_box_lookup_with_key(ui_context* ui, ui_key key)
|
|||
|
||||
ui_box* ui_box_lookup_str8(str8 string)
|
||||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
ui_key key = ui_key_from_string(string);
|
||||
return(ui_box_lookup_with_key(ui, key));
|
||||
}
|
||||
|
||||
ui_box* ui_box_lookup(const char* string)
|
||||
{
|
||||
return(ui_box_lookup_str8(str8_from_cstring((char*)string)));
|
||||
ui_key key = ui_key_make_str8(string);
|
||||
return(ui_box_lookup_key(key));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -308,9 +336,58 @@ void ui_style_prev(ui_pattern pattern, ui_style* style, ui_style_mask mask)
|
|||
*rule->style = *style;
|
||||
|
||||
ListAppend(&ui->lastBox->afterRules, &rule->boxElt);
|
||||
rule->owner = ui->lastBox;
|
||||
}
|
||||
}
|
||||
|
||||
void ui_style_box_before(ui_box* box, ui_pattern pattern, ui_style* style, ui_style_mask mask)
|
||||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
if(ui)
|
||||
{
|
||||
ui_style_rule* rule = mem_arena_alloc_type(&ui->frameArena, ui_style_rule);
|
||||
rule->pattern = pattern;
|
||||
rule->mask = mask;
|
||||
rule->style = mem_arena_alloc_type(&ui->frameArena, ui_style);
|
||||
*rule->style = *style;
|
||||
|
||||
ListAppend(&box->beforeRules, &rule->boxElt);
|
||||
rule->owner = box;
|
||||
}
|
||||
}
|
||||
|
||||
ui_pattern ui_pattern_all(void)
|
||||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
ui_pattern pattern = {0};
|
||||
ui_pattern_push(&ui->frameArena, &pattern, (ui_selector){.kind = UI_SEL_ANY});
|
||||
return(pattern);
|
||||
}
|
||||
|
||||
ui_pattern ui_pattern_owner(void)
|
||||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
ui_pattern pattern = {0};
|
||||
ui_pattern_push(&ui->frameArena, &pattern, (ui_selector){.kind = UI_SEL_OWNER});
|
||||
return(pattern);
|
||||
}
|
||||
|
||||
void ui_box_set_size(ui_box* box, ui_axis axis, ui_size_kind kind, f32 value, f32 strictness)
|
||||
{
|
||||
ui_style style = {0};
|
||||
style.size.s[axis] = (ui_size){kind, value, strictness};
|
||||
ui_style_mask mask = (axis == UI_AXIS_X) ? UI_STYLE_SIZE_X : UI_STYLE_SIZE_Y;
|
||||
ui_style_box_before(box, ui_pattern_owner(), &style, mask);
|
||||
}
|
||||
|
||||
void ui_box_set_layout(ui_box* box, ui_axis axis, ui_align alignX, ui_align alignY)
|
||||
{
|
||||
ui_style style = {.layout = {axis, .align.x = alignX, .align.y = alignY}};
|
||||
ui_style_box_before(box, ui_pattern_owner(), &style, UI_STYLE_LAYOUT);
|
||||
}
|
||||
|
||||
void ui_apply_style_with_mask(ui_style* dst, ui_style* src, ui_style_mask mask);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ui boxes
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -363,8 +440,8 @@ ui_box* ui_box_make_str8(str8 string, ui_flags flags)
|
|||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
|
||||
ui_key key = ui_key_from_string(string);
|
||||
ui_box* box = ui_box_lookup_with_key(ui, key);
|
||||
ui_key key = ui_key_make_str8(string);
|
||||
ui_box* box = ui_box_lookup_key(key);
|
||||
|
||||
if(!box)
|
||||
{
|
||||
|
@ -402,27 +479,28 @@ ui_box* ui_box_make_str8(str8 string, ui_flags flags)
|
|||
box->string = str8_push_copy(&ui->frameArena, string);
|
||||
box->flags = flags;
|
||||
|
||||
//NOTE: create style and setup non-inherited attributes to default values
|
||||
box->targetStyle = mem_arena_alloc_type(&ui->frameArena, ui_style);
|
||||
memset(box->targetStyle, 0, sizeof(ui_style));
|
||||
ui_apply_style_with_mask(box->targetStyle, &UI_STYLE_DEFAULTS, ~0ULL);
|
||||
|
||||
//NOTE: set tags, before rules and last box
|
||||
box->tags = ui->nextBoxTags;
|
||||
ui->nextBoxTags = (list_info){0};
|
||||
|
||||
box->beforeRules = ui->nextBoxRules;
|
||||
for_each_in_list(&box->beforeRules, rule, ui_style_rule, boxElt)
|
||||
{
|
||||
rule->owner = box;
|
||||
}
|
||||
ui->nextBoxRules = (list_info){0};
|
||||
|
||||
box->afterRules = (list_info){0};
|
||||
|
||||
ui->lastBox = box;
|
||||
|
||||
return(box);
|
||||
}
|
||||
|
||||
ui_box* ui_box_make(const char* cstring, ui_flags flags)
|
||||
{
|
||||
str8 string = str8_from_cstring((char*)cstring);
|
||||
return(ui_box_make_str8(string, flags));
|
||||
}
|
||||
|
||||
ui_box* ui_box_begin_str8(str8 string, ui_flags flags)
|
||||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
|
@ -431,12 +509,6 @@ ui_box* ui_box_begin_str8(str8 string, ui_flags flags)
|
|||
return(box);
|
||||
}
|
||||
|
||||
ui_box* ui_box_begin(const char* cstring, ui_flags flags)
|
||||
{
|
||||
str8 string = str8_from_cstring((char*)cstring);
|
||||
return(ui_box_begin_str8(string, flags));
|
||||
}
|
||||
|
||||
ui_box* ui_box_end(void)
|
||||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
|
@ -456,18 +528,7 @@ void ui_box_set_render_proc(ui_box* box, ui_box_render_proc proc, void* data)
|
|||
box->renderProc = proc;
|
||||
box->renderData = data;
|
||||
}
|
||||
/*
|
||||
void ui_box_set_size(ui_box* box, ui_axis axis, ui_size_kind kind, f32 value, f32 strictness)
|
||||
{
|
||||
box->targetStyle->size[axis] = (ui_size){kind, value, strictness};
|
||||
}
|
||||
|
||||
void ui_box_set_floating(ui_box* box, ui_axis axis, f32 pos)
|
||||
{
|
||||
box->floating[axis] = true;
|
||||
box->floatTarget.c[axis] = pos;
|
||||
}
|
||||
*/
|
||||
void ui_box_set_closed(ui_box* box, bool closed)
|
||||
{
|
||||
box->closed = closed;
|
||||
|
@ -619,20 +680,20 @@ void ui_box_compute_styling(ui_context* ui, ui_box* box)
|
|||
{
|
||||
if(flags & UI_STYLE_ANIMATE_SIZE_X)
|
||||
{
|
||||
ui_animate_ui_size(ui, &box->style.size[UI_AXIS_X], targetStyle->size[UI_AXIS_X], animationTime);
|
||||
ui_animate_ui_size(ui, &box->style.size.s[UI_AXIS_X], targetStyle->size.s[UI_AXIS_X], animationTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
box->style.size[UI_AXIS_X] = targetStyle->size[UI_AXIS_X];
|
||||
box->style.size.s[UI_AXIS_X] = targetStyle->size.s[UI_AXIS_X];
|
||||
}
|
||||
|
||||
if(flags & UI_STYLE_ANIMATE_SIZE_Y)
|
||||
{
|
||||
ui_animate_ui_size(ui, &box->style.size[UI_AXIS_Y], targetStyle->size[UI_AXIS_Y], animationTime);
|
||||
ui_animate_ui_size(ui, &box->style.size.s[UI_AXIS_Y], targetStyle->size.s[UI_AXIS_Y], animationTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
box->style.size[UI_AXIS_Y] = targetStyle->size[UI_AXIS_Y];
|
||||
box->style.size.s[UI_AXIS_Y] = targetStyle->size.s[UI_AXIS_Y];
|
||||
}
|
||||
|
||||
if(flags & UI_STYLE_ANIMATE_COLOR)
|
||||
|
@ -689,6 +750,9 @@ void ui_box_compute_styling(ui_context* ui, ui_box* box)
|
|||
{
|
||||
box->style.roundness = targetStyle->roundness;
|
||||
}
|
||||
|
||||
//TODO: non animatable attributes use mask
|
||||
box->style.layout = targetStyle->layout;
|
||||
box->style.font = targetStyle->font;
|
||||
}
|
||||
}
|
||||
|
@ -697,11 +761,45 @@ void ui_apply_style_with_mask(ui_style* dst, ui_style* src, ui_style_mask mask)
|
|||
{
|
||||
if(mask & UI_STYLE_SIZE_X)
|
||||
{
|
||||
dst->size[UI_AXIS_X] = src->size[UI_AXIS_X];
|
||||
dst->size.s[UI_AXIS_X] = src->size.s[UI_AXIS_X];
|
||||
}
|
||||
if(mask & UI_STYLE_SIZE_Y)
|
||||
{
|
||||
dst->size[UI_AXIS_Y] = src->size[UI_AXIS_Y];
|
||||
dst->size.s[UI_AXIS_Y] = src->size.s[UI_AXIS_Y];
|
||||
}
|
||||
if(mask & UI_STYLE_LAYOUT_AXIS)
|
||||
{
|
||||
dst->layout.axis = src->layout.axis;
|
||||
}
|
||||
if(mask & UI_STYLE_LAYOUT_ALIGN_X)
|
||||
{
|
||||
dst->layout.align.x = src->layout.align.x;
|
||||
}
|
||||
if(mask & UI_STYLE_LAYOUT_ALIGN_Y)
|
||||
{
|
||||
dst->layout.align.y = src->layout.align.y;
|
||||
}
|
||||
if(mask & UI_STYLE_LAYOUT_SPACING)
|
||||
{
|
||||
dst->layout.spacing = src->layout.spacing;
|
||||
}
|
||||
if(mask & UI_STYLE_LAYOUT_MARGIN_X)
|
||||
{
|
||||
dst->layout.margin.x = src->layout.margin.y;
|
||||
}
|
||||
if(mask & UI_STYLE_LAYOUT_MARGIN_Y)
|
||||
{
|
||||
dst->layout.margin.y = src->layout.margin.y;
|
||||
}
|
||||
if(mask & UI_STYLE_FLOAT_X)
|
||||
{
|
||||
dst->floating[UI_AXIS_X] = src->floating[UI_AXIS_X];
|
||||
dst->floatTarget.x = src->floatTarget.x;
|
||||
}
|
||||
if(mask & UI_STYLE_FLOAT_Y)
|
||||
{
|
||||
dst->floating[UI_AXIS_Y] = src->floating[UI_AXIS_Y];
|
||||
dst->floatTarget.y = src->floatTarget.y;
|
||||
}
|
||||
if(mask & UI_STYLE_COLOR)
|
||||
{
|
||||
|
@ -742,11 +840,19 @@ void ui_apply_style_with_mask(ui_style* dst, ui_style* src, ui_style_mask mask)
|
|||
}
|
||||
|
||||
|
||||
bool ui_style_selector_match(ui_box* box, ui_selector* selector)
|
||||
bool ui_style_selector_match(ui_box* box, ui_style_rule* rule, ui_selector* selector)
|
||||
{
|
||||
bool res = false;
|
||||
switch(selector->kind)
|
||||
{
|
||||
case UI_SEL_ANY:
|
||||
res = true;
|
||||
break;
|
||||
|
||||
case UI_SEL_OWNER:
|
||||
res = (box == rule->owner);
|
||||
break;
|
||||
|
||||
case UI_SEL_TEXT:
|
||||
res = !str8_cmp(box->string, selector->text);
|
||||
break;
|
||||
|
@ -763,17 +869,22 @@ bool ui_style_selector_match(ui_box* box, ui_selector* selector)
|
|||
}
|
||||
} break;
|
||||
|
||||
case UI_SEL_HOVER:
|
||||
res = box->hot;
|
||||
break;
|
||||
|
||||
case UI_SEL_ACTIVE:
|
||||
res = box->active;
|
||||
break;
|
||||
|
||||
case UI_SEL_DRAGGING:
|
||||
res = box->dragging;
|
||||
break;
|
||||
case UI_SEL_STATUS:
|
||||
{
|
||||
res = true;
|
||||
if(selector->status & UI_HOVER)
|
||||
{
|
||||
res = res && box->hot;
|
||||
}
|
||||
if(selector->status & UI_ACTIVE)
|
||||
{
|
||||
res = res && box->active;
|
||||
}
|
||||
if(selector->status & UI_DRAGGING)
|
||||
{
|
||||
res = res && box->dragging;
|
||||
}
|
||||
} break;
|
||||
|
||||
case UI_SEL_KEY:
|
||||
res = ui_key_equal(box->key, selector->key);
|
||||
|
@ -786,9 +897,18 @@ bool ui_style_selector_match(ui_box* box, ui_selector* selector)
|
|||
void ui_style_rule_match(ui_context* ui, ui_box* box, ui_style_rule* rule, list_info* buildList, list_info* tmpList)
|
||||
{
|
||||
ui_selector* selector = ListFirstEntry(&rule->pattern.l, ui_selector, listElt);
|
||||
if(ui_style_selector_match(box, selector))
|
||||
bool match = ui_style_selector_match(box, rule, selector);
|
||||
|
||||
selector = ListNextEntry(&rule->pattern.l, selector, ui_selector, listElt);
|
||||
while(match && selector && selector->op == UI_SEL_AND)
|
||||
{
|
||||
if(!selector->listElt.next)
|
||||
match = match && ui_style_selector_match(box, rule, selector);
|
||||
selector = ListNextEntry(&rule->pattern.l, selector, ui_selector, listElt);
|
||||
}
|
||||
|
||||
if(match)
|
||||
{
|
||||
if(!selector)
|
||||
{
|
||||
ui_apply_style_with_mask(box->targetStyle, rule->style, rule->mask);
|
||||
}
|
||||
|
@ -798,10 +918,10 @@ void ui_style_rule_match(ui_context* ui, ui_box* box, ui_style_rule* rule, list_
|
|||
ui_style_rule* derived = mem_arena_alloc_type(&ui->frameArena, ui_style_rule);
|
||||
derived->mask = rule->mask;
|
||||
derived->style = rule->style;
|
||||
derived->pattern.l = (list_info){selector->listElt.next, rule->pattern.l.last};
|
||||
derived->pattern.l = (list_info){&selector->listElt, rule->pattern.l.last};
|
||||
|
||||
ListPush(buildList, &derived->buildElt);
|
||||
ListPush(tmpList, &derived->tmpElt);
|
||||
ListAppend(buildList, &derived->buildElt);
|
||||
ListAppend(tmpList, &derived->tmpElt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -825,6 +945,7 @@ void ui_styling_prepass(ui_context* ui, ui_box* box, list_info* before, list_inf
|
|||
for_each_in_list(&box->beforeRules, rule, ui_style_rule, boxElt)
|
||||
{
|
||||
ListAppend(before, &rule->buildElt);
|
||||
ListAppend(&tmpBefore, &rule->tmpElt);
|
||||
ui_style_rule_match(ui, box, rule, before, &tmpBefore);
|
||||
}
|
||||
|
||||
|
@ -836,6 +957,7 @@ void ui_styling_prepass(ui_context* ui, ui_box* box, list_info* before, list_inf
|
|||
for_each_in_list(&box->afterRules, rule, ui_style_rule, boxElt)
|
||||
{
|
||||
ListAppend(after, &rule->buildElt);
|
||||
ListAppend(&tmpAfter, &rule->tmpElt);
|
||||
ui_style_rule_match(ui, box, rule, after, &tmpAfter);
|
||||
}
|
||||
|
||||
|
@ -850,8 +972,8 @@ void ui_styling_prepass(ui_context* ui, ui_box* box, list_info* before, list_inf
|
|||
ui_style* style = &box->style;
|
||||
|
||||
mp_rect textBox = {};
|
||||
ui_size desiredSize[2] = {box->style.size[UI_AXIS_X],
|
||||
box->style.size[UI_AXIS_Y]};
|
||||
ui_size desiredSize[2] = {box->style.size.s[UI_AXIS_X],
|
||||
box->style.size.s[UI_AXIS_Y]};
|
||||
|
||||
if( desiredSize[UI_AXIS_X].kind == UI_SIZE_TEXT
|
||||
||desiredSize[UI_AXIS_Y].kind == UI_SIZE_TEXT)
|
||||
|
@ -897,15 +1019,16 @@ void ui_layout_upward_dependent_size(ui_context* ui, ui_box* box, int axis)
|
|||
return;
|
||||
}
|
||||
|
||||
ui_size* size = &box->style.size[axis];
|
||||
ui_size* size = &box->style.size.s[axis];
|
||||
|
||||
if(size->kind == UI_SIZE_PARENT_RATIO)
|
||||
if(size->kind == UI_SIZE_PARENT)
|
||||
{
|
||||
ui_box* parent = box->parent;
|
||||
if( parent
|
||||
&& parent->style.size[axis].kind != UI_SIZE_CHILDREN)
|
||||
&& parent->style.size.s[axis].kind != UI_SIZE_CHILDREN)
|
||||
{
|
||||
box->rect.c[2+axis] = parent->rect.c[2+axis] * size->value;
|
||||
f32 margin = parent->style.layout.margin.m[axis];
|
||||
box->rect.c[2+axis] = maximum(0, parent->rect.c[2+axis] - 2*margin) * size->value;
|
||||
}
|
||||
//TODO else?
|
||||
}
|
||||
|
@ -919,8 +1042,10 @@ void ui_layout_upward_dependent_size(ui_context* ui, ui_box* box, int axis)
|
|||
void ui_layout_downward_dependent_size(ui_context* ui, ui_box* box, int axis)
|
||||
{
|
||||
f32 sum = 0;
|
||||
|
||||
if(box->style.layout.axis == axis)
|
||||
{
|
||||
int count = 0;
|
||||
for_each_in_list(&box->children, child, ui_box, listElt)
|
||||
{
|
||||
if(!ui_box_hidden(child))
|
||||
|
@ -929,9 +1054,11 @@ void ui_layout_downward_dependent_size(ui_context* ui, ui_box* box, int axis)
|
|||
if(!child->style.floating[axis])
|
||||
{
|
||||
sum += child->rect.c[2+axis];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
sum += maximum(0, count-1)*box->style.layout.spacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -950,10 +1077,11 @@ void ui_layout_downward_dependent_size(ui_context* ui, ui_box* box, int axis)
|
|||
|
||||
box->childrenSum[axis] = sum;
|
||||
|
||||
ui_size* size = &box->style.size[axis];
|
||||
ui_size* size = &box->style.size.s[axis];
|
||||
if(size->kind == UI_SIZE_CHILDREN)
|
||||
{
|
||||
box->rect.c[2+axis] = sum + size->value*2;
|
||||
f32 margin = box->style.layout.margin.m[axis];
|
||||
box->rect.c[2+axis] = sum + margin*2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -976,20 +1104,17 @@ void ui_layout_compute_rect(ui_context* ui, ui_box* box, vec2 pos)
|
|||
|
||||
ui_axis layoutAxis = box->style.layout.axis;
|
||||
ui_axis secondAxis = (layoutAxis == UI_AXIS_X) ? UI_AXIS_Y : UI_AXIS_X;
|
||||
ui_align* align = box->style.layout.align;
|
||||
f32 spacing = box->style.layout.spacing;
|
||||
|
||||
ui_align* align = box->style.layout.align.a;
|
||||
|
||||
vec2 origin = {box->rect.x - box->scroll.x,
|
||||
box->rect.y - box->scroll.y};
|
||||
vec2 currentPos = origin;
|
||||
|
||||
vec2 margin = {0, 0};
|
||||
for(int i=0; i<UI_AXIS_COUNT; i++)
|
||||
{
|
||||
if(box->style.size[i].kind == UI_SIZE_CHILDREN)
|
||||
{
|
||||
margin.c[i] = box->style.size[i].value;
|
||||
}
|
||||
}
|
||||
vec2 margin = {box->style.layout.margin.x,
|
||||
box->style.layout.margin.y};
|
||||
|
||||
currentPos.x += margin.x;
|
||||
currentPos.y += margin.y;
|
||||
|
||||
|
@ -1038,7 +1163,7 @@ void ui_layout_compute_rect(ui_context* ui, ui_box* box, vec2 pos)
|
|||
|
||||
if(!child->style.floating[layoutAxis])
|
||||
{
|
||||
currentPos.c[layoutAxis] += child->rect.c[2+layoutAxis];
|
||||
currentPos.c[layoutAxis] += child->rect.c[2+layoutAxis] + spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1128,7 +1253,7 @@ void ui_draw_box(ui_box* box)
|
|||
|
||||
if(box->flags & UI_FLAG_CLIP)
|
||||
{
|
||||
mg_clip_push(box->rect.x, box->rect.y, box->rect.w, box->rect.h);
|
||||
// mg_clip_push(box->rect.x, box->rect.y, box->rect.w, box->rect.h);
|
||||
}
|
||||
|
||||
if(box->flags & UI_FLAG_DRAW_BACKGROUND)
|
||||
|
@ -1165,7 +1290,7 @@ void ui_draw_box(ui_box* box)
|
|||
|
||||
if(box->flags & UI_FLAG_CLIP)
|
||||
{
|
||||
mg_clip_pop();
|
||||
// mg_clip_pop();
|
||||
}
|
||||
|
||||
if(box->flags & UI_FLAG_DRAW_BORDER)
|
||||
|
@ -1216,24 +1341,27 @@ void ui_begin_frame(u32 width, u32 height, ui_style defaultStyle)
|
|||
ui->clipStack = 0;
|
||||
ui->z = 0;
|
||||
|
||||
// ui_push_size(UI_AXIS_X, UI_SIZE_PIXELS, width, 0);
|
||||
// ui_push_size(UI_AXIS_Y, UI_SIZE_PIXELS, height, 0);
|
||||
defaultStyle.size.s[UI_AXIS_X] = (ui_size){UI_SIZE_PIXELS, width, 0};
|
||||
defaultStyle.size.s[UI_AXIS_Y] = (ui_size){UI_SIZE_PIXELS, height, 0};
|
||||
|
||||
ui->root = ui_box_begin("_root_", 0);
|
||||
*ui->root->targetStyle = defaultStyle;
|
||||
|
||||
ui_box* contents = ui_box_make("_contents_", 0);
|
||||
// ui_box_set_floating(contents, UI_AXIS_X, 0);
|
||||
// ui_box_set_floating(contents, UI_AXIS_Y, 0);
|
||||
ui_style_next(ui_pattern_owner(),
|
||||
&(ui_style){.layout = {UI_AXIS_Y, UI_ALIGN_START, UI_ALIGN_START},
|
||||
.floating = {true, true},
|
||||
.floatTarget = {0, 0}},
|
||||
UI_STYLE_LAYOUT | UI_STYLE_FLOAT_X | UI_STYLE_FLOAT_Y);
|
||||
|
||||
// ui_box_set_layout(contents, UI_AXIS_Y, UI_ALIGN_START, UI_ALIGN_START);
|
||||
ui_box* contents = ui_box_make("_contents_", 0);
|
||||
|
||||
ui_style_next(ui_pattern_owner(),
|
||||
&(ui_style){.layout = {UI_AXIS_Y, UI_ALIGN_START, UI_ALIGN_START},
|
||||
.floating = {true, true},
|
||||
.floatTarget = {0, 0}},
|
||||
UI_STYLE_LAYOUT | UI_STYLE_FLOAT_X | UI_STYLE_FLOAT_Y);
|
||||
|
||||
ui->overlay = ui_box_make("_overlay_", 0);
|
||||
// ui_box_set_floating(ui->overlay, UI_AXIS_X, 0);
|
||||
// ui_box_set_floating(ui->overlay, UI_AXIS_Y, 0);
|
||||
|
||||
// ui_pop_size(UI_AXIS_X);
|
||||
// ui_pop_size(UI_AXIS_Y);
|
||||
|
||||
ui->nextBoxRules = (list_info){0};
|
||||
ui->nextBoxTags = (list_info){0};
|
||||
|
@ -1300,11 +1428,14 @@ void ui_cleanup(void)
|
|||
|
||||
ui_sig ui_label_str8(str8 label)
|
||||
{
|
||||
ui_style_next(ui_pattern_all(),
|
||||
&(ui_style){.size.width = {UI_SIZE_TEXT, 0, 0},
|
||||
.size.height = {UI_SIZE_TEXT, 0, 0}},
|
||||
UI_STYLE_SIZE_X | UI_STYLE_SIZE_Y);
|
||||
|
||||
ui_flags flags = UI_FLAG_CLIP
|
||||
| UI_FLAG_DRAW_TEXT;
|
||||
ui_box* box = ui_box_make_str8(label, flags);
|
||||
// ui_box_set_size(box, UI_AXIS_X, UI_SIZE_TEXT, 0, 0);
|
||||
// ui_box_set_size(box, UI_AXIS_Y, UI_SIZE_TEXT, 0, 0);
|
||||
|
||||
ui_sig sig = ui_box_sig(box);
|
||||
return(sig);
|
||||
|
@ -1317,18 +1448,48 @@ ui_sig ui_label(const char* label)
|
|||
|
||||
ui_sig ui_button_str8(str8 label)
|
||||
{
|
||||
ui_context* ui = ui_get_context();
|
||||
|
||||
ui_style defaultStyle = {.size.width = {UI_SIZE_TEXT, 5, 0},
|
||||
.size.height = {UI_SIZE_TEXT, 5, 0},
|
||||
.bgColor = {0.5, 0.5, 0.5, 1},
|
||||
.borderColor = {0.2, 0.2, 0.2, 1},
|
||||
.borderSize = 2,
|
||||
.roundness = 10};
|
||||
|
||||
ui_style_mask defaultMask = UI_STYLE_SIZE_X
|
||||
| UI_STYLE_SIZE_Y
|
||||
| UI_STYLE_BG_COLOR
|
||||
| UI_STYLE_BORDER_COLOR
|
||||
| UI_STYLE_BORDER_SIZE
|
||||
| UI_STYLE_ROUNDNESS;
|
||||
|
||||
ui_style_next(ui_pattern_all(), &defaultStyle, defaultMask);
|
||||
|
||||
ui_style activeStyle = {.bgColor = {0.3, 0.3, 0.3, 1},
|
||||
.borderColor = {0.2, 0.2, 0.2, 1},
|
||||
.borderSize = 4};
|
||||
ui_style_mask activeMask = UI_STYLE_BG_COLOR
|
||||
| UI_STYLE_BORDER_COLOR
|
||||
| UI_STYLE_BORDER_SIZE;
|
||||
ui_pattern activePattern = {0};
|
||||
ui_pattern_push(&ui->frameArena,
|
||||
&activePattern,
|
||||
(ui_selector){.kind = UI_SEL_STATUS,
|
||||
.status = UI_ACTIVE|UI_HOVER});
|
||||
ui_style_next(activePattern, &activeStyle, activeMask);
|
||||
|
||||
ui_flags flags = UI_FLAG_CLICKABLE
|
||||
| UI_FLAG_CLIP
|
||||
| UI_FLAG_DRAW_FOREGROUND
|
||||
| UI_FLAG_DRAW_BACKGROUND
|
||||
| UI_FLAG_DRAW_BORDER
|
||||
| UI_FLAG_DRAW_TEXT
|
||||
| UI_FLAG_HOT_ANIMATION
|
||||
| UI_FLAG_ACTIVE_ANIMATION;
|
||||
|
||||
ui_box* box = ui_box_make_str8(label, flags);
|
||||
ui_tag_box(box, "button");
|
||||
|
||||
//TODO
|
||||
// ui_box_set_tag(box, UI_STYLE_TAG_BUTTON);
|
||||
ui_sig sig = ui_box_sig(box);
|
||||
|
||||
if(sig.hovering)
|
||||
|
@ -1356,6 +1517,112 @@ ui_sig ui_button(const char* label)
|
|||
return(ui_button_str8(str8_from_cstring((char*)label)));
|
||||
}
|
||||
|
||||
|
||||
ui_box* ui_slider(const char* label, f32 thumbRatio, f32* scrollValue)
|
||||
{
|
||||
ui_box* frame = ui_box_begin(label, 0);
|
||||
{
|
||||
ui_style_box_before(frame, ui_pattern_all(), &(ui_style){0}, UI_STYLE_LAYOUT);
|
||||
|
||||
ui_axis trackAxis = (frame->rect.w > frame->rect.h) ? UI_AXIS_X : UI_AXIS_Y;
|
||||
ui_axis secondAxis = (trackAxis == UI_AXIS_Y) ? UI_AXIS_X : UI_AXIS_Y;
|
||||
|
||||
f32 roundness = 0.5*frame->rect.c[2+secondAxis];
|
||||
f32 animationTime = 0.5;
|
||||
|
||||
ui_style trackStyle = {.bgColor = {0.5, 0.5, 0.5, 1},
|
||||
.roundness = roundness};
|
||||
ui_style thumbStyle = {.bgColor = {0.3, 0.3, 0.3, 1},
|
||||
.roundness = roundness};
|
||||
|
||||
ui_style_mask styleMask = UI_STYLE_BG_COLOR | UI_STYLE_ROUNDNESS;
|
||||
|
||||
ui_flags trackFlags = UI_FLAG_CLIP
|
||||
| UI_FLAG_DRAW_BACKGROUND
|
||||
| UI_FLAG_HOT_ANIMATION
|
||||
| UI_FLAG_ACTIVE_ANIMATION;
|
||||
|
||||
ui_box* track = ui_box_begin("track", trackFlags);
|
||||
ui_style_box_before(track, ui_pattern_owner(), &trackStyle, styleMask);
|
||||
|
||||
ui_box_set_size(track, trackAxis, UI_SIZE_PARENT, 1., 0);
|
||||
ui_box_set_size(track, secondAxis, UI_SIZE_PARENT, 1., 0);
|
||||
ui_box_set_layout(track, trackAxis, UI_ALIGN_START, UI_ALIGN_START);
|
||||
|
||||
f32 beforeRatio = (*scrollValue) * (1. - thumbRatio);
|
||||
f32 afterRatio = (1. - *scrollValue) * (1. - thumbRatio);
|
||||
|
||||
ui_box* beforeSpacer = ui_box_make("before", 0);
|
||||
ui_box_set_size(beforeSpacer, trackAxis, UI_SIZE_PARENT, beforeRatio, 0);
|
||||
ui_box_set_size(beforeSpacer, secondAxis, UI_SIZE_PARENT, 1., 0);
|
||||
|
||||
ui_flags thumbFlags = UI_FLAG_CLICKABLE
|
||||
| UI_FLAG_DRAW_BACKGROUND
|
||||
| UI_FLAG_HOT_ANIMATION
|
||||
| UI_FLAG_ACTIVE_ANIMATION;
|
||||
|
||||
ui_box* thumb = ui_box_make("thumb", thumbFlags);
|
||||
ui_style_box_before(thumb, ui_pattern_owner(), &thumbStyle, styleMask);
|
||||
ui_box_set_size(thumb, trackAxis, UI_SIZE_PARENT, thumbRatio, 0);
|
||||
ui_box_set_size(thumb, secondAxis, UI_SIZE_PARENT, 1., 0);
|
||||
|
||||
ui_box* afterSpacer = ui_box_make("after", 0);
|
||||
ui_box_set_size(afterSpacer, trackAxis, UI_SIZE_PARENT, afterRatio, 0);
|
||||
ui_box_set_size(afterSpacer, secondAxis, UI_SIZE_PARENT, 1., 0);
|
||||
ui_box_end();
|
||||
|
||||
//NOTE: interaction
|
||||
ui_sig thumbSig = ui_box_sig(thumb);
|
||||
if(thumbSig.dragging)
|
||||
{
|
||||
f32 trackExtents = track->rect.c[2+trackAxis] - thumb->rect.c[2+trackAxis];
|
||||
f32 delta = thumbSig.delta.c[trackAxis]/trackExtents;
|
||||
f32 oldValue = *scrollValue;
|
||||
|
||||
*scrollValue += delta;
|
||||
*scrollValue = Clamp(*scrollValue, 0, 1);
|
||||
}
|
||||
|
||||
ui_sig trackSig = ui_box_sig(track);
|
||||
|
||||
if(ui_box_active(frame))
|
||||
{
|
||||
//NOTE: activated from outside
|
||||
ui_box_set_hot(track, true);
|
||||
ui_box_set_hot(thumb, true);
|
||||
ui_box_activate(track);
|
||||
ui_box_activate(thumb);
|
||||
}
|
||||
|
||||
if(trackSig.hovering)
|
||||
{
|
||||
ui_box_set_hot(track, true);
|
||||
ui_box_set_hot(thumb, true);
|
||||
}
|
||||
else if(thumbSig.wheel.c[trackAxis] == 0)
|
||||
{
|
||||
ui_box_set_hot(track, false);
|
||||
ui_box_set_hot(thumb, false);
|
||||
}
|
||||
|
||||
if(thumbSig.dragging)
|
||||
{
|
||||
ui_box_activate(track);
|
||||
ui_box_activate(thumb);
|
||||
}
|
||||
else if(thumbSig.wheel.c[trackAxis] == 0)
|
||||
{
|
||||
ui_box_deactivate(track);
|
||||
ui_box_deactivate(thumb);
|
||||
ui_box_deactivate(frame);
|
||||
}
|
||||
|
||||
} ui_box_end();
|
||||
|
||||
return(frame);
|
||||
}
|
||||
|
||||
|
||||
ui_box* ui_scrollbar(const char* label, f32 thumbRatio, f32* scrollValue)
|
||||
{
|
||||
ui_box* frame = ui_box_begin(label, 0);
|
||||
|
@ -1366,6 +1633,7 @@ ui_box* ui_scrollbar(const char* label, f32 thumbRatio, f32* scrollValue)
|
|||
f32 roundness = 0.5*frame->rect.c[2+secondAxis];
|
||||
f32 animationTime = 0.5;
|
||||
|
||||
|
||||
/* ui_push_bg_color((mg_color){0, 0, 0, 0});
|
||||
ui_push_fg_color((mg_color){0, 0, 0, 0});
|
||||
ui_push_roundness(roundness);
|
||||
|
@ -1383,16 +1651,16 @@ ui_box* ui_scrollbar(const char* label, f32 thumbRatio, f32* scrollValue)
|
|||
|
||||
ui_box* track = ui_box_begin("track", trackFlags);
|
||||
|
||||
// ui_box_set_size(track, trackAxis, UI_SIZE_PARENT_RATIO, 1., 0);
|
||||
// ui_box_set_size(track, secondAxis, UI_SIZE_PARENT_RATIO, 1., 0);
|
||||
// ui_box_set_size(track, trackAxis, UI_SIZE_PARENT, 1., 0);
|
||||
// ui_box_set_size(track, secondAxis, UI_SIZE_PARENT, 1., 0);
|
||||
//ui_box_set_layout(track, trackAxis, UI_ALIGN_START, UI_ALIGN_START);
|
||||
|
||||
f32 beforeRatio = (*scrollValue) * (1. - thumbRatio);
|
||||
f32 afterRatio = (1. - *scrollValue) * (1. - thumbRatio);
|
||||
|
||||
ui_box* beforeSpacer = ui_box_make("before", 0);
|
||||
// ui_box_set_size(beforeSpacer, trackAxis, UI_SIZE_PARENT_RATIO, beforeRatio, 0);
|
||||
// ui_box_set_size(beforeSpacer, secondAxis, UI_SIZE_PARENT_RATIO, 1., 0);
|
||||
// ui_box_set_size(beforeSpacer, trackAxis, UI_SIZE_PARENT, beforeRatio, 0);
|
||||
// ui_box_set_size(beforeSpacer, secondAxis, UI_SIZE_PARENT, 1., 0);
|
||||
|
||||
ui_flags thumbFlags = UI_FLAG_CLICKABLE
|
||||
| UI_FLAG_DRAW_FOREGROUND
|
||||
|
@ -1400,12 +1668,12 @@ ui_box* ui_scrollbar(const char* label, f32 thumbRatio, f32* scrollValue)
|
|||
| UI_FLAG_ACTIVE_ANIMATION;
|
||||
|
||||
ui_box* thumb = ui_box_make("thumb", thumbFlags);
|
||||
// ui_box_set_size(thumb, trackAxis, UI_SIZE_PARENT_RATIO, thumbRatio, 0);
|
||||
// ui_box_set_size(thumb, secondAxis, UI_SIZE_PARENT_RATIO, 1., 0);
|
||||
// ui_box_set_size(thumb, trackAxis, UI_SIZE_PARENT, thumbRatio, 0);
|
||||
// ui_box_set_size(thumb, secondAxis, UI_SIZE_PARENT, 1., 0);
|
||||
|
||||
ui_box* afterSpacer = ui_box_make("after", 0);
|
||||
// ui_box_set_size(afterSpacer, trackAxis, UI_SIZE_PARENT_RATIO, afterRatio, 0);
|
||||
// ui_box_set_size(afterSpacer, secondAxis, UI_SIZE_PARENT_RATIO, 1., 0);
|
||||
// ui_box_set_size(afterSpacer, trackAxis, UI_SIZE_PARENT, afterRatio, 0);
|
||||
// ui_box_set_size(afterSpacer, secondAxis, UI_SIZE_PARENT, 1., 0);
|
||||
|
||||
ui_box_end();
|
||||
/*
|
||||
|
@ -1500,7 +1768,7 @@ void ui_panel_end()
|
|||
f32 sliderX = panel->scroll.x /(contentsW - panel->rect.w);
|
||||
|
||||
scrollBarX = ui_scrollbar("scrollerX", thumbRatioX, &sliderX);
|
||||
// ui_box_set_size(scrollBarX, UI_AXIS_X, UI_SIZE_PARENT_RATIO, 1., 0);
|
||||
// ui_box_set_size(scrollBarX, UI_AXIS_X, UI_SIZE_PARENT, 1., 0);
|
||||
// ui_box_set_size(scrollBarX, UI_AXIS_Y, UI_SIZE_PIXELS, 10, 0);
|
||||
|
||||
panel->scroll.x = sliderX * (contentsW - panel->rect.w);
|
||||
|
@ -1518,7 +1786,7 @@ void ui_panel_end()
|
|||
|
||||
scrollBarY = ui_scrollbar("scrollerY", thumbRatioY, &sliderY);
|
||||
// ui_box_set_size(scrollBarY, UI_AXIS_X, UI_SIZE_PIXELS, 10, 0);
|
||||
// ui_box_set_size(scrollBarY, UI_AXIS_Y, UI_SIZE_PARENT_RATIO, 1., 0);
|
||||
// ui_box_set_size(scrollBarY, UI_AXIS_Y, UI_SIZE_PARENT, 1., 0);
|
||||
|
||||
panel->scroll.y = sliderY * (contentsH - panel->rect.h);
|
||||
if(sig.hovering)
|
||||
|
@ -1575,7 +1843,7 @@ void ui_tooltip_end(void)
|
|||
void ui_menu_bar_begin(const char* name)
|
||||
{
|
||||
ui_box* bar = ui_box_begin(name, UI_FLAG_DRAW_BACKGROUND);
|
||||
// ui_box_set_size(bar, UI_AXIS_X, UI_SIZE_PARENT_RATIO, 1., 0);
|
||||
// ui_box_set_size(bar, UI_AXIS_X, UI_SIZE_PARENT, 1., 0);
|
||||
// ui_box_set_size(bar, UI_AXIS_Y, UI_SIZE_CHILDREN, 0, 0);
|
||||
//ui_box_set_layout(bar, UI_AXIS_X, UI_ALIGN_START, UI_ALIGN_START);
|
||||
/*
|
||||
|
|
175
src/ui.h
175
src/ui.h
|
@ -52,19 +52,39 @@ typedef enum
|
|||
UI_ALIGN_CENTER,
|
||||
} ui_align;
|
||||
|
||||
typedef union ui_layout_align
|
||||
{
|
||||
struct
|
||||
{
|
||||
ui_align x;
|
||||
ui_align y;
|
||||
};
|
||||
ui_align a[UI_AXIS_COUNT];
|
||||
} ui_layout_align;
|
||||
|
||||
typedef struct ui_layout
|
||||
{
|
||||
ui_axis axis;
|
||||
ui_align align[UI_AXIS_COUNT];
|
||||
f32 spacing;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
f32 x;
|
||||
f32 y;
|
||||
};
|
||||
f32 m[UI_AXIS_COUNT];
|
||||
} margin;
|
||||
ui_layout_align align;
|
||||
|
||||
} ui_layout;
|
||||
|
||||
typedef enum
|
||||
typedef enum ui_size_kind
|
||||
{
|
||||
UI_SIZE_TEXT,
|
||||
UI_SIZE_PIXELS,
|
||||
UI_SIZE_CHILDREN,
|
||||
UI_SIZE_PARENT_RATIO,
|
||||
UI_SIZE_PARENT,
|
||||
|
||||
} ui_size_kind;
|
||||
|
||||
|
@ -75,6 +95,16 @@ typedef struct ui_size
|
|||
f32 strictness;
|
||||
} ui_size;
|
||||
|
||||
typedef union ui_box_size
|
||||
{
|
||||
struct
|
||||
{
|
||||
ui_size width;
|
||||
ui_size height;
|
||||
};
|
||||
ui_size s[UI_AXIS_COUNT];
|
||||
} ui_box_size;
|
||||
|
||||
typedef enum { UI_STYLE_ANIMATE_SIZE_X = 1<<1,
|
||||
UI_STYLE_ANIMATE_SIZE_Y = 1<<2,
|
||||
UI_STYLE_ANIMATE_COLOR = 1<<3,
|
||||
|
@ -88,7 +118,7 @@ typedef enum { UI_STYLE_ANIMATE_SIZE_X = 1<<1,
|
|||
|
||||
typedef struct ui_style
|
||||
{
|
||||
ui_size size[UI_AXIS_COUNT];
|
||||
ui_box_size size;
|
||||
ui_layout layout;
|
||||
bool floating[UI_AXIS_COUNT];
|
||||
vec2 floatTarget;
|
||||
|
@ -109,16 +139,31 @@ enum
|
|||
UI_STYLE_NONE = 0,
|
||||
UI_STYLE_SIZE_X = 1<<1,
|
||||
UI_STYLE_SIZE_Y = 1<<2,
|
||||
UI_STYLE_COLOR = 1<<3,
|
||||
UI_STYLE_BG_COLOR = 1<<4,
|
||||
UI_STYLE_BORDER_COLOR = 1<<6,
|
||||
UI_STYLE_BORDER_SIZE = 1<<7,
|
||||
UI_STYLE_ROUNDNESS = 1<<8,
|
||||
UI_STYLE_FONT = 1<<9,
|
||||
UI_STYLE_FONT_SIZE = 1<<10,
|
||||
UI_STYLE_ANIMATION_TIME = 1<<11,
|
||||
UI_STYLE_ANIMATION_FLAGS = 1<<12,
|
||||
//...
|
||||
UI_STYLE_LAYOUT_AXIS = 1<<3,
|
||||
UI_STYLE_LAYOUT_ALIGN_X = 1<<4,
|
||||
UI_STYLE_LAYOUT_ALIGN_Y = 1<<5,
|
||||
UI_STYLE_LAYOUT_SPACING = 1<<6,
|
||||
UI_STYLE_LAYOUT_MARGIN_X = 1<<7,
|
||||
UI_STYLE_LAYOUT_MARGIN_Y = 1<<8,
|
||||
UI_STYLE_FLOAT_X = 1<<9,
|
||||
UI_STYLE_FLOAT_Y = 1<<10,
|
||||
UI_STYLE_COLOR = 1<<11,
|
||||
UI_STYLE_BG_COLOR = 1<<12,
|
||||
UI_STYLE_BORDER_COLOR = 1<<13,
|
||||
UI_STYLE_BORDER_SIZE = 1<<14,
|
||||
UI_STYLE_ROUNDNESS = 1<<15,
|
||||
UI_STYLE_FONT = 1<<16,
|
||||
UI_STYLE_FONT_SIZE = 1<<17,
|
||||
UI_STYLE_ANIMATION_TIME = 1<<18,
|
||||
UI_STYLE_ANIMATION_FLAGS = 1<<19,
|
||||
|
||||
//masks
|
||||
UI_STYLE_LAYOUT = UI_STYLE_LAYOUT_AXIS
|
||||
| UI_STYLE_LAYOUT_ALIGN_X
|
||||
| UI_STYLE_LAYOUT_ALIGN_Y
|
||||
| UI_STYLE_LAYOUT_SPACING
|
||||
| UI_STYLE_LAYOUT_MARGIN_X
|
||||
| UI_STYLE_LAYOUT_MARGIN_Y,
|
||||
|
||||
UI_STYLE_MASK_INHERITED = UI_STYLE_COLOR
|
||||
| UI_STYLE_FONT
|
||||
|
@ -132,43 +177,62 @@ typedef struct ui_tag { u64 hash; } ui_tag;
|
|||
|
||||
typedef enum
|
||||
{
|
||||
UI_SEL_ANY,
|
||||
UI_SEL_OWNER,
|
||||
UI_SEL_TEXT,
|
||||
UI_SEL_TAG,
|
||||
UI_SEL_HOVER,
|
||||
UI_SEL_ACTIVE,
|
||||
UI_SEL_DRAGGING,
|
||||
UI_SEL_STATUS,
|
||||
UI_SEL_KEY,
|
||||
//...
|
||||
} ui_selector_kind;
|
||||
|
||||
typedef u8 ui_status;
|
||||
enum
|
||||
{
|
||||
UI_NONE = 0,
|
||||
UI_HOVER = 1<<1,
|
||||
UI_ACTIVE = 1<<2,
|
||||
UI_DRAGGING = 1<<3,
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UI_SEL_DESCENDANT = 0,
|
||||
UI_SEL_AND = 1,
|
||||
//...
|
||||
} ui_selector_op;
|
||||
|
||||
typedef struct ui_selector
|
||||
{
|
||||
list_elt listElt;
|
||||
ui_selector_kind kind;
|
||||
ui_selector_op op;
|
||||
union
|
||||
{
|
||||
str8 text;
|
||||
ui_key key;
|
||||
ui_tag tag;
|
||||
ui_status status;
|
||||
//...
|
||||
};
|
||||
} ui_selector;
|
||||
|
||||
typedef struct ui_pattern { list_info l; } ui_pattern;
|
||||
|
||||
typedef struct ui_box ui_box;
|
||||
|
||||
typedef struct ui_style_rule
|
||||
{
|
||||
list_elt boxElt;
|
||||
list_elt buildElt;
|
||||
list_elt tmpElt;
|
||||
|
||||
ui_box* owner;
|
||||
ui_pattern pattern;
|
||||
ui_style_mask mask;
|
||||
ui_style* style;
|
||||
} ui_style_rule;
|
||||
|
||||
typedef struct ui_box ui_box;
|
||||
|
||||
typedef struct ui_sig
|
||||
{
|
||||
ui_box* box;
|
||||
|
@ -242,22 +306,38 @@ struct ui_box
|
|||
|
||||
typedef struct ui_context ui_context;
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// UI context initialization and frame cycle
|
||||
//-------------------------------------------------------------------------------------
|
||||
void ui_init(void);
|
||||
ui_context* ui_get_context(void);
|
||||
void ui_set_context(ui_context* context);
|
||||
|
||||
void ui_begin_frame(u32 width, u32 height, ui_style defaultStyle);
|
||||
void ui_end_frame(void);
|
||||
#define ui_frame(width, height, defaultStyle) defer_loop(ui_begin_frame(width, height, defaultStyle), ui_end_frame())
|
||||
|
||||
void ui_draw(void);
|
||||
|
||||
ui_box* ui_box_lookup(const char* string);
|
||||
#define ui_frame(width, height, defaultStyle) defer_loop(ui_begin_frame(width, height, defaultStyle), ui_end_frame())
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Box keys
|
||||
//-------------------------------------------------------------------------------------
|
||||
ui_key ui_key_make_str8(str8 string);
|
||||
ui_key ui_key_make_path(str8_list path);
|
||||
|
||||
ui_box* ui_box_lookup_key(ui_key key);
|
||||
ui_box* ui_box_lookup_str8(str8 string);
|
||||
ui_box* ui_box_make(const char* string, ui_flags flags);
|
||||
ui_box* ui_box_begin(const char* string, ui_flags flags);
|
||||
|
||||
// C-string helper
|
||||
#define ui_key_make(s) ui_key_make_str8(str8_lit(s))
|
||||
#define ui_box_lookup(s) ui_box_lookup_str8(str8_lit(s))
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Box hierarchy building
|
||||
//-------------------------------------------------------------------------------------
|
||||
ui_box* ui_box_make_str8(str8 string, ui_flags flags);
|
||||
ui_box* ui_box_begin_str8(str8 string, ui_flags flags);
|
||||
|
||||
ui_box* ui_box_end(void);
|
||||
#define ui_container(name, flags) defer_loop(ui_box_begin(name, flags), ui_box_end())
|
||||
|
||||
|
@ -265,10 +345,16 @@ void ui_box_push(ui_box* box);
|
|||
void ui_box_pop(void);
|
||||
ui_box* ui_box_top(void);
|
||||
|
||||
ui_tag ui_tag_make(str8 string);
|
||||
void ui_tag_box(ui_box* box, str8 string);
|
||||
void ui_tag_next(str8 string);
|
||||
void ui_box_set_render_proc(ui_box* box, ui_box_render_proc proc, void* data);
|
||||
|
||||
// C-string helpers
|
||||
#define ui_box_lookup(s) ui_box_lookup_str8(str8_lit(s))
|
||||
#define ui_box_make(s, flags) ui_box_make_str8(str8_lit(s), flags)
|
||||
#define ui_box_begin(s, flags) ui_box_begin_str8(str8_lit(s), flags)
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Box status and signals
|
||||
//-------------------------------------------------------------------------------------
|
||||
bool ui_box_closed(ui_box* box);
|
||||
void ui_box_set_closed(ui_box* box, bool closed);
|
||||
|
||||
|
@ -279,15 +365,23 @@ void ui_box_deactivate(ui_box* box);
|
|||
bool ui_box_hot(ui_box* box);
|
||||
void ui_box_set_hot(ui_box* box, bool hot);
|
||||
|
||||
void ui_box_set_render_proc(ui_box* box, ui_box_render_proc proc, void* data);
|
||||
/*
|
||||
void ui_box_set_layout(ui_box* box, ui_axis axis, ui_align alignX, ui_align alignY);
|
||||
void ui_box_set_size(ui_box* box, ui_axis axis, ui_size_kind kind, f32 value, f32 strictness);
|
||||
void ui_box_set_floating(ui_box* box, ui_axis axis, f32 pos);
|
||||
void ui_box_set_style_selector(ui_box* box, ui_style_selector selector);
|
||||
*/
|
||||
ui_sig ui_box_sig(ui_box* box);
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Tagging
|
||||
//-------------------------------------------------------------------------------------
|
||||
ui_tag ui_tag_make_str8(str8 string);
|
||||
void ui_tag_box_str8(ui_box* box, str8 string);
|
||||
void ui_tag_next_str8(str8 string);
|
||||
|
||||
// C-string helpers
|
||||
#define ui_tag_make(s) ui_tag_make_str8(str8_lit(s))
|
||||
#define ui_tag_box(b, s) ui_tag_box_str8(b, str8_lit(s))
|
||||
#define ui_tag_next(s) ui_tag_next_str8(str8_lit(s))
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Styling
|
||||
//-------------------------------------------------------------------------------------
|
||||
//NOTE: styling API
|
||||
//WARN: You can use a pattern in multiple rules, but be aware that a pattern is references an underlying list of selectors,
|
||||
// hence pushing to a pattern also modifies rules in which the pattern was previously used!
|
||||
|
@ -295,6 +389,15 @@ void ui_pattern_push(mem_arena* arena, ui_pattern* pattern, ui_selector selector
|
|||
void ui_style_next(ui_pattern pattern, ui_style* style, ui_style_mask mask);
|
||||
void ui_style_prev(ui_pattern pattern, ui_style* style, ui_style_mask mask);
|
||||
|
||||
// common patterns helpers
|
||||
ui_pattern ui_pattern_all(void);
|
||||
ui_pattern ui_pattern_owner(void);
|
||||
|
||||
// single box styling helpers
|
||||
void ui_box_set_size(ui_box* box, ui_axis axis, ui_size_kind kind, f32 value, f32 stricness);
|
||||
void ui_box_set_layout(ui_box* box, ui_axis axis, ui_align alignX, ui_align alignY);
|
||||
//...
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Basic widget helpers
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -309,10 +412,10 @@ enum {
|
|||
};
|
||||
|
||||
ui_sig ui_label(const char* label);
|
||||
ui_sig ui_label_str8(str8 label);
|
||||
|
||||
ui_sig ui_button(const char* label);
|
||||
ui_sig ui_button_str8(str8 label);
|
||||
|
||||
ui_box* ui_slider(const char* label, f32 thumbRatio, f32* scrollValue);
|
||||
ui_box* ui_scrollbar(const char* label, f32 thumbRatio, f32* scrollValue);
|
||||
|
||||
ui_box* ui_panel_begin(const char* name);
|
||||
|
|
Loading…
Reference in New Issue