This commit is contained in:
Alessandro Mauri 2025-10-02 23:19:42 +02:00
parent e7cfa3517f
commit 32a57d5293
7 changed files with 117 additions and 33 deletions

View File

@ -58,6 +58,7 @@ struct Elem {
Rect children_bounds;
ElemType type;
Layout layout;
int z_index;
union {
ElemDiv div;
ElemButton button;
@ -100,6 +101,7 @@ struct Ctx {
bool has_focus;
struct input {
InputEvents events;
int z_index; // the layer the input events need to be propageted to
struct mouse {
Point pos, delta;
// mouse_down: bitmap of mouse buttons that are held
@ -178,6 +180,11 @@ 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.tree_idx = ctx.tree.add(ctx.active_div, id);
return elem;
}
@ -242,10 +249,11 @@ fn void? Ctx.frame_begin(&ctx)
// if the window has focus then the root element also has focus, no other
// computation needed, child elements need to check the mouse positon and
// other stuff
ctx.input.z_index = 0;
//elem.flags.has_focus = ctx.has_focus;
elem.bounds = {0, 0, ctx.width, ctx.height};
elem.div.z_index = 0;
elem.z_index = 0;
elem.div.scroll_x.enabled = false;
elem.div.scroll_y.enabled = false;
elem.layout.dir = ROW;
@ -309,7 +317,8 @@ $endif
// sort the command buffer by the z-index
// FIXME: sorting the buffer fucks with scissor commands that have to be kept in place
//ctx.cmd_queue.sort()!;
// TODO: instead of sorting at the end perform ordered inserts into the command buffer
ctx.cmd_queue.sort()!;
// foreach (i, c: ctx.cmd_queue) {
// io::printf("[%d]: ", i);
@ -335,6 +344,8 @@ macro bool Ctx.elem_focus(&ctx, Elem *elem)
// FIXME: hacked together, please do better
fn ElemEvents Ctx.get_elem_events(&ctx, Elem *elem)
{
if (ctx.input.z_index != elem.z_index) return {};
bool hover = ctx.is_hovered(elem);
bool focus = ctx.elem_focus(elem) || (hover && ctx.is_mouse_pressed(BTN_LEFT));

View File

@ -47,6 +47,7 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon)
update_parent_size(elem, parent);
elem.events = ctx.get_elem_events(elem);
// if (ctx.input.z_index == elem.z_index) println("true ", elem.z_index);
Rect content_bounds = elem.content_bounds();
Rect icon_bounds = {
@ -72,12 +73,12 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon)
s.bg = s.accent;
}
ctx.push_rect(elem.bounds.pad(style.margin), parent.div.z_index, &s)!;
ctx.push_rect(elem.bounds.pad(style.margin), parent.z_index, &s)!;
if (icon != "") {
ctx.push_sprite(icon_bounds, sprite.uv(), ctx.sprite_atlas.id, parent.div.z_index, type: sprite.type)!;
ctx.push_sprite(icon_bounds, sprite.uv(), ctx.sprite_atlas.id, parent.z_index, type: sprite.type)!;
}
if (label != "") {
ctx.layout_string(label, text_bounds, CENTER, parent.div.z_index, style.fg)!;
ctx.layout_string(label, text_bounds, CENTER, parent.z_index, style.fg)!;
}
return elem.events;
}
@ -138,20 +139,20 @@ fn void? Ctx.checkbox_id(&ctx, Id id, String description, bool* active, String t
s.border = style.border;
s.radius = style.radius;
ctx.layout_string(description, text_bounds, CENTER, parent.div.z_index, style.fg)!;
ctx.layout_string(description, text_bounds, CENTER, parent.z_index, style.fg)!;
if (tick_sprite != "") {
ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
ctx.push_rect(check_bounds, parent.z_index, &s)!;
if (*active) {
Sprite* sprite = ctx.sprite_atlas.get(tick_sprite)!;
Id tex_id = ctx.sprite_atlas.id;
ctx.push_sprite(sprite.rect().center_to(check_bounds), sprite.uv(), tex_id, parent.div.z_index, type: sprite.type)!;
ctx.push_sprite(sprite.rect().center_to(check_bounds), sprite.uv(), tex_id, parent.z_index, type: sprite.type)!;
}
} else {
if (*active) {
s.bg = style.primary;
ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
ctx.push_rect(check_bounds, parent.z_index, &s)!;
} else {
ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
ctx.push_rect(check_bounds, parent.z_index, &s)!;
}
}
}
@ -216,10 +217,10 @@ fn void? Ctx.toggle_id(&ctx, Id id, String description, bool* active)
s.secondary = style.secondary;
s.border = style.border;
s.radius = style.radius;
ctx.layout_string(description, text_bounds, CENTER, parent.div.z_index, style.fg)!;
ctx.push_rect(toggle_bounds, parent.div.z_index, &s)!;
ctx.layout_string(description, text_bounds, CENTER, parent.z_index, style.fg)!;
ctx.push_rect(toggle_bounds, parent.z_index, &s)!;
s.bg = style.primary;
s.border = {};
ctx.push_rect(toggle.pad(style.border), parent.div.z_index, &s)!;
ctx.push_rect(toggle.pad(style.border), parent.z_index, &s)!;
}

View File

@ -15,7 +15,6 @@ struct ElemDiv {
bool on;
float value;
}
int z_index;
}
@ -81,8 +80,8 @@ fn void? Ctx.div_begin_id(&ctx,
elem.div.scroll_x.enabled = scroll_x;
elem.div.scroll_y.enabled = scroll_y;
elem.div.z_index = parent.div.z_index + 1;
if (ctx.input.z_index < elem.z_index) ctx.input.z_index = elem.z_index;
// update layout with correct info
elem.layout = {
.w = width,
@ -97,11 +96,11 @@ fn void? Ctx.div_begin_id(&ctx,
elem.layout.origin.y = off.y;
}
ctx.push_rect(elem.bounds.pad(style.margin), elem.div.z_index, style)!;
ctx.push_rect(elem.bounds.pad(style.margin), elem.z_index, style)!;
// update the ctx scissor, it HAS to be after drawing the background
ctx.div_scissor = elem.bounds.pad(elem.layout.content_offset);
ctx.push_scissor(elem.bounds.pad(elem.layout.content_offset), elem.div.z_index)!;
ctx.push_scissor(elem.bounds.pad(elem.layout.content_offset), elem.z_index)!;
elem.events = ctx.get_elem_events(elem);
@ -160,9 +159,67 @@ fn Id? Ctx.div_end(&ctx)
ctx.active_div = ctx.tree.parentof(ctx.active_div);
Elem* parent = ctx.get_parent()!;
ctx.div_scissor = parent.bounds.pad(parent.layout.content_offset);
ctx.reset_scissor(elem.div.z_index)!;
ctx.reset_scissor(elem.z_index)!;
update_parent_size(elem, parent);
return elem.id;
}
macro bool? Ctx.popup_begin(&ctx, Point pos,
Size width, Size height,
LayoutDirection dir = ROW, Anchor anchor = TOP_LEFT,
bool scroll_x = false, bool scroll_y = false,
...
)
=> ctx.popup_begin_id(@compute_id($vasplat), pos, width, height, dir, anchor, scroll_x, scroll_y);
fn bool? Ctx.popup_begin_id(&ctx,
Id id,
Point pos,
Size width, Size height,
LayoutDirection dir, Anchor anchor,
bool scroll_x, bool scroll_y
)
{
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
ctx.active_div = elem.tree_idx;
Style* style = ctx.styles.get_style(@str_hash("popup"));
elem.div.scroll_x.enabled = scroll_x;
elem.div.scroll_y.enabled = scroll_y;
elem.z_index++;
if (ctx.input.z_index < elem.z_index) ctx.input.z_index = elem.z_index;
// update layout with correct info
elem.layout = {
.w = width,
.h = height,
.dir = dir,
.anchor = anchor,
.content_offset = style.margin + style.border + style.padding,
.absolute = true,
.origin.x = pos.x - parent.bounds.x,
.origin.y = pos.y - parent.bounds.y,
};
ctx.push_rect(elem.bounds.pad(style.margin), elem.z_index, style)!;
// update the ctx scissor, it HAS to be after drawing the background
ctx.div_scissor = elem.bounds.pad(elem.layout.content_offset);
ctx.push_scissor(elem.bounds.pad(elem.layout.content_offset), elem.z_index)!;
elem.events = ctx.get_elem_events(elem);
// check close condition, mouse release anywhere outside the div bounds
if ((ctx.mouse_released() & BTN_ANY) && !elem.events.mouse_hover) {
return false;
}
// TODO: check active
// TODO: check resizeable
return true;
}

View File

@ -57,11 +57,11 @@ fn ElemEvents? Ctx.slider_hor_id(&ctx, Id id, Size w, Size h, float* value, floa
Style s = *style;
Rect padding = s.padding;
s.padding = {};
ctx.push_rect(bg_bounds, parent.div.z_index, &s)!;
ctx.push_rect(bg_bounds, parent.z_index, &s)!;
s.bg = s.primary;
s.padding = padding;
s.border = {};
ctx.push_rect(elem.slider.handle, parent.div.z_index, &s)!;
ctx.push_rect(elem.slider.handle, parent.z_index, &s)!;
return elem.events;
}
@ -121,11 +121,11 @@ fn ElemEvents? Ctx.slider_ver_id(&ctx, Id id, Size w, Size h, float* value, floa
Style s = *style;
Rect padding = s.padding;
s.padding = {};
ctx.push_rect(bg_bounds, parent.div.z_index, &s)!;
ctx.push_rect(bg_bounds, parent.z_index, &s)!;
s.bg = s.primary;
s.padding = padding;
s.border = {};
ctx.push_rect(elem.slider.handle, parent.div.z_index, &s)!;
ctx.push_rect(elem.slider.handle, parent.z_index, &s)!;
return elem.events;
}
@ -177,8 +177,8 @@ fn void? Ctx.scrollbar(&ctx, Id id, float *value, float handle_percent, bool ver
Rect bg_bounds = elem.bounds.pad(style.margin);
ctx.push_rect(bg_bounds, parent.div.z_index, style)!;
ctx.push_rect(elem.slider.handle, parent.div.z_index, &&(Style){.bg = style.primary, .radius = style.radius})!;
ctx.push_rect(bg_bounds, parent.z_index, style)!;
ctx.push_rect(elem.slider.handle, parent.z_index, &&(Style){.bg = style.primary, .radius = style.radius})!;
}
macro short calc_slider(short off, short dim, float value) => (short)off + (short)(dim * value);

View File

@ -22,5 +22,5 @@ fn void? Ctx.sprite_id(&ctx, Id id, String name)
update_parent_size(elem, parent);
Id tex_id = ctx.sprite_atlas.id;
return ctx.push_sprite(elem.bounds, sprite.uv(), tex_id, parent.div.z_index, type: sprite.type)!;
return ctx.push_sprite(elem.bounds, sprite.uv(), tex_id, parent.z_index, type: sprite.type)!;
}

