diff --git a/lib/ugui.c3l/src/ugui_button.c3 b/lib/ugui.c3l/src/ugui_button.c3 index f9582bc..81b817f 100644 --- a/lib/ugui.c3l/src/ugui_button.c3 +++ b/lib/ugui.c3l/src/ugui_button.c3 @@ -40,7 +40,7 @@ fn ElemEvents? Ctx.button(&ctx, String label, Rect size, bool state = false) } // Draw the button - ctx.push_rect(elem.bounds, col, do_border: true, do_radius: true)!; + ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!; return elem.events; } @@ -80,8 +80,8 @@ fn ElemEvents? Ctx.button_label(&ctx, String label, Rect size = {0,0,short.max,s Point off = ctx.center_text(text_size, elem.bounds); text_size.x += off.x; text_size.y += off.y; - ctx.push_rect(elem.bounds, col, do_border: true, do_radius: true)!; - ctx.push_string(text_size, label)!; + ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!; + ctx.push_string(text_size, label, parent.div.z_index)!; return elem.events; } @@ -116,13 +116,13 @@ fn ElemEvents? Ctx.button_icon(&ctx, String label, String icon, String on_icon = Id tex_id = ctx.sprite_atlas.id; if (state && on_icon != "") { - ctx.push_sprite(elem.bounds, on_sprite.uv(), tex_id, type: on_sprite.type)!; + ctx.push_sprite(elem.bounds, on_sprite.uv(), tex_id, parent.div.z_index, type: on_sprite.type)!; } else { - ctx.push_sprite(elem.bounds, def_sprite.uv(), tex_id, type: def_sprite.type)!; + ctx.push_sprite(elem.bounds, def_sprite.uv(), tex_id, parent.div.z_index, type: def_sprite.type)!; } // Draw the button - ctx.push_rect(elem.bounds, col, do_border: true, do_radius: true)!; + ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!; return elem.events; } @@ -159,7 +159,7 @@ fn void? Ctx.checkbox(&ctx, String label, String description, Point off, bool* s Color col; if (tick_sprite != {}) { col = ctx.style.bgcolor; - ctx.push_rect(elem.bounds, col, do_border: true, do_radius: true)!; + ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!; if (*state) { ctx.draw_sprite_raw(tick_sprite, elem.bounds)!; } @@ -170,7 +170,7 @@ fn void? Ctx.checkbox(&ctx, String label, String description, Point off, bool* s col = 0xff00ffffu.to_rgba(); } // Draw the button - ctx.push_rect(elem.bounds, col, do_border: true, do_radius: true)!; + ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!; } } @@ -211,7 +211,7 @@ fn void? Ctx.toggle(&ctx, String label, String description, Point off, bool* sta } // Draw the button // FIXME: THIS IS SHIT - ctx.push_rect(elem.bounds, ctx.style.bgcolor, do_border: true, do_radius: true)!; + ctx.push_rect(elem.bounds, ctx.style.bgcolor, parent.div.z_index, do_border: true, do_radius: true)!; Rect t = elem.bounds.add({*state ? (DEFAULT_SWITCH_SIZE+3) : +3, +3, -DEFAULT_SWITCH_SIZE-6, -6}); - ctx.push_rect(t, col, do_border: false, do_radius: true)!; + ctx.push_rect(t, col, parent.div.z_index, do_border: false, do_radius: true)!; } diff --git a/lib/ugui.c3l/src/ugui_cmd.c3 b/lib/ugui.c3l/src/ugui_cmd.c3 index eee78d4..51120bb 100644 --- a/lib/ugui.c3l/src/ugui_cmd.c3 +++ b/lib/ugui.c3l/src/ugui_cmd.c3 @@ -1,6 +1,7 @@ module ugui; import std::ascii; +import std::io; // command type enum CmdType { @@ -37,8 +38,9 @@ struct CmdScissor { } // command structure -struct Cmd { +struct Cmd (Printable) { CmdType type; + int z_index; union { CmdRect rect; CmdUpdateAtlas update_atlas; @@ -47,6 +49,12 @@ struct Cmd { } } +// implement the Printable interface +fn usz? Cmd.to_format(Cmd* cmd, Formatter *f) @dynamic +{ + return f.printf("Cmd{ type: %s, z_index: %d }", cmd.type, cmd.z_index); +} + macro bool cull_rect(Rect rect, Rect clip = {0,0,short.max,short.max}) { bool no_area = rect.w <= 0 || rect.h <= 0; @@ -54,8 +62,9 @@ macro bool cull_rect(Rect rect, Rect clip = {0,0,short.max,short.max}) } // FIXME: this whole thing could be done at compile time, maybe -macro Ctx.push_cmd(&ctx, Cmd *cmd) +macro Ctx.push_cmd(&ctx, Cmd *cmd, int z_index) { + cmd.z_index = z_index; Rect rect; switch (cmd.type) { case CMD_RECT: rect = cmd.rect.rect; @@ -66,9 +75,18 @@ macro Ctx.push_cmd(&ctx, Cmd *cmd) return ctx.cmd_queue.enqueue(cmd); } +fn void? Ctx.push_scissor(&ctx, Rect rect, int z_index) +{ + Cmd sc = { + .type = CMD_SCISSOR, + .scissor.rect = rect.intersection(ctx.div_scissor), + }; + ctx.push_cmd(&sc, z_index)!; +} + // FIXME: is this really the best solution? // "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, bool do_border = false, bool do_padding = false, bool do_radius = false) +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 padding = ctx.style.padding; @@ -82,7 +100,7 @@ fn void? Ctx.push_rect(&ctx, Rect rect, Color color, bool do_border = false, boo .rect.color = border_color, .rect.radius = do_radius ? radius : 0, }; - ctx.push_cmd(&cmd)!; + ctx.push_cmd(&cmd, z_index)!; } Cmd cmd = { @@ -97,11 +115,11 @@ fn void? Ctx.push_rect(&ctx, Rect rect, Color color, bool do_border = false, boo .rect.radius = do_radius ? radius : 0, }; if (cull_rect(cmd.rect.rect, ctx.div_scissor)) return; - ctx.push_cmd(&cmd)!; + ctx.push_cmd(&cmd, z_index)!; } // TODO: add texture id -fn void? Ctx.push_sprite(&ctx, Rect bounds, Rect texture, Id texture_id, Color hue = 0xffffffffu.to_rgba(), SpriteType type = SPRITE_NORMAL) +fn void? Ctx.push_sprite(&ctx, Rect bounds, Rect texture, Id texture_id, int z_index, Color hue = 0xffffffffu.to_rgba(), SpriteType type = SPRITE_NORMAL) { Cmd cmd = { .type = CMD_SPRITE, @@ -111,16 +129,16 @@ fn void? Ctx.push_sprite(&ctx, Rect bounds, Rect texture, Id texture_id, Color h .sprite.texture_id = texture_id, .sprite.hue = hue, }; - ctx.push_cmd(&cmd)!; + ctx.push_cmd(&cmd, z_index)!; } -fn void? Ctx.push_string(&ctx, Rect bounds, String text, Color hue = 0xffffffffu.to_rgba()) +fn void? Ctx.push_string(&ctx, Rect bounds, String text, int z_index, Color hue = 0xffffffffu.to_rgba()) { if (text.len == 0) { return; } - ctx.push_scissor(bounds)!; + ctx.push_scissor(bounds, z_index)!; short baseline = (short)ctx.font.ascender; short line_height = (short)ctx.font.ascender - (short)ctx.font.descender; @@ -152,7 +170,7 @@ fn void? Ctx.push_string(&ctx, Rect bounds, String text, Color hue = 0xffffffffu .h = gp.h, }; // push the sprite only if it collides with the bounds - if (!cull_rect(gb, bounds)) ctx.push_sprite(gb, gt, texture_id, hue)!; + if (!cull_rect(gb, bounds)) ctx.push_sprite(gb, gt, texture_id, z_index, hue)!; line_len += gp.adv; } else if (cp == '\n'){ orig.y += line_height + line_gap; @@ -163,7 +181,7 @@ fn void? Ctx.push_string(&ctx, Rect bounds, String text, Color hue = 0xffffffffu } // FIXME: we never get here if an error was thrown before - ctx.push_scissor({})!; + ctx.push_scissor({}, z_index)!; } fn void? Ctx.push_update_atlas(&ctx, Atlas* atlas) @@ -178,14 +196,7 @@ fn void? Ctx.push_update_atlas(&ctx, Atlas* atlas) .bpp = (ushort)atlas.type.bpp(), }, }; - ctx.push_cmd(&up)!; + // update the atlases before everything else + ctx.push_cmd(&up, -1)!; } -fn void? Ctx.push_scissor(&ctx, Rect rect) -{ - Cmd sc = { - .type = CMD_SCISSOR, - .scissor.rect = rect.intersection(ctx.div_scissor), - }; - ctx.push_cmd(&sc)!; -} diff --git a/lib/ugui.c3l/src/ugui_core.c3 b/lib/ugui.c3l/src/ugui_core.c3 index 8c4cf75..8078218 100644 --- a/lib/ugui.c3l/src/ugui_core.c3 +++ b/lib/ugui.c3l/src/ugui_core.c3 @@ -244,6 +244,7 @@ fn void? Ctx.frame_begin(&ctx) }, .div = { .layout = LAYOUT_ROW, + .z_index = 0, .children_bounds = { .w = ctx.width, .h = ctx.height, @@ -263,6 +264,8 @@ fn void? Ctx.frame_begin(&ctx) // TODO: add a background color taken from a theme or config } +const int DEBUG = 1; + fn void? Ctx.frame_end(&ctx) { Elem* root = ctx.get_elem_by_tree_idx(0)!; @@ -285,10 +288,12 @@ fn void? Ctx.frame_end(&ctx) ctx.sprite_atlas.should_update = false; } -$if 1: +// debug +$if DEBUG == 1: // draw mouse position Cmd cmd = { .type = CMD_RECT, + .z_index = int.max, // hopefully over everything else .rect.rect = { .x = ctx.input.mouse.pos.x - 2, .y = ctx.input.mouse.pos.y - 2, @@ -298,6 +303,12 @@ $if 1: .rect.color = 0xff00ffffu.to_rgba() }; ctx.cmd_queue.enqueue(&cmd)!; + + // dump the command buffer + io::printn("Command Buffer Dump:"); + foreach(idx, c: ctx.cmd_queue) { + io::printfn("\t [%d] = {%s}", idx, c); + } $endif } diff --git a/lib/ugui.c3l/src/ugui_div.c3 b/lib/ugui.c3l/src/ugui_div.c3 index bff69a3..d4dcae6 100644 --- a/lib/ugui.c3l/src/ugui_div.c3 +++ b/lib/ugui.c3l/src/ugui_div.c3 @@ -18,6 +18,7 @@ struct ElemDiv { bool on; float value; } + int z_index; Rect children_bounds; // current frame children bounds Rect pcb; // previous frame children bounds Point origin_r, origin_c; @@ -46,6 +47,8 @@ fn void? Ctx.div_begin(&ctx, String label, Rect size, bool scroll_x = false, boo } elem.div.scroll_x.enabled = scroll_x; elem.div.scroll_y.enabled = scroll_y; + elem.div.z_index = parent.div.z_index + 1; + io::printn(elem.div.z_index); // 2. layout the element Rect wanted_size = { @@ -59,7 +62,7 @@ fn void? Ctx.div_begin(&ctx, String label, Rect size, bool scroll_x = false, boo // update the ctx scissor ctx.div_scissor = elem.bounds; - ctx.push_scissor(elem.bounds)!; + ctx.push_scissor(elem.bounds, elem.div.z_index)!; // 4. Fill the div fields elem.div.origin_c = { @@ -71,7 +74,7 @@ fn void? Ctx.div_begin(&ctx, String label, Rect size, bool scroll_x = false, boo // Add the background to the draw stack bool do_border = parent.div.layout == LAYOUT_FLOATING; - ctx.push_rect(elem.bounds, ctx.style.bgcolor, do_border: do_border)!; + ctx.push_rect(elem.bounds, ctx.style.bgcolor, elem.div.z_index, do_border: do_border)!; elem.events = ctx.get_elem_events(elem); diff --git a/lib/ugui.c3l/src/ugui_slider.c3 b/lib/ugui.c3l/src/ugui_slider.c3 index cdcccf8..a161389 100644 --- a/lib/ugui.c3l/src/ugui_slider.c3 +++ b/lib/ugui.c3l/src/ugui_slider.c3 @@ -61,8 +61,8 @@ fn ElemEvents? Ctx.slider_hor(&ctx, } // Draw the slider background and handle - ctx.push_rect(elem.bounds, bgcolor)!; - ctx.push_rect(elem.slider.handle, handlecolor)!; + ctx.push_rect(elem.bounds, bgcolor, parent.div.z_index)!; + ctx.push_rect(elem.slider.handle, handlecolor, parent.div.z_index)!; return elem.events; } @@ -124,8 +124,8 @@ fn ElemEvents? Ctx.slider_ver(&ctx, } // Draw the slider background and handle - ctx.push_rect(elem.bounds, bgcolor)!; - ctx.push_rect(elem.slider.handle, handlecolor)!; + ctx.push_rect(elem.bounds, bgcolor, parent.div.z_index)!; + ctx.push_rect(elem.slider.handle, handlecolor, parent.div.z_index)!; return elem.events; } diff --git a/lib/ugui.c3l/src/ugui_sprite.c3 b/lib/ugui.c3l/src/ugui_sprite.c3 index 1f94b27..0aa913f 100644 --- a/lib/ugui.c3l/src/ugui_sprite.c3 +++ b/lib/ugui.c3l/src/ugui_sprite.c3 @@ -164,12 +164,13 @@ fn void? Ctx.draw_sprite(&ctx, String label, String name, Point off = {0,0}) Id tex_id = ctx.sprite_atlas.id; - return ctx.push_sprite(elem.bounds, uv, tex_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) { + Elem *parent = ctx.get_parent()!; Sprite* sprite = ctx.sprite_atlas.get(name)!; Id tex_id = ctx.sprite_atlas.id; - return ctx.push_sprite(bounds, sprite.uv(), tex_id, type: sprite.type)!; + return ctx.push_sprite(bounds, sprite.uv(), tex_id, parent.div.z_index, type: sprite.type)!; } diff --git a/lib/ugui.c3l/src/ugui_text.c3 b/lib/ugui.c3l/src/ugui_text.c3 index dea4562..bf04077 100644 --- a/lib/ugui.c3l/src/ugui_text.c3 +++ b/lib/ugui.c3l/src/ugui_text.c3 @@ -26,5 +26,5 @@ fn void? Ctx.text_unbounded(&ctx, String label, String text) elem.bounds = ctx.position_element(parent, text_size, true); if (elem.bounds.is_null()) { return; } - ctx.push_string(elem.bounds, text)!; + ctx.push_string(elem.bounds, text, parent.div.z_index)!; }