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 min_size = style.size;
ushort half_lh = (ushort)(ctx.font.line_height() / 2); 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 inner_pad = label != "" && icon != "" ? half_lh : 0;
ushort right_pad = left_pad; /*
* +--------------------------------------+
/* |left_pad * | +--------+ |
* +--v-----------------------------------+
* |<->+--------+ |
* | | | +-----------------+ | * | | | +-----------------+ |
* | | icon | | label | | * | | icon | | label | |
* | | | +-----------------+ | * | | | +-----------------+ |
* | +--------+<->| |<->| * | +--------+<->| |
* +-------------^--------------------^---+ * +-------------^------------------------+
* |inner_pad |right_pad * |inner_pad
*/ */
Point content_size = {
elem.layout.w = { .x = icon_size.w + inner_pad, // text sizing is handled differently
.min = (short)max(min_size, left_pad + icon_size.w + inner_pad + text_size.width.min + right_pad), .y = icon_size.h + inner_pad,
.max = (short)max(min_size, left_pad + icon_size.w + inner_pad + text_size.width.max + right_pad),
}; };
elem.layout.h = { //elem.layout.w = @fit(min_size);
.min = (short)max(min_size, left_pad + icon_size.h + text_size.height.min + right_pad), elem.layout.w = @fit(min_size);
.max = (short)max(min_size, left_pad + icon_size.w + text_size.height.max + right_pad), elem.layout.h = @fit(min_size);
}; elem.layout.children.w = @exact(content_size.x);
// add style border and padding 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.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_grow(elem, parent);
update_parent_size(elem, parent); update_parent_size(elem, parent);
elem.events = ctx.get_elem_events(elem); elem.events = ctx.get_elem_events(elem);
Rect content_bounds = elem.content_bounds(); 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 = { Rect icon_bounds = {
.x = content_bounds.x, .x = content_bounds.x,
.y = content_bounds.y, .y = content_bounds.y,
.w = icon_size.w + right_pad + inner_pad, .w = icon_size.w,
.h = (short)max(icon_size.h, content_bounds.h) .h = icon_size.h
}; };
icon_bounds = icon_size.center_to(icon_bounds); 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; bool is_active = ctx.elem_focus(elem) || elem.events.mouse_hover;
Style s = *style; Style s = *style;
if (is_active) { 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)!; ctx.push_sprite(icon_bounds, sprite.uv(), ctx.sprite_atlas.id, parent.div.z_index, type: sprite.type)!;
} }
if (label != "") { 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, true)!;
ctx.push_string(text_bounds, label, parent.div.z_index, style.fg)!;
} }
return elem.events; return elem.events;
} }

View File

@ -335,6 +335,7 @@ fn Rect? Ctx.get_text_bounds(&ctx, String text)
struct TextSize { struct TextSize {
Size width, height; Size width, height;
int area;
} }
// Measeure the size of a string. // Measeure the size of a string.
@ -393,8 +394,12 @@ fn TextSize? Ctx.measure_string(&ctx, String text)
word_width = 0; word_width = 0;
words++; words++;
default: default:
word_width += gp.w + gp.ox; //word_width += gp.w + gp.ox;
if (off < text.len) word_width += gp.adv; if (off < text.len) {
word_width += gp.adv;
} else {
word_width += gp.w + gp.ox;
}
} }
} }
// end of string is also end of word // 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.width.max = bounds.w;
ts.height.min = bounds.h; ts.height.min = bounds.h;
ts.height.max = words * line_height + line_gap * (words-1); ts.height.max = words * line_height + line_gap * (words-1);
ts.area = bounds.w * bounds.h;
return ts; return ts;
} }

View File

