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);
}
if (cull_rect(rect, ctx.div_scissor)) {
// io::print("NOPE: ");
// io::print(cmd.rect.rect);
// io::printn(cmd.z_index);
// println("NOPE: ", cmd.rect.rect, cmd.z_index);
// unreachable();
return;
}

View File

@ -165,10 +165,9 @@ macro Id @compute_id(...)
// resets all flags except is_new which is set accordingly
fn Elem*? Ctx.get_elem(&ctx, Id id, ElemType type)
{
Elem empty_elem;
bool is_new;
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.is_new = is_new;
elem.id = id;

View File

@ -30,10 +30,6 @@ struct SpriteAtlas {
bool should_update;
}
struct ElemSprite {
Id id;
}
// name: some examples are "icons" or "images"
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)!;
}
/*
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"));
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();
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.children.w = @exact(content_size.x);
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;
update_parent_grow(elem, parent);
@ -86,47 +83,82 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon)
return elem.events;
}
/*
// FIXME: this should be inside the style
macro Ctx.checkbox(&ctx, String desc, Point off, bool* active, String tick_sprite = {}, ...)
=> ctx.checkbox_id(@compute_id($vasplat), desc, off, active, tick_sprite);
fn void? Ctx.checkbox_id(&ctx, Id id, String description, Point off, bool* active, String tick_sprite)
macro Ctx.checkbox(&ctx, String desc, bool* active, String tick_sprite = "", ...)
=> ctx.checkbox_id(@compute_id($vasplat), desc, active, 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)!;
Style* style = ctx.styles.get_style(@str_hash("checkbox"));
Rect size = {off.x, off.y, style.size, style.size};
elem.bounds = ctx.layout_element(parent, size, style);
short inner_pad = description != "" ? style.size/2 : 0;
/*
* |< >| style.size/2
* +---------------------|---|-----------+
* | | .-----. ---|--
* | +-----------------+ ' ### ' | ^
* | | description | | ##### | | style.size
* | +-----------------+ . ### . | v
* | '-----' ---|--
* +-------------------------|-------|---+
* |<----->| style.size
*/
elem.layout.w = @fit(style.size);
elem.layout.h = @fit(style.size);
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;
// 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;
update_parent_grow(elem, parent);
update_parent_size(elem, parent);
elem.events = ctx.get_elem_events(elem);
if (elem.events.mouse_hover && elem.events.mouse_release) *active = !(*active);
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;
if (tick_sprite != {}) {
ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
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) {
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 {
ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
if (*active) {
ushort x = style.size / 4;
Rect check = elem.bounds.add({x, x, -x*2, -x*2});
Style s = *style;
s.bg = s.primary;
s.margin = s.border = s.padding = {};
ctx.push_rect(check, parent.div.z_index, &s)!;
s.bg = style.primary;
ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
} else {
ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
}
}
}
/*
// FIXME: this should be inside the style
macro Ctx.toggle(&ctx, String desc, Point off, bool* active)
=> ctx.toggle_id(@compute_id($vasplat), desc, off, active);
@ -156,5 +188,4 @@ fn void? Ctx.toggle_id(&ctx, Id id, String description, Point off, bool* active)
s.bg = s.primary;
s.margin = s.border = s.padding = {};
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)!;
Elem* parent = ctx.get_parent()!;
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);
}

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;
padding: 1;
radius: 10;
size: 16;
size: 20;
bg: #3c3836ff;
fg: #fbf1c7ff;
primary: #cc241dff;

View File

@ -360,7 +360,7 @@ fn void calculator(ugui::Ctx* ui)
case "c":
len = 0;
case "d":
len--;
if (len > 0) len--;
}
// ui input/output
@ -389,9 +389,7 @@ fn void calculator(ugui::Ctx* ui)
ui.button("3")!!.mouse_press ? buffer[len++] = '3' : 0;
ui.button("(")!!.mouse_press ? buffer[len++] = '(' : 0;
}!!;
ui.@div(ugui::@exact(10), ugui::@exact(10)) {}!!;
ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) {
ui.button("x")!!.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.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;
// 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")!!;
}!!;
}!!; }!!;
}