use a tuple in get_elem

This commit is contained in:
Alessandro Mauri 2025-10-03 15:19:52 +02:00
parent 32a57d5293
commit 8cecb57d93
9 changed files with 51 additions and 46 deletions

View File

@ -7,6 +7,7 @@ import fifo;
import std::io; import std::io;
import std::core::string; import std::core::string;
import std::core::mem::allocator; import std::core::mem::allocator;
import std::collections::pair;
macro println(...) macro println(...)
@ -68,6 +69,9 @@ struct Elem {
} }
} }
// Tuple of Element pointers, used when it is useful to get both parent and child
alias PElemTuple = pair::Pair{Elem*, Elem*};
// relationships between elements are stored in a tree, it stores just the ids // relationships between elements are stored in a tree, it stores just the ids
alias IdTree = mtree::MTree{Id}; alias IdTree = mtree::MTree{Id};
@ -130,10 +134,8 @@ struct Ctx {
// return a pointer to the parent of the current active div // return a pointer to the parent of the current active div
fn Elem*? Ctx.get_parent(&ctx) fn Elem*? Ctx.get_parent(&ctx)
{ {
Id parent_id = ctx.tree.get(ctx.active_div); Id parent_id = ctx.tree[ctx.active_div]!;
Elem*? parent = ctx.cache.search(parent_id); Elem* parent = ctx.cache.search(parent_id)!;
if (catch parent) return parent;
if (parent.type != ETYPE_DIV) return WRONG_ELEMENT_TYPE?;
return parent; return parent;
} }
@ -146,7 +148,7 @@ const uint GOLDEN_RATIO = 0x9E3779B9;
fn Id? Ctx.gen_id(&ctx, Id id2) fn Id? Ctx.gen_id(&ctx, Id id2)
{ {
// FIXME: this is SHIT // FIXME: this is SHIT
Id id1 = ctx.tree.get(ctx.active_div); Id id1 = ctx.tree.get(ctx.active_div)!;
// Mix the two IDs non-linearly // Mix the two IDs non-linearly
Id mixed = id1 ^ id2.rotate_left(13); Id mixed = id1 ^ id2.rotate_left(13);
mixed ^= id1.rotate_left(7); mixed ^= id1.rotate_left(7);
@ -166,10 +168,13 @@ macro Id @compute_id(...)
// get or push an element from the cache, return a pointer to it // get or push an element from the cache, return a pointer to it
// resets all flags except is_new which is set accordingly // resets all flags except is_new which is set accordingly
fn Elem*? Ctx.get_elem(&ctx, Id id, ElemType type) fn PElemTuple? Ctx.get_elem(&ctx, Id id, ElemType type)
{ {
bool is_new; bool is_new;
Elem* parent;
Elem* elem; Elem* elem;
parent = ctx.get_parent() ?? &&(Elem){};
elem = ctx.cache.get_or_insert(&&(Elem){}, id, &is_new)!; elem = ctx.cache.get_or_insert(&&(Elem){}, id, &is_new)!;
elem.flags = (ElemFlags)0; elem.flags = (ElemFlags)0;
elem.flags.is_new = is_new; elem.flags.is_new = is_new;
@ -180,13 +185,9 @@ fn Elem*? Ctx.get_elem(&ctx, Id id, ElemType type)
} else { } else {
elem.type = type; elem.type = type;
} }
// FIXME: this is crap elem.z_index = parent.z_index;
if (ctx.tree.is_used(ctx.active_div)) {
elem.z_index = ctx.get_active_div()!.z_index;
}
elem.tree_idx = ctx.tree.add(ctx.active_div, id); elem.tree_idx = ctx.tree.add(ctx.active_div, id);
return elem; return {elem, parent};
} }
// find an element, does not allocate a new one in cache // find an element, does not allocate a new one in cache
@ -203,7 +204,7 @@ macro Elem* Ctx.find_elem(&ctx, Id id)
fn Elem*? Ctx.get_active_div(&ctx) fn Elem*? Ctx.get_active_div(&ctx)
{ {
Id id = ctx.tree.get(ctx.active_div); Id id = ctx.tree.get(ctx.active_div)!;
return ctx.cache.search(id); return ctx.cache.search(id);
} }
@ -240,7 +241,7 @@ fn void? Ctx.frame_begin(&ctx)
// 1. Reset the active div // 1. Reset the active div
// 2. Get the root element from the cache and update it // 2. Get the root element from the cache and update it
ctx.active_div = 0; ctx.active_div = 0;
Elem* elem = ctx.get_elem(ROOT_ID, ETYPE_DIV)!; Elem* elem = ctx.get_elem(ROOT_ID, ETYPE_DIV)!.first;
ctx.active_div = elem.tree_idx; ctx.active_div = elem.tree_idx;
// The root should have the updated flag only if the size of the window // The root should have the updated flag only if the size of the window
// was changed between frasmes, this propagates an element size recalculation // was changed between frasmes, this propagates an element size recalculation
@ -279,7 +280,7 @@ fn void? Ctx.frame_end(&ctx)
} }
// DO THE LAYOUT // DO THE LAYOUT
ctx.layout_element_tree(); ctx.layout_element_tree()!;
// 1. clear the tree // 1. clear the tree
ctx.tree.nuke(); ctx.tree.nuke();

