use new style system

This commit is contained in:
Alessandro Mauri 2025-07-05 16:37:08 +02:00
parent 9fc1d90455
commit 777e974841
10 changed files with 235 additions and 155 deletions

View File

@ -17,23 +17,21 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, Rect size, bool active)
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_norm = ctx.styles.get_style(@str_hash("button"));
elem.bounds = ctx.position_element(parent, size, true); elem.bounds = ctx.position_element(parent, size, style_norm);
// if the bounds are null the element is outside the div view, // if the bounds are null the element is outside the div view,
// no interaction should occur so just return // no interaction should occur so just return
if (elem.bounds.is_null()) { return {}; } if (elem.bounds.is_null()) { return {}; }
Color col = 0x0000ffffu.to_rgba(); Style* style_active = ctx.styles.get_style(@str_hash("button-active"));
elem.events = ctx.get_elem_events(elem); elem.events = ctx.get_elem_events(elem);
if (active) { bool is_active = active || ctx.elem_focus(elem) || elem.events.mouse_hover;
col = 0xff0000ffu.to_rgba();
} else if (ctx.elem_focus(elem) || elem.events.mouse_hover) {
col = 0xff00ffffu.to_rgba();
}
// Draw the button // Draw the button
ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!; ctx.push_rect(elem.bounds, parent.div.z_index, is_active ? style_active : style_norm)!;
return elem.events; return elem.events;
} }
@ -50,18 +48,18 @@ fn ElemEvents? Ctx.button_label_id(&ctx, Id id, String label, Rect size, bool ac
short line_height = (short)ctx.font.ascender - (short)ctx.font.descender; short line_height = (short)ctx.font.ascender - (short)ctx.font.descender;
Rect text_size = ctx.get_text_bounds(label)!; Rect text_size = ctx.get_text_bounds(label)!;
Rect btn_size = text_size.add({0,0,10,10}); Rect btn_size = text_size.add({0,0,10,10});
Style* style_norm = ctx.styles.get_style(@str_hash("button"));
// 2. Layout // 2. Layout
elem.bounds = ctx.position_element(parent, btn_size, true); elem.bounds = ctx.position_element(parent, btn_size, style_norm);
if (elem.bounds.is_null()) { return {}; } if (elem.bounds.is_null()) { return {}; }
Color col = 0x0000ffffu.to_rgba(); Style* style_active = ctx.styles.get_style(@str_hash("button-active"));
elem.events = ctx.get_elem_events(elem); elem.events = ctx.get_elem_events(elem);
if (active) {
col = 0xff0000ffu.to_rgba(); bool is_active = active || ctx.elem_focus(elem) || elem.events.mouse_hover;
} else if (ctx.elem_focus(elem) || elem.events.mouse_hover) { Style* style = is_active ? style_active : style_norm;
col = 0xff00ffffu.to_rgba();
}
// Draw the button // Draw the button
text_size.x = elem.bounds.x; text_size.x = elem.bounds.x;
@ -69,8 +67,8 @@ fn ElemEvents? Ctx.button_label_id(&ctx, Id id, String label, Rect size, bool ac
Point off = ctx.center_text(text_size, elem.bounds); Point off = ctx.center_text(text_size, elem.bounds);
text_size.x += off.x; text_size.x += off.x;
text_size.y += off.y; text_size.y += off.y;
ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!; ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
ctx.push_string(text_size, label, parent.div.z_index)!; ctx.push_string(text_size, label, parent.div.z_index, style.fg)!;
return elem.events; return elem.events;
} }
@ -88,15 +86,21 @@ fn ElemEvents? Ctx.button_icon_id(&ctx, Id id, String icon, String on_icon, bool
Sprite* on_sprite = ctx.sprite_atlas.get(on_icon) ?? &&(Sprite){}; Sprite* on_sprite = ctx.sprite_atlas.get(on_icon) ?? &&(Sprite){};
Rect max_size = def_sprite.rect().max(on_sprite.rect()); Rect max_size = def_sprite.rect().max(on_sprite.rect());
elem.bounds = ctx.position_element(parent, max_size, true); Style* style_norm = ctx.styles.get_style(@str_hash("button"));
elem.bounds = ctx.position_element(parent, max_size, style_norm);
// if the bounds are null the element is outside the div view, // if the bounds are null the element is outside the div view,
// no interaction should occur so just return // no interaction should occur so just return
if (elem.bounds.is_null()) { return {}; } if (elem.bounds.is_null()) { return {}; }
Color col = 0x0000ffffu.to_rgba(); Style* style_active = ctx.styles.get_style(@str_hash("button-active"));
elem.events = ctx.get_elem_events(elem); elem.events = ctx.get_elem_events(elem);
bool is_active = active || ctx.elem_focus(elem) || elem.events.mouse_hover;
Style* style = is_active ? style_active : style_norm;
Id tex_id = ctx.sprite_atlas.id; Id tex_id = ctx.sprite_atlas.id;
if (active && on_icon != "") { if (active && on_icon != "") {
ctx.push_sprite(elem.bounds, on_sprite.uv(), tex_id, parent.div.z_index, type: on_sprite.type)!; ctx.push_sprite(elem.bounds, on_sprite.uv(), tex_id, parent.div.z_index, type: on_sprite.type)!;
@ -105,7 +109,7 @@ fn ElemEvents? Ctx.button_icon_id(&ctx, Id id, String icon, String on_icon, bool
} }
// Draw the button // Draw the button
ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!; ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
return elem.events; return elem.events;
} }
@ -120,9 +124,10 @@ fn void? Ctx.checkbox_id(&ctx, Id id, String description, Point off, bool* activ
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"));
Rect size = {off.x, off.y, DEFAULT_CHECKBOX_SIZE, DEFAULT_CHECKBOX_SIZE}; Rect size = {off.x, off.y, DEFAULT_CHECKBOX_SIZE, DEFAULT_CHECKBOX_SIZE};
elem.bounds = ctx.position_element(parent, size, true); 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,
// no interaction should occur so just return // no interaction should occur so just return
@ -131,18 +136,20 @@ fn void? Ctx.checkbox_id(&ctx, Id id, String description, Point off, bool* activ
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);
Color col = ctx.style.bgcolor;
if (tick_sprite != {}) { if (tick_sprite != {}) {
ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!; ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
if (*active) { if (*active) {
ctx.draw_sprite_raw(tick_sprite, elem.bounds, center: true)!; ctx.draw_sprite_raw(tick_sprite, elem.bounds, center: true)!;
} }
} else { } else {
ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!; ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
if (*active) { if (*active) {
ushort x = DEFAULT_CHECKBOX_SIZE / 4; ushort x = DEFAULT_CHECKBOX_SIZE / 4;
Rect check = elem.bounds.add({x, x, -x*2, -x*2}); Rect check = elem.bounds.add({x, x, -x*2, -x*2});
ctx.push_rect(check, 0xff0000ffu.to_rgba(), parent.div.z_index, do_radius: true)!; Style s = *style;
s.bg = s.primary;
s.margin = s.border = s.padding = {};
ctx.push_rect(check, parent.div.z_index, &s)!;
} }
} }
} }
@ -157,9 +164,10 @@ fn void? Ctx.toggle_id(&ctx, Id id, String description, Point off, bool* active)
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("toggle"));
Rect size = {off.x, off.y, DEFAULT_SWITCH_SIZE*2, DEFAULT_SWITCH_SIZE}; Rect size = {off.x, off.y, DEFAULT_SWITCH_SIZE*2, DEFAULT_SWITCH_SIZE};
elem.bounds = ctx.position_element(parent, size, true); 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,
// no interaction should occur so just return // no interaction should occur so just return
@ -168,15 +176,12 @@ fn void? Ctx.toggle_id(&ctx, Id id, String description, Point off, bool* active)
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);
Color col;
if (*active) {
col = 0xff0000ffu.to_rgba();
} else {
col = 0xff00ffffu.to_rgba();
}
// Draw the button // Draw the button
// FIXME: THIS IS SHIT // FIXME: THIS IS SHIT
ctx.push_rect(elem.bounds, ctx.style.bgcolor, parent.div.z_index, do_border: true, do_radius: true)!; 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 ? (DEFAULT_SWITCH_SIZE+3) : +3, +3, -DEFAULT_SWITCH_SIZE-6, -6});
ctx.push_rect(t, col, parent.div.z_index, do_border: false, do_radius: true)!; Style s = *style;
s.bg = s.primary;
s.margin = s.border = s.padding = {};
ctx.push_rect(t, parent.div.z_index, &s)!;
} }

