track focused and hovered elements
This commit is contained in:
parent
4bd827ce5c
commit
f7985f8c7f
@ -122,7 +122,7 @@ fn int main(String[] args)
|
|||||||
ui.div_begin("main", ugui::Rect{.w=ui.width/2})!!;
|
ui.div_begin("main", ugui::Rect{.w=ui.width/2})!!;
|
||||||
{|
|
{|
|
||||||
|
|
||||||
ui.layout_set_row()!!;
|
ui.layout_set_column()!!;
|
||||||
if (ui.button("button0", ugui::Rect{0,0,30,30}, toggle)!!.mouse_press) {
|
if (ui.button("button0", ugui::Rect{0,0,30,30}, toggle)!!.mouse_press) {
|
||||||
io::printn("press button0");
|
io::printn("press button0");
|
||||||
toggle = !toggle;
|
toggle = !toggle;
|
||||||
|
@ -4,8 +4,7 @@ import std::io;
|
|||||||
|
|
||||||
// button element
|
// button element
|
||||||
struct ElemButton {
|
struct ElemButton {
|
||||||
Color color;
|
int filler;
|
||||||
bool active;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw a button, return the events on that button
|
// draw a button, return the events on that button
|
||||||
@ -20,7 +19,6 @@ fn ElemEvents! Ctx.button(&ctx, String label, Rect size, bool state = false)
|
|||||||
|
|
||||||
if (elem.flags.is_new) {
|
if (elem.flags.is_new) {
|
||||||
elem.type = ETYPE_BUTTON;
|
elem.type = ETYPE_BUTTON;
|
||||||
elem.button.color = uint_to_rgba(0x0000ffff);
|
|
||||||
} else if (elem.type != ETYPE_BUTTON) {
|
} else if (elem.type != ETYPE_BUTTON) {
|
||||||
return UgError.WRONG_ELEMENT_TYPE?;
|
return UgError.WRONG_ELEMENT_TYPE?;
|
||||||
}
|
}
|
||||||
@ -31,22 +29,16 @@ fn ElemEvents! Ctx.button(&ctx, String label, Rect size, bool state = false)
|
|||||||
// no interaction should occur so just return
|
// no interaction should occur so just return
|
||||||
if (elem.bounds.is_null()) { return ElemEvents{}; }
|
if (elem.bounds.is_null()) { return ElemEvents{}; }
|
||||||
|
|
||||||
|
Color col = uint_to_rgba(0x0000ffff);
|
||||||
elem.events = ctx.get_elem_events(elem);
|
elem.events = ctx.get_elem_events(elem);
|
||||||
if (elem.events.mouse_hover) {
|
|
||||||
if (parent.flags.has_focus) {
|
|
||||||
elem.flags.has_focus = true;
|
|
||||||
elem.button.color = uint_to_rgba(0x00ff00ff);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
elem.button.color = uint_to_rgba(0x0000ffff);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
elem.button.color = uint_to_rgba(0xff00ffff);
|
col = uint_to_rgba(0xff0000ff);
|
||||||
|
} else if (ctx.elem_focus(elem) || elem.events.mouse_hover) {
|
||||||
|
col = uint_to_rgba(0xff00ffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the button
|
// Draw the button
|
||||||
ctx.push_rect(elem.bounds, elem.button.color, do_border: true, do_radius: true)!;
|
ctx.push_rect(elem.bounds, col, do_border: true, do_radius: true)!;
|
||||||
|
|
||||||
return elem.events;
|
return elem.events;
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,7 @@ enum ElemType {
|
|||||||
|
|
||||||
bitstruct ElemFlags : uint {
|
bitstruct ElemFlags : uint {
|
||||||
bool updated : 0;
|
bool updated : 0;
|
||||||
bool has_focus : 1;
|
bool is_new : 1;
|
||||||
bool is_new : 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bitstruct ElemEvents : uint {
|
bitstruct ElemEvents : uint {
|
||||||
@ -134,6 +133,9 @@ struct Ctx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Id hover_id;
|
||||||
|
Id focus_id;
|
||||||
|
|
||||||
Rect div_scissor; // the current div bounds used for scissor test
|
Rect div_scissor; // the current div bounds used for scissor test
|
||||||
isz active_div; // tree node indicating the current active div
|
isz active_div; // tree node indicating the current active div
|
||||||
}
|
}
|
||||||
@ -195,13 +197,15 @@ macro Ctx.get_elem(&ctx, Id id)
|
|||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Since ids are now keyed with the element's parent id, this function does not work
|
||||||
|
// outside of the element's div block.
|
||||||
// this searches an element in the cache by label, it does not create a new element
|
// this searches an element in the cache by label, it does not create a new element
|
||||||
// if it does't find one
|
// if it does't find one
|
||||||
macro Ctx.get_elem_by_label(&ctx, String label)
|
//macro Ctx.get_elem_by_label(&ctx, String label)
|
||||||
{
|
//{
|
||||||
Id id = label.hash();
|
// Id id = ctx.get_id(label);
|
||||||
return ctx.cache.search(id);
|
// return ctx.cache.search(id);
|
||||||
}
|
//}
|
||||||
|
|
||||||
macro Ctx.get_elem_by_tree_idx(&ctx, isz idx) @private
|
macro Ctx.get_elem_by_tree_idx(&ctx, isz idx) @private
|
||||||
{
|
{
|
||||||
@ -252,7 +256,7 @@ fn void! Ctx.frame_begin(&ctx)
|
|||||||
// if the window has focus then the root element also has focus, no other
|
// 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
|
// computation needed, child elements need to check the mouse positon and
|
||||||
// other stuff
|
// other stuff
|
||||||
elem.flags.has_focus = ctx.has_focus;
|
//elem.flags.has_focus = ctx.has_focus;
|
||||||
|
|
||||||
Elem def_root = {
|
Elem def_root = {
|
||||||
.id = ROOT_ID,
|
.id = ROOT_ID,
|
||||||
@ -317,8 +321,39 @@ $endif
|
|||||||
|
|
||||||
<*
|
<*
|
||||||
* @ensure elem != null
|
* @ensure elem != null
|
||||||
*>
|
*>
|
||||||
fn bool Ctx.is_hovered(&ctx, Elem *elem)
|
macro bool Ctx.is_hovered(&ctx, Elem *elem)
|
||||||
{
|
{
|
||||||
return point_in_rect(ctx.input.mouse.pos, elem.bounds);
|
return point_in_rect(ctx.input.mouse.pos, 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
|
||||||
|
macro ElemEvents Ctx.get_elem_events(&ctx, Elem *elem)
|
||||||
|
{
|
||||||
|
//io::printfn("id %x, focus id %x", elem.id, ctx.focus_id);
|
||||||
|
|
||||||
|
bool hover = ctx.is_hovered(elem);
|
||||||
|
bool focus = ctx.focus_id == elem.id || (hover && ctx.is_mouse_pressed(BTN_LEFT));
|
||||||
|
|
||||||
|
if (hover) {
|
||||||
|
ctx.hover_id = elem.id;
|
||||||
|
}
|
||||||
|
if (focus) {
|
||||||
|
ctx.focus_id = elem.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElemEvents ev = {
|
||||||
|
.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),
|
||||||
|
};
|
||||||
|
return ev;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -23,9 +23,6 @@ struct ElemDiv {
|
|||||||
Rect children_bounds; // current frame children bounds
|
Rect children_bounds; // current frame children bounds
|
||||||
Rect pcb; // previous frame children bounds
|
Rect pcb; // previous frame children bounds
|
||||||
Point origin_r, origin_c;
|
Point origin_r, origin_c;
|
||||||
// the id of the active element, this field is set and reset by the elements themselves and it is
|
|
||||||
// used to keep track of which element should handle some input events between frames
|
|
||||||
Id active_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void! Ctx.div_begin(&ctx, String label, Rect size, bool scroll_x = false, bool scroll_y = false)
|
fn void! Ctx.div_begin(&ctx, String label, Rect size, bool scroll_x = false, bool scroll_y = false)
|
||||||
@ -71,13 +68,6 @@ fn void! Ctx.div_begin(&ctx, String label, Rect size, bool scroll_x = false, boo
|
|||||||
|
|
||||||
// TODO: check active
|
// TODO: check active
|
||||||
// TODO: check resizeable
|
// TODO: check resizeable
|
||||||
|
|
||||||
if (parent.flags.has_focus) {
|
|
||||||
if (point_in_rect(ctx.input.mouse.pos, elem.bounds)) {
|
|
||||||
elem.flags.has_focus = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void! Ctx.div_end(&ctx)
|
fn void! Ctx.div_end(&ctx)
|
||||||
@ -87,7 +77,9 @@ fn void! Ctx.div_end(&ctx)
|
|||||||
Elem* elem = ctx.get_elem_by_tree_idx(ctx.active_div)!;
|
Elem* elem = ctx.get_elem_by_tree_idx(ctx.active_div)!;
|
||||||
elem.div.pcb = elem.div.children_bounds;
|
elem.div.pcb = elem.div.children_bounds;
|
||||||
|
|
||||||
elem.events = ctx.get_elem_events(elem);
|
// FIXME: this causes all elements inside the div to loose focus since the mouse press happens
|
||||||
|
// both inside the element and inside the div bounds
|
||||||
|
//elem.events = ctx.get_elem_events(elem);
|
||||||
|
|
||||||
Rect cb = elem.div.pcb;
|
Rect cb = elem.div.pcb;
|
||||||
// children bounds bottom-right corner
|
// children bounds bottom-right corner
|
||||||
|
@ -59,20 +59,6 @@ macro Ctx.is_mouse_pressed(&ctx, MouseButtons btn) => (ctx.mouse_pressed() & btn
|
|||||||
macro Ctx.is_mouse_released(&ctx, MouseButtons btn) => (ctx.mouse_released() & btn) != BTN_NONE;
|
macro Ctx.is_mouse_released(&ctx, MouseButtons btn) => (ctx.mouse_released() & btn) != BTN_NONE;
|
||||||
macro Ctx.is_mouse_down(&ctx, MouseButtons btn) => (ctx.mouse_down() & btn) != BTN_NONE;
|
macro Ctx.is_mouse_down(&ctx, MouseButtons btn) => (ctx.mouse_down() & btn) != BTN_NONE;
|
||||||
|
|
||||||
macro ElemEvents Ctx.get_elem_events(&ctx, Elem *elem)
|
|
||||||
{
|
|
||||||
// TODO: add the other events
|
|
||||||
// FIXME: active should be elsewhere
|
|
||||||
bool active = ctx.is_hovered(elem);
|
|
||||||
ElemEvents ev = {
|
|
||||||
.mouse_hover = ctx.is_hovered(elem),
|
|
||||||
.mouse_press = active & ctx.is_mouse_pressed(BTN_ANY),
|
|
||||||
.mouse_release = active & ctx.is_mouse_released(BTN_ANY),
|
|
||||||
.mouse_hold = active & ctx.is_mouse_down(BTN_ANY),
|
|
||||||
};
|
|
||||||
return ev;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mouse Button moved
|
// Mouse Button moved
|
||||||
fn void Ctx.input_mouse_button(&ctx, MouseButtons buttons)
|
fn void Ctx.input_mouse_button(&ctx, MouseButtons buttons)
|
||||||
{
|
{
|
||||||
|
@ -54,8 +54,7 @@ fn ElemEvents! Ctx.slider_hor(&ctx,
|
|||||||
Point m = ctx.input.mouse.pos;
|
Point m = ctx.input.mouse.pos;
|
||||||
elem.events = ctx.get_elem_events(elem);
|
elem.events = ctx.get_elem_events(elem);
|
||||||
|
|
||||||
if (parent.flags.has_focus && elem.events.mouse_hover &&
|
if (ctx.elem_focus(elem) && elem.events.mouse_hold) {
|
||||||
point_in_rect(m, handle) && elem.events.mouse_hold) {
|
|
||||||
*value = calc_value(elem.bounds.x, m.x, elem.bounds.w, hw);
|
*value = calc_value(elem.bounds.x, m.x, elem.bounds.w, hw);
|
||||||
elem.slider.handle.x = calc_slider(elem.bounds.x, elem.bounds.w-hw, *value);
|
elem.slider.handle.x = calc_slider(elem.bounds.x, elem.bounds.w-hw, *value);
|
||||||
elem.events.update = true;
|
elem.events.update = true;
|
||||||
@ -117,10 +116,8 @@ fn ElemEvents! Ctx.slider_ver(&ctx,
|
|||||||
|
|
||||||
Point m = ctx.input.mouse.pos;
|
Point m = ctx.input.mouse.pos;
|
||||||
elem.events = ctx.get_elem_events(elem);
|
elem.events = ctx.get_elem_events(elem);
|
||||||
|
|
||||||
if (parent.flags.has_focus && elem.events.mouse_hover &&
|
if (ctx.elem_focus(elem) && elem.events.mouse_hold) {
|
||||||
point_in_rect(m, handle) &&
|
|
||||||
elem.events.mouse_hold) {
|
|
||||||
*value = calc_value(elem.bounds.y, m.y, elem.bounds.h, hh);
|
*value = calc_value(elem.bounds.y, m.y, elem.bounds.h, hh);
|
||||||
elem.slider.handle.y = calc_slider(elem.bounds.y, elem.bounds.h-hh, *value);
|
elem.slider.handle.y = calc_slider(elem.bounds.y, elem.bounds.h-hh, *value);
|
||||||
elem.events.update = true;
|
elem.events.update = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user