View File

@ -35,7 +35,7 @@ fn void? Ctx.text_id(&ctx, Id id, String text)
update_parent_size(elem, parent);
ctx.layout_string(text, elem.bounds.pad(elem.layout.content_offset), TOP_LEFT, parent.div.z_index, style.fg)!;
ctx.layout_string(text, elem.bounds.pad(elem.layout.content_offset), TOP_LEFT, parent.z_index, style.fg)!;
}
@ -75,17 +75,17 @@ fn ElemEvents? Ctx.text_box_id(&ctx, Id id, Size w, Size h, TextEdit* te, Anchor
Rect bg_bounds = elem.bounds.pad(style.margin);
Rect text_bounds = elem.bounds.pad(elem.layout.content_offset);
ctx.push_rect(bg_bounds, parent.div.z_index, style)!;
ctx.push_rect(bg_bounds, parent.z_index, style)!;
Rect cur;
cur = ctx.layout_string(elem.text.te.to_string(), text_bounds, text_alignment, parent.div.z_index, style.fg, elem.text.te.cursor)!;
cur = ctx.layout_string(elem.text.te.to_string(), text_bounds, text_alignment, parent.z_index, style.fg, elem.text.te.cursor)!;
// draw the cursor if the element has focus
cur.w = 2;
cur.x -= 2;
if (elem.events.has_focus) {
ctx.push_scissor(text_bounds, parent.div.z_index)!;
ctx.push_rect(cur, parent.div.z_index, &&(Style){.bg = style.fg})!;
ctx.reset_scissor(parent.div.z_index)!;
ctx.push_scissor(text_bounds, parent.z_index)!;
ctx.push_rect(cur, parent.z_index, &&(Style){.bg = style.fg})!;
ctx.reset_scissor(parent.z_index)!;
}
return elem.events;
}