View File

@ -90,21 +90,20 @@ fn void? Ctx.push_scissor(&ctx, Rect rect, int z_index)
ctx.push_cmd(&sc, z_index)!; ctx.push_cmd(&sc, z_index)!;
} }
// FIXME: is this really the best solution? fn void? Ctx.push_rect(&ctx, Rect rect, int z_index, Style* style)
// "rect" is the bounding box of the element, which includes the border and the padding (so not just the content)
fn void? Ctx.push_rect(&ctx, Rect rect, Color color, int z_index, bool do_border = false, bool do_padding = false, bool do_radius = false)
{ {
Rect border = ctx.style.border; Rect border = style.border;
Rect padding = ctx.style.padding; Rect padding = style.padding;
ushort radius = ctx.style.radius; ushort radius = style.radius;
Color border_color = ctx.style.brcolor; Color bg = style.bg;
Color border_color = style.secondary;
if (do_border) { if (!border.is_null()) {
Cmd cmd = { Cmd cmd = {
.type = CMD_RECT, .type = CMD_RECT,
.rect.rect = rect, .rect.rect = rect,
.rect.color = border_color, .rect.color = border_color,
.rect.radius = do_radius ? radius : 0, .rect.radius = radius,
}; };
ctx.push_cmd(&cmd, z_index)!; ctx.push_cmd(&cmd, z_index)!;
} }
@ -112,13 +111,13 @@ fn void? Ctx.push_rect(&ctx, Rect rect, Color color, int z_index, bool do_border
Cmd cmd = { Cmd cmd = {
.type = CMD_RECT, .type = CMD_RECT,
.rect.rect = { .rect.rect = {
.x = rect.x + (do_border ? border.x : 0) + (do_padding ? padding.x : 0), .x = rect.x + border.x + padding.x,
.y = rect.y + (do_border ? border.y : 0) + (do_padding ? padding.y : 0), .y = rect.y + border.y + padding.y,
.w = rect.w - (do_border ? border.x+border.w : 0) - (do_padding ? padding.x+padding.w : 0), .w = rect.w - (border.x+border.w) - (padding.x+padding.w),
.h = rect.h - (do_border ? border.y+border.h : 0) - (do_padding ? padding.y+padding.h : 0), .h = rect.h - (border.y+border.h) - (padding.y+padding.h),
}, },
.rect.color = color, .rect.color = bg,
.rect.radius = do_radius ? radius : 0, .rect.radius = radius,
}; };
if (cull_rect(cmd.rect.rect, ctx.div_scissor)) return; if (cull_rect(cmd.rect.rect, ctx.div_scissor)) return;
ctx.push_cmd(&cmd, z_index)!; ctx.push_cmd(&cmd, z_index)!;
@ -137,7 +136,7 @@ fn void? Ctx.push_sprite(&ctx, Rect bounds, Rect texture, Id texture_id, int z_i
ctx.push_cmd(&cmd, z_index)!; ctx.push_cmd(&cmd, z_index)!;
} }
fn void? Ctx.push_string(&ctx, Rect bounds, char[] text, int z_index, Color hue = 0xffffffffu.to_rgba()) fn void? Ctx.push_string(&ctx, Rect bounds, char[] text, int z_index, Color hue)
{ {
if (text.len == 0) { if (text.len == 0) {
return; return;

View File

@ -82,7 +82,6 @@ struct Ctx {
StyleMap styles; StyleMap styles;
// total size in pixels of the context // total size in pixels of the context
ushort width, height; ushort width, height;
Style* style; // TODO: rename to "active_style" or something
Font font; Font font;
SpriteAtlas sprite_atlas; SpriteAtlas sprite_atlas;
@ -200,8 +199,6 @@ fn void? Ctx.init(&ctx)
defer catch { ctx.styles.free(); } defer catch { ctx.styles.free(); }
ctx.active_div = 0; ctx.active_div = 0;
ctx.style = &DEFAULT_STYLE;
} }
fn void Ctx.free(&ctx) fn void Ctx.free(&ctx)

View File

@ -39,6 +39,8 @@ 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);
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.z_index = parent.div.z_index + 1; elem.div.z_index = parent.div.z_index + 1;
@ -50,7 +52,7 @@ fn void? Ctx.div_begin_id(&ctx, Id id, Rect size, bool scroll_x, bool scroll_y)
.w = size.w < 0 ? max(elem.div.pcb.w, (short)-size.w) : size.w, .w = size.w < 0 ? max(elem.div.pcb.w, (short)-size.w) : size.w,
.h = size.h < 0 ? max(elem.div.pcb.h, (short)-size.h) : size.h, .h = size.h < 0 ? max(elem.div.pcb.h, (short)-size.h) : size.h,
}; };
elem.bounds = ctx.position_element(parent, wanted_size); elem.bounds = ctx.position_element(parent, wanted_size, style);
elem.div.children_bounds = {}; elem.div.children_bounds = {};
// update the ctx scissor // update the ctx scissor
@ -67,7 +69,7 @@ fn void? Ctx.div_begin_id(&ctx, Id id, Rect size, bool scroll_x, bool scroll_y)
// Add the background to the draw stack // Add the background to the draw stack
bool do_border = parent.div.layout == LAYOUT_FLOATING; bool do_border = parent.div.layout == LAYOUT_FLOATING;
ctx.push_rect(elem.bounds, ctx.style.bgcolor, elem.div.z_index, do_border: do_border)!; ctx.push_rect(elem.bounds, elem.div.z_index, style)!;
elem.events = ctx.get_elem_events(elem); elem.events = ctx.get_elem_events(elem);
@ -104,8 +106,8 @@ fn void? Ctx.div_end(&ctx)
// vertical overflow // vertical overflow
elem.div.scroll_y.on = cbc.y > bc.y && elem.div.scroll_y.enabled; elem.div.scroll_y.on = cbc.y > bc.y && elem.div.scroll_y.enabled;
Id hsid = ctx.gen_id("div_scrollbar_horizontal".hash())!; Id hsid = ctx.gen_id(@str_hash("div_scrollbar_horizontal"))!;
Id vsid = ctx.gen_id("div_scrollbar_vertical".hash())!; Id vsid = ctx.gen_id(@str_hash("div_scrollbar_vertical"))!;
short wdim = elem.div.scroll_y.on ? (ctx.focus_id == vsid || ctx.is_hovered(ctx.find_elem(vsid)) ? SCROLLBAR_DIM*3 : SCROLLBAR_DIM) : 0; short wdim = elem.div.scroll_y.on ? (ctx.focus_id == vsid || ctx.is_hovered(ctx.find_elem(vsid)) ? SCROLLBAR_DIM*3 : SCROLLBAR_DIM) : 0;
short hdim = elem.div.scroll_x.on ? (ctx.focus_id == hsid || ctx.is_hovered(ctx.find_elem(hsid)) ? SCROLLBAR_DIM*3 : SCROLLBAR_DIM) : 0; short hdim = elem.div.scroll_x.on ? (ctx.focus_id == hsid || ctx.is_hovered(ctx.find_elem(hsid)) ? SCROLLBAR_DIM*3 : SCROLLBAR_DIM) : 0;

View File

@ -106,7 +106,7 @@ macro Point Elem.get_view_off(&elem)
@require ctx != null @require ctx != null
@require parent.type == ETYPE_DIV @require parent.type == ETYPE_DIV
*> *>
fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false) fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, Style* style)
{ {
ElemDiv* div = &parent.div; ElemDiv* div = &parent.div;
@ -142,10 +142,10 @@ fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false)
// offset placement and area // offset placement and area
child_placement = child_placement.off(origin.add(rect.position())); child_placement = child_placement.off(origin.add(rect.position()));
child_occupied = child_occupied.off(origin.add(rect.position())); child_occupied = child_occupied.off(origin.add(rect.position()));
if (style) {
Rect margin = ctx.style.margin; Rect margin = style.margin;
Rect border = ctx.style.border; Rect border = style.border;
Rect padding = ctx.style.padding; Rect padding = style.padding;
// padding, grows both the placement and occupied area // padding, grows both the placement and occupied area
child_placement = child_placement.grow(padding.position().add(padding.size())); child_placement = child_placement.grow(padding.position().add(padding.size()));
@ -160,7 +160,7 @@ fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false)
// oh yeah also adjust the rect if i was to grow // oh yeah also adjust the rect if i was to grow
if (adapt_x) rect.w -= padding.x+padding.w + border.x+border.w + margin.x+margin.w; if (adapt_x) rect.w -= padding.x+padding.w + border.x+border.w + margin.x+margin.w;
if (adapt_y) rect.h -= padding.y+padding.h + border.y+border.h + margin.y+margin.h; if (adapt_y) rect.h -= padding.y+padding.h + border.y+border.h + margin.y+margin.h;
}
// set the size // set the size
child_placement = child_placement.grow(rect.size()); child_placement = child_placement.grow(rect.size());
child_occupied = child_occupied.grow(rect.size()); child_occupied = child_occupied.grow(rect.size());

