diff --git a/lib/ugui.c3l/src/core.c3 b/lib/ugui.c3l/src/core.c3 index 1788110..c5210ee 100644 --- a/lib/ugui.c3l/src/core.c3 +++ b/lib/ugui.c3l/src/core.c3 @@ -7,6 +7,7 @@ import fifo; import std::io; import std::core::string; import std::core::mem::allocator; +import std::collections::pair; 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 alias IdTree = mtree::MTree{Id}; @@ -130,10 +134,8 @@ struct Ctx { // return a pointer to the parent of the current active div fn Elem*? Ctx.get_parent(&ctx) { - Id parent_id = ctx.tree.get(ctx.active_div); - Elem*? parent = ctx.cache.search(parent_id); - if (catch parent) return parent; - if (parent.type != ETYPE_DIV) return WRONG_ELEMENT_TYPE?; + Id parent_id = ctx.tree[ctx.active_div]!; + Elem* parent = ctx.cache.search(parent_id)!; return parent; } @@ -146,7 +148,7 @@ const uint GOLDEN_RATIO = 0x9E3779B9; fn Id? Ctx.gen_id(&ctx, Id id2) { // 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 Id mixed = id1 ^ id2.rotate_left(13); 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 // 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; + Elem* parent; Elem* elem; + parent = ctx.get_parent() ?? &&(Elem){}; + elem = ctx.cache.get_or_insert(&&(Elem){}, id, &is_new)!; elem.flags = (ElemFlags)0; elem.flags.is_new = is_new; @@ -180,13 +185,9 @@ fn Elem*? Ctx.get_elem(&ctx, Id id, ElemType type) } else { elem.type = type; } - // FIXME: this is crap - if (ctx.tree.is_used(ctx.active_div)) { - elem.z_index = ctx.get_active_div()!.z_index; - } - + elem.z_index = parent.z_index; 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 @@ -203,7 +204,7 @@ macro Elem* Ctx.find_elem(&ctx, Id id) 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); } @@ -240,7 +241,7 @@ fn void? Ctx.frame_begin(&ctx) // 1. Reset the active div // 2. Get the root element from the cache and update it 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; // The root should have the updated flag only if the size of the window // was changed between frasmes, this propagates an element size recalculation @@ -279,7 +280,7 @@ fn void? Ctx.frame_end(&ctx) } // DO THE LAYOUT - ctx.layout_element_tree(); + ctx.layout_element_tree()!; // 1. clear the tree ctx.tree.nuke(); diff --git a/lib/ugui.c3l/src/layout.c3 b/lib/ugui.c3l/src/layout.c3 index 92702e4..5a850c6 100644 --- a/lib/ugui.c3l/src/layout.c3 +++ b/lib/ugui.c3l/src/layout.c3 @@ -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; 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; int ch; // RESOLVE KNOWN DIMENSIONS 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)) { resolve_dimensions(p, &&{}); } else { @@ -317,7 +317,7 @@ fn void Ctx.layout_element_tree(&ctx) // RESOLVE GROW CHILDREN 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)) { resolve_grow_elements(p, &&{}); } else { @@ -327,7 +327,7 @@ fn void Ctx.layout_element_tree(&ctx) // RESOLVE CHILDREN PLACEMENT 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)) { resolve_placement(p, &&{}); update_children_bounds(p, &&{}); diff --git a/lib/ugui.c3l/src/mtree.c3 b/lib/ugui.c3l/src/mtree.c3 index 22d4cc8..db71cb9 100644 --- a/lib/ugui.c3l/src/mtree.c3 +++ b/lib/ugui.c3l/src/mtree.c3 @@ -312,8 +312,12 @@ fn void MTree.prune(&tree, int parent) } -<* @require tree.is_used(ref) *> -fn Type MTree.get(&tree, int ref) => tree.elem_vec[ref]; +<* @require ref >= 0 , ref < tree.elem_vec.len *> +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) *> fn Type MTree.parentof(&tree, int ref) => tree.refs_vec[ref].parent; diff --git a/lib/ugui.c3l/src/widgets/button.c3 b/lib/ugui.c3l/src/widgets/button.c3 index d732dc6..bfece9e 100644 --- a/lib/ugui.c3l/src/widgets/button.c3 +++ b/lib/ugui.c3l/src/widgets/button.c3 @@ -13,8 +13,8 @@ macro Ctx.button(&ctx, String label = "", String icon = "", ...) fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon) { id = ctx.gen_id(id)!; - Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!; + Elem* parent, elem; + ctx.get_elem(id, ETYPE_BUTTON)!.unpack(&elem, &parent); Style* style = ctx.styles.get_style(@str_hash("button")); 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) { id = ctx.gen_id(id)!; - Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!; + Elem* parent, elem; + ctx.get_elem(id, ETYPE_BUTTON)!.unpack(&elem, &parent); Style* style = ctx.styles.get_style(@str_hash("checkbox")); 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)!; - Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!; + Elem* parent, elem; + ctx.get_elem(id, ETYPE_BUTTON)!.unpack(&elem, &parent); Style* style = ctx.styles.get_style(@str_hash("toggle")); short inner_pad = description != "" ? style.size/2 : 0; diff --git a/lib/ugui.c3l/src/widgets/div.c3 b/lib/ugui.c3l/src/widgets/div.c3 index 566920f..a8a185c 100644 --- a/lib/ugui.c3l/src/widgets/div.c3 +++ b/lib/ugui.c3l/src/widgets/div.c3 @@ -72,8 +72,8 @@ fn void? Ctx.div_begin_id(&ctx, { id = ctx.gen_id(id)!; - Elem* elem = ctx.get_elem(id, ETYPE_DIV)!; - Elem* parent = ctx.get_parent()!; + Elem* parent, elem; + ctx.get_elem(id, ETYPE_DIV)!.unpack(&elem, &parent); ctx.active_div = elem.tree_idx; 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)!; - Elem* elem = ctx.get_elem(id, ETYPE_DIV)!; - Elem* parent = ctx.find_elem(ctx.active_div); // pop-up parent is always root + Elem* parent, elem; + ctx.get_elem(id, ETYPE_DIV)!.unpack(&elem, &parent); ctx.active_div = elem.tree_idx; Style* style = ctx.styles.get_style(@str_hash("popup")); diff --git a/lib/ugui.c3l/src/widgets/separator.c3 b/lib/ugui.c3l/src/widgets/separator.c3 index d0272fc..1c1adae 100644 --- a/lib/ugui.c3l/src/widgets/separator.c3 +++ b/lib/ugui.c3l/src/widgets/separator.c3 @@ -6,8 +6,8 @@ macro Ctx.separator(&ctx, int width, int height, ...) fn void? Ctx.separator_id(&ctx, Id id, int width, int height) { id = ctx.gen_id(id)!; - Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id, ETYPE_NONE)!; + Elem* parent, elem; + ctx.get_elem(id, ETYPE_NONE)!.unpack(&elem, &parent); elem.layout.w = @exact((short)width); elem.layout.h = @exact((short)height); diff --git a/lib/ugui.c3l/src/widgets/slider.c3 b/lib/ugui.c3l/src/widgets/slider.c3 index 31b961c..2073dac 100644 --- a/lib/ugui.c3l/src/widgets/slider.c3 +++ b/lib/ugui.c3l/src/widgets/slider.c3 @@ -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)!; - Elem* parent = ctx.get_parent()!; - Elem* elem = ctx.get_elem(id, ETYPE_SLIDER)!; + Elem* parent, elem; + ctx.get_elem(id, ETYPE_SLIDER)!.unpack(&elem, &parent); Style* style = ctx.styles.get_style(@str_hash("slider")); 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)!; - Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id, ETYPE_SLIDER)!; + Elem* parent, elem; + ctx.get_elem(id, ETYPE_SLIDER)!.unpack(&elem, &parent); Style* style = ctx.styles.get_style(@str_hash("slider")); 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)!; - Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id, ETYPE_SLIDER)!; + Elem* parent, elem; + ctx.get_elem(id, ETYPE_SLIDER)!.unpack(&elem, &parent); Style* style = ctx.styles.get_style(@str_hash("scrollbar")); Rect pb = parent.bounds.pad(parent.layout.content_offset); diff --git a/lib/ugui.c3l/src/widgets/sprite.c3 b/lib/ugui.c3l/src/widgets/sprite.c3 index 1886a78..ab54dc3 100644 --- a/lib/ugui.c3l/src/widgets/sprite.c3 +++ b/lib/ugui.c3l/src/widgets/sprite.c3 @@ -9,8 +9,8 @@ macro Ctx.sprite(&ctx, String name, ...) fn void? Ctx.sprite_id(&ctx, Id id, String name) { id = ctx.gen_id(id)!; - Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id, ETYPE_SPRITE)!; + Elem* parent, elem; + ctx.get_elem(id, ETYPE_SPRITE)!.unpack(&elem, &parent); Style* style = ctx.styles.get_style(@str_hash("sprite")); Sprite* sprite = ctx.sprite_atlas.get(name)!; diff --git a/lib/ugui.c3l/src/widgets/text.c3 b/lib/ugui.c3l/src/widgets/text.c3 index bd65c56..8849fc1 100644 --- a/lib/ugui.c3l/src/widgets/text.c3 +++ b/lib/ugui.c3l/src/widgets/text.c3 @@ -18,8 +18,8 @@ fn void? Ctx.text_id(&ctx, Id id, String text) { id = ctx.gen_id(id)!; - Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id, ETYPE_TEXT)!; + Elem* parent, elem; + ctx.get_elem(id, ETYPE_TEXT)!.unpack(&elem, &parent); Style* style = ctx.styles.get_style(@str_hash("text")); 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)!; - Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id, ETYPE_TEXT)!; + Elem* parent, elem; + ctx.get_elem(id, ETYPE_TEXT)!.unpack(&elem, &parent); Style* style = ctx.styles.get_style(@str_hash("text-box")); elem.text.te = te;