layout actually works now

This commit is contained in:
Alessandro Mauri 2025-09-06 23:07:43 +02:00
parent 869c7871f9
commit db63b2c6b1
6 changed files with 125 additions and 109 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}
}!!;
}!!;
}!!;
}!!; }!!;
}