From 250a0fb3b5e85caeaea574757c5dec178f974667 Mon Sep 17 00:00:00 2001 From: Alessandro Mauri Date: Thu, 7 Nov 2024 18:35:20 +0100 Subject: [PATCH] initial work on scrollable divs --- src/main.c3 | 13 ++++++++-- src/ugui_data.c3 | 16 ++++++++++++ src/ugui_div.c3 | 64 ++++++++++++++++++++++++++++++++++++++++++++++ src/ugui_impl.c3 | 56 +--------------------------------------- src/ugui_layout.c3 | 38 +++++++++------------------ 5 files changed, 104 insertions(+), 83 deletions(-) create mode 100644 src/ugui_div.c3 diff --git a/src/main.c3 b/src/main.c3 index 8f9bd51..93dfbb8 100644 --- a/src/main.c3 +++ b/src/main.c3 @@ -51,10 +51,10 @@ fn int main(String[] args) ctx.frame_begin()!!; // main div, fill the whole window - ctx.div_begin("main", ugui::DIV_FILL)!!; + ctx.div_begin("main", ugui::Rect{.w=ctx.width/2})!!; {| ctx.layout_set_column()!!; - if (ctx.button("button0", ugui::Rect{100,100,30,30})!!.mouse_press) { + if (ctx.button("button0", ugui::Rect{0,0,30,30})!!.mouse_press) { io::printn("press button0"); } ctx.layout_next_column()!!; @@ -72,6 +72,15 @@ fn int main(String[] args) |}; ctx.div_end()!!; + ctx.div_begin("second", ugui::DIV_FILL)!!; + {| + if (ctx.slider_ver("slider_other", ugui::Rect{0,0,30,100})!!.update) { + ugui::Elem* e = ctx.get_elem_by_label("slider_other")!!; + io::printfn("other slider: %f", e.slider.value); + } + |}; + ctx.div_end()!!; + ctx.frame_end()!!; /* End UI Handling */ diff --git a/src/ugui_data.c3 b/src/ugui_data.c3 index 3d9d208..834eeff 100644 --- a/src/ugui_data.c3 +++ b/src/ugui_data.c3 @@ -192,3 +192,19 @@ macro point_in_rect(Point p, Rect r) { return (p.x >= r.x && p.x <= r.x + r.w) && (p.y >= r.y && p.y <= r.y + r.h); } + +// return true if rect a contains b +macro rect_contains(Rect a, Rect b) +{ + return (a.x <= b.x && a.y <= b.y && a.x+a.w >= b.x+b.w && a.y+a.h >= b.y+b.h); +} + +macro rect_intersection(Rect a, Rect b) +{ + return Rect{ + .x = (short)max(a.x, b.x), + .y = (short)max(a.y, b.y), + .w = (short)min(a.x+a.w, b.x+b.w) - (short)max(a.x, b.x), + .h = (short)min(a.y+a.h, b.y+b.h) - (short)max(a.y, b.y), + }; +} diff --git a/src/ugui_div.c3 b/src/ugui_div.c3 new file mode 100644 index 0000000..6980a47 --- /dev/null +++ b/src/ugui_div.c3 @@ -0,0 +1,64 @@ +module ugui; + + +fn void! Ctx.div_begin(&ctx, String label, Rect size) +{ + Id id = hash(label); + + Elem *parent = ctx.get_parent()!; + Elem* c_elem = ctx.get_elem(id)!; + isz div_node = ctx.tree.add(id, ctx.active_div)!; + ctx.active_div = div_node; + + // 1. Fill the element fields + c_elem.type = ETYPE_DIV; + + // do layout and update flags only if the element was updated + if (c_elem.flags.is_new || parent.flags.updated) { + // 2. layout the element + c_elem.bounds = ctx.position_element(parent, size); + + // 3. Mark the element as updated + c_elem.flags.updated = true; + // 4. Fill the div fields + c_elem.div.layout = parent.div.layout; + c_elem.div.origin_c = Point{ + .x = c_elem.bounds.x, + .y = c_elem.bounds.y, + }; + c_elem.div.color_bg = uint_to_rgba(0xff0000ff); + c_elem.div.origin_r = c_elem.div.origin_c; + } + + // Add the background to the draw stack + Cmd cmd = { + .type = CMD_RECT, + .rect = { + .rect = c_elem.bounds, + .color = c_elem.div.color_bg, + }, + }; + ctx.cmd_queue.enqueue(&cmd)!; + + // TODO: check active + // TODO: check resizeable + + // TODO: check scrollbars + // if the bounds are outside of the view then allocate space for scrollbars + DivLayout old_layout = c_elem.div.layout; + c_elem.div.layout = LAYOUT_FLOATING; + c_elem.div.layout = old_layout; + + if (parent.flags.has_focus) { + if (point_in_rect(ctx.input.mouse.pos, c_elem.bounds)) { + c_elem.flags.has_focus = true; + } + } + +} + +fn void! Ctx.div_end(&ctx) +{ + // the active_div returns to the parent of the current one + ctx.active_div = ctx.tree.parentof(ctx.active_div)!; +} diff --git a/src/ugui_impl.c3 b/src/ugui_impl.c3 index 57da04f..5a84e42 100644 --- a/src/ugui_impl.c3 +++ b/src/ugui_impl.c3 @@ -81,7 +81,7 @@ fn void! Ctx.frame_begin(&ctx) .h = ctx.height, }, .div = { - .layout = LAYOUT_ROW, + .layout = LAYOUT_ROW, }, .flags = c_elem.flags, }; @@ -120,60 +120,6 @@ $if 1: $endif } -fn void! Ctx.div_begin(&ctx, String label, Rect size) -{ - Id id = hash(label); - - Elem *parent = ctx.get_parent()!; - Elem* c_elem = ctx.get_elem(id)!; - isz div_node = ctx.tree.add(id, ctx.active_div)!; - ctx.active_div = div_node; - - // 1. Fill the element fields - c_elem.type = ETYPE_DIV; - - // do layout and update flags only if the element was updated - if (c_elem.flags.is_new || parent.flags.updated) { - // 2. layout the element - c_elem.bounds = ctx.position_element(parent, size); - - // 3. Mark the element as updated - c_elem.flags.updated = true; - // 4. Fill the div fields - c_elem.div.layout = parent.div.layout; - c_elem.div.origin_c = Point{ - .x = c_elem.bounds.x, - .y = c_elem.bounds.y, - }; - c_elem.div.color_bg = uint_to_rgba(0xff0000ff); - c_elem.div.origin_r = c_elem.div.origin_c; - } else if (parent.flags.has_focus) { - if (point_in_rect(ctx.input.mouse.pos, c_elem.bounds)) { - c_elem.flags.has_focus = true; - } - } else { - // TODO: check active - // TODO: check scrollbars - // TODO: check resizeable - } - - // Add the background to the draw stack - Cmd cmd = { - .type = CMD_RECT, - .rect = { - .rect = c_elem.bounds, - .color = c_elem.div.color_bg, - }, - }; - ctx.cmd_queue.enqueue(&cmd)!; -} - -fn void! Ctx.div_end(&ctx) -{ - // the active_div returns to the parent of the current one - ctx.active_div = ctx.tree.parentof(ctx.active_div)!; -} - /** * @ensure elem != null **/ diff --git a/src/ugui_layout.c3 b/src/ugui_layout.c3 index 5b60602..c3416f6 100644 --- a/src/ugui_layout.c3 +++ b/src/ugui_layout.c3 @@ -77,7 +77,7 @@ fn void! Ctx.layout_next_column(&ctx) // position the rectangle inside the parent according to the layout fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false) { - Rect elem_rect; + Rect bounds; Point origin; // 1. Select the right origin @@ -92,30 +92,29 @@ fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false) } // 2. Position the rect - elem_rect.x = origin.x + rect.x; - elem_rect.y = origin.y + rect.y; + bounds.x = (short)max(origin.x + rect.x, 0); + bounds.y = (short)max(origin.y + rect.y, 0); // 3. Calculate width & height - // TODO: what about negative values? // FIXME: account for origin offset!! - elem_rect.w = rect.w > 0 ? rect.w : parent.bounds.w; - elem_rect.h = rect.h > 0 ? rect.h : parent.bounds.h; + bounds.w = rect.w > 0 ? rect.w : parent.bounds.w; + bounds.h = rect.h > 0 ? rect.h : parent.bounds.h; // 4. Update the origins of the parent parent.div.origin_r = Point{ - .x = elem_rect.x + elem_rect.w, - .y = elem_rect.y, + .x = bounds.x + bounds.w, + .y = bounds.y, }; parent.div.origin_c = Point{ - .x = elem_rect.x, - .y = elem_rect.y + elem_rect.h, + .x = bounds.x, + .y = bounds.y + bounds.h, }; // if using the style then apply margins // FIXME: this does not work if (style && parent.div.layout != LAYOUT_FLOATING) { - elem_rect.x += ctx.style.margin.x; - elem_rect.y += ctx.style.margin.y; + bounds.x += ctx.style.margin.x; + bounds.y += ctx.style.margin.y; // total keep-out borders Rect margin_tot = { @@ -136,18 +135,5 @@ fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false) parent.div.origin_c.y += margin_tot.y + margin_tot.h; } - /* - printf( - "positioning rect: %lx {%d %d %d %d}(%d %d %d %d) . {%d %d %d - %d}\n", parent.id, rect.x, rect.y, rect.w, rect.h, parent.bounds.x, - parent.bounds.y, - parent.bounds.w, - parent.bounds.h, - elem_rect.x, - elem_rect.y, - elem_rect.w, - elem_rect.h - ); - */ - return elem_rect; + return bounds; }