re-implemented checkbox

This commit is contained in:
Alessandro Mauri 2025-09-12 12:48:29 +02:00
parent be951c616a
commit e328a67d96
8 changed files with 98 additions and 86 deletions

View File

@ -97,9 +97,7 @@ macro Ctx.push_cmd(&ctx, Cmd *cmd, int z_index)
default: return ctx.cmd_queue.enqueue(cmd); default: return ctx.cmd_queue.enqueue(cmd);
} }
if (cull_rect(rect, ctx.div_scissor)) { if (cull_rect(rect, ctx.div_scissor)) {
// io::print("NOPE: "); // println("NOPE: ", cmd.rect.rect, cmd.z_index);
// io::print(cmd.rect.rect);
// io::printn(cmd.z_index);
// unreachable(); // unreachable();
return; return;
} }

View File

@ -165,10 +165,9 @@ macro Id @compute_id(...)
// 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, ElemType type) fn Elem*? Ctx.get_elem(&ctx, Id id, ElemType type)
{ {
Elem empty_elem;
bool is_new; bool is_new;
Elem* elem; Elem* elem;
elem = ctx.cache.get_or_insert(&empty_elem, id, &is_new)!; elem = ctx.cache.get_or_insert(&&(Elem){}, id, &is_new)!;
elem.flags = (ElemFlags)0; elem.flags = (ElemFlags)0;
elem.flags.is_new = is_new; elem.flags.is_new = is_new;
elem.id = id; elem.id = id;

View File

@ -30,10 +30,6 @@ struct SpriteAtlas {
bool should_update; bool should_update;
} }
struct ElemSprite {
Id id;
}
// name: some examples are "icons" or "images" // name: some examples are "icons" or "images"
fn void? SpriteAtlas.init(&this, String name, AtlasType type, ushort width, ushort height) fn void? SpriteAtlas.init(&this, String name, AtlasType type, ushort width, ushort height)
{ {
@ -109,47 +105,3 @@ fn void? Ctx.import_sprite_file_qoi(&ctx, String name, String path, SpriteType t
ctx.sprite_atlas.insert(name, type, pixels, (ushort)desc.width, (ushort)desc.height, (ushort)desc.width)!; ctx.sprite_atlas.insert(name, type, pixels, (ushort)desc.width, (ushort)desc.height, (ushort)desc.width)!;
} }
/*
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, ETYPE_SPRITE)!;
Style* style = ctx.styles.get_style(@str_hash("sprite"));
Sprite* sprite = ctx.sprite_atlas.get(name)!;
Rect uv = { sprite.u, sprite.v, sprite.w, sprite.h };
Rect bounds = { 0, 0, sprite.w, sprite.h };
elem.bounds = ctx.layout_element(parent, bounds.off(off), style);
elem.sprite.id = ctx.get_sprite_atlas_id(name);
// if the bounds are null the element is outside the div view,
// no interaction should occur so just return
if (elem.bounds.is_null()) return;
Id tex_id = ctx.sprite_atlas.id;
return ctx.push_sprite(elem.bounds, uv, tex_id, parent.div.z_index)!;
}
fn void? Ctx.draw_sprite_raw(&ctx, String name, Rect bounds, bool center = false)
{
Elem *parent = ctx.get_parent()!;
Sprite* sprite = ctx.sprite_atlas.get(name)!;
Id tex_id = ctx.sprite_atlas.id;
if (center) {
Point off = {.x = (bounds.w - sprite.w) / 2, .y = (bounds.h - sprite.h) / 2};
bounds = bounds.off(off);
}
return ctx.push_sprite(bounds, sprite.uv(), tex_id, parent.div.z_index, type: sprite.type)!;
}
*/

View File

@ -18,9 +18,6 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon)
Style* style = ctx.styles.get_style(@str_hash("button")); Style* style = ctx.styles.get_style(@str_hash("button"));
Sprite* sprite = icon != "" ? ctx.sprite_atlas.get(icon)! : &&(Sprite){}; Sprite* sprite = icon != "" ? ctx.sprite_atlas.get(icon)! : &&(Sprite){};
// TODO: get min size by style
TextSize text_size = ctx.measure_string(label)!;
Rect icon_size = sprite.rect(); Rect icon_size = sprite.rect();
ushort min_size = style.size; ushort min_size = style.size;
@ -44,7 +41,7 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon)
elem.layout.h = @fit(min_size); elem.layout.h = @fit(min_size);
elem.layout.children.w = @exact(content_size.x); elem.layout.children.w = @exact(content_size.x);
elem.layout.children.h = @exact(content_size.y); elem.layout.children.h = @exact(content_size.y);
elem.layout.text = text_size; elem.layout.text = ctx.measure_string(label)!;
elem.layout.content_offset = style.margin + style.border + style.padding; elem.layout.content_offset = style.margin + style.border + style.padding;
update_parent_grow(elem, parent); update_parent_grow(elem, parent);
@ -86,47 +83,82 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon)
return elem.events; return elem.events;
} }
/*
// FIXME: this should be inside the style macro Ctx.checkbox(&ctx, String desc, bool* active, String tick_sprite = "", ...)
macro Ctx.checkbox(&ctx, String desc, Point off, bool* active, String tick_sprite = {}, ...) => ctx.checkbox_id(@compute_id($vasplat), desc, active, tick_sprite);
=> ctx.checkbox_id(@compute_id($vasplat), desc, off, active, tick_sprite); fn void? Ctx.checkbox_id(&ctx, Id id, String description, bool* active, String tick_sprite)
fn void? Ctx.checkbox_id(&ctx, Id id, String description, Point off, bool* active, String tick_sprite)
{ {
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, ETYPE_BUTTON)!; Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!;
Style* style = ctx.styles.get_style(@str_hash("checkbox")); Style* style = ctx.styles.get_style(@str_hash("checkbox"));
Rect size = {off.x, off.y, style.size, style.size}; short inner_pad = description != "" ? style.size/2 : 0;
elem.bounds = ctx.layout_element(parent, size, style); /*
* |< >| style.size/2
* +---------------------|---|-----------+
* | | .-----. ---|--
* | +-----------------+ ' ### ' | ^
* | | description | | ##### | | style.size
* | +-----------------+ . ### . | v
* | '-----' ---|--
* +-------------------------|-------|---+
* |<----->| style.size
*/
// if the bounds are null the element is outside the div view, elem.layout.w = @fit(style.size);
// no interaction should occur so just return elem.layout.h = @fit(style.size);
if (elem.bounds.is_null()) return; elem.layout.children.w = @exact(style.size + inner_pad);
elem.layout.children.h = @exact(style.size);
elem.layout.text = ctx.measure_string(description)!;
elem.layout.content_offset = style.margin + style.border + style.padding;
update_parent_grow(elem, parent);
update_parent_size(elem, parent);
elem.events = ctx.get_elem_events(elem); elem.events = ctx.get_elem_events(elem);
if (elem.events.mouse_hover && elem.events.mouse_release) *active = !(*active); if (elem.events.mouse_hover && elem.events.mouse_release) *active = !(*active);
if (tick_sprite != {}) {
ctx.push_rect(elem.bounds, parent.div.z_index, style)!; Rect content_bounds = elem.bounds.pad(elem.layout.content_offset);
Rect text_bounds = {
.x = content_bounds.x,
.y = content_bounds.y,
.w = content_bounds.w - inner_pad - style.size,
.h = content_bounds.h
};
Rect check_bounds = {
.x = content_bounds.x + text_bounds.w + inner_pad,
.y = content_bounds.y + (content_bounds.h - style.size)/2,
.w = style.size,
.h = style.size,
};
Style s;
s.bg = style.bg;
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)!;
if (tick_sprite != "") {
ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
if (*active) { if (*active) {
ctx.draw_sprite_raw(tick_sprite, elem.bounds, center: true)!; 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)!;
} }
} else { } else {
ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
if (*active) { if (*active) {
ushort x = style.size / 4; s.bg = style.primary;
Rect check = elem.bounds.add({x, x, -x*2, -x*2}); ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
Style s = *style; } else {
s.bg = s.primary; ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
s.margin = s.border = s.padding = {};
ctx.push_rect(check, parent.div.z_index, &s)!;
} }
} }
} }
/*
// FIXME: this should be inside the style // FIXME: this should be inside the style
macro Ctx.toggle(&ctx, String desc, Point off, bool* active) macro Ctx.toggle(&ctx, String desc, Point off, bool* active)
=> ctx.toggle_id(@compute_id($vasplat), desc, off, active); => ctx.toggle_id(@compute_id($vasplat), desc, off, active);
@ -157,4 +189,3 @@ fn void? Ctx.toggle_id(&ctx, Id id, String description, Point off, bool* active)
s.margin = s.border = s.padding = {}; s.margin = s.border = s.padding = {};
ctx.push_rect(t, parent.div.z_index, &s)!; ctx.push_rect(t, parent.div.z_index, &s)!;
} }
*/

