actually correct input handling
This commit is contained in:
parent
fb3a964f7f
commit
b5ef86d092
17
TODO
17
TODO
@ -4,12 +4,11 @@
|
||||
[x] Implement div.view and scrollbars
|
||||
[x] Port font system from C to C3 (rewrite1)
|
||||
[ ] Update ARCHITECTURE.md
|
||||
[ ] Write a README.md
|
||||
[x] Write a README.md
|
||||
[x] Use an arena allocator for cache
|
||||
[ ] Do not redraw if there was no update (no layout and no draw)
|
||||
[ ] Do command buffer damage tracking based on a context grid (see rxi writeup)
|
||||
[x] Better handling of the active and focused widgets, try
|
||||
to maintain focus until mouse release (fix scroll bars)
|
||||
[x] Better handling of the active and focused widgets, try to maintain focus until mouse release (fix scroll bars)
|
||||
[x] Clip element bounds to parent div, specifically text
|
||||
[ ] Resizeable divs
|
||||
[x] Implement a z index and sort command buffer based on that
|
||||
@ -30,14 +29,14 @@ to maintain focus until mouse release (fix scroll bars)
|
||||
[ ] .png
|
||||
[ ] .jpg
|
||||
[ ] gif support?
|
||||
[ ] layout_set_max_rows() and layout_set_max_columns()
|
||||
[x] layout_set_max_rows() and layout_set_max_columns()
|
||||
[x] Maybe SDF sprites??
|
||||
[x] Stylesheets and stylesheet import
|
||||
[x] use SDF to draw anti-aliased rounded rectangles https://zed.dev/blog/videogame
|
||||
[ ] Subdivide modules into ugui::ug for exported functions and ugui::core for
|
||||
internal use functions (used to create widgets)
|
||||
[x] The render loop RAPES the gpu, valve pls fix
|
||||
[ ] The way the element structures are implemented wastes a lot of memory since
|
||||
[x] The way the element structures are implemented wastes a lot of memory since
|
||||
each struct Elem, struct Cmd, etc. is as big as the largest element. It would
|
||||
be better to use a different allcation strategy.
|
||||
[ ] Add a way to handle time events like double clicks
|
||||
@ -52,7 +51,7 @@ to maintain focus until mouse release (fix scroll bars)
|
||||
[x] Center elements to the row/column
|
||||
[x] Text wrapping / reflow
|
||||
[x] Implement a better and unified way to place a glyph and get the cursor position, maybe with a struct
|
||||
[ ] Correct whitespace handling in text (\t \r etc)
|
||||
[x] Correct whitespace handling in text (\t \r etc)
|
||||
[x] Consider a multi-pass recursive approach to layout (like https://github.com/nicbarker/clay)
|
||||
instead of the curren multi-frame approach.
|
||||
[x] Implement column/row sizing (min, max)
|
||||
@ -79,8 +78,8 @@ to maintain focus until mouse release (fix scroll bars)
|
||||
[x] Mouse scroll wheel
|
||||
[ ] Touch input
|
||||
[x] Do not set input event to true if the movement was zero (like no mouse movement)
|
||||
[ ] Use input event flags, for example to consume the input event
|
||||
[ ] Fix bug in text box: when spamming keys you can get multiple characters in the text input field
|
||||
[x] Use input event flags, for example to consume the input event
|
||||
[x] Fix bug in text box: when spamming keys you can get multiple characters in the text input field
|
||||
of the context, this causes a bug where only the first char is actually used
|
||||
|
||||
## Commands
|
||||
@ -89,7 +88,7 @@ to maintain focus until mouse release (fix scroll bars)
|
||||
- border width
|
||||
- border radius
|
||||
[x] add a command to update an atlas
|
||||
[ ] New window command, useful for popups
|
||||
[x] New window command, useful for popups
|
||||
[x] Text command returns the text bounds, this way we can avoid the pattern
|
||||
draw_text(a, pos) -> off = compute_bounds(a) -> draw_text(b, pos+off) -> ...
|
||||
[ ] Rounded rectangle with different radius for each corner
|
||||
|
@ -90,20 +90,8 @@ alias ElemCache = cache::Cache{Id, Elem, MAX_ELEMENTS};
|
||||
|
||||
faultdef INVALID_SIZE, EVENT_UNSUPPORTED, WRONG_ELEMENT_TYPE, WRONG_ID;
|
||||
|
||||
struct Ctx {
|
||||
IdTree tree;
|
||||
ElemCache cache;
|
||||
CmdQueue cmd_queue;
|
||||
StyleMap styles;
|
||||
// total size in pixels of the context
|
||||
ushort width, height;
|
||||
Font font;
|
||||
SpriteAtlas sprite_atlas;
|
||||
|
||||
bool has_focus;
|
||||
struct input {
|
||||
struct InputData {
|
||||
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
|
||||
@ -120,7 +108,20 @@ struct Ctx {
|
||||
usz text_len;
|
||||
ModKeys modkeys;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Ctx {
|
||||
IdTree tree;
|
||||
ElemCache cache;
|
||||
CmdQueue cmd_queue;
|
||||
StyleMap styles;
|
||||
// total size in pixels of the context
|
||||
ushort width, height;
|
||||
Font font;
|
||||
SpriteAtlas sprite_atlas;
|
||||
|
||||
bool has_focus;
|
||||
InputData input, current_input;
|
||||
|
||||
Id hover_id;
|
||||
Id focus_id;
|
||||
@ -249,7 +250,6 @@ 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};
|
||||
@ -262,30 +262,41 @@ fn void? Ctx.frame_begin(&ctx)
|
||||
elem.layout.h = @exact(ctx.height);
|
||||
|
||||
ctx.div_scissor = elem.bounds;
|
||||
|
||||
// The root element does not push anything to the stack
|
||||
// TODO: add a background color taken from a theme or config
|
||||
}
|
||||
|
||||
fn void? Ctx.frame_end(&ctx)
|
||||
{
|
||||
// FIXME: this is not guaranteed to be root. the user might forget to close a div or some other element
|
||||
Elem* root = ctx.get_active_div()!;
|
||||
if (root.id != ROOT_ID) {
|
||||
io::printn(root.id);
|
||||
return WRONG_ID?;
|
||||
}
|
||||
|
||||
// 2. clear input fields
|
||||
ctx.input = ctx.current_input;
|
||||
ctx.current_input.events = {};
|
||||
ctx.current_input.keyboard.text_len = 0;
|
||||
|
||||
// DO THE LAYOUT
|
||||
ctx.layout_element_tree()!;
|
||||
|
||||
foreach (idx, id : ctx.tree.elem_vec) {
|
||||
if (!ctx.tree.is_used((int)idx)) continue;
|
||||
Elem* c = ctx.find_elem(id);
|
||||
// reset events
|
||||
c.events = {};
|
||||
// reset shown flag
|
||||
// TODO: use shown_last_frame to avoid this loop entirely
|
||||
c.flags.shown = false;
|
||||
}
|
||||
|
||||
// Propagate input events to the right elements
|
||||
ctx.set_elem_events(ctx.hover_id);
|
||||
ctx.set_elem_events(ctx.focus_id);
|
||||
|
||||
|
||||
// 1. clear the tree
|
||||
ctx.tree.nuke();
|
||||
|
||||
// 2. clear input fields
|
||||
ctx.input.events = (InputEvents)0;
|
||||
ctx.input.keyboard.text_len = 0;
|
||||
|
||||
// send atlas updates
|
||||
if (ctx.font.should_update) {
|
||||
ctx.push_update_atlas(&ctx.font.atlas)!;
|
||||
@ -325,27 +336,47 @@ $endif
|
||||
// }
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
macro bool Ctx.is_hovered(&ctx, Elem *elem) => ctx.input.mouse.pos.in_rect(elem.bounds);
|
||||
|
||||
// Check if the element is hovered and/or focused, if it is update the context ids.
|
||||
// The order in which the elements are passed to this function is not relevant
|
||||
fn void Ctx.update_hover_and_focus(&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);
|
||||
bool focus = ctx.elem_focus(elem) || (hover && ctx.is_mouse_pressed(BTN_LEFT));
|
||||
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) {
|
||||
Elem* prev_hover = ctx.find_elem(ctx.hover_id);
|
||||
bool different = prev_hover.id != elem.id;
|
||||
bool still_hovered = ctx.is_hovered(prev_hover);
|
||||
bool shown = prev_hover.flags.shown;
|
||||
bool above = prev_hover.z_index > elem.z_index;
|
||||
|
||||
hover = !(different && still_hovered && shown && above);
|
||||
}
|
||||
|
||||
if (hover) { ctx.hover_id = elem.id; }
|
||||
if (focus) { ctx.focus_id = elem.id; }
|
||||
if (focus) {
|
||||
Elem* prev_focus = ctx.find_elem(ctx.hover_id);
|
||||
bool different = prev_focus.id != elem.id;
|
||||
bool shown = prev_focus.flags.shown;
|
||||
bool above = prev_focus.z_index > elem.z_index;
|
||||
|
||||
ElemEvents ev = {
|
||||
focus = !(different && shown && above);
|
||||
}
|
||||
|
||||
if (hover) ctx.hover_id = elem.id;
|
||||
if (focus) ctx.focus_id = elem.id;
|
||||
}
|
||||
|
||||
// FIXME: this does not work with touch
|
||||
fn void Ctx.set_elem_events(&ctx, Id id)
|
||||
{
|
||||
bool hover = id == ctx.hover_id;
|
||||
bool focus = id == ctx.focus_id;
|
||||
Elem* e = ctx.find_elem(id);
|
||||
|
||||
e.events = {
|
||||
.has_focus = focus,
|
||||
.mouse_hover = hover,
|
||||
.mouse_press = hover && focus && ctx.is_mouse_pressed(BTN_ANY),
|
||||
@ -356,6 +387,4 @@ fn ElemEvents Ctx.get_elem_events(&ctx, Elem *elem)
|
||||
.key_repeat = focus && ctx.input.events.key_repeat,
|
||||
.text_input = focus && (ctx.input.keyboard.text_len || ctx.input.keyboard.modkeys & KMOD_TXT),
|
||||
};
|
||||
return ev;
|
||||
}
|
||||
*/
|
||||
|
@ -71,7 +71,7 @@ const ModKeys KEY_ANY = (ModKeys)(ModKeys.inner.max);
|
||||
|
||||
fn bool Ctx.check_key_combo(&ctx, ModKeys mod, String ...keys)
|
||||
{
|
||||
bool is_mod = (bool)(ctx.input.keyboard.modkeys & mod);
|
||||
bool is_mod = (bool)(ctx.current_input.keyboard.modkeys & mod);
|
||||
bool is_keys = true;
|
||||
String haystack = (String)ctx.get_keys();
|
||||
foreach (needle: keys) {
|
||||
@ -86,7 +86,7 @@ fn void? Ctx.input_window_size(&ctx, short width, short height)
|
||||
if (width <= 0 || height <= 0) {
|
||||
return INVALID_SIZE?;
|
||||
}
|
||||
ctx.input.events.resize = ctx.width != width || ctx.height != height;
|
||||
ctx.current_input.events.resize = ctx.width != width || ctx.height != height;
|
||||
ctx.width = width;
|
||||
ctx.height = height;
|
||||
}
|
||||
@ -96,13 +96,13 @@ fn void Ctx.input_changefocus(&ctx, bool has_focus)
|
||||
{
|
||||
// FIXME: raylib only has an API to query the focus status so we have to
|
||||
// update the input flag only if the focus changed
|
||||
ctx.input.events.change_focus = ctx.has_focus != has_focus;
|
||||
ctx.current_input.events.change_focus = ctx.has_focus != has_focus;
|
||||
ctx.has_focus = has_focus;
|
||||
}
|
||||
|
||||
macro Ctx.mouse_pressed(&ctx) => ctx.input.mouse.updated & ctx.input.mouse.down;
|
||||
macro Ctx.mouse_released(&ctx) => ctx.input.mouse.updated & ~ctx.input.mouse.down;
|
||||
macro Ctx.mouse_down(&ctx) => ctx.input.mouse.down;
|
||||
macro Ctx.mouse_pressed(&ctx) => ctx.current_input.mouse.updated & ctx.current_input.mouse.down;
|
||||
macro Ctx.mouse_released(&ctx) => ctx.current_input.mouse.updated & ~ctx.current_input.mouse.down;
|
||||
macro Ctx.mouse_down(&ctx) => ctx.current_input.mouse.down;
|
||||
|
||||
// FIXME: hthis compairson could be done with a cast using MouseButtons.inner
|
||||
// property but I could not figure out how
|
||||
@ -113,63 +113,63 @@ macro Ctx.is_mouse_down(&ctx, MouseButtons btn) => (ctx.mouse_down() & btn) != B
|
||||
// Mouse Buttons down
|
||||
fn void Ctx.input_mouse_button(&ctx, MouseButtons buttons)
|
||||
{
|
||||
ctx.input.mouse.updated = ctx.input.mouse.down ^ buttons;
|
||||
ctx.input.mouse.down = buttons;
|
||||
ctx.input.events.mouse_btn = (uint)ctx.input.mouse.down != 0 || (uint)ctx.input.mouse.updated != 0;
|
||||
ctx.current_input.mouse.updated = ctx.current_input.mouse.down ^ buttons;
|
||||
ctx.current_input.mouse.down = buttons;
|
||||
ctx.current_input.events.mouse_btn = (uint)ctx.current_input.mouse.down != 0 || (uint)ctx.current_input.mouse.updated != 0;
|
||||
}
|
||||
|
||||
// Mouse was moved, report absolute position
|
||||
fn void Ctx.input_mouse_abs(&ctx, short x, short y)
|
||||
{
|
||||
ctx.input.mouse.pos.x = math::clamp(x, (short)0, ctx.width);
|
||||
ctx.input.mouse.pos.y = math::clamp(y, (short)0, ctx.height);
|
||||
ctx.current_input.mouse.pos.x = math::clamp(x, (short)0, ctx.width);
|
||||
ctx.current_input.mouse.pos.y = math::clamp(y, (short)0, ctx.height);
|
||||
|
||||
short dx, dy;
|
||||
dx = x - ctx.input.mouse.pos.x;
|
||||
dy = y - ctx.input.mouse.pos.y;
|
||||
dx = x - ctx.current_input.mouse.pos.x;
|
||||
dy = y - ctx.current_input.mouse.pos.y;
|
||||
|
||||
ctx.input.mouse.delta.x = dx;
|
||||
ctx.input.mouse.delta.y = dy;
|
||||
ctx.current_input.mouse.delta.x = dx;
|
||||
ctx.current_input.mouse.delta.y = dy;
|
||||
|
||||
ctx.input.events.mouse_move = dx != 0 || dy != 0;
|
||||
ctx.current_input.events.mouse_move = dx != 0 || dy != 0;
|
||||
}
|
||||
|
||||
// Mouse was moved, report relative motion
|
||||
fn void Ctx.input_mouse_delta(&ctx, short dx, short dy)
|
||||
{
|
||||
ctx.input.mouse.delta.x = dx;
|
||||
ctx.input.mouse.delta.y = dy;
|
||||
ctx.current_input.mouse.delta.x = dx;
|
||||
ctx.current_input.mouse.delta.y = dy;
|
||||
|
||||
short mx, my;
|
||||
mx = ctx.input.mouse.pos.x + dx;
|
||||
my = ctx.input.mouse.pos.y + dy;
|
||||
mx = ctx.current_input.mouse.pos.x + dx;
|
||||
my = ctx.current_input.mouse.pos.y + dy;
|
||||
|
||||
ctx.input.mouse.pos.x = math::clamp(mx, (short)0, ctx.width);
|
||||
ctx.input.mouse.pos.y = math::clamp(my, (short)0, ctx.height);
|
||||
ctx.current_input.mouse.pos.x = math::clamp(mx, (short)0, ctx.width);
|
||||
ctx.current_input.mouse.pos.y = math::clamp(my, (short)0, ctx.height);
|
||||
|
||||
ctx.input.events.mouse_move = dx != 0 || dy != 0;
|
||||
ctx.current_input.events.mouse_move = dx != 0 || dy != 0;
|
||||
}
|
||||
|
||||
fn void Ctx.input_mouse_wheel(&ctx, short x, short y, float scale = 1.0)
|
||||
{
|
||||
ctx.input.mouse.scroll.x = (short)((float)-x*scale);
|
||||
ctx.input.mouse.scroll.y = (short)((float)-y*scale);
|
||||
ctx.input.events.mouse_scroll = x !=0 || y != 0;
|
||||
ctx.current_input.mouse.scroll.x = (short)((float)-x*scale);
|
||||
ctx.current_input.mouse.scroll.y = (short)((float)-y*scale);
|
||||
ctx.current_input.events.mouse_scroll = x !=0 || y != 0;
|
||||
}
|
||||
|
||||
fn void Ctx.input_key_press(&ctx)
|
||||
{
|
||||
ctx.input.events.key_press = true;
|
||||
ctx.current_input.events.key_press = true;
|
||||
}
|
||||
|
||||
fn void Ctx.input_key_release(&ctx)
|
||||
{
|
||||
ctx.input.events.key_release = true;
|
||||
ctx.current_input.events.key_release = true;
|
||||
}
|
||||
|
||||
fn void Ctx.input_key_repeat(&ctx)
|
||||
{
|
||||
ctx.input.events.key_repeat = true;
|
||||
ctx.current_input.events.key_repeat = true;
|
||||
}
|
||||
|
||||
// append utf-8 encoded text to the context text input
|
||||
@ -177,12 +177,12 @@ fn void Ctx.input_text_utf8(&ctx, char[] text)
|
||||
{
|
||||
if (text.len == 0) { return; }
|
||||
|
||||
usz remaining = ctx.input.keyboard.text.len - ctx.input.keyboard.text_len;
|
||||
usz remaining = ctx.current_input.keyboard.text.len - ctx.current_input.keyboard.text_len;
|
||||
usz len = text.len > remaining ? remaining : text.len;
|
||||
char[] s = ctx.input.keyboard.text[ctx.input.keyboard.text_len ..];
|
||||
char[] s = ctx.current_input.keyboard.text[ctx.current_input.keyboard.text_len ..];
|
||||
s[..len-1] = text[..len-1];
|
||||
ctx.input.keyboard.text_len += len;
|
||||
ctx.input.events.text_input = true;
|
||||
ctx.current_input.keyboard.text_len += len;
|
||||
ctx.current_input.events.text_input = true;
|
||||
}
|
||||
|
||||
fn void Ctx.input_text_unicode(&ctx, char[] text)
|
||||
@ -190,8 +190,8 @@ fn void Ctx.input_text_unicode(&ctx, char[] text)
|
||||
if (text.ptr == null || text.len == 0) { return; }
|
||||
|
||||
char[32] tmp;
|
||||
usz remaining = ctx.input.keyboard.text.len - ctx.input.keyboard.text_len;
|
||||
char[] s = ctx.input.keyboard.text[ctx.input.keyboard.text_len ..];
|
||||
usz remaining = ctx.current_input.keyboard.text.len - ctx.current_input.keyboard.text_len;
|
||||
char[] s = ctx.current_input.keyboard.text[ctx.current_input.keyboard.text_len ..];
|
||||
|
||||
usz off;
|
||||
foreach (idx, cp: text) {
|
||||
@ -200,9 +200,9 @@ fn void Ctx.input_text_unicode(&ctx, char[] text)
|
||||
s[off..off+enc] = tmp[..enc];
|
||||
off += enc;
|
||||
}
|
||||
ctx.input.keyboard.text_len += off;
|
||||
ctx.current_input.keyboard.text_len += off;
|
||||
|
||||
ctx.input.events.text_input = true;
|
||||
ctx.current_input.events.text_input = true;
|
||||
}
|
||||
|
||||
fn void Ctx.input_char(&ctx, char c)
|
||||
@ -218,6 +218,6 @@ fn ModKeys Ctx.get_mod(&ctx) => ctx.input.keyboard.modkeys;
|
||||
// TODO: make this call repetible to input modkeys one by one
|
||||
fn void Ctx.input_mod_keys(&ctx, ModKeys modkeys)
|
||||
{
|
||||
ctx.input.keyboard.modkeys = modkeys;
|
||||
ctx.input.events.mod_key = (uint)ctx.input.keyboard.modkeys != 0;
|
||||
ctx.current_input.keyboard.modkeys = modkeys;
|
||||
ctx.current_input.events.mod_key = (uint)ctx.current_input.keyboard.modkeys != 0;
|
||||
}
|
||||
|
@ -297,72 +297,6 @@ 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;
|
||||
@ -400,11 +334,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;
|
||||
|
||||
// FIXME: this stuff would be better elsewhere but we are already iteraring through all
|
||||
// elements so here it fits really well
|
||||
ctx.update_hover_and_focus(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,6 +199,8 @@ macro bool 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);
|
||||
}
|
||||
|
||||
macro bool Point.outside(Point p, Rect r) => !p.in_rect(r);
|
||||
|
||||
macro Point Point.add(Point a, Point b) @operator_s(+) => {.x = a.x+b.x, .y = a.y+b.y};
|
||||
macro Point Point.sub(Point a, Point b) @operator_s(-) => {.x = a.x-b.x, .y = a.y-b.y};
|
||||
macro Point Point.neg(Point p) @operator_s(-) => {-p.x, -p.y};
|
||||
@ -241,20 +243,22 @@ macro uint Color.to_uint(c) => c.r | (c.g << 8) | (c.b << 16) | (c.a << 24);
|
||||
// SIZE //
|
||||
// ---------------------------------------------------------------------------------- //
|
||||
|
||||
macro short short.add_no_of(short a, short b) => (short)max(min((int)a + (int)b, short.max), short.min) @inline;
|
||||
|
||||
struct Size {
|
||||
short min, max;
|
||||
}
|
||||
|
||||
macro Size @grow() => {.min = 0, .max = 0};
|
||||
macro Size @exact(short s) => {.min = s, .max = s};
|
||||
// PROBLEM WE ARE OVERFLOWING
|
||||
macro Size @fit(short min = 0, short max = 999) => {.min = min, .max = max};
|
||||
macro Size @fit(short min = 0, short max = short.max) => {.min = min, .max = max};
|
||||
|
||||
macro bool Size.@is_grow(s) => (s.min == 0 && s.max == 0);
|
||||
macro bool Size.@is_exact(s) => (s.min == s.max && s.min != 0);
|
||||
macro bool Size.@is_fit(s) => (s.min != s.max);
|
||||
|
||||
macro Size Size.add(a, Size b) @operator_s(+) => {.min = a.min+b.min, .max = a.max+b.max};
|
||||
macro Size Size.sub(a, Size b) @operator_s(-) => {.min = a.min-b.min, .max = a.max-b.max};
|
||||
macro Size Size.add(a, Size b) @operator_s(+) => {.min = a.min.add_no_of(b.min), .max = a.max.add_no_of(b.max)};
|
||||
macro Size Size.sub(a, Size b) @operator_s(-) => {.min = a.min.add_no_of(-b.min), .max = a.max.add_no_of(-b.max)};
|
||||
|
||||
macro Size Size.combine(a, Size b) => {.min = max(a.min, b.min), .max = min(a.max, b.max)};
|
||||
macro Size Size.comb_max(a, Size b) => {.min = max(a.min, b.min), .max = max(a.max, b.max)};
|
||||
|
@ -87,7 +87,6 @@ fn void? Ctx.div_begin_id(&ctx,
|
||||
|
||||
elem.div.scroll_x.enabled = scroll_x;
|
||||
elem.div.scroll_y.enabled = scroll_y;
|
||||
if (ctx.input.z_index < elem.z_index) ctx.input.z_index = elem.z_index;
|
||||
|
||||
// update layout with correct info
|
||||
elem.layout = {
|
||||
@ -199,7 +198,6 @@ fn bool? Ctx.popup_begin_id(&ctx,
|
||||
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 = {
|
||||
@ -222,7 +220,7 @@ fn bool? Ctx.popup_begin_id(&ctx,
|
||||
//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) {
|
||||
if ((ctx.mouse_released() & BTN_ANY) && ctx.input.mouse.pos.outside(elem.bounds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ fn int main(String[] args)
|
||||
|
||||
if (ui.check_key_combo(ugui::KMOD_CTRL, "q")) quit = true;
|
||||
|
||||
const String APPLICATION = "popup";
|
||||
const String APPLICATION = "calculator";
|
||||
$switch APPLICATION:
|
||||
$case "debug":
|
||||
debug_app(&ui);
|
||||
@ -397,6 +397,7 @@ fn void calculator(ugui::Ctx* ui, TextEdit* te)
|
||||
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) {
|
||||
@ -468,19 +469,17 @@ 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()!!;
|
||||
}
|
||||
ui.@center(COLUMN) {
|
||||
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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user