better default style handling

This commit is contained in:
Alessandro Mauri 2025-07-06 23:13:16 +02:00
parent c1bf8e891b
commit 9afb0d2acd
9 changed files with 45 additions and 24 deletions

View File

@ -115,7 +115,6 @@ fn ElemEvents? Ctx.button_icon_id(&ctx, Id id, String icon, String on_icon, bool
} }
// FIXME: this should be inside the style // FIXME: this should be inside the style
const ushort DEFAULT_CHECKBOX_SIZE = 16;
macro Ctx.checkbox(&ctx, String desc, Point off, 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, off, active, 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) fn void? Ctx.checkbox_id(&ctx, Id id, String description, Point off, bool* active, String tick_sprite)
@ -126,7 +125,7 @@ fn void? Ctx.checkbox_id(&ctx, Id id, String description, Point off, bool* activ
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, DEFAULT_CHECKBOX_SIZE, DEFAULT_CHECKBOX_SIZE}; Rect size = {off.x, off.y, style.size, style.size};
elem.bounds = ctx.position_element(parent, size, style); elem.bounds = ctx.position_element(parent, size, style);
// if the bounds are null the element is outside the div view, // if the bounds are null the element is outside the div view,
@ -144,7 +143,7 @@ fn void? Ctx.checkbox_id(&ctx, Id id, String description, Point off, bool* activ
} else { } else {
ctx.push_rect(elem.bounds, parent.div.z_index, style)!; ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
if (*active) { if (*active) {
ushort x = DEFAULT_CHECKBOX_SIZE / 4; ushort x = style.size / 4;
Rect check = elem.bounds.add({x, x, -x*2, -x*2}); Rect check = elem.bounds.add({x, x, -x*2, -x*2});
Style s = *style; Style s = *style;
s.bg = s.primary; s.bg = s.primary;
@ -155,7 +154,6 @@ fn void? Ctx.checkbox_id(&ctx, Id id, String description, Point off, bool* activ
} }
// FIXME: this should be inside the style // FIXME: this should be inside the style
const short DEFAULT_SWITCH_SIZE = 16;
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);
fn void? Ctx.toggle_id(&ctx, Id id, String description, Point off, bool* active) fn void? Ctx.toggle_id(&ctx, Id id, String description, Point off, bool* active)
@ -166,7 +164,7 @@ fn void? Ctx.toggle_id(&ctx, Id id, String description, Point off, bool* active)
Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!; Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!;
Style* style = ctx.styles.get_style(@str_hash("toggle")); Style* style = ctx.styles.get_style(@str_hash("toggle"));
Rect size = {off.x, off.y, DEFAULT_SWITCH_SIZE*2, DEFAULT_SWITCH_SIZE}; Rect size = {off.x, off.y, style.size*2, style.size};
elem.bounds = ctx.position_element(parent, size, style); elem.bounds = ctx.position_element(parent, size, style);
// if the bounds are null the element is outside the div view, // if the bounds are null the element is outside the div view,
@ -179,7 +177,7 @@ fn void? Ctx.toggle_id(&ctx, Id id, String description, Point off, bool* active)
// Draw the button // Draw the button
// FIXME: THIS IS SHIT // FIXME: THIS IS SHIT
ctx.push_rect(elem.bounds, parent.div.z_index, style)!; ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
Rect t = elem.bounds.add({*active ? (DEFAULT_SWITCH_SIZE+3) : +3, +3, -DEFAULT_SWITCH_SIZE-6, -6}); Rect t = elem.bounds.add({*active ? (style.size+3) : +3, +3, -style.size-6, -6});
Style s = *style; Style s = *style;
s.bg = s.primary; s.bg = s.primary;
s.margin = s.border = s.padding = {}; s.margin = s.border = s.padding = {};

View File

@ -196,6 +196,7 @@ fn void? Ctx.init(&ctx)
defer catch { (void)ctx.cmd_queue.free(); } defer catch { (void)ctx.cmd_queue.free(); }
ctx.styles.init(allocator::heap()); ctx.styles.init(allocator::heap());
ctx.styles.register_style(&DEFAULT_STYLE, @str_hash("default"));
defer catch { ctx.styles.free(); } defer catch { ctx.styles.free(); }
ctx.active_div = 0; ctx.active_div = 0;

View File

@ -3,8 +3,6 @@ module ugui;
import std::io; import std::io;
import std::math; import std::math;
const short SCROLLBAR_DIM = 5;
// div element // div element
struct ElemDiv { struct ElemDiv {
Layout layout; Layout layout;
@ -18,6 +16,7 @@ struct ElemDiv {
bool on; bool on;
float value; float value;
} }
ushort scroll_size;
int z_index; int z_index;
Rect children_bounds; // current frame children bounds Rect children_bounds; // current frame children bounds
Rect pcb; // previous frame children bounds Rect pcb; // previous frame children bounds
@ -39,10 +38,12 @@ fn void? Ctx.div_begin_id(&ctx, Id id, Rect size, bool scroll_x, bool scroll_y)
Elem* elem = ctx.get_elem(id, ETYPE_DIV)!; Elem* elem = ctx.get_elem(id, ETYPE_DIV)!;
ctx.active_div = elem.tree_idx; ctx.active_div = elem.tree_idx;
Style* style = ctx.styles.get_style(0); Style* style = ctx.styles.get_style(@str_hash("default"));
Style* slider_style = ctx.styles.get_style(@str_hash("slider"));
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.scroll_size = slider_style.size ? slider_style.size : (style.size ? style.size : DEFAULT_STYLE.size);
elem.div.z_index = parent.div.z_index + 1; elem.div.z_index = parent.div.z_index + 1;
// 2. layout the element // 2. layout the element
@ -110,8 +111,8 @@ fn void? Ctx.div_end(&ctx)
Id vsid_raw = @str_hash("div_scrollbar_vertical"); Id vsid_raw = @str_hash("div_scrollbar_vertical");
Id hsid_real = ctx.gen_id(@str_hash("div_scrollbar_horizontal"))!; Id hsid_real = ctx.gen_id(@str_hash("div_scrollbar_horizontal"))!;
Id vsid_real = ctx.gen_id(@str_hash("div_scrollbar_vertical"))!; Id vsid_real = ctx.gen_id(@str_hash("div_scrollbar_vertical"))!;
short wdim = elem.div.scroll_y.on ? (ctx.focus_id == vsid_real || ctx.is_hovered(ctx.find_elem(vsid_real)) ? SCROLLBAR_DIM*3 : SCROLLBAR_DIM) : 0; short wdim = elem.div.scroll_y.on ? (ctx.focus_id == vsid_real || ctx.is_hovered(ctx.find_elem(vsid_real)) ? elem.div.scroll_size*2 : elem.div.scroll_size) : 0;
short hdim = elem.div.scroll_x.on ? (ctx.focus_id == hsid_real || ctx.is_hovered(ctx.find_elem(hsid_real)) ? SCROLLBAR_DIM*3 : SCROLLBAR_DIM) : 0; short hdim = elem.div.scroll_x.on ? (ctx.focus_id == hsid_real || ctx.is_hovered(ctx.find_elem(hsid_real)) ? elem.div.scroll_size*2 : elem.div.scroll_size) : 0;
if (elem.div.scroll_y.on) { if (elem.div.scroll_y.on) {
if (ctx.input.events.mouse_scroll && ctx.hover_id == elem.id) { if (ctx.input.events.mouse_scroll && ctx.hover_id == elem.id) {

View File

@ -84,11 +84,11 @@ macro Rect Elem.get_view(&elem)
Rect off; Rect off;
if (elem.div.scroll_x.enabled && elem.div.scroll_x.on) { if (elem.div.scroll_x.enabled && elem.div.scroll_x.on) {
off.x = (short)((float)(elem.div.pcb.w - elem.bounds.w) * elem.div.scroll_x.value); off.x = (short)((float)(elem.div.pcb.w - elem.bounds.w) * elem.div.scroll_x.value);
off.w = -SCROLLBAR_DIM; off.w = -elem.div.scroll_size;
} }
if (elem.div.scroll_y.enabled && elem.div.scroll_y.on) { if (elem.div.scroll_y.enabled && elem.div.scroll_y.on) {
off.y = (short)((float)(elem.div.pcb.h - elem.bounds.h) * elem.div.scroll_y.value); off.y = (short)((float)(elem.div.pcb.h - elem.bounds.h) * elem.div.scroll_y.value);
off.h = -SCROLLBAR_DIM; off.h = -elem.div.scroll_size;
} }
return elem.bounds.add(off); return elem.bounds.add(off);
} }

View File

@ -50,9 +50,12 @@ fn ElemEvents? Ctx.slider_hor_id(&ctx, Id id, Rect size, float* value, float hpe
} }
// Draw the slider background and handle // Draw the slider background and handle
ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
Style s = *style; Style s = *style;
Rect padding = s.padding;
s.padding = {};
ctx.push_rect(elem.bounds, parent.div.z_index, &s)!;
s.bg = s.primary; s.bg = s.primary;
s.padding = padding;
ctx.push_rect(elem.slider.handle, parent.div.z_index, &s)!; ctx.push_rect(elem.slider.handle, parent.div.z_index, &s)!;
return elem.events; return elem.events;
@ -111,9 +114,12 @@ fn ElemEvents? Ctx.slider_ver_id(&ctx, Id id, Rect size, float* value, float hpe
} }
// Draw the slider background and handle // Draw the slider background and handle
ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
Style s = *style; Style s = *style;
Rect padding = s.padding;
s.padding = {};
ctx.push_rect(elem.bounds, parent.div.z_index, &s)!;
s.bg = s.primary; s.bg = s.primary;
s.padding = padding;
ctx.push_rect(elem.slider.handle, parent.div.z_index, &s)!; ctx.push_rect(elem.slider.handle, parent.div.z_index, &s)!;
return elem.events; return elem.events;

View File

@ -120,7 +120,7 @@ fn void? Ctx.sprite_id(&ctx, Id id, String name, Point off)
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id, ETYPE_SPRITE)!; Elem *elem = ctx.get_elem(id, ETYPE_SPRITE)!;
Style* style = ctx.styles.get_style(0); Style* style = ctx.styles.get_style(@str_hash("sprite"));
Sprite* sprite = ctx.sprite_atlas.get(name)!; Sprite* sprite = ctx.sprite_atlas.get(name)!;
Rect uv = { sprite.u, sprite.v, sprite.w, sprite.h }; Rect uv = { sprite.u, sprite.v, sprite.w, sprite.h };

View File

@ -17,6 +17,7 @@ struct Style { // css box model
Color accent; // accent color Color accent; // accent color
ushort radius; ushort radius;
short size;
} }
const Style DEFAULT_STYLE = { const Style DEFAULT_STYLE = {
@ -24,6 +25,7 @@ const Style DEFAULT_STYLE = {
.border = {2, 2, 2, 2}, .border = {2, 2, 2, 2},
.padding = {1, 1, 1, 1}, .padding = {1, 1, 1, 1},
.radius = 12, .radius = 12,
.size = 16,
.bg = 0x282828ffu.@to_rgba(), .bg = 0x282828ffu.@to_rgba(),
.fg = 0xfbf1c7ffu.@to_rgba(), .fg = 0xfbf1c7ffu.@to_rgba(),
@ -46,7 +48,8 @@ fn void StyleMap.register_style(&map, Style* style, Id id)
fn Style* StyleMap.get_style(&map, Id id) fn Style* StyleMap.get_style(&map, Id id)
{ {
Style*? s = map.get_ref(id); Style*? s = map.get_ref(id);
if (catch e = s) { if (catch s) {
// io::eprintfn("WARNING: style %x not found, using default style", id);
return &DEFAULT_STYLE; return &DEFAULT_STYLE;
} }
return s; return s;
@ -61,7 +64,6 @@ fn int StyleMap.import_style_string(&map, String text)
while (p.parse_style() == true) { while (p.parse_style() == true) {
added++; added++;
// set the default style correctly // set the default style correctly
if (p.style_id == @str_hash("default")) p.style_id = 0;
map.register_style(&p.style, p.style_id); map.register_style(&p.style, p.style_id);
if (p.lex.peep_token().type == EOF) break; if (p.lex.peep_token().type == EOF) break;
} }
@ -83,7 +85,6 @@ fn int Ctx.import_style_from_file(&ctx, String path)
} }
// TODO: add a "size" property that controls the size of elements like checkboxes
/* /*
* Style can be serialized and deserialized with a subset of CSS * Style can be serialized and deserialized with a subset of CSS
* <style name> { * <style name> {
@ -91,6 +92,7 @@ fn int Ctx.import_style_from_file(&ctx, String path)
* border: left right top bottom; * border: left right top bottom;
* margin: left right top bottoms; * margin: left right top bottoms;
* radius: uint; * radius: uint;
* size: uint;
* Color: #RRGGBBAA; * Color: #RRGGBBAA;
* Color: #RRGGBBAA; * Color: #RRGGBBAA;
* Color: #RRGGBBAA; * Color: #RRGGBBAA;
@ -368,10 +370,20 @@ fn bool Parser.parse_property(&p)
short r; short r;
if (p.parse_number(&r) == false) return false; if (p.parse_number(&r) == false) return false;
if (r < 0) { if (r < 0) {
io::eprintfn("CSS parsing error at %d:%d: radius must be a positive number, got %d", t.line, t.col, r); io::eprintfn("CSS parsing error at %d:%d: 'radius' must be a positive number, got %d", t.line, t.col, r);
return false; return false;
} }
p.style.radius = (ushort)r; p.style.radius = (ushort)r;
case "size":
short s;
if (p.parse_number(&s) == false) return false;
if (s < 0) {
io::eprintfn("CSS parsing error at %d:%d: 'size' must be a positive number, got %d", t.line, t.col, s);
return false;
}
p.style.size = (ushort)s;
default: default:
io::eprintfn("CSS parsing error at %d:%d: '%s' is not a valid property", prop.line, prop.col, prop.text); io::eprintfn("CSS parsing error at %d:%d: '%s' is not a valid property", prop.line, prop.col, prop.text);

View File

@ -15,7 +15,7 @@ fn void? Ctx.text_unbounded_id(&ctx, Id id, String text)
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id, ETYPE_TEXT)!; Elem *elem = ctx.get_elem(id, ETYPE_TEXT)!;
Style* style = ctx.styles.get_style(0); Style* style = ctx.styles.get_style(@str_hash("text"));
elem.text.str = text; elem.text.str = text;
@ -36,7 +36,7 @@ fn ElemEvents? Ctx.text_box_id(&ctx, Id id, Rect size, char[] text, usz* text_le
Elem *parent = ctx.get_parent()!; Elem *parent = ctx.get_parent()!;
Elem *elem = ctx.get_elem(id, ETYPE_TEXT)!; Elem *elem = ctx.get_elem(id, ETYPE_TEXT)!;
Style* style = ctx.styles.get_style(0); Style* style = ctx.styles.get_style(@str_hash("text-box"));
elem.text.str = text; elem.text.str = text;

View File

@ -94,7 +94,7 @@ checkbox {
border: 2 2 2 2; border: 2 2 2 2;
padding: 1 1 1 1; padding: 1 1 1 1;
radius: 10; radius: 10;
size: 16;
bg: #3c3836ff; bg: #3c3836ff;
fg: #fbf1c7ff; fg: #fbf1c7ff;
primary: #cc241dff; primary: #cc241dff;
@ -107,7 +107,7 @@ toggle {
border: 2 2 2 2; border: 2 2 2 2;
padding: 1 1 1 1; padding: 1 1 1 1;
radius: 10; radius: 10;
size: 16;
bg: #3c3836ff; bg: #3c3836ff;
fg: #fbf1c7ff; fg: #fbf1c7ff;
primary: #cc241dff; primary: #cc241dff;
@ -117,6 +117,9 @@ toggle {
slider { slider {
margin: 2 2 2 2; margin: 2 2 2 2;
padding: 2 2 2 2;
radius: 4;
size: 8;
bg: #3c3836ff; bg: #3c3836ff;
fg: #fbf1c7ff; fg: #fbf1c7ff;
primary: #cc241dff; primary: #cc241dff;