popups
This commit is contained in:
parent
e7cfa3517f
commit
32a57d5293
@ -58,6 +58,7 @@ struct Elem {
|
||||
Rect children_bounds;
|
||||
ElemType type;
|
||||
Layout layout;
|
||||
int z_index;
|
||||
union {
|
||||
ElemDiv div;
|
||||
ElemButton button;
|
||||
@ -100,6 +101,7 @@ struct Ctx {
|
||||
bool has_focus;
|
||||
struct input {
|
||||
InputEvents events;
|
||||
int z_index; // the layer the input events need to be propageted to
|
||||
struct mouse {
|
||||
Point pos, delta;
|
||||
// mouse_down: bitmap of mouse buttons that are held
|
||||
@ -178,6 +180,11 @@ fn Elem*? Ctx.get_elem(&ctx, Id id, ElemType type)
|
||||
} else {
|
||||
elem.type = type;
|
||||
}
|
||||
// FIXME: this is crap
|
||||
if (ctx.tree.is_used(ctx.active_div)) {
|
||||
elem.z_index = ctx.get_active_div()!.z_index;
|
||||
}
|
||||
|
||||
elem.tree_idx = ctx.tree.add(ctx.active_div, id);
|
||||
return elem;
|
||||
}
|
||||
@ -242,10 +249,11 @@ fn void? Ctx.frame_begin(&ctx)
|
||||
// if the window has focus then the root element also has focus, no other
|
||||
// computation needed, child elements need to check the mouse positon and
|
||||
// other stuff
|
||||
ctx.input.z_index = 0;
|
||||
//elem.flags.has_focus = ctx.has_focus;
|
||||
|
||||
elem.bounds = {0, 0, ctx.width, ctx.height};
|
||||
elem.div.z_index = 0;
|
||||
elem.z_index = 0;
|
||||
elem.div.scroll_x.enabled = false;
|
||||
elem.div.scroll_y.enabled = false;
|
||||
elem.layout.dir = ROW;
|
||||
@ -309,7 +317,8 @@ $endif
|
||||
|
||||
// sort the command buffer by the z-index
|
||||
// FIXME: sorting the buffer fucks with scissor commands that have to be kept in place
|
||||
//ctx.cmd_queue.sort()!;
|
||||
// TODO: instead of sorting at the end perform ordered inserts into the command buffer
|
||||
ctx.cmd_queue.sort()!;
|
||||
|
||||
// foreach (i, c: ctx.cmd_queue) {
|
||||
// io::printf("[%d]: ", i);
|
||||
@ -335,6 +344,8 @@ macro bool Ctx.elem_focus(&ctx, Elem *elem)
|
||||
// FIXME: hacked together, please do better
|
||||
fn ElemEvents Ctx.get_elem_events(&ctx, Elem *elem)
|
||||
{
|
||||
if (ctx.input.z_index != elem.z_index) return {};
|
||||
|
||||
bool hover = ctx.is_hovered(elem);
|
||||
bool focus = ctx.elem_focus(elem) || (hover && ctx.is_mouse_pressed(BTN_LEFT));
|
||||
|
||||
|
@ -47,6 +47,7 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon)
|
||||
update_parent_size(elem, parent);
|
||||
|
||||
elem.events = ctx.get_elem_events(elem);
|
||||
// if (ctx.input.z_index == elem.z_index) println("true ", elem.z_index);
|
||||
Rect content_bounds = elem.content_bounds();
|
||||
|
||||
Rect icon_bounds = {
|
||||
@ -72,12 +73,12 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon)
|
||||
s.bg = s.accent;
|
||||
}
|
||||
|
||||
ctx.push_rect(elem.bounds.pad(style.margin), parent.div.z_index, &s)!;
|
||||
ctx.push_rect(elem.bounds.pad(style.margin), parent.z_index, &s)!;
|
||||
if (icon != "") {
|
||||
ctx.push_sprite(icon_bounds, sprite.uv(), ctx.sprite_atlas.id, parent.div.z_index, type: sprite.type)!;
|
||||
ctx.push_sprite(icon_bounds, sprite.uv(), ctx.sprite_atlas.id, parent.z_index, type: sprite.type)!;
|
||||
}
|
||||
if (label != "") {
|
||||
ctx.layout_string(label, text_bounds, CENTER, parent.div.z_index, style.fg)!;
|
||||
ctx.layout_string(label, text_bounds, CENTER, parent.z_index, style.fg)!;
|
||||
}
|
||||
return elem.events;
|
||||
}
|
||||
@ -138,20 +139,20 @@ fn void? Ctx.checkbox_id(&ctx, Id id, String description, bool* active, String t
|
||||
s.border = style.border;
|
||||
s.radius = style.radius;
|
||||
|
||||
ctx.layout_string(description, text_bounds, CENTER, parent.div.z_index, style.fg)!;
|
||||
ctx.layout_string(description, text_bounds, CENTER, parent.z_index, style.fg)!;
|
||||
if (tick_sprite != "") {
|
||||
ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
|
||||
ctx.push_rect(check_bounds, parent.z_index, &s)!;
|
||||
if (*active) {
|
||||
Sprite* sprite = ctx.sprite_atlas.get(tick_sprite)!;
|
||||
Id tex_id = ctx.sprite_atlas.id;
|
||||
ctx.push_sprite(sprite.rect().center_to(check_bounds), sprite.uv(), tex_id, parent.div.z_index, type: sprite.type)!;
|
||||
ctx.push_sprite(sprite.rect().center_to(check_bounds), sprite.uv(), tex_id, parent.z_index, type: sprite.type)!;
|
||||
}
|
||||
} else {
|
||||
if (*active) {
|
||||
s.bg = style.primary;
|
||||
ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
|
||||
ctx.push_rect(check_bounds, parent.z_index, &s)!;
|
||||
} else {
|
||||
ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
|
||||
ctx.push_rect(check_bounds, parent.z_index, &s)!;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -216,10 +217,10 @@ fn void? Ctx.toggle_id(&ctx, Id id, String description, bool* active)
|
||||
s.secondary = style.secondary;
|
||||
s.border = style.border;
|
||||
s.radius = style.radius;
|
||||
ctx.layout_string(description, text_bounds, CENTER, parent.div.z_index, style.fg)!;
|
||||
ctx.push_rect(toggle_bounds, parent.div.z_index, &s)!;
|
||||
ctx.layout_string(description, text_bounds, CENTER, parent.z_index, style.fg)!;
|
||||
ctx.push_rect(toggle_bounds, parent.z_index, &s)!;
|
||||
s.bg = style.primary;
|
||||
s.border = {};
|
||||
ctx.push_rect(toggle.pad(style.border), parent.div.z_index, &s)!;
|
||||
ctx.push_rect(toggle.pad(style.border), parent.z_index, &s)!;
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ struct ElemDiv {
|
||||
bool on;
|
||||
float value;
|
||||
}
|
||||
int z_index;
|
||||
}
|
||||
|
||||
|
||||
@ -81,8 +80,8 @@ fn void? Ctx.div_begin_id(&ctx,
|
||||
|
||||
elem.div.scroll_x.enabled = scroll_x;
|
||||
elem.div.scroll_y.enabled = scroll_y;
|
||||
elem.div.z_index = parent.div.z_index + 1;
|
||||
|
||||
if (ctx.input.z_index < elem.z_index) ctx.input.z_index = elem.z_index;
|
||||
|
||||
// update layout with correct info
|
||||
elem.layout = {
|
||||
.w = width,
|
||||
@ -97,11 +96,11 @@ fn void? Ctx.div_begin_id(&ctx,
|
||||
elem.layout.origin.y = off.y;
|
||||
}
|
||||
|
||||
ctx.push_rect(elem.bounds.pad(style.margin), elem.div.z_index, style)!;
|
||||
ctx.push_rect(elem.bounds.pad(style.margin), elem.z_index, style)!;
|
||||
|
||||
// update the ctx scissor, it HAS to be after drawing the background
|
||||
ctx.div_scissor = elem.bounds.pad(elem.layout.content_offset);
|
||||
ctx.push_scissor(elem.bounds.pad(elem.layout.content_offset), elem.div.z_index)!;
|
||||
ctx.push_scissor(elem.bounds.pad(elem.layout.content_offset), elem.z_index)!;
|
||||
|
||||
elem.events = ctx.get_elem_events(elem);
|
||||
|
||||
@ -160,9 +159,67 @@ fn Id? Ctx.div_end(&ctx)
|
||||
ctx.active_div = ctx.tree.parentof(ctx.active_div);
|
||||
Elem* parent = ctx.get_parent()!;
|
||||
ctx.div_scissor = parent.bounds.pad(parent.layout.content_offset);
|
||||
ctx.reset_scissor(elem.div.z_index)!;
|
||||
ctx.reset_scissor(elem.z_index)!;
|
||||
|
||||
update_parent_size(elem, parent);
|
||||
|
||||
return elem.id;
|
||||
}
|
||||
|
||||
macro bool? Ctx.popup_begin(&ctx, Point pos,
|
||||
Size width, Size height,
|
||||
LayoutDirection dir = ROW, Anchor anchor = TOP_LEFT,
|
||||
bool scroll_x = false, bool scroll_y = false,
|
||||
...
|
||||
)
|
||||
=> ctx.popup_begin_id(@compute_id($vasplat), pos, width, height, dir, anchor, scroll_x, scroll_y);
|
||||
fn bool? Ctx.popup_begin_id(&ctx,
|
||||
Id id,
|
||||
Point pos,
|
||||
Size width, Size height,
|
||||
LayoutDirection dir, Anchor anchor,
|
||||
bool scroll_x, bool scroll_y
|
||||
)
|
||||
{
|
||||
id = ctx.gen_id(id)!;
|
||||
|
||||
Elem* elem = ctx.get_elem(id, ETYPE_DIV)!;
|
||||
Elem* parent = ctx.find_elem(ctx.active_div); // pop-up parent is always root
|
||||
ctx.active_div = elem.tree_idx;
|
||||
|
||||
Style* style = ctx.styles.get_style(@str_hash("popup"));
|
||||
|
||||
elem.div.scroll_x.enabled = scroll_x;
|
||||
elem.div.scroll_y.enabled = scroll_y;
|
||||
elem.z_index++;
|
||||
if (ctx.input.z_index < elem.z_index) ctx.input.z_index = elem.z_index;
|
||||
|
||||
// update layout with correct info
|
||||
elem.layout = {
|
||||
.w = width,
|
||||
.h = height,
|
||||
.dir = dir,
|
||||
.anchor = anchor,
|
||||
.content_offset = style.margin + style.border + style.padding,
|
||||
.absolute = true,
|
||||
.origin.x = pos.x - parent.bounds.x,
|
||||
.origin.y = pos.y - parent.bounds.y,
|
||||
};
|
||||
|
||||
ctx.push_rect(elem.bounds.pad(style.margin), elem.z_index, style)!;
|
||||
|
||||
// update the ctx scissor, it HAS to be after drawing the background
|
||||
ctx.div_scissor = elem.bounds.pad(elem.layout.content_offset);
|
||||
ctx.push_scissor(elem.bounds.pad(elem.layout.content_offset), elem.z_index)!;
|
||||
|
||||
elem.events = ctx.get_elem_events(elem);
|
||||
|
||||
// check close condition, mouse release anywhere outside the div bounds
|
||||
if ((ctx.mouse_released() & BTN_ANY) && !elem.events.mouse_hover) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: check active
|
||||
// TODO: check resizeable
|
||||
return true;
|
||||
}
|
||||
|
@ -57,11 +57,11 @@ fn ElemEvents? Ctx.slider_hor_id(&ctx, Id id, Size w, Size h, float* value, floa
|
||||
Style s = *style;
|
||||
Rect padding = s.padding;
|
||||
s.padding = {};
|
||||
ctx.push_rect(bg_bounds, parent.div.z_index, &s)!;
|
||||
ctx.push_rect(bg_bounds, parent.z_index, &s)!;
|
||||
s.bg = s.primary;
|
||||
s.padding = padding;
|
||||
s.border = {};
|
||||
ctx.push_rect(elem.slider.handle, parent.div.z_index, &s)!;
|
||||
ctx.push_rect(elem.slider.handle, parent.z_index, &s)!;
|
||||
|
||||
return elem.events;
|
||||
}
|
||||
@ -121,11 +121,11 @@ fn ElemEvents? Ctx.slider_ver_id(&ctx, Id id, Size w, Size h, float* value, floa
|
||||
Style s = *style;
|
||||
Rect padding = s.padding;
|
||||
s.padding = {};
|
||||
ctx.push_rect(bg_bounds, parent.div.z_index, &s)!;
|
||||
ctx.push_rect(bg_bounds, parent.z_index, &s)!;
|
||||
s.bg = s.primary;
|
||||
s.padding = padding;
|
||||
s.border = {};
|
||||
ctx.push_rect(elem.slider.handle, parent.div.z_index, &s)!;
|
||||
ctx.push_rect(elem.slider.handle, parent.z_index, &s)!;
|
||||
|
||||
return elem.events;
|
||||
}
|
||||
@ -177,8 +177,8 @@ fn void? Ctx.scrollbar(&ctx, Id id, float *value, float handle_percent, bool ver
|
||||
|
||||
|
||||
Rect bg_bounds = elem.bounds.pad(style.margin);
|
||||
ctx.push_rect(bg_bounds, parent.div.z_index, style)!;
|
||||
ctx.push_rect(elem.slider.handle, parent.div.z_index, &&(Style){.bg = style.primary, .radius = style.radius})!;
|
||||
ctx.push_rect(bg_bounds, parent.z_index, style)!;
|
||||
ctx.push_rect(elem.slider.handle, parent.z_index, &&(Style){.bg = style.primary, .radius = style.radius})!;
|
||||
}
|
||||
|
||||
macro short calc_slider(short off, short dim, float value) => (short)off + (short)(dim * value);
|
||||
|
@ -22,5 +22,5 @@ fn void? Ctx.sprite_id(&ctx, Id id, String name)
|
||||
update_parent_size(elem, parent);
|
||||
|
||||
Id tex_id = ctx.sprite_atlas.id;
|
||||
return ctx.push_sprite(elem.bounds, sprite.uv(), tex_id, parent.div.z_index, type: sprite.type)!;
|
||||
return ctx.push_sprite(elem.bounds, sprite.uv(), tex_id, parent.z_index, type: sprite.type)!;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ fn void? Ctx.text_id(&ctx, Id id, String text)
|
||||
|
||||
update_parent_size(elem, parent);
|
||||
|
||||
ctx.layout_string(text, elem.bounds.pad(elem.layout.content_offset), TOP_LEFT, parent.div.z_index, style.fg)!;
|
||||
ctx.layout_string(text, elem.bounds.pad(elem.layout.content_offset), TOP_LEFT, parent.z_index, style.fg)!;
|
||||
}
|
||||
|
||||
|
||||
@ -75,17 +75,17 @@ fn ElemEvents? Ctx.text_box_id(&ctx, Id id, Size w, Size h, TextEdit* te, Anchor
|
||||
|
||||
Rect bg_bounds = elem.bounds.pad(style.margin);
|
||||
Rect text_bounds = elem.bounds.pad(elem.layout.content_offset);
|
||||
ctx.push_rect(bg_bounds, parent.div.z_index, style)!;
|
||||
ctx.push_rect(bg_bounds, parent.z_index, style)!;
|
||||
Rect cur;
|
||||
cur = ctx.layout_string(elem.text.te.to_string(), text_bounds, text_alignment, parent.div.z_index, style.fg, elem.text.te.cursor)!;
|
||||
cur = ctx.layout_string(elem.text.te.to_string(), text_bounds, text_alignment, parent.z_index, style.fg, elem.text.te.cursor)!;
|
||||
|
||||
// draw the cursor if the element has focus
|
||||
cur.w = 2;
|
||||
cur.x -= 2;
|
||||
if (elem.events.has_focus) {
|
||||
ctx.push_scissor(text_bounds, parent.div.z_index)!;
|
||||
ctx.push_rect(cur, parent.div.z_index, &&(Style){.bg = style.fg})!;
|
||||
ctx.reset_scissor(parent.div.z_index)!;
|
||||
ctx.push_scissor(text_bounds, parent.z_index)!;
|
||||
ctx.push_rect(cur, parent.z_index, &&(Style){.bg = style.fg})!;
|
||||
ctx.reset_scissor(parent.z_index)!;
|
||||
}
|
||||
return elem.events;
|
||||
}
|
17
src/main.c3
17
src/main.c3
@ -209,7 +209,7 @@ fn int main(String[] args)
|
||||
|
||||
if (ui.check_key_combo(ugui::KMOD_CTRL, "q")) quit = true;
|
||||
|
||||
const String APPLICATION = "debug";
|
||||
const String APPLICATION = "calculator";
|
||||
$switch APPLICATION:
|
||||
$case "debug":
|
||||
debug_app(&ui);
|
||||
@ -382,6 +382,20 @@ fn void calculator(ugui::Ctx* ui, TextEdit* te)
|
||||
if (len > 0) len--;
|
||||
}
|
||||
|
||||
static bool toggle;
|
||||
static ugui::Point pos;
|
||||
if (ui.is_mouse_released(ugui::BTN_RIGHT)) {
|
||||
pos = ui.input.mouse.pos;
|
||||
toggle = !toggle;
|
||||
}
|
||||
if (toggle) {
|
||||
toggle = ui.popup_begin(pos, ugui::@fit(50), ugui::@fit(100), COLUMN)!!;
|
||||
ui.button("Uno")!!;
|
||||
ui.button("Due")!!;
|
||||
ui.button("Tre")!!;
|
||||
ui.button("Quattro")!!;
|
||||
ui.div_end()!!;
|
||||
}
|
||||
// ui input/output
|
||||
ui.@div(ugui::@grow(), ugui::@grow(), ROW, CENTER) { // center everything on the screen
|
||||
ui.@div(ugui::@fit(), ugui::@fit(), COLUMN, TOP_LEFT) {
|
||||
@ -446,4 +460,5 @@ fn void calculator(ugui::Ctx* ui, TextEdit* te)
|
||||
ui.text_box(ugui::@grow(), ugui::@exact(100), te, RIGHT)!!;
|
||||
}!!;
|
||||
}!!; }!!;
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user