View File

@ -209,7 +209,7 @@ fn int main(String[] args)
if (ui.check_key_combo(ugui::KMOD_CTRL, "q")) quit = true;
const String APPLICATION = "debug";
const String APPLICATION = "calculator";
$switch APPLICATION:
$case "debug":
debug_app(&ui);
@ -382,6 +382,20 @@ fn void calculator(ugui::Ctx* ui, TextEdit* te)
if (len > 0) len--;
}
static bool toggle;
static ugui::Point pos;
if (ui.is_mouse_released(ugui::BTN_RIGHT)) {
pos = ui.input.mouse.pos;
toggle = !toggle;
}
if (toggle) {
toggle = ui.popup_begin(pos, ugui::@fit(50), ugui::@fit(100), COLUMN)!!;
ui.button("Uno")!!;
ui.button("Due")!!;
ui.button("Tre")!!;
ui.button("Quattro")!!;
ui.div_end()!!;
}
// ui input/output
ui.@div(ugui::@grow(), ugui::@grow(), ROW, CENTER) { // center everything on the screen
ui.@div(ugui::@fit(), ugui::@fit(), COLUMN, TOP_LEFT) {
@ -446,4 +460,5 @@ fn void calculator(ugui::Ctx* ui, TextEdit* te)
ui.text_box(ugui::@grow(), ugui::@exact(100), te, RIGHT)!!;
}!!;
}!!; }!!;
}