diff --git a/lib/ugui.c3l/src/ugui_button.c3 b/lib/ugui.c3l/src/ugui_button.c3 index e255476..d963713 100644 --- a/lib/ugui.c3l/src/ugui_button.c3 +++ b/lib/ugui.c3l/src/ugui_button.c3 @@ -25,57 +25,51 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon) ushort min_size = style.size; ushort half_lh = (ushort)(ctx.font.line_height() / 2); - ushort left_pad = label != "" ? half_lh : 0; ushort inner_pad = label != "" && icon != "" ? half_lh : 0; - ushort right_pad = left_pad; - - /* |left_pad - * +--v-----------------------------------+ - * |<->+--------+ | + /* + * +--------------------------------------+ + * | +--------+ | * | | | +-----------------+ | * | | icon | | label | | * | | | +-----------------+ | - * | +--------+<->| |<->| - * +-------------^--------------------^---+ - * |inner_pad |right_pad + * | +--------+<->| | + * +-------------^------------------------+ + * |inner_pad */ - - elem.layout.w = { - .min = (short)max(min_size, left_pad + icon_size.w + inner_pad + text_size.width.min + right_pad), - .max = (short)max(min_size, left_pad + icon_size.w + inner_pad + text_size.width.max + right_pad), + Point content_size = { + .x = icon_size.w + inner_pad, // text sizing is handled differently + .y = icon_size.h + inner_pad, }; - elem.layout.h = { - .min = (short)max(min_size, left_pad + icon_size.h + text_size.height.min + right_pad), - .max = (short)max(min_size, left_pad + icon_size.w + text_size.height.max + right_pad), - }; - // add style border and padding + //elem.layout.w = @fit(min_size); + elem.layout.w = @fit(min_size); + elem.layout.h = @fit(min_size); + elem.layout.children.w = @exact(content_size.x); + elem.layout.children.h = @exact(content_size.y); + elem.layout.text = text_size; elem.layout.content_offset = style.margin + style.border + style.padding; - elem.layout.children.w = elem.layout.w; - elem.layout.children.h = elem.layout.h; - update_parent_grow(elem, parent); update_parent_size(elem, parent); elem.events = ctx.get_elem_events(elem); Rect content_bounds = elem.content_bounds(); - - Rect text_bounds = { - .x = content_bounds.x + icon_size.w + left_pad + inner_pad, - .y = content_bounds.y, - .w = content_bounds.w - icon_size.w - left_pad - inner_pad - right_pad, - .h = content_bounds.h - }; - //text_bounds = text_size.center_to(text_bounds); - + Rect icon_bounds = { .x = content_bounds.x, .y = content_bounds.y, - .w = icon_size.w + right_pad + inner_pad, - .h = (short)max(icon_size.h, content_bounds.h) + .w = icon_size.w, + .h = icon_size.h }; icon_bounds = icon_size.center_to(icon_bounds); + Rect text_bounds = { + .x = content_bounds.x + icon_bounds.w + inner_pad, + .y = content_bounds.y, + .w = content_bounds.w - icon_bounds.w - inner_pad, + .h = content_bounds.h, + }; + //text_bounds = text_size.center_to(text_bounds); + bool is_active = ctx.elem_focus(elem) || elem.events.mouse_hover; Style s = *style; if (is_active) { @@ -88,8 +82,7 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon) ctx.push_sprite(icon_bounds, sprite.uv(), ctx.sprite_atlas.id, parent.div.z_index, type: sprite.type)!; } if (label != "") { - ctx.push_rect(text_bounds, parent.div.z_index, &&{.bg=0xff0000abu.@to_rgba()})!; - ctx.push_string(text_bounds, label, parent.div.z_index, style.fg)!; + ctx.push_string(text_bounds, label, parent.div.z_index, style.fg, true)!; } return elem.events; } diff --git a/lib/ugui.c3l/src/ugui_font.c3 b/lib/ugui.c3l/src/ugui_font.c3 index ed9c112..12fca7c 100644 --- a/lib/ugui.c3l/src/ugui_font.c3 +++ b/lib/ugui.c3l/src/ugui_font.c3 @@ -335,6 +335,7 @@ fn Rect? Ctx.get_text_bounds(&ctx, String text) struct TextSize { Size width, height; + int area; } // Measeure the size of a string. @@ -393,8 +394,12 @@ fn TextSize? Ctx.measure_string(&ctx, String text) word_width = 0; words++; default: - word_width += gp.w + gp.ox; - if (off < text.len) word_width += gp.adv; + //word_width += gp.w + gp.ox; + if (off < text.len) { + word_width += gp.adv; + } else { + word_width += gp.w + gp.ox; + } } } // end of string is also end of word @@ -403,6 +408,7 @@ fn TextSize? Ctx.measure_string(&ctx, String text) ts.width.max = bounds.w; ts.height.min = bounds.h; ts.height.max = words * line_height + line_gap * (words-1); + ts.area = bounds.w * bounds.h; return ts; } diff --git a/lib/ugui.c3l/src/ugui_layout.c3 b/lib/ugui.c3l/src/ugui_layout.c3 index b6854b7..bae4ea7 100644 --- a/lib/ugui.c3l/src/ugui_layout.c3 +++ b/lib/ugui.c3l/src/ugui_layout.c3 @@ -25,6 +25,7 @@ struct Layout { struct children { // the children size includes the children's margin/border/pading Size w, h; } + TextSize text; ushort grow_children; short occupied; struct origin { @@ -51,6 +52,32 @@ macro Size Layout.total_height(&el) return {.min = min.h, .max = max.h}; } +// Returns the width and height of a @FIT() element based on it's wanted size (min/max) +// and the content size, this function is used to both update the parent's children size and +// give the dimensions of a fit element +macro Point Layout.get_dimensions(&el) +{ + Size content_width = el.children.w + el.text.width; + Size width = el.w.combine(content_width); + short final_width = width.greater(); + + short text_height; + if (el.text.area != 0) { + short text_width = (@exact(final_width) - el.children.w).combine(el.text.width).min; + text_height = @exact((short)(el.text.area / text_width)).combine(el.text.height).min; + } + + Size content_height = el.children.h + @exact(text_height); + Size height = el.h.combine(content_height); + short final_height = height.greater(); + + Point dim = { + .x = final_width + el.content_offset.x + el.content_offset.w, + .y = final_height + el.content_offset.y + el.content_offset.h, + }; + return dim; +} + // The content space of the element macro Point Elem.content_space(&e) { @@ -76,14 +103,16 @@ fn void update_parent_size(Elem* child, Elem* parent) { Layout* cl = &child.layout; Layout* pl = &parent.layout; + + Point child_size = cl.get_dimensions(); switch (pl.dir) { case ROW: // on rows grow the ch width by the child width and only grow ch height if it exceeds - pl.children.w += cl.total_width(); - pl.children.h = pl.children.h.comb_max(cl.total_height()); + pl.children.w += @exact(child_size.x); + pl.children.h = pl.children.h.comb_max(@exact(child_size.y)); case COLUMN: // do the opposite on column - pl.children.w = pl.children.w.comb_max(cl.total_width()); - pl.children.h += cl.total_height(); + pl.children.w = pl.children.w.comb_max(@exact(child_size.x)); + pl.children.h += @exact(child_size.y); } } @@ -120,7 +149,10 @@ fn void resolve_dimensions(Elem* e, Elem* p) { Layout* el = &e.layout; Layout* pl = &p.layout; + + Point elem_dimensions = el.get_dimensions(); + short text_min_height; // ASSIGN WIDTH switch { case el.w.@is_exact(): @@ -130,16 +162,7 @@ fn void resolve_dimensions(Elem* e, Elem* p) // done in another pass break; case el.w.@is_fit(): // fit the element's children - Size elem_width = el.w; // the element's content width - Size children_width = el.children.w; // element children (content) width - Size combined = elem_width.combine(children_width); - - if (combined.min <= combined.max) { // OK! - // the final element width is the content width plus padding and border - e.bounds.w = min(elem_width.max, children_width.max) + el.content_offset.x + el.content_offset.w; - } else { - unreachable("Cannot fit children width: min:%d max:%d", combined.min, combined.max); - } + e.bounds.w = elem_dimensions.x; default: unreachable("width is not exact, grow or fit"); } @@ -152,16 +175,7 @@ fn void resolve_dimensions(Elem* e, Elem* p) break; // done in another pass case el.h.@is_fit(): // fit the element's children - Size elem_height = el.h; // the element's content width - Size children_height = el.children.h; // element children (content) width - Size combined = elem_height.combine(children_height); - - if (combined.min <= combined.max) { // OK! - // the final element width is the content width plus padding and border - e.bounds.h = min(elem_height.max, children_height.max) + el.content_offset.y + el.content_offset.h; - } else { - unreachable("Cannot fit children height: min:%d max:%d", combined.min, combined.max); - } + e.bounds.h = elem_dimensions.y; default: unreachable("width is not exact, grow or fit"); } diff --git a/lib/ugui.c3l/src/ugui_shapes.c3 b/lib/ugui.c3l/src/ugui_shapes.c3 index e3a6e81..53a7635 100644 --- a/lib/ugui.c3l/src/ugui_shapes.c3 +++ b/lib/ugui.c3l/src/ugui_shapes.c3 @@ -247,7 +247,8 @@ struct Size { macro Size @grow() => {.min = 0, .max = 0}; macro Size @exact(short s) => {.min = s, .max = s}; -macro Size @fit(short min = 0, short max = short.max/2) => {.min = min, .max = max}; + // PROBLEM WE ARE OVERFLOWING +macro Size @fit(short min = 0, short max = 999) => {.min = min, .max = max}; macro bool Size.@is_grow(s) => (s.min == 0 && s.max == 0); macro bool Size.@is_exact(s) => (s.min == s.max && s.min != 0); macro bool Size.@is_fit(s) => (s.min != s.max); @@ -258,3 +259,5 @@ macro Size Size.sub(a, Size b) @operator_s(-) => {.min = a.min-b.min, .max = a.m macro Size Size.combine(a, Size b) => {.min = max(a.min, b.min), .max = min(a.max, b.max)}; macro Size Size.comb_max(a, Size b) => {.min = max(a.min, b.min), .max = max(a.max, b.max)}; macro Size Size.comb_min(a, Size b) => {.min = min(a.min, b.min), .max = min(a.max, b.max)}; + +macro short Size.greater(a) => a.min > a.max ? a.min : a.max; diff --git a/resources/style.css b/resources/style.css index 4681c69..4564354 100644 --- a/resources/style.css +++ b/resources/style.css @@ -2,9 +2,9 @@ default { bg: #282828ff; fg: #fbf1c7ff; primary: #cc241dff; - secondary: #458588ff; + secondary: #6c19ca8f; accent: #fabd2fff; - border: 0; + border: 1; padding: 0; margin: 0; } diff --git a/src/main.c3 b/src/main.c3 index 83848bb..53fb2a6 100644 --- a/src/main.c3 +++ b/src/main.c3 @@ -363,54 +363,54 @@ fn void calculator(ugui::Ctx* ui) } // ui input/output - ui.@div(ugui::@grow(), ugui::@grow(), ROW, CENTER) { + ui.@div(ugui::@grow(), ugui::@grow(), ROW, CENTER) { // center everything on the screen + ui.@div(ugui::@fit(), ugui::@fit(), COLUMN, TOP_LEFT) { -/* - ui.@div({0,0,250,50}) { - ui.text_unbounded((String)buffer[:len])!!; + ui.@div(ugui::@grow(), ugui::@exact(100), ROW, RIGHT) { + ui.button("TODO")!!; }!!; -*/ - - ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { - ui.button("7")!!.mouse_press ? buffer[len++] = '7' : 0; - ui.button("4")!!.mouse_press ? buffer[len++] = '4' : 0; - ui.button("1")!!.mouse_press ? buffer[len++] = '1' : 0; - ui.button("0")!!.mouse_press ? buffer[len++] = '0' : 0; - }!!; - ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { - ui.button("8")!!.mouse_press ? buffer[len++] = '8' : 0; - ui.button("5")!!.mouse_press ? buffer[len++] = '5' : 0; - ui.button("2")!!.mouse_press ? buffer[len++] = '2' : 0; - ui.button(".")!!.mouse_press ? buffer[len++] = '.' : 0; - }!!; - ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { - ui.button("9")!!.mouse_press ? buffer[len++] = '9' : 0; - ui.button("6")!!.mouse_press ? buffer[len++] = '6' : 0; - ui.button("3")!!.mouse_press ? buffer[len++] = '3' : 0; - ui.button("(")!!.mouse_press ? buffer[len++] = '(' : 0; - }!!; - - ui.@div(ugui::@exact(10), ugui::@exact(10)) {}!!; - - ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { - ui.button("x")!!.mouse_press ? buffer[len++] = '*' : 0; - ui.button("/")!!.mouse_press ? buffer[len++] = '/' : 0; - ui.button("+")!!.mouse_press ? buffer[len++] = '+' : 0; - ui.button(")")!!.mouse_press ? buffer[len++] = ')' : 0; - }!!; - ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { - ui.button("C")!!.mouse_press ? len = 0 : 0; - ui.button("D")!!.mouse_press ? len-- : 0; - ui.button("-")!!.mouse_press ? buffer[len++] = '-' : 0; + ui.@div(ugui::@fit(), ugui::@fit(), ROW, TOP_LEFT) { + ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { + ui.button("7")!!.mouse_press ? buffer[len++] = '7' : 0; + ui.button("4")!!.mouse_press ? buffer[len++] = '4' : 0; + ui.button("1")!!.mouse_press ? buffer[len++] = '1' : 0; + ui.button("0")!!.mouse_press ? buffer[len++] = '0' : 0; + }!!; + ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { + ui.button("8")!!.mouse_press ? buffer[len++] = '8' : 0; + ui.button("5")!!.mouse_press ? buffer[len++] = '5' : 0; + ui.button("2")!!.mouse_press ? buffer[len++] = '2' : 0; + ui.button(".")!!.mouse_press ? buffer[len++] = '.' : 0; + }!!; + ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { + ui.button("9")!!.mouse_press ? buffer[len++] = '9' : 0; + ui.button("6")!!.mouse_press ? buffer[len++] = '6' : 0; + ui.button("3")!!.mouse_press ? buffer[len++] = '3' : 0; + ui.button("(")!!.mouse_press ? buffer[len++] = '(' : 0; + }!!; + + ui.@div(ugui::@exact(10), ugui::@exact(10)) {}!!; - // eval the expression with 'bc' - if (ui.button("=")!!.mouse_press || eval) { - char[128] out; - String y = string::tformat("echo '%s' | bc", (String)buffer[:len]); - String x = process::execute_stdout_to_buffer(out[:128], (String[]){"sh", "-c", y}) ?? ""; - buffer[:x.len] = x[..]; - len = x.len; - } + ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { + ui.button("x")!!.mouse_press ? buffer[len++] = '*' : 0; + ui.button("/")!!.mouse_press ? buffer[len++] = '/' : 0; + ui.button("+")!!.mouse_press ? buffer[len++] = '+' : 0; + ui.button(")")!!.mouse_press ? buffer[len++] = ')' : 0; + }!!; + ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { + ui.button("C")!!.mouse_press ? len = 0 : 0; + ui.button("D")!!.mouse_press ? len-- : 0; + ui.button("-")!!.mouse_press ? buffer[len++] = '-' : 0; + + // eval the expression with 'bc' + if (ui.button("=")!!.mouse_press || eval) { + char[128] out; + String y = string::tformat("echo '%s' | bc", (String)buffer[:len]); + String x = process::execute_stdout_to_buffer(out[:128], (String[]){"sh", "-c", y}) ?? ""; + buffer[:x.len] = x[..]; + len = x.len; + } + }!!; }!!; - }!!; + }!!; }!!; }