From c49a689304575374d6d485e5e6660c07c03387cb Mon Sep 17 00:00:00 2001 From: Alessandro Mauri Date: Tue, 1 Jul 2025 16:03:11 +0200 Subject: [PATCH] get_elem now also pushes into the tree and check the correct type --- TODO | 2 ++ lib/ugui.c3l/src/ugui_button.c3 | 50 ++++----------------------------- lib/ugui.c3l/src/ugui_core.c3 | 49 +++++++++++++++----------------- lib/ugui.c3l/src/ugui_div.c3 | 12 ++------ lib/ugui.c3l/src/ugui_slider.c3 | 15 ++-------- lib/ugui.c3l/src/ugui_sprite.c3 | 16 +++-------- lib/ugui.c3l/src/ugui_text.c3 | 16 ++--------- src/main.c3 | 2 +- 8 files changed, 41 insertions(+), 121 deletions(-) diff --git a/TODO b/TODO index a3055f3..0c832c3 100644 --- a/TODO +++ b/TODO @@ -64,6 +64,8 @@ to maintain focus until mouse release (fix scroll bars) - border radius [x] add a command to update an atlas [ ] New window command, useful for popups +[ ] Text command returns the text bounds, this way we can avoid the pattern + draw_text(a, pos) -> off = compute_bounds(a) -> draw_text(b, pos+off) -> ... ## Atlas diff --git a/lib/ugui.c3l/src/ugui_button.c3 b/lib/ugui.c3l/src/ugui_button.c3 index 93e519f..2e98af1 100644 --- a/lib/ugui.c3l/src/ugui_button.c3 +++ b/lib/ugui.c3l/src/ugui_button.c3 @@ -16,15 +16,7 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, Rect size, bool active) id = ctx.gen_id(id)!; Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id)!; - // add it to the tree - ctx.tree.add(id, ctx.active_div)!; - - if (elem.flags.is_new) { - elem.type = ETYPE_BUTTON; - } else if (elem.type != ETYPE_BUTTON) { - return WRONG_ELEMENT_TYPE?; - } + Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!; elem.bounds = ctx.position_element(parent, size, true); @@ -53,13 +45,7 @@ fn ElemEvents? Ctx.button_label_id(&ctx, Id id, String label, Rect size, bool ac id = ctx.gen_id(id)!; Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id)!; - // add it to the tree - ctx.tree.add(id, ctx.active_div)!; - - // 1. Fill the element fields - // this resets the flags - elem.type = ETYPE_BUTTON; + Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!; short line_height = (short)ctx.font.ascender - (short)ctx.font.descender; Rect text_size = ctx.get_text_bounds(label)!; @@ -96,15 +82,7 @@ fn ElemEvents? Ctx.button_icon_id(&ctx, Id id, String icon, String on_icon, bool id = ctx.gen_id(id)!; Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id)!; - // add it to the tree - ctx.tree.add(id, ctx.active_div)!; - - if (elem.flags.is_new) { - elem.type = ETYPE_BUTTON; - } else if (elem.type != ETYPE_BUTTON) { - return WRONG_ELEMENT_TYPE?; - } + Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!; Sprite* def_sprite = ctx.sprite_atlas.get(icon)!; Sprite* on_sprite = ctx.sprite_atlas.get(on_icon) ?? &&(Sprite){}; @@ -141,15 +119,7 @@ fn void? Ctx.checkbox_id(&ctx, Id id, String description, Point off, bool* activ id = ctx.gen_id(id)!; Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id)!; - // add it to the tree - ctx.tree.add(id, ctx.active_div)!; - - if (elem.flags.is_new) { - elem.type = ETYPE_BUTTON; - } else if (elem.type != ETYPE_BUTTON) { - return WRONG_ELEMENT_TYPE?; - } + Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!; Rect size = {off.x, off.y, DEFAULT_CHECKBOX_SIZE, DEFAULT_CHECKBOX_SIZE}; elem.bounds = ctx.position_element(parent, size, true); @@ -186,17 +156,7 @@ fn void? Ctx.toggle_id(&ctx, Id id, String description, Point off, bool* active) id = ctx.gen_id(id)!; Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id)!; - // add it to the tree - ctx.tree.add(id, ctx.active_div)!; - - // FIXME: for now switches and buttons have no members so the element types - // can be the same - if (elem.flags.is_new) { - elem.type = ETYPE_BUTTON; - } else if (elem.type != ETYPE_BUTTON) { - return WRONG_ELEMENT_TYPE?; - } + Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!; Rect size = {off.x, off.y, DEFAULT_SWITCH_SIZE*2, DEFAULT_SWITCH_SIZE}; elem.bounds = ctx.position_element(parent, size, true); diff --git a/lib/ugui.c3l/src/ugui_core.c3 b/lib/ugui.c3l/src/ugui_core.c3 index cb64e8b..d0354f8 100644 --- a/lib/ugui.c3l/src/ugui_core.c3 +++ b/lib/ugui.c3l/src/ugui_core.c3 @@ -40,6 +40,7 @@ bitstruct ElemEvents : uint { // element structure struct Elem { Id id; + isz tree_idx; ElemFlags flags; ElemEvents events; Rect bounds; @@ -158,7 +159,7 @@ 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) +fn Elem*? Ctx.get_elem(&ctx, Id id, ElemType type) { Elem empty_elem; bool is_new; @@ -166,8 +167,13 @@ fn Elem*? Ctx.get_elem(&ctx, Id id) elem = ctx.cache.get_or_insert(&empty_elem, id, &is_new)!; elem.flags = (ElemFlags)0; elem.flags.is_new = is_new; - // FIXME: should this be here? or is it better to have the elements set the id? elem.id = id; + if (is_new == false && elem.type != type) { + return WRONG_ELEMENT_TYPE?; + } else { + elem.type = type; + } + elem.tree_idx = ctx.tree.add(id, ctx.active_div)!; return elem; } @@ -223,11 +229,13 @@ fn void Ctx.free(&ctx) fn void? Ctx.frame_begin(&ctx) { - + // 1. Reset the active div // 2. Get the root element from the cache and update it - Elem* elem = ctx.get_elem(ROOT_ID)!; + ctx.active_div = 0; + Elem* elem = ctx.get_elem(ROOT_ID, ETYPE_DIV)!; + ctx.active_div = elem.tree_idx; // The root should have the updated flag only if the size of the window - // was changed between frames, this propagates an element size recalculation + // was changed between frasmes, this propagates an element size recalculation // down the element tree elem.flags.updated = ctx.input.events.resize; // if the window has focus then the root element also has focus, no other @@ -235,28 +243,15 @@ fn void? Ctx.frame_begin(&ctx) // other stuff //elem.flags.has_focus = ctx.has_focus; - Elem def_root = { - .id = ROOT_ID, - .type = ETYPE_DIV, - .bounds = { - .w = ctx.width, - .h = ctx.height, - }, - .div = { - .layout = LAYOUT_ROW, - .z_index = 0, - .children_bounds = { - .w = ctx.width, - .h = ctx.height, - } - }, - .flags = elem.flags, - }; - - *elem = def_root; - - // 3. Push the root element into the element tree - ctx.active_div = ctx.tree.add(ROOT_ID, 0)!; + elem.bounds = {0, 0, ctx.width, ctx.height}; + elem.div.layout = LAYOUT_ROW; + elem.div.z_index = 0; + elem.div.children_bounds = elem.bounds; + elem.div.scroll_x.enabled = false; + elem.div.scroll_y.enabled = false; + elem.div.pcb = {}; + elem.div.origin_c = {}; + elem.div.origin_r = {}; ctx.div_scissor = {0, 0, ctx.width, ctx.height}; diff --git a/lib/ugui.c3l/src/ugui_div.c3 b/lib/ugui.c3l/src/ugui_div.c3 index f259096..ed02156 100644 --- a/lib/ugui.c3l/src/ugui_div.c3 +++ b/lib/ugui.c3l/src/ugui_div.c3 @@ -36,17 +36,9 @@ fn void? Ctx.div_begin_id(&ctx, Id id, Rect size, bool scroll_x, bool scroll_y) id = ctx.gen_id(id)!; Elem* parent = ctx.get_parent()!; - Elem* elem = ctx.get_elem(id)!; - isz div_node = ctx.tree.add(id, ctx.active_div)!; - ctx.active_div = div_node; + Elem* elem = ctx.get_elem(id, ETYPE_DIV)!; + ctx.active_div = elem.tree_idx; - bool is_new = elem.flags.is_new; - - if (elem.flags.is_new) { - elem.type = ETYPE_DIV; - } else if (elem.type != ETYPE_DIV) { - return WRONG_ELEMENT_TYPE?; - } elem.div.scroll_x.enabled = scroll_x; elem.div.scroll_y.enabled = scroll_y; elem.div.z_index = parent.div.z_index + 1; diff --git a/lib/ugui.c3l/src/ugui_slider.c3 b/lib/ugui.c3l/src/ugui_slider.c3 index 7fb6d9a..55cd7fc 100644 --- a/lib/ugui.c3l/src/ugui_slider.c3 +++ b/lib/ugui.c3l/src/ugui_slider.c3 @@ -35,16 +35,7 @@ fn ElemEvents? Ctx.slider_hor_id(&ctx, id = ctx.gen_id(id)!; Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id)!; - // add it to the tree - ctx.tree.add(id, ctx.active_div)!; - - // 1. Fill the element fields - if (elem.flags.is_new) { - elem.type = ETYPE_SLIDER; - } else if (elem.type != ETYPE_SLIDER) { - return WRONG_ELEMENT_TYPE?; - } + Elem *elem = ctx.get_elem(id, ETYPE_SLIDER)!; // 2. Layout elem.bounds = ctx.position_element(parent, size, true); @@ -106,9 +97,7 @@ fn ElemEvents? Ctx.slider_ver_id(&ctx, id = ctx.gen_id(id)!; Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id)!; - // add it to the tree - ctx.tree.add(id, ctx.active_div)!; + Elem *elem = ctx.get_elem(id, ETYPE_SLIDER)!; // 1. Fill the element fields if (elem.flags.is_new) { diff --git a/lib/ugui.c3l/src/ugui_sprite.c3 b/lib/ugui.c3l/src/ugui_sprite.c3 index 216b1e2..0976281 100644 --- a/lib/ugui.c3l/src/ugui_sprite.c3 +++ b/lib/ugui.c3l/src/ugui_sprite.c3 @@ -111,22 +111,14 @@ fn void? Ctx.import_sprite_file_qoi(&ctx, String name, String path, SpriteType t } -macro Ctx.draw_sprite(&ctx, String name, Point off = {0,0}, ...) - => ctx.draw_sprite_id(@compute_id($vasplat), name, off); -fn void? Ctx.draw_sprite_id(&ctx, Id id, String name, Point off) +macro Ctx.sprite(&ctx, String name, Point off = {0,0}, ...) + => ctx.sprite_id(@compute_id($vasplat), name, off); +fn void? Ctx.sprite_id(&ctx, Id id, String name, Point off) { id = ctx.gen_id(id)!; Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id)!; - // add it to the tree - ctx.tree.add(id, ctx.active_div)!; - - if (elem.flags.is_new) { - elem.type = ETYPE_SPRITE; - } else if (elem.type != ETYPE_SPRITE) { - return WRONG_ELEMENT_TYPE?; - } + Elem *elem = ctx.get_elem(id, ETYPE_SPRITE)!; Sprite* sprite = ctx.sprite_atlas.get(name)!; diff --git a/lib/ugui.c3l/src/ugui_text.c3 b/lib/ugui.c3l/src/ugui_text.c3 index dda6ce4..de15b33 100644 --- a/lib/ugui.c3l/src/ugui_text.c3 +++ b/lib/ugui.c3l/src/ugui_text.c3 @@ -14,13 +14,8 @@ fn void? Ctx.text_unbounded_id(&ctx, Id id, String text) id = ctx.gen_id(id)!; Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id)!; - // add it to the tree - ctx.tree.add(id, ctx.active_div)!; + Elem *elem = ctx.get_elem(id, ETYPE_TEXT)!; - // 1. Fill the element fields - // this resets the flags - elem.type = ETYPE_TEXT; elem.text.str = text; // if the element is new or the parent was updated then redo layout @@ -39,13 +34,8 @@ fn ElemEvents? Ctx.text_box_id(&ctx, Id id, Rect size, char[] text, usz* text_le id = ctx.gen_id(id)!; Elem *parent = ctx.get_parent()!; - Elem *elem = ctx.get_elem(id)!; - // add it to the tree - ctx.tree.add(id, ctx.active_div)!; - - // 1. Fill the element fields - // this resets the flags - elem.type = ETYPE_TEXT; + Elem *elem = ctx.get_elem(id, ETYPE_TEXT)!; + elem.text.str = text; // layout the text box diff --git a/src/main.c3 b/src/main.c3 index 337cf81..0d55283 100644 --- a/src/main.c3 +++ b/src/main.c3 @@ -231,7 +231,7 @@ fn int main(String[] args) ui.checkbox("", {}, &check)!!; ui.toggle("", {}, &toggle)!!; }; - ui.draw_sprite("tux")!!; + ui.sprite("tux")!!; static char[128] text_box = "ciao mamma"; static usz text_len = "ciao mamma".len;