initial work on scrollable divs

c3
Alessandro Mauri 2 weeks ago
parent 8bc38452b3
commit 250a0fb3b5
  1. 13
      src/main.c3
  2. 16
      src/ugui_data.c3
  3. 64
      src/ugui_div.c3
  4. 56
      src/ugui_impl.c3
  5. 38
      src/ugui_layout.c3

@ -51,10 +51,10 @@ fn int main(String[] args)
ctx.frame_begin()!!; ctx.frame_begin()!!;
// main div, fill the whole window // 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()!!; 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"); io::printn("press button0");
} }
ctx.layout_next_column()!!; ctx.layout_next_column()!!;
@ -72,6 +72,15 @@ fn int main(String[] args)
|}; |};
ctx.div_end()!!; 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()!!; ctx.frame_end()!!;
/* End UI Handling */ /* End UI Handling */

@ -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 (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),
};
}

@ -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)!;
}

@ -81,7 +81,7 @@ fn void! Ctx.frame_begin(&ctx)
.h = ctx.height, .h = ctx.height,
}, },
.div = { .div = {
.layout = LAYOUT_ROW, .layout = LAYOUT_ROW,
}, },
.flags = c_elem.flags, .flags = c_elem.flags,
}; };
@ -120,60 +120,6 @@ $if 1:
$endif $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 * @ensure elem != null
**/ **/

@ -77,7 +77,7 @@ fn void! Ctx.layout_next_column(&ctx)
// position the rectangle inside the parent according to the layout // position the rectangle inside the parent according to the layout
fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false) fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false)
{ {
Rect elem_rect; Rect bounds;
Point origin; Point origin;
// 1. Select the right 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 // 2. Position the rect
elem_rect.x = origin.x + rect.x; bounds.x = (short)max(origin.x + rect.x, 0);
elem_rect.y = origin.y + rect.y; bounds.y = (short)max(origin.y + rect.y, 0);
// 3. Calculate width & height // 3. Calculate width & height
// TODO: what about negative values?
// FIXME: account for origin offset!! // FIXME: account for origin offset!!
elem_rect.w = rect.w > 0 ? rect.w : parent.bounds.w; bounds.w = rect.w > 0 ? rect.w : parent.bounds.w;
elem_rect.h = rect.h > 0 ? rect.h : parent.bounds.h; bounds.h = rect.h > 0 ? rect.h : parent.bounds.h;
// 4. Update the origins of the parent // 4. Update the origins of the parent
parent.div.origin_r = Point{ parent.div.origin_r = Point{
.x = elem_rect.x + elem_rect.w, .x = bounds.x + bounds.w,
.y = elem_rect.y, .y = bounds.y,
}; };
parent.div.origin_c = Point{ parent.div.origin_c = Point{
.x = elem_rect.x, .x = bounds.x,
.y = elem_rect.y + elem_rect.h, .y = bounds.y + bounds.h,
}; };
// if using the style then apply margins // if using the style then apply margins
// FIXME: this does not work // FIXME: this does not work
if (style && parent.div.layout != LAYOUT_FLOATING) { if (style && parent.div.layout != LAYOUT_FLOATING) {
elem_rect.x += ctx.style.margin.x; bounds.x += ctx.style.margin.x;
elem_rect.y += ctx.style.margin.y; bounds.y += ctx.style.margin.y;
// total keep-out borders // total keep-out borders
Rect margin_tot = { 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; parent.div.origin_c.y += margin_tot.y + margin_tot.h;
} }
/* return bounds;
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;
} }

Loading…
Cancel
Save