diff --git a/examples/ui_style_test/main.c b/examples/ui_style_test/main.c index 4175373..d70207a 100644 --- a/examples/ui_style_test/main.c +++ b/examples/ui_style_test/main.c @@ -78,6 +78,7 @@ 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"); + f32 value = box->targetStyle->size.c[axis].value; switch(box->targetStyle->size.c[axis].kind) { case UI_SIZE_TEXT: @@ -89,11 +90,15 @@ void debug_print_size(ui_box* box, ui_axis axis, int indent) break; case UI_SIZE_PARENT: - printf("parent\n"); + printf("parent: %f\n", value); + break; + + case UI_SIZE_PARENT_MINUS_PIXELS: + printf("parent minus pixels: %f\n", value); break; case UI_SIZE_PIXELS: - printf("pixels\n"); + printf("pixels: %f\n", value); break; } @@ -233,7 +238,10 @@ void panel_end(void) ui_box* scrollBarX = 0; ui_box* scrollBarY = 0; - if(contentsW > panel->rect.w) + bool needsScrollX = contentsW > panel->rect.w; + bool needsScrollY = contentsH > panel->rect.h; + + if(needsScrollX) { f32 thumbRatioX = panel->rect.w / contentsW; f32 sliderX = panel->scroll.x /(contentsW - panel->rect.w); @@ -242,8 +250,9 @@ void panel_end(void) .size.height = {UI_SIZE_PIXELS, 10, 0}, .floating.x = true, .floating.y = true, - .floatTarget = {0, panel->rect.h - 12}}, - UI_STYLE_SIZE); + .floatTarget = {0, panel->rect.h - 10}}, + UI_STYLE_SIZE + |UI_STYLE_FLOAT); scrollBarX = ui_slider("scrollerX", thumbRatioX, &sliderX); @@ -255,16 +264,18 @@ void panel_end(void) } } - if(contentsH > panel->rect.h) + if(needsScrollY) { f32 thumbRatioY = panel->rect.h / contentsH; f32 sliderY = panel->scroll.y /(contentsH - panel->rect.h); + f32 spacerSize = needsScrollX ? 10 : 0; + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 10, 0}, - .size.height = {UI_SIZE_PARENT, 1., 0}, + .size.height = {UI_SIZE_PARENT_MINUS_PIXELS, spacerSize, 0}, .floating.x = true, .floating.y = true, - .floatTarget = {panel->rect.w - 12, 0}}, + .floatTarget = {panel->rect.w - 10, 0}}, UI_STYLE_SIZE |UI_STYLE_FLOAT); @@ -277,22 +288,9 @@ void panel_end(void) ui_box_activate(scrollBarY); } } - panel->scroll.x = Clamp(panel->scroll.x, 0, contentsW - panel->rect.w); panel->scroll.y = Clamp(panel->scroll.y, 0, contentsH - panel->rect.h); - if(scrollBarX) - { -// ui_box_set_floating(scrollBarX, UI_AXIS_X, panel->scroll.x); -// ui_box_set_floating(scrollBarX, UI_AXIS_Y, panel->scroll.y + panel->rect.h - 12); - } - - if(scrollBarY) - { -// ui_box_set_floating(scrollBarY, UI_AXIS_X, panel->scroll.x + panel->rect.w - 12); -// ui_box_set_floating(scrollBarY, UI_AXIS_Y, panel->scroll.y); - } - ui_box_end(); } @@ -416,15 +414,17 @@ int main() } ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, - .size.height = {UI_SIZE_PIXELS, 500}}, + .size.height = {UI_SIZE_PARENT, 1, 1}}, UI_STYLE_SIZE); ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X}, UI_STYLE_LAYOUT_AXIS); ui_container("contents", debugFlags) { ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 0.5}, - .size.height = {UI_SIZE_PARENT, 1}}, - UI_STYLE_SIZE); + .size.height = {UI_SIZE_PARENT, 1}, + .borderColor = {0, 0, 1, 1}}, + UI_STYLE_SIZE + |UI_STYLE_BORDER_COLOR); ui_container("left", debugFlags) { @@ -519,13 +519,14 @@ int main() } } } - +/* ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 0.5}, .size.height = {UI_SIZE_PARENT, 1}}, UI_STYLE_SIZE); ui_container("right", debugFlags) { + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, .size.height = {UI_SIZE_PARENT, 0.33}}, UI_STYLE_SIZE); @@ -555,136 +556,46 @@ int main() widget_view("Color") { ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, - .size.height = {UI_SIZE_PARENT, 0.7}}, - UI_STYLE_SIZE); + .size.height = {UI_SIZE_PARENT, 0.7}, + .layout.axis = UI_AXIS_X}, + UI_STYLE_SIZE + |UI_STYLE_LAYOUT_AXIS); panel("Panel", UI_FLAG_DRAW_BORDER) { + ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X}, + UI_STYLE_LAYOUT_AXIS); + ui_container("contents", 0) + { + ui_style_next(&(ui_style){.layout.spacing = 20}, + UI_STYLE_LAYOUT_SPACING); + ui_container("buttons", 0) + { + ui_button("Button A"); + ui_button("Button B"); + ui_button("Button C"); + ui_button("Button D"); + } - ui_style_next(&(ui_style){.layout.spacing = 20}, - UI_STYLE_LAYOUT_SPACING); - ui_container("buttons", 0) - { - ui_button("Button A"); - ui_button("Button B"); - ui_button("Button C"); - ui_button("Button D"); + ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X, + .layout.spacing = 20}, + UI_STYLE_LAYOUT_SPACING + |UI_STYLE_LAYOUT_AXIS); + + ui_container("buttons2", 0) + { + ui_button("Button A"); + ui_button("Button B"); + ui_button("Button C"); + ui_button("Button D"); + } } } } - } - } - } - - /* - ui_pattern pattern = {0}; - ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TEXT, .text = STR8("b")}); - ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TAG, .tag = ui_tag_make("foo")}); - ui_style_match_before(pattern, &(ui_style){.fontSize = 36}, UI_STYLE_FONT_SIZE); - - ui_style_match_before(ui_pattern_all(), - &defaultStyle, - UI_STYLE_FONT - |UI_STYLE_FONT_SIZE - |UI_STYLE_COLOR - |UI_STYLE_BORDER_SIZE - |UI_STYLE_BORDER_COLOR - |UI_STYLE_SIZE_WIDTH - |UI_STYLE_SIZE_HEIGHT - |UI_STYLE_LAYOUT); - - - pattern = (ui_pattern){0}; - ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TEXT, .text = STR8("c")}); - ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TAG, .tag = ui_tag_make("button")}); - ui_style_match_after(pattern, - &(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("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_match_after(pattern, - &(ui_style){.bgColor = {0.5, 1, 0.5, 1}}, - UI_STYLE_BG_COLOR); - - ui_style_next(&(ui_style){.bgColor = {0.7, 0.7, 0.7, 1}}, UI_STYLE_BG_COLOR); - ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, .size.height = {UI_SIZE_PARENT, 1}}, UI_STYLE_SIZE); - - ui_container("a", defaultFlags) - { - ui_pattern pattern = {0}; - ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TEXT, .text = STR8("b")}); - ui_style_match_before(pattern, &(ui_style){.fontSize = 22}, UI_STYLE_FONT_SIZE); - - ui_container("b", defaultFlags) - { - ui_container("c", defaultFlags) - { - if(ui_button("button d").clicked) - { - printf("clicked button d\n"); - } - } - - ui_container("e", defaultFlags) - { - ui_tag_next("foo"); - if(ui_button("button f").clicked) - { - printf("clicked button f\n"); - } - - ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, - .size.height = {UI_SIZE_PIXELS, 20, 0}}, - UI_STYLE_SIZE); - static f32 slider1 = 0; - ui_slider("slider1", 0.3, &slider1); - - - ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, - .size.height = {UI_SIZE_PIXELS, 20, 0}}, - UI_STYLE_SIZE); - static f32 slider2 = 0; - ui_slider("slider2", 0.3, &slider2); - - ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, - .size.height = {UI_SIZE_PIXELS, 20}}, - UI_STYLE_SIZE); - static f32 slider3 = 0; - ui_slider("slider3", 0.3, &slider3); - - - ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 20}, - .size.height = {UI_SIZE_PIXELS, 200}}, - UI_STYLE_SIZE); - static f32 slider4 = 0; - ui_slider("slider4", 0.3, &slider4); - - - } - } - ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X}, UI_STYLE_LAYOUT_AXIS); - ui_container("f", defaultFlags) - { - ui_tag_next("foo"); - ui_label("label d"); - - ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 300}, - .size.height = {UI_SIZE_TEXT}}, - UI_STYLE_SIZE); - static str8 text = {}; - ui_text_box_result res = ui_text_box("textbox", mem_scratch(), text); - if(res.changed) - { - mem_arena_clear(&textArena); - text = str8_push_copy(&textArena, res.text); - } + }*/ } } - */ } if(printDebugStyle) { @@ -693,32 +604,8 @@ int main() 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("hello, world")); - mg_fill(); - - mg_matrix_pop(); - - mg_set_text_flip(oldTextFlip); -*/ mg_flush(); mg_surface_present(surface); diff --git a/src/osx_app.m b/src/osx_app.m index 76bfe7a..8f49982 100644 --- a/src/osx_app.m +++ b/src/osx_app.m @@ -890,7 +890,7 @@ static void mp_process_mouse_button(NSEvent* nsEvent, mp_window_data* window, mp double factor = [nsEvent hasPreciseScrollingDeltas] ? 0.1 : 1.0; event.move.x = 0; event.move.y = 0; - event.move.deltaX = [nsEvent scrollingDeltaX]*factor; + event.move.deltaX = -[nsEvent scrollingDeltaX]*factor; event.move.deltaY = -[nsEvent scrollingDeltaY]*factor; event.move.mods = mp_convert_osx_mods([nsEvent modifierFlags]); diff --git a/src/ui.c b/src/ui.c index 979024e..8547c7c 100644 --- a/src/ui.c +++ b/src/ui.c @@ -18,10 +18,10 @@ static ui_style UI_STYLE_DEFAULTS = { .size.width = {.kind = UI_SIZE_CHILDREN, .value = 0, - .strictness = 0}, + .relax = 0}, .size.height = {.kind = UI_SIZE_CHILDREN, .value = 0, - .strictness = 0}, + .relax = 0}, .layout = {.axis = UI_AXIS_Y, .align = {UI_ALIGN_START, @@ -622,7 +622,7 @@ void ui_animate_ui_size(ui_context* ui, ui_size* size, ui_size target, f32 anima { size->kind = target.kind; ui_animate_f32(ui, &size->value, target.value, animationTime); - ui_animate_f32(ui, &size->strictness, target.strictness, animationTime); + ui_animate_f32(ui, &size->relax, target.relax, animationTime); } void ui_box_compute_styling(ui_context* ui, ui_box* box) @@ -1037,6 +1037,7 @@ void ui_layout_upward_dependent_size(ui_context* ui, ui_box* box, int axis) ui_size* size = &box->style.size.c[axis]; + if(size->kind == UI_SIZE_PARENT) { ui_box* parent = box->parent; @@ -1045,7 +1046,15 @@ void ui_layout_upward_dependent_size(ui_context* ui, ui_box* box, int axis) f32 margin = parent->style.layout.margin.c[axis]; box->rect.c[2+axis] = maximum(0, parent->rect.c[2+axis] - parent->spacing[axis] - 2*margin) * size->value; } - //TODO else? + } + else if(size->kind == UI_SIZE_PARENT_MINUS_PIXELS) + { + ui_box* parent = box->parent; + if(parent) + { + f32 margin = parent->style.layout.margin.c[axis]; + box->rect.c[2+axis] = maximum(0, parent->rect.c[2+axis] - parent->spacing[axis] - 2*margin - size->value); + } } for_list(&box->children, child, ui_box, listElt) @@ -1055,8 +1064,95 @@ void ui_layout_upward_dependent_size(ui_context* ui, ui_box* box, int axis) } void ui_layout_solve_conflicts(ui_context* ui, ui_box* box, int axis) -{ - //TODO +{/* + f32 totalContents = box->childrenSum[axis] + + box->spacing[axis] + + 2*box->style.layout.margin.c[axis]; +*/ + f32 sum = 0; + + if(box->style.layout.axis == axis) + { + //NOTE: if we're solving in the layout axis, first recompute the total size + // and total slack of children. + + //NOTE: we also recompute children that depend on the parent. Maybe we could combine with upward dependent stuff... + f32 margin = box->style.layout.margin.c[axis]; + f32 parentAvailableSize = maximum(0, box->rect.c[2+axis] - box->spacing[axis] - 2*margin); + f32 slack = 0; + + for_list(&box->children, child, ui_box, listElt) + { + ui_size* size = &child->style.size.c[axis]; + if(size->kind == UI_SIZE_PARENT) + { + child->rect.c[2+axis] = parentAvailableSize * size->value; + } + else if(size->kind == UI_SIZE_PARENT_MINUS_PIXELS) + { + child->rect.c[2+axis] = maximum(0, parentAvailableSize - size->value); + } + + if(!ui_box_hidden(child) && !child->style.floating.c[axis]) + { + sum += child->rect.c[2+axis]; + slack += child->rect.c[2+axis] * child->style.size.c[axis].relax; + } + } + + f32 totalContents = sum + box->spacing[axis] + 2*box->style.layout.margin.c[axis]; + f32 excess = ClampLowBound(totalContents - box->rect.c[2+axis], 0); + f32 alpha = Clamp(excess / slack, 0, 1); + + //NOTE: then remove excess proportionally to each box slack, and recompute children sum. + sum = 0; + for_list(&box->children, child, ui_box, listElt) + { + f32 relax = child->style.size.c[axis].relax; + child->rect.c[2+axis] -= alpha * child->rect.c[2+axis] * relax; + sum += child->rect.c[2+axis]; + } + } + else + { + //NOTE: if we're solving on the secondary axis, we remove excess to each box individually + // according to its own slack. Children sum is the maximum child size. + + f32 margin = box->style.layout.margin.c[axis]; + f32 parentAvailableSize = maximum(0, box->rect.c[2+axis] - box->spacing[axis] - 2*margin); + + for_list(&box->children, child, ui_box, listElt) + { + ui_size* size = &child->style.size.c[axis]; + if(size->kind == UI_SIZE_PARENT) + { + child->rect.c[2+axis] = parentAvailableSize * size->value; + } + else if(size->kind == UI_SIZE_PARENT_MINUS_PIXELS) + { + child->rect.c[2+axis] = maximum(0, parentAvailableSize - size->value); + } + + if(!ui_box_hidden(child) && !child->style.floating.c[axis]) + { + f32 totalContents = child->rect.c[2+axis] + 2*box->style.layout.margin.c[axis]; + f32 excess = ClampLowBound(totalContents - box->rect.c[2+axis], 0); + + f32 relax = child->style.size.c[axis].relax; + child->rect.c[2+axis] -= minimum(excess, child->rect.c[2+axis]*relax); + + sum = maximum(sum, child->rect.c[2+axis]); + } + } + } + + box->childrenSum[axis] = sum; + + //NOTE: recurse in children + for_list(&box->children, child, ui_box, listElt) + { + ui_layout_solve_conflicts(ui, child, axis); + } } void ui_layout_compute_rect(ui_context* ui, ui_box* box, vec2 pos) diff --git a/src/ui.h b/src/ui.h index 5a33543..7b73ee2 100644 --- a/src/ui.h +++ b/src/ui.h @@ -85,6 +85,7 @@ typedef enum ui_size_kind UI_SIZE_PIXELS, UI_SIZE_CHILDREN, UI_SIZE_PARENT, + UI_SIZE_PARENT_MINUS_PIXELS, } ui_size_kind; @@ -92,7 +93,7 @@ typedef struct ui_size { ui_size_kind kind; f32 value; - f32 strictness; + f32 relax; } ui_size; typedef union ui_box_size