View File

@ -161,7 +161,7 @@ fn void? Ctx.div_end(&ctx)
ctx.active_div = ctx.tree.parentof(ctx.active_div)!; ctx.active_div = ctx.tree.parentof(ctx.active_div)!;
Elem* parent = ctx.get_parent()!; Elem* parent = ctx.get_parent()!;
ctx.div_scissor = parent.bounds; ctx.div_scissor = parent.bounds;
ctx.push_scissor(parent.bounds, elem.div.z_index)!; ctx.reset_scissor(elem.div.z_index)!;
update_parent_size(elem, parent); update_parent_size(elem, parent);
} }

View File

@ -0,0 +1,27 @@
module ugui;
struct ElemSprite {
Id id;
}
macro Ctx.sprite(&ctx, String name, ...)
=> ctx.sprite_id(@compute_id($vasplat), 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)!;
Style* style = ctx.styles.get_style(@str_hash("sprite"));
Sprite* sprite = ctx.sprite_atlas.get(name)!;
elem.sprite.id = ctx.get_sprite_atlas_id(name);
elem.layout.w = elem.layout.children.w = @exact(sprite.w);
elem.layout.h = elem.layout.children.h = @exact(sprite.h);
update_parent_grow(elem, parent);
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)!;
}

View File

@ -28,7 +28,7 @@ checkbox {
border: 2; border: 2;
padding: 1; padding: 1;
radius: 10; radius: 10;
size: 16; size: 20;
bg: #3c3836ff; bg: #3c3836ff;
fg: #fbf1c7ff; fg: #fbf1c7ff;
primary: #cc241dff; primary: #cc241dff;

View File

@ -360,7 +360,7 @@ fn void calculator(ugui::Ctx* ui)
case "c": case "c":
len = 0; len = 0;
case "d": case "d":
len--; if (len > 0) len--;
} }
// ui input/output // ui input/output
@ -389,9 +389,7 @@ fn void calculator(ugui::Ctx* ui)
ui.button("3")!!.mouse_press ? buffer[len++] = '3' : 0; ui.button("3")!!.mouse_press ? buffer[len++] = '3' : 0;
ui.button("(")!!.mouse_press ? buffer[len++] = '(' : 0; ui.button("(")!!.mouse_press ? buffer[len++] = '(' : 0;
}!!; }!!;
ui.@div(ugui::@exact(10), ugui::@exact(10)) {}!!; ui.@div(ugui::@exact(10), ugui::@exact(10)) {}!!;
ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) {
ui.button("x")!!.mouse_press ? buffer[len++] = '*' : 0; ui.button("x")!!.mouse_press ? buffer[len++] = '*' : 0;
ui.button("/")!!.mouse_press ? buffer[len++] = '/' : 0; ui.button("/")!!.mouse_press ? buffer[len++] = '/' : 0;
@ -400,7 +398,7 @@ fn void calculator(ugui::Ctx* ui)
}!!; }!!;
ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) { ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) {
ui.button("C")!!.mouse_press ? len = 0 : 0; ui.button("C")!!.mouse_press ? len = 0 : 0;
ui.button("D")!!.mouse_press ? len-- : 0; ui.button("D")!!.mouse_press ? len > 0 ? len-- : 0 : 0;
ui.button("-")!!.mouse_press ? buffer[len++] = '-' : 0; ui.button("-")!!.mouse_press ? buffer[len++] = '-' : 0;
// eval the expression with 'bc' // eval the expression with 'bc'
@ -413,5 +411,12 @@ fn void calculator(ugui::Ctx* ui)
} }
}!!; }!!;
}!!; }!!;
ui.@div(ugui::@grow(), ugui::@grow(), anchor: CENTER) {
static bool state;
ui.checkbox("boolean", &state, "tick")!!;
ui.sprite("tux")!!;
}!!;
}!!; }!!; }!!; }!!;
} }