Compare commits

...

2 Commits

Author SHA1 Message Date
167676f478 use $feature() to enable debug features 2025-10-03 15:31:44 +02:00
8cecb57d93 use a tuple in get_elem 2025-10-03 15:19:52 +02:00
11 changed files with 54 additions and 53 deletions

View File

@ -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
@ -267,8 +268,6 @@ fn void? Ctx.frame_begin(&ctx)
// TODO: add a background color taken from a theme or config
}
const int DEBUG = 1;
fn void? Ctx.frame_end(&ctx)
{
// FIXME: this is not guaranteed to be root. the user might forget to close a div or some other element
@ -279,7 +278,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();
@ -299,7 +298,7 @@ fn void? Ctx.frame_end(&ctx)
}
// debug
$if DEBUG == 1:
$if $feature(DEBUG_POINTER):
// draw mouse position
Cmd cmd = {
.type = CMD_RECT,

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;
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, &&{});

View File

@ -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;

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)
{
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;

View File

@ -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"));

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)
{
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);

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)!;
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);

View File

@ -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)!;

View File

@ -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;

View File

@ -3,7 +3,7 @@
"warnings": ["no-unused"],
"dependency-search-paths": ["lib", "lib/vendor/libraries"],
"dependencies": ["sdl3", "ugui"],
"features": [],
"features": ["DEBUG_POINTER"],
"authors": ["Alessandro Mauri <ale@shitposting.expert>"],
"version": "0.1.0",
"sources": ["src/**"],
@ -14,7 +14,6 @@
"type": "executable"
}
},
"cpu": "native",
"opt": "O0",
"debug-info": "full"
}

View File

@ -36,7 +36,6 @@ import ugui;
// CONSTANTS //
// ============================================================================================== //
const int DEBUG = 1;
const bool CYCLE = true;
const int MAX_QUAD_BATCH = 2048;
@ -147,7 +146,7 @@ struct Renderer {
fn void Renderer.init(&self, ZString title, uint width, uint height, bool vsync)
{
// set wayland hint automagically
$if DEBUG == 0:
$if $feature(RENDER_DEBUG) == false && $feature(USE_WAYLAND) == true:
bool has_wayland = false;
for (int i = 0; i < sdl::get_num_video_drivers(); i++) {
ZString driver = sdl::get_video_driver(i);