View File

@ -14,31 +14,21 @@ struct ElemSlider {
* | |#####| | * | |#####| |
* +----+-----+---------------------+ * +----+-----+---------------------+
*/ */
macro Ctx.slider_hor(&ctx, macro Ctx.slider_hor(&ctx, Rect size, float* value, float hpercent = 0.25, ...)
Rect size, => ctx.slider_hor_id(@compute_id($vasplat), size, value, hpercent);
float* value,
float hpercent = 0.25,
Color bgcolor = 0x0000ffffu.to_rgba(),
Color handlecolor = 0x0ff000ffu.to_rgba(), ...)
=> ctx.slider_hor_id(@compute_id($vasplat), size, value, hpercent, bgcolor, handlecolor);
<* <*
@require value != null @require value != null
*> *>
fn ElemEvents? Ctx.slider_hor_id(&ctx, fn ElemEvents? Ctx.slider_hor_id(&ctx, Id id, Rect size, float* value, float hpercent = 0.25)
Id id,
Rect size,
float* value,
float hpercent = 0.25,
Color bgcolor = 0x0000ffffu.to_rgba(),
Color handlecolor = 0x0ff000ffu.to_rgba())
{ {
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_SLIDER)!; Elem* elem = ctx.get_elem(id, ETYPE_SLIDER)!;
Style* style = ctx.styles.get_style(@str_hash("slider"));
// 2. Layout // 2. Layout
elem.bounds = ctx.position_element(parent, size, true); elem.bounds = ctx.position_element(parent, size, style);
// handle width // handle width
short hw = (short)(elem.bounds.w * hpercent); short hw = (short)(elem.bounds.w * hpercent);
@ -60,8 +50,10 @@ fn ElemEvents? Ctx.slider_hor_id(&ctx,
} }
// Draw the slider background and handle // Draw the slider background and handle
ctx.push_rect(elem.bounds, bgcolor, parent.div.z_index)!; ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
ctx.push_rect(elem.slider.handle, handlecolor, parent.div.z_index)!; Style s = *style;
s.bg = s.primary;
ctx.push_rect(elem.slider.handle, parent.div.z_index, &s)!;
return elem.events; return elem.events;
} }
@ -79,25 +71,15 @@ fn ElemEvents? Ctx.slider_hor_id(&ctx,
* | | * | |
* +--+ * +--+
*/ */
macro Ctx.slider_ver(&ctx, macro Ctx.slider_ver(&ctx, Rect size, float* value, float hpercent = 0.25, ...)
Rect size, => ctx.slider_ver_id(@compute_id($vasplat), size, value, hpercent);
float* value, fn ElemEvents? Ctx.slider_ver_id(&ctx, Id id, Rect size, float* value, float hpercent = 0.25)
float hpercent = 0.25,
Color bgcolor = 0x0000ffffu.to_rgba(),
Color handlecolor = 0x0ff000ffu.to_rgba(), ...)
=> ctx.slider_ver_id(@compute_id($vasplat), size, value, hpercent, bgcolor, handlecolor);
fn ElemEvents? Ctx.slider_ver_id(&ctx,
Id id,
Rect size,
float* value,
float hpercent = 0.25,
Color bgcolor = 0x0000ffffu.to_rgba(),
Color handlecolor = 0x0ff000ffu.to_rgba())
{ {
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_SLIDER)!; Elem *elem = ctx.get_elem(id, ETYPE_SLIDER)!;
Style* style = ctx.styles.get_style(@str_hash("slider"));
// 1. Fill the element fields // 1. Fill the element fields
if (elem.flags.is_new) { if (elem.flags.is_new) {
@ -107,7 +89,7 @@ fn ElemEvents? Ctx.slider_ver_id(&ctx,
} }
// 2. Layout // 2. Layout
elem.bounds = ctx.position_element(parent, size, true); elem.bounds = ctx.position_element(parent, size, style);
// handle height // handle height
short hh = (short)(elem.bounds.h * hpercent); short hh = (short)(elem.bounds.h * hpercent);
@ -129,8 +111,10 @@ fn ElemEvents? Ctx.slider_ver_id(&ctx,
} }
// Draw the slider background and handle // Draw the slider background and handle
ctx.push_rect(elem.bounds, bgcolor, parent.div.z_index)!; ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
ctx.push_rect(elem.slider.handle, handlecolor, parent.div.z_index)!; Style s = *style;
s.bg = s.primary;
ctx.push_rect(elem.slider.handle, parent.div.z_index, &s)!;
return elem.events; return elem.events;
} }