View File

@ -297,17 +297,17 @@ fn void resolve_placement(Elem* c, Elem* p)
} }
} }
fn void Ctx.layout_element_tree(&ctx) fn void? Ctx.layout_element_tree(&ctx)
{ {
int current; int current;
for (int n; (current = ctx.tree.level_order_it(0, n)) >= 0; n++) { for (int n; (current = ctx.tree.level_order_it(0, n)) >= 0; n++) {
Elem* p = ctx.find_elem(ctx.tree.get(current)); Elem* p = ctx.find_elem(ctx.tree.get(current))!;
p.layout.origin = -p.layout.scroll_offset; p.layout.origin = -p.layout.scroll_offset;
int ch; int ch;
// RESOLVE KNOWN DIMENSIONS // RESOLVE KNOWN DIMENSIONS
for (int i; (ch = ctx.tree.children_it(current, i)) >= 0; i++) { for (int i; (ch = ctx.tree.children_it(current, i)) >= 0; i++) {
Elem* c = ctx.find_elem(ctx.tree.get(ch)); Elem* c = ctx.find_elem(ctx.tree.get(ch))!;
if (ctx.tree.is_root(ch)) { if (ctx.tree.is_root(ch)) {
resolve_dimensions(p, &&{}); resolve_dimensions(p, &&{});
} else { } else {
@ -317,7 +317,7 @@ fn void Ctx.layout_element_tree(&ctx)
// RESOLVE GROW CHILDREN // RESOLVE GROW CHILDREN
for (int i; (ch = ctx.tree.children_it(current, i)) >= 0; i++) { for (int i; (ch = ctx.tree.children_it(current, i)) >= 0; i++) {
Elem* c = ctx.find_elem(ctx.tree.get(ch)); Elem* c = ctx.find_elem(ctx.tree.get(ch))!;
if (ctx.tree.is_root(ch)) { if (ctx.tree.is_root(ch)) {
resolve_grow_elements(p, &&{}); resolve_grow_elements(p, &&{});
} else { } else {
@ -327,7 +327,7 @@ fn void Ctx.layout_element_tree(&ctx)
// RESOLVE CHILDREN PLACEMENT // RESOLVE CHILDREN PLACEMENT
for (int i; (ch = ctx.tree.children_it(current, i)) >= 0; i++) { for (int i; (ch = ctx.tree.children_it(current, i)) >= 0; i++) {
Elem* c = ctx.find_elem(ctx.tree.get(ch)); Elem* c = ctx.find_elem(ctx.tree.get(ch))!;
if (ctx.tree.is_root(ch)) { if (ctx.tree.is_root(ch)) {
resolve_placement(p, &&{}); resolve_placement(p, &&{});
update_children_bounds(p, &&{}); update_children_bounds(p, &&{});

View File

@ -312,8 +312,12 @@ fn void MTree.prune(&tree, int parent)
} }
<* @require tree.is_used(ref) *> <* @require ref >= 0 , ref < tree.elem_vec.len *>
fn Type MTree.get(&tree, int ref) => tree.elem_vec[ref]; fn Type? MTree.get(&tree, int ref) @operator([])
{
if (tree.is_used(ref)) return tree.elem_vec[ref];
return NOT_FOUND?;
}
<* @require tree.is_used(ref) *> <* @require tree.is_used(ref) *>
fn Type MTree.parentof(&tree, int ref) => tree.refs_vec[ref].parent; fn Type MTree.parentof(&tree, int ref) => tree.refs_vec[ref].parent;

View File

@ -13,8 +13,8 @@ macro Ctx.button(&ctx, String label = "", String icon = "", ...)
fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon) fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon)
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem* parent, elem;
Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!; ctx.get_elem(id, ETYPE_BUTTON)!.unpack(&elem, &parent);
Style* style = ctx.styles.get_style(@str_hash("button")); Style* style = ctx.styles.get_style(@str_hash("button"));
Sprite* sprite = icon != "" ? ctx.sprite_atlas.get(icon)! : &&(Sprite){}; Sprite* sprite = icon != "" ? ctx.sprite_atlas.get(icon)! : &&(Sprite){};
@ -89,8 +89,8 @@ macro Ctx.checkbox(&ctx, String desc, bool* active, String tick_sprite = "", ...
fn void? Ctx.checkbox_id(&ctx, Id id, String description, bool* active, String tick_sprite) fn void? Ctx.checkbox_id(&ctx, Id id, String description, bool* active, String tick_sprite)
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem* parent, elem;
Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!; ctx.get_elem(id, ETYPE_BUTTON)!.unpack(&elem, &parent);
Style* style = ctx.styles.get_style(@str_hash("checkbox")); Style* style = ctx.styles.get_style(@str_hash("checkbox"));
short inner_pad = description != "" ? style.size/2 : 0; short inner_pad = description != "" ? style.size/2 : 0;
@ -163,8 +163,8 @@ fn void? Ctx.toggle_id(&ctx, Id id, String description, bool* active)
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem* parent, elem;
Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!; ctx.get_elem(id, ETYPE_BUTTON)!.unpack(&elem, &parent);
Style* style = ctx.styles.get_style(@str_hash("toggle")); Style* style = ctx.styles.get_style(@str_hash("toggle"));
short inner_pad = description != "" ? style.size/2 : 0; short inner_pad = description != "" ? style.size/2 : 0;

View File

@ -72,8 +72,8 @@ fn void? Ctx.div_begin_id(&ctx,
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem* elem = ctx.get_elem(id, ETYPE_DIV)!; Elem* parent, elem;
Elem* parent = ctx.get_parent()!; ctx.get_elem(id, ETYPE_DIV)!.unpack(&elem, &parent);
ctx.active_div = elem.tree_idx; ctx.active_div = elem.tree_idx;
Style* style = ctx.styles.get_style(@str_hash("div")); Style* style = ctx.styles.get_style(@str_hash("div"));
@ -183,8 +183,8 @@ fn bool? Ctx.popup_begin_id(&ctx,
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem* elem = ctx.get_elem(id, ETYPE_DIV)!; Elem* parent, elem;
Elem* parent = ctx.find_elem(ctx.active_div); // pop-up parent is always root ctx.get_elem(id, ETYPE_DIV)!.unpack(&elem, &parent);
ctx.active_div = elem.tree_idx; ctx.active_div = elem.tree_idx;
Style* style = ctx.styles.get_style(@str_hash("popup")); Style* style = ctx.styles.get_style(@str_hash("popup"));

View File

@ -6,8 +6,8 @@ macro Ctx.separator(&ctx, int width, int height, ...)
fn void? Ctx.separator_id(&ctx, Id id, int width, int height) fn void? Ctx.separator_id(&ctx, Id id, int width, int height)
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem* parent, elem;
Elem *elem = ctx.get_elem(id, ETYPE_NONE)!; ctx.get_elem(id, ETYPE_NONE)!.unpack(&elem, &parent);
elem.layout.w = @exact((short)width); elem.layout.w = @exact((short)width);
elem.layout.h = @exact((short)height); elem.layout.h = @exact((short)height);

View File

@ -22,8 +22,8 @@ fn ElemEvents? Ctx.slider_hor_id(&ctx, Id id, Size w, Size h, float* value, floa
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem* parent = ctx.get_parent()!; Elem* parent, elem;
Elem* elem = ctx.get_elem(id, ETYPE_SLIDER)!; ctx.get_elem(id, ETYPE_SLIDER)!.unpack(&elem, &parent);
Style* style = ctx.styles.get_style(@str_hash("slider")); Style* style = ctx.styles.get_style(@str_hash("slider"));
elem.layout.w = w; elem.layout.w = w;
@ -85,8 +85,8 @@ fn ElemEvents? Ctx.slider_ver_id(&ctx, Id id, Size w, Size h, float* value, floa
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem* parent, elem;
Elem *elem = ctx.get_elem(id, ETYPE_SLIDER)!; ctx.get_elem(id, ETYPE_SLIDER)!.unpack(&elem, &parent);
Style* style = ctx.styles.get_style(@str_hash("slider")); Style* style = ctx.styles.get_style(@str_hash("slider"));
elem.layout.w = w; elem.layout.w = w;
@ -135,8 +135,8 @@ fn void? Ctx.scrollbar(&ctx, Id id, float *value, float handle_percent, bool ver
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem* parent, elem;
Elem *elem = ctx.get_elem(id, ETYPE_SLIDER)!; ctx.get_elem(id, ETYPE_SLIDER)!.unpack(&elem, &parent);
Style* style = ctx.styles.get_style(@str_hash("scrollbar")); Style* style = ctx.styles.get_style(@str_hash("scrollbar"));
Rect pb = parent.bounds.pad(parent.layout.content_offset); Rect pb = parent.bounds.pad(parent.layout.content_offset);

View File

@ -9,8 +9,8 @@ macro Ctx.sprite(&ctx, String name, ...)
fn void? Ctx.sprite_id(&ctx, Id id, String name) fn void? Ctx.sprite_id(&ctx, Id id, String name)
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem* parent, elem;
Elem *elem = ctx.get_elem(id, ETYPE_SPRITE)!; ctx.get_elem(id, ETYPE_SPRITE)!.unpack(&elem, &parent);
Style* style = ctx.styles.get_style(@str_hash("sprite")); Style* style = ctx.styles.get_style(@str_hash("sprite"));
Sprite* sprite = ctx.sprite_atlas.get(name)!; Sprite* sprite = ctx.sprite_atlas.get(name)!;

View File

@ -18,8 +18,8 @@ fn void? Ctx.text_id(&ctx, Id id, String text)
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem* parent, elem;
Elem *elem = ctx.get_elem(id, ETYPE_TEXT)!; ctx.get_elem(id, ETYPE_TEXT)!.unpack(&elem, &parent);
Style* style = ctx.styles.get_style(@str_hash("text")); Style* style = ctx.styles.get_style(@str_hash("text"));
Id text_hash = text.hash(); Id text_hash = text.hash();
@ -45,8 +45,8 @@ fn ElemEvents? Ctx.text_box_id(&ctx, Id id, Size w, Size h, TextEdit* te, Anchor
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem* parent, elem;
Elem *elem = ctx.get_elem(id, ETYPE_TEXT)!; ctx.get_elem(id, ETYPE_TEXT)!.unpack(&elem, &parent);
Style* style = ctx.styles.get_style(@str_hash("text-box")); Style* style = ctx.styles.get_style(@str_hash("text-box"));
elem.text.te = te; elem.text.te = te;