get_elem now also pushes into the tree and check the correct type

This commit is contained in:
Alessandro Mauri 2025-07-01 16:03:11 +02:00
parent 849b267f91
commit c49a689304
8 changed files with 41 additions and 121 deletions

2
TODO
View File

@ -64,6 +64,8 @@ to maintain focus until mouse release (fix scroll bars)
- border radius - border radius
[x] add a command to update an atlas [x] add a command to update an atlas
[ ] New window command, useful for popups [ ] 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 ## Atlas

View File

@ -16,15 +16,7 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, Rect size, bool active)
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id)!; Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!;
// 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.bounds = ctx.position_element(parent, size, true); 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)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id)!; Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!;
// 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;
short line_height = (short)ctx.font.ascender - (short)ctx.font.descender; short line_height = (short)ctx.font.ascender - (short)ctx.font.descender;
Rect text_size = ctx.get_text_bounds(label)!; 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)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id)!; Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!;
// 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?;
}
Sprite* def_sprite = ctx.sprite_atlas.get(icon)!; Sprite* def_sprite = ctx.sprite_atlas.get(icon)!;
Sprite* on_sprite = ctx.sprite_atlas.get(on_icon) ?? &&(Sprite){}; 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)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id)!; Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!;
// 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?;
}
Rect size = {off.x, off.y, DEFAULT_CHECKBOX_SIZE, DEFAULT_CHECKBOX_SIZE}; Rect size = {off.x, off.y, DEFAULT_CHECKBOX_SIZE, DEFAULT_CHECKBOX_SIZE};
elem.bounds = ctx.position_element(parent, size, true); 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)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id)!; Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!;
// 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?;
}
Rect size = {off.x, off.y, DEFAULT_SWITCH_SIZE*2, DEFAULT_SWITCH_SIZE}; Rect size = {off.x, off.y, DEFAULT_SWITCH_SIZE*2, DEFAULT_SWITCH_SIZE};
elem.bounds = ctx.position_element(parent, size, true); elem.bounds = ctx.position_element(parent, size, true);

View File

@ -40,6 +40,7 @@ bitstruct ElemEvents : uint {
// element structure // element structure
struct Elem { struct Elem {
Id id; Id id;
isz tree_idx;
ElemFlags flags; ElemFlags flags;
ElemEvents events; ElemEvents events;
Rect bounds; Rect bounds;
@ -158,7 +159,7 @@ 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) fn Elem*? Ctx.get_elem(&ctx, Id id, ElemType type)
{ {
Elem empty_elem; Elem empty_elem;
bool is_new; 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 = ctx.cache.get_or_insert(&empty_elem, id, &is_new)!;
elem.flags = (ElemFlags)0; elem.flags = (ElemFlags)0;
elem.flags.is_new = is_new; 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; 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; return elem;
} }
@ -223,11 +229,13 @@ fn void Ctx.free(&ctx)
fn void? Ctx.frame_begin(&ctx) fn void? Ctx.frame_begin(&ctx)
{ {
// 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
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 // 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 // down the element tree
elem.flags.updated = ctx.input.events.resize; elem.flags.updated = ctx.input.events.resize;
// if the window has focus then the root element also has focus, no other // 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 // other stuff
//elem.flags.has_focus = ctx.has_focus; //elem.flags.has_focus = ctx.has_focus;
Elem def_root = { elem.bounds = {0, 0, ctx.width, ctx.height};
.id = ROOT_ID, elem.div.layout = LAYOUT_ROW;
.type = ETYPE_DIV, elem.div.z_index = 0;
.bounds = { elem.div.children_bounds = elem.bounds;
.w = ctx.width, elem.div.scroll_x.enabled = false;
.h = ctx.height, elem.div.scroll_y.enabled = false;
}, elem.div.pcb = {};
.div = { elem.div.origin_c = {};
.layout = LAYOUT_ROW, elem.div.origin_r = {};
.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)!;
ctx.div_scissor = {0, 0, ctx.width, ctx.height}; ctx.div_scissor = {0, 0, ctx.width, ctx.height};

View File

@ -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)!; id = ctx.gen_id(id)!;
Elem* parent = ctx.get_parent()!; Elem* parent = ctx.get_parent()!;
Elem* elem = ctx.get_elem(id)!; Elem* elem = ctx.get_elem(id, ETYPE_DIV)!;
isz div_node = ctx.tree.add(id, ctx.active_div)!; ctx.active_div = elem.tree_idx;
ctx.active_div = div_node;
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_x.enabled = scroll_x;
elem.div.scroll_y.enabled = scroll_y; elem.div.scroll_y.enabled = scroll_y;
elem.div.z_index = parent.div.z_index + 1; elem.div.z_index = parent.div.z_index + 1;

View File

@ -35,16 +35,7 @@ fn ElemEvents? Ctx.slider_hor_id(&ctx,
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id)!; Elem *elem = ctx.get_elem(id, ETYPE_SLIDER)!;
// 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?;
}
// 2. Layout // 2. Layout
elem.bounds = ctx.position_element(parent, size, true); elem.bounds = ctx.position_element(parent, size, true);
@ -106,9 +97,7 @@ fn ElemEvents? Ctx.slider_ver_id(&ctx,
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id)!; Elem *elem = ctx.get_elem(id, ETYPE_SLIDER)!;
// add it to the tree
ctx.tree.add(id, ctx.active_div)!;
// 1. Fill the element fields // 1. Fill the element fields
if (elem.flags.is_new) { if (elem.flags.is_new) {

View File

@ -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}, ...) macro Ctx.sprite(&ctx, String name, Point off = {0,0}, ...)
=> ctx.draw_sprite_id(@compute_id($vasplat), name, off); => ctx.sprite_id(@compute_id($vasplat), name, off);
fn void? Ctx.draw_sprite_id(&ctx, Id id, String name, Point off) fn void? Ctx.sprite_id(&ctx, Id id, String name, Point off)
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id)!; Elem *elem = ctx.get_elem(id, ETYPE_SPRITE)!;
// 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?;
}
Sprite* sprite = ctx.sprite_atlas.get(name)!; Sprite* sprite = ctx.sprite_atlas.get(name)!;

View File

@ -14,13 +14,8 @@ fn void? Ctx.text_unbounded_id(&ctx, Id id, String text)
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id)!; Elem *elem = ctx.get_elem(id, ETYPE_TEXT)!;
// 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.text.str = text; elem.text.str = text;
// if the element is new or the parent was updated then redo layout // 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)!; id = ctx.gen_id(id)!;
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id)!; Elem *elem = ctx.get_elem(id, ETYPE_TEXT)!;
// 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.text.str = text; elem.text.str = text;
// layout the text box // layout the text box

View File

@ -231,7 +231,7 @@ fn int main(String[] args)
ui.checkbox("", {}, &check)!!; ui.checkbox("", {}, &check)!!;
ui.toggle("", {}, &toggle)!!; ui.toggle("", {}, &toggle)!!;
}; };
ui.draw_sprite("tux")!!; ui.sprite("tux")!!;
static char[128] text_box = "ciao mamma"; static char[128] text_box = "ciao mamma";
static usz text_len = "ciao mamma".len; static usz text_len = "ciao mamma".len;