@ -25,6 +25,7 @@ struct Layout {
struct children { // the children size includes the children's margin/border/pading struct children { // the children size includes the children's margin/border/pading
Size w, h; Size w, h;
} }
TextSize text;
ushort grow_children; ushort grow_children;
short occupied; short occupied;
struct origin { struct origin {
@ -51,6 +52,32 @@ macro Size Layout.total_height(&el)
return {.min = min.h, .max = max.h}; 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 // The content space of the element
macro Point Elem.content_space(&e) macro Point Elem.content_space(&e)
{ {
@ -76,14 +103,16 @@ fn void update_parent_size(Elem* child, Elem* parent)
{ {
Layout* cl = &child.layout; Layout* cl = &child.layout;
Layout* pl = &parent.layout; Layout* pl = &parent.layout;
Point child_size = cl.get_dimensions();
switch (pl.dir) { switch (pl.dir) {
case ROW: // on rows grow the ch width by the child width and only grow ch height if it exceeds 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.w += @exact(child_size.x);
pl.children.h = pl.children.h.comb_max(cl.total_height()); pl.children.h = pl.children.h.comb_max(@exact(child_size.y));
case COLUMN: // do the opposite on column case COLUMN: // do the opposite on column
pl.children.w = pl.children.w.comb_max(cl.total_width()); pl.children.w = pl.children.w.comb_max(@exact(child_size.x));
pl.children.h += cl.total_height(); pl.children.h += @exact(child_size.y);
} }
} }
@ -120,7 +149,10 @@ fn void resolve_dimensions(Elem* e, Elem* p)
{ {
Layout* el = &e.layout; Layout* el = &e.layout;
Layout* pl = &p.layout; Layout* pl = &p.layout;
Point elem_dimensions = el.get_dimensions();
short text_min_height;
// ASSIGN WIDTH // ASSIGN WIDTH
switch { switch {
case el.w.@is_exact(): case el.w.@is_exact():
@ -130,16 +162,7 @@ fn void resolve_dimensions(Elem* e, Elem* p)
// done in another pass // done in another pass
break; break;
case el.w.@is_fit(): // fit the element's children case el.w.@is_fit(): // fit the element's children
Size elem_width = el.w; // the element's content width e.bounds.w = elem_dimensions.x;
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);
}
default: unreachable("width is not exact, grow or fit"); default: unreachable("width is not exact, grow or fit");
} }
@ -152,16 +175,7 @@ fn void resolve_dimensions(Elem* e, Elem* p)
break; break;
// done in another pass // done in another pass
case el.h.@is_fit(): // fit the element's children case el.h.@is_fit(): // fit the element's children
Size elem_height = el.h; // the element's content width e.bounds.h = elem_dimensions.y;
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);
}
default: unreachable("width is not exact, grow or fit"); 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 @grow() => {.min = 0, .max = 0};
macro Size @exact(short s) => {.min = s, .max = s}; 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_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_exact(s) => (s.min == s.max && s.min != 0);
macro bool Size.@is_fit(s) => (s.min != s.max); 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.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_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 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; bg: #282828ff;
fg: #fbf1c7ff; fg: #fbf1c7ff;
primary: #cc241dff; primary: #cc241dff;
secondary: #458588ff; secondary: #6c19ca8f;
accent: #fabd2fff; accent: #fabd2fff;
border: 0; border: 1;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }

View File

@ -363,54 +363,54 @@ fn void calculator(ugui::Ctx* ui)
} }
// ui input/output // 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(ugui::@grow(), ugui::@exact(100), ROW, RIGHT) {
ui.@div({0,0,250,50}) { ui.button("TODO")!!;
ui.text_unbounded((String)buffer[:len])!!;
}!!; }!!;
*/ ui.@div(ugui::@fit(), ugui::@fit(), ROW, TOP_LEFT) {
ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) {
ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { ui.button("7")!!.mouse_press ? buffer[len++] = '7' : 0;
ui.button("7")!!.mouse_press ? buffer[len++] = '7' : 0; ui.button("4")!!.mouse_press ? buffer[len++] = '4' : 0;
ui.button("4")!!.mouse_press ? buffer[len++] = '4' : 0; ui.button("1")!!.mouse_press ? buffer[len++] = '1' : 0;
ui.button("1")!!.mouse_press ? buffer[len++] = '1' : 0; ui.button("0")!!.mouse_press ? buffer[len++] = '0' : 0;
ui.button("0")!!.mouse_press ? buffer[len++] = '0' : 0; }!!;
}!!; ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) {
ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { ui.button("8")!!.mouse_press ? buffer[len++] = '8' : 0;
ui.button("8")!!.mouse_press ? buffer[len++] = '8' : 0; ui.button("5")!!.mouse_press ? buffer[len++] = '5' : 0;
ui.button("5")!!.mouse_press ? buffer[len++] = '5' : 0; ui.button("2")!!.mouse_press ? buffer[len++] = '2' : 0;
ui.button("2")!!.mouse_press ? buffer[len++] = '2' : 0; ui.button(".")!!.mouse_press ? buffer[len++] = '.' : 0;
ui.button(".")!!.mouse_press ? buffer[len++] = '.' : 0; }!!;
}!!; ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) {
ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { ui.button("9")!!.mouse_press ? buffer[len++] = '9' : 0;
ui.button("9")!!.mouse_press ? buffer[len++] = '9' : 0; ui.button("6")!!.mouse_press ? buffer[len++] = '6' : 0;
ui.button("6")!!.mouse_press ? buffer[len++] = '6' : 0; ui.button("3")!!.mouse_press ? buffer[len++] = '3' : 0;
ui.button("3")!!.mouse_press ? buffer[len++] = '3' : 0; ui.button("(")!!.mouse_press ? buffer[len++] = '(' : 0;
ui.button("(")!!.mouse_press ? buffer[len++] = '(' : 0; }!!;
}!!;
ui.@div(ugui::@exact(10), ugui::@exact(10)) {}!!;
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;
// eval the expression with 'bc' ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) {
if (ui.button("=")!!.mouse_press || eval) { ui.button("x")!!.mouse_press ? buffer[len++] = '*' : 0;
char[128] out; ui.button("/")!!.mouse_press ? buffer[len++] = '/' : 0;
String y = string::tformat("echo '%s' | bc", (String)buffer[:len]); ui.button("+")!!.mouse_press ? buffer[len++] = '+' : 0;
String x = process::execute_stdout_to_buffer(out[:128], (String[]){"sh", "-c", y}) ?? ""; ui.button(")")!!.mouse_press ? buffer[len++] = ')' : 0;
buffer[:x.len] = x[..]; }!!;
len = x.len; 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;
}
}!!;
}!!; }!!;
}!!; }!!; }!!;
} }