View File

@ -120,12 +120,13 @@ 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);
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 };
Rect bounds = { 0, 0, sprite.w, sprite.h }; Rect bounds = { 0, 0, sprite.w, sprite.h };
elem.bounds = ctx.position_element(parent, bounds.off(off), true); elem.bounds = ctx.position_element(parent, bounds.off(off), style);
elem.sprite.id = ctx.get_sprite_atlas_id(name); elem.sprite.id = ctx.get_sprite_atlas_id(name);
// if the bounds are null the element is outside the div view, // if the bounds are null the element is outside the div view,

View File

@ -9,9 +9,13 @@ struct Style { // css box model
Rect padding; Rect padding;
Rect border; Rect border;
Rect margin; Rect margin;
Color bgcolor; // background color
Color fgcolor; // foreground color Color bg; // background color
Color brcolor; // border color Color fg; // foreground color
Color primary; // primary color
Color secondary; // secondary color
Color accent; // accent color
ushort radius; ushort radius;
} }
@ -19,10 +23,13 @@ const Style DEFAULT_STYLE = {
.margin = {2, 2, 2, 2}, .margin = {2, 2, 2, 2},
.border = {2, 2, 2, 2}, .border = {2, 2, 2, 2},
.padding = {1, 1, 1, 1}, .padding = {1, 1, 1, 1},
.bgcolor = 0x282828ffu.@to_rgba(),
.fgcolor = 0xfbf1c7ffu.@to_rgba(),
.brcolor = 0xd79921ffu.@to_rgba(),
.radius = 12, .radius = 12,
.bg = 0x282828ffu.@to_rgba(),
.fg = 0xfbf1c7ffu.@to_rgba(),
.primary = 0xcc241dffu.@to_rgba(),
.secondary = 0x458588ffu.@to_rgba(),
.accent = 0xfabd2fffu.@to_rgba(),
}; };
// style is stored in a hashmap, each style has an Id that can be generated by a string or whatever // style is stored in a hashmap, each style has an Id that can be generated by a string or whatever
@ -53,6 +60,8 @@ 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
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;
} }
@ -74,16 +83,19 @@ 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> {
* padding : left right top bottom; * padding: left right top bottom;
* border : left right top bottom; * border: left right top bottom;
* margin : left right top bottoms; * margin: left right top bottoms;
* bgcolor : #RRGGBBAA; * radius: uint;
* fgcolor : #RRGGBBAA; * Color: #RRGGBBAA;
* brcolor : #RRGGBBAA; * Color: #RRGGBBAA;
* radius : uint; * Color: #RRGGBBAA;
* Color: #RRGGBBAA;
* Color: #RRGGBBAA;
* } * }
* The field "style name" will be hashed and the hash used as the id int the style map. * The field "style name" will be hashed and the hash used as the id int the style map.
* Fields may be excluded, each excluded field is set to zero. * Fields may be excluded, each excluded field is set to zero.
@ -205,7 +217,7 @@ fn Token Lexer.next_token(&lex)
case ascii::is_alpha_m(lex.peep()): // identifier case ascii::is_alpha_m(lex.peep()): // identifier
t.type = IDENTIFIER; t.type = IDENTIFIER;
while (ascii::is_alnum_m(lex.peep())) { while (ascii::is_alnum_m(lex.peep()) || lex.peep() == '-' || lex.peep() == '_') {
if (lex.advance() == 0) { t.type = INVALID; break; } if (lex.advance() == 0) { t.type = INVALID; break; }
} }
t.text = lex.text[t.off..lex.off-1]; t.text = lex.text[t.off..lex.off-1];
@ -284,6 +296,8 @@ macro bool Parser.expect(&p, Token* t, TokenType type)
fn bool Parser.parse_style(&p) fn bool Parser.parse_style(&p)
{ {
Token t; Token t;
p.style = {};
p.style_id = 0;
// style name // style name
if (p.expect(&t, IDENTIFIER) == false) return false; if (p.expect(&t, IDENTIFIER) == false) return false;
@ -325,20 +339,30 @@ fn bool Parser.parse_property(&p)
if (p.parse_size(&margin) == false) return false; if (p.parse_size(&margin) == false) return false;
p.style.margin = margin; p.style.margin = margin;
case "bgcolor": case "bg":
Color bgcolor; Color bg;
if (p.parse_color(&bgcolor) == false) return false; if (p.parse_color(&bg) == false) return false;
p.style.bgcolor = bgcolor; p.style.bg = bg;
case "fgcolor": case "fg":
Color fgcolor; Color fg;
if (p.parse_color(&fgcolor) == false) return false; if (p.parse_color(&fg) == false) return false;
p.style.fgcolor = fgcolor; p.style.fg = fg;
case "brcolor": case "primary":
Color brcolor; Color primary;
if (p.parse_color(&brcolor) == false) return false; if (p.parse_color(&primary) == false) return false;
p.style.brcolor = brcolor; p.style.primary = primary;
case "secondary":
Color secondary;
if (p.parse_color(&secondary) == false) return false;
p.style.secondary = secondary;
case "accent":
Color accent;
if (p.parse_color(&accent) == false) return false;
p.style.accent = accent;
case "radius": case "radius":
short r; short r;

View File

@ -15,16 +15,17 @@ 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);
elem.text.str = text; elem.text.str = text;
// if the element is new or the parent was updated then redo layout // if the element is new or the parent was updated then redo layout
Rect text_size = ctx.get_text_bounds(text)!; Rect text_size = ctx.get_text_bounds(text)!;
// 2. Layout // 2. Layout
elem.bounds = ctx.position_element(parent, text_size, true); elem.bounds = ctx.position_element(parent, text_size, style);
if (elem.bounds.is_null()) { return; } if (elem.bounds.is_null()) { return; }
ctx.push_string(elem.bounds, text, parent.div.z_index)!; ctx.push_string(elem.bounds, text, parent.div.z_index, style.fg)!;
} }
macro Ctx.text_box(&ctx, Rect size, char[] text, usz* text_len, ...) macro Ctx.text_box(&ctx, Rect size, char[] text, usz* text_len, ...)
@ -35,11 +36,12 @@ 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);
elem.text.str = text; elem.text.str = text;
// layout the text box // layout the text box
elem.bounds = ctx.position_element(parent, size, true); elem.bounds = ctx.position_element(parent, size, style);
// check input and update the text // check input and update the text
elem.events = ctx.get_elem_events(elem); elem.events = ctx.get_elem_events(elem);
@ -79,10 +81,10 @@ fn ElemEvents? Ctx.text_box_id(&ctx, Id id, Rect size, char[] text, usz* text_le
}; };
cursor = cursor.off(elem.bounds.position()); cursor = cursor.off(elem.bounds.position());
ctx.push_rect(text_box, 0xabababffu.to_rgba(), parent.div.z_index, do_border: true)!; ctx.push_rect(text_box, parent.div.z_index, style)!;
ctx.push_string(text_box, text[:*text_len], parent.div.z_index)!; ctx.push_string(text_box, text[:*text_len], parent.div.z_index, style.fg)!;
ctx.push_rect(input_box, 0x424242ffu.to_rgba(), parent.div.z_index)!; ctx.push_rect(input_box, parent.div.z_index, style)!;
ctx.push_rect(cursor, 0x00000042u.to_rgba(), parent.div.z_index)!; ctx.push_rect(cursor, parent.div.z_index, style)!;
return elem.events; return elem.events;
} }

View File

@ -54,6 +54,77 @@ const char[*] RECT_FS_PATH = "resources/shaders/compiled/rect.frag.spv";
const char[*] SPRITE_VS_PATH = "resources/shaders/compiled/sprite.vert.spv"; const char[*] SPRITE_VS_PATH = "resources/shaders/compiled/sprite.vert.spv";
const char[*] RECT_VS_PATH = "resources/shaders/compiled/rect.vert.spv"; const char[*] RECT_VS_PATH = "resources/shaders/compiled/rect.vert.spv";
const String STYLESHEET = `
default {
bg: #282828ff;
fg: #fbf1c7ff;
primary: #cc241dff;
secondary: #458588ff;
accent: #fabd2fff;
}
button {
margin: 2 2 2 2;
border: 2 2 2 2;
padding: 1 1 1 1;
radius: 10;
bg: #3c3836ff;
fg: #fbf1c7ff;
primary: #cc241dff;
secondary: #458588ff;
accent: #fabd2fff;
}
button-active {
margin: 2 2 2 2;
border: 2 2 2 2;
padding: 1 1 1 1;
radius: 10;
bg: #504945ff;
fg: #fbf1c7ff;
primary: #cc241dff;
secondary: #cc241dff;
accent: #fabd2fff;
}
checkbox {
margin: 2 2 2 2;
border: 2 2 2 2;
padding: 1 1 1 1;
radius: 10;
bg: #3c3836ff;
fg: #fbf1c7ff;
primary: #cc241dff;
secondary: #458588ff;
accent: #fabd2fff;
}
toggle {
margin: 2 2 2 2;
border: 2 2 2 2;
padding: 1 1 1 1;
radius: 10;
bg: #3c3836ff;
fg: #fbf1c7ff;
primary: #cc241dff;
secondary: #458588ff;
accent: #fabd2fff;
}
slider {
margin: 2 2 2 2;
bg: #3c3836ff;
fg: #fbf1c7ff;
primary: #cc241dff;
secondary: #458588ff;
accent: #fabd2fff;
}
`;
fn int main(String[] args) fn int main(String[] args)
{ {
@ -113,14 +184,8 @@ fn int main(String[] args)
ren.create_pipeline("UGUI_PIPELINE_RECT", RECT); ren.create_pipeline("UGUI_PIPELINE_RECT", RECT);
// TESTING CSS // CSS INPUT
String stylesheet = ` io::printfn("imported %d styles", ui.import_style_from_string(STYLESHEET));
ciao {
margin: 12 24px 12mm 3;
brcolor: #ffff00ff;
radius: 10;
}`;
io::printfn("imported %d styles", ui.import_style_from_string(stylesheet));
isz frame; isz frame;
double fps; double fps;
@ -278,6 +343,7 @@ fn int main(String[] args)
TimeStats uts = ui_times.get_stats(); TimeStats uts = ui_times.get_stats();
ui.layout_set_floating()!!; ui.layout_set_floating()!!;
// FIXME: I cannot anchor shit to the bottom of the screen
ui.div_begin({0, ui.height-150, -300, 150})!!; ui.div_begin({0, ui.height-150, -300, 150})!!;
{ {
ui.layout_set_column()!!; ui.layout_set_column()!!;