diff --git a/lib/ugui.c3l/src/core.c3 b/lib/ugui.c3l/src/core.c3 index 0771a70..05d3483 100644 --- a/lib/ugui.c3l/src/core.c3 +++ b/lib/ugui.c3l/src/core.c3 @@ -34,7 +34,8 @@ enum ElemType { bitstruct ElemFlags : uint { bool updated : 0; - bool is_new : 1; + bool is_new : 1; // element is new in the cache + bool shown : 2; // element has been shown (drawn) this frame } bitstruct ElemEvents : uint { @@ -175,6 +176,7 @@ fn PElemTuple? Ctx.get_elem(&ctx, Id id, ElemType type) elem = ctx.cache.get_or_insert(&&(Elem){}, id, &is_new)!; elem.flags = (ElemFlags)0; elem.flags.is_new = is_new; + elem.flags.shown = true; elem.id = id; elem.layout = {}; if (is_new == false && elem.type != type) { @@ -323,24 +325,13 @@ $endif // } } -<* - * @ensure elem != null -*> -macro bool Ctx.is_hovered(&ctx, Elem *elem) -{ - return ctx.input.mouse.pos.in_rect(elem.bounds); -} - -macro bool Ctx.elem_focus(&ctx, Elem *elem) -{ - return ctx.focus_id == elem.id; -} - // TODO: add other events // FIXME: this does not work with touch // FIXME: hacked together, please do better +/* fn ElemEvents Ctx.get_elem_events(&ctx, Elem *elem) { + // FIXME: gross hack to not leak events under a pop-up if (ctx.input.z_index != elem.z_index) return {}; bool hover = ctx.is_hovered(elem); @@ -367,3 +358,4 @@ fn ElemEvents Ctx.get_elem_events(&ctx, Elem *elem) }; return ev; } +*/ diff --git a/lib/ugui.c3l/src/layout.c3 b/lib/ugui.c3l/src/layout.c3 index 5a850c6..e7d4606 100644 --- a/lib/ugui.c3l/src/layout.c3 +++ b/lib/ugui.c3l/src/layout.c3 @@ -297,6 +297,72 @@ fn void resolve_placement(Elem* c, Elem* p) } } +macro bool Ctx.is_hovered(&ctx, Elem *elem) => ctx.input.mouse.pos.in_rect(elem.bounds); + +fn void Ctx.update_elem_events(&ctx, Elem* elem) +{ + bool hover = ctx.is_hovered(elem); + bool focus = ctx.focus_id == elem.id || (hover && ctx.is_mouse_pressed(BTN_ANY)); + + if (ctx.is_mouse_pressed(BTN_ANY) && !hover){ + focus = false; + if (ctx.focus_id == elem.id) ctx.focus_id = 0; + } + + if (hover) { + // TODO: this constant cache lookup could be slow + Elem* prev_hover = ctx.find_elem(ctx.hover_id); + if (prev_hover.id != elem.id && prev_hover.flags.shown) { + if (prev_hover.z_index <= elem.z_index) { + // remove hover events from prev_hover + prev_hover.events.mouse_hover = false; + prev_hover.events.mouse_press = false; + prev_hover.events.mouse_release = false; + prev_hover.events.mouse_hold = false; + } else { + hover = false; + } + } + } + + if (focus) { + // TODO: this constant cache lookup could be slow + Elem* prev_focus = ctx.find_elem(ctx.hover_id); + // update the focus id and element only if the current element is at the same level + // or above the previous element that held focus + if (prev_focus.z_index <= elem.z_index) { + // remove focus events from prev_focus + prev_focus.events.has_focus = false; + prev_focus.events.mouse_press = false; + prev_focus.events.mouse_release = false; + prev_focus.events.mouse_hold = false; + prev_focus.events.key_press = false; + prev_focus.events.key_release = false; + prev_focus.events.key_repeat = false; + prev_focus.events.text_input = false; + // update the hover id + ctx.focus_id = elem.id; + } else if (prev_focus.flags.shown) { + focus = false; + } + } + + if (hover) ctx.hover_id = elem.id; + + ElemEvents ev = { + .has_focus = focus, + .mouse_hover = hover, + .mouse_press = hover && focus && ctx.is_mouse_pressed(BTN_ANY), + .mouse_release = hover && focus && ctx.is_mouse_released(BTN_ANY), + .mouse_hold = hover && focus && ctx.is_mouse_down(BTN_ANY), + .key_press = focus && ctx.input.events.key_press, + .key_release = focus && ctx.input.events.key_release, + .key_repeat = focus && ctx.input.events.key_repeat, + .text_input = focus && (ctx.input.keyboard.text_len || ctx.input.keyboard.modkeys & KMOD_TXT), + }; + elem.events = ev; +} + fn void? Ctx.layout_element_tree(&ctx) { int current; @@ -334,7 +400,11 @@ fn void? Ctx.layout_element_tree(&ctx) } else { resolve_placement(c, p); update_children_bounds(c, p); + + // reset shown flag } + ctx.update_elem_events(c); + c.flags.shown = false; } } } diff --git a/lib/ugui.c3l/src/widgets/button.c3 b/lib/ugui.c3l/src/widgets/button.c3 index bfece9e..eeb1484 100644 --- a/lib/ugui.c3l/src/widgets/button.c3 +++ b/lib/ugui.c3l/src/widgets/button.c3 @@ -46,7 +46,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); + //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(); @@ -66,7 +66,7 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon) }; //text_bounds = text_size.center_to(text_bounds); - bool is_active = ctx.elem_focus(elem) || elem.events.mouse_hover; + bool is_active = elem.events.has_focus || elem.events.mouse_hover; Style s = *style; if (is_active) { s.secondary = s.primary; @@ -115,7 +115,7 @@ fn void? Ctx.checkbox_id(&ctx, Id id, String description, bool* active, String t update_parent_size(elem, parent); - 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); @@ -189,7 +189,7 @@ fn void? Ctx.toggle_id(&ctx, Id id, String description, bool* active) update_parent_size(elem, parent); - 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); Rect content_bounds = elem.bounds.pad(elem.layout.content_offset); diff --git a/lib/ugui.c3l/src/widgets/div.c3 b/lib/ugui.c3l/src/widgets/div.c3 index a4d78c2..37dd5b3 100644 --- a/lib/ugui.c3l/src/widgets/div.c3 +++ b/lib/ugui.c3l/src/widgets/div.c3 @@ -18,6 +18,13 @@ struct ElemDiv { } +macro Ctx.@center(&ctx, LayoutDirection dir = ROW, ...; @body()) +{ + ctx.@div(@grow(), @grow(), dir, CENTER) { + @body(); + }!; +} + macro Ctx.@row(&ctx, Anchor anchor = TOP_LEFT, ...; @body()) { ctx.@div(@fit(), @fit(), ROW, anchor: anchor) { @@ -102,7 +109,7 @@ fn void? Ctx.div_begin_id(&ctx, 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); + //elem.events = ctx.get_elem_events(elem); // TODO: check active // TODO: check resizeable @@ -212,7 +219,7 @@ fn bool? Ctx.popup_begin_id(&ctx, 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); + //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) { diff --git a/lib/ugui.c3l/src/widgets/slider.c3 b/lib/ugui.c3l/src/widgets/slider.c3 index 2073dac..70927e7 100644 --- a/lib/ugui.c3l/src/widgets/slider.c3 +++ b/lib/ugui.c3l/src/widgets/slider.c3 @@ -45,9 +45,9 @@ fn ElemEvents? Ctx.slider_hor_id(&ctx, Id id, Size w, Size h, float* value, floa elem.slider.handle = handle; Point m = ctx.input.mouse.pos; - elem.events = ctx.get_elem_events(elem); + //elem.events = ctx.get_elem_events(elem); - if (ctx.elem_focus(elem) && ctx.is_mouse_down(BTN_LEFT)) { + if (elem.events.has_focus && ctx.is_mouse_down(BTN_LEFT)) { *value = calc_value(content_bounds.x, m.x, content_bounds.w, hw); elem.slider.handle.x = calc_slider(content_bounds.x, content_bounds.w-hw, *value); elem.events.update = true; @@ -109,9 +109,9 @@ fn ElemEvents? Ctx.slider_ver_id(&ctx, Id id, Size w, Size h, float* value, floa elem.slider.handle = handle; Point m = ctx.input.mouse.pos; - elem.events = ctx.get_elem_events(elem); + //elem.events = ctx.get_elem_events(elem); - if (ctx.elem_focus(elem) && ctx.is_mouse_down(BTN_LEFT)) { + if (elem.events.has_focus && ctx.is_mouse_down(BTN_LEFT)) { *value = calc_value(content_bounds.y, m.y, content_bounds.h, hh); elem.slider.handle.y = calc_slider(content_bounds.y, content_bounds.h-hh, *value); elem.events.update = true; @@ -156,7 +156,7 @@ fn void? Ctx.scrollbar(&ctx, Id id, float *value, float handle_percent, bool ver update_parent_size(elem, parent); Rect content_bounds = elem.bounds.pad(elem.layout.content_offset); - elem.events = ctx.get_elem_events(elem); + //elem.events = ctx.get_elem_events(elem); short o = vertical ? content_bounds.y : content_bounds.x; short m = vertical ? ctx.input.mouse.pos.y : ctx.input.mouse.pos.x; diff --git a/lib/ugui.c3l/src/widgets/text.c3 b/lib/ugui.c3l/src/widgets/text.c3 index 8849fc1..e7c4caf 100644 --- a/lib/ugui.c3l/src/widgets/text.c3 +++ b/lib/ugui.c3l/src/widgets/text.c3 @@ -65,7 +65,7 @@ fn ElemEvents? Ctx.text_box_id(&ctx, Id id, Size w, Size h, TextEdit* te, Anchor update_parent_size(elem, parent); // check input and update the text - elem.events = ctx.get_elem_events(elem); + //elem.events = ctx.get_elem_events(elem); if (elem.events.text_input || elem.events.key_press) { ctx.text_edit(elem.text.te); diff --git a/src/main.c3 b/src/main.c3 index a17ed3c..f1d31f2 100644 --- a/src/main.c3 +++ b/src/main.c3 @@ -208,12 +208,14 @@ fn int main(String[] args) if (ui.check_key_combo(ugui::KMOD_CTRL, "q")) quit = true; -const String APPLICATION = "calculator"; +const String APPLICATION = "popup"; $switch APPLICATION: $case "debug": debug_app(&ui); $case "calculator": calculator(&ui, &te); +$case "popup": + popup(&ui); $endswitch // Timings counter @@ -459,5 +461,26 @@ fn void calculator(ugui::Ctx* ui, TextEdit* te) ui.text_box(ugui::@grow(), ugui::@exact(100), te, RIGHT)!!; }!!; }!!; }!!; - +} + +fn void popup(ugui::Ctx* ui) +{ + static bool toggle; + static ugui::Point pos; + + ui.@center(COLUMN) { + if (toggle) { + toggle = ui.popup_begin(pos, ugui::@fit(), ugui::@fit(), COLUMN)!!; + ui.button("POP")!!; + ui.button("UP")!!; + ui.div_end()!!; + } + if (ui.button("ciao")!!.mouse_release) { + pos = ui.input.mouse.pos; + toggle = ~toggle; + } + if (ui.button("mamma")!!.mouse_press) ugui::println("pressed!"); + }!!; + + ugui::println("focus id: ", ui.focus_id, " hover id: ", ui.hover_id); }