This commit is contained in:
Alessandro Mauri 2025-10-12 13:19:52 +02:00
commit eb62e9ad72
10 changed files with 179 additions and 124 deletions

17
TODO
View File

@ -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

View File

@ -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 {
@ -89,6 +90,26 @@ alias ElemCache = cache::Cache{Id, Elem, MAX_ELEMENTS};
faultdef INVALID_SIZE, EVENT_UNSUPPORTED, WRONG_ELEMENT_TYPE, WRONG_ID;
struct InputData {
InputEvents events;
struct mouse {
Point pos, delta;
// mouse_down: bitmap of mouse buttons that are held
// mouse_updated: bitmap of mouse buttons that have been updated
// mouse_released = mouse_updated & ~mouse_down
// mouse_pressed = mouse_updated & mouse_down
MouseButtons down;
MouseButtons updated;
// scroll wheel
Point scroll;
}
struct keyboard {
char[TEXT_MAX] text;
usz text_len;
ModKeys modkeys;
}
}
struct Ctx {
IdTree tree;
ElemCache cache;
@ -100,26 +121,7 @@ struct Ctx {
SpriteAtlas sprite_atlas;
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
// mouse_updated: bitmap of mouse buttons that have been updated
// mouse_released = mouse_updated & ~mouse_down
// mouse_pressed = mouse_updated & mouse_down
MouseButtons down;
MouseButtons updated;
// scroll wheel
Point scroll;
}
struct keyboard {
char[TEXT_MAX] text;
usz text_len;
ModKeys modkeys;
}
}
InputData input, current_input;
Id hover_id;
Id focus_id;
@ -175,6 +177,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) {
@ -247,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};
@ -260,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)!;
@ -323,38 +336,47 @@ $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;
}
macro bool Ctx.is_hovered(&ctx, Elem *elem) => ctx.input.mouse.pos.in_rect(elem.bounds);
// 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)
// 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)
{
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 (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;
focus = !(different && shown && above);
}
if (hover) ctx.hover_id = elem.id;
if (focus) ctx.focus_id = elem.id;
}
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);
ElemEvents ev = {
e.events = {
.has_focus = focus,
.mouse_hover = hover,
.mouse_press = hover && focus && ctx.is_mouse_pressed(BTN_ANY),
@ -365,5 +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;
}

View File

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

View File

@ -335,6 +335,10 @@ fn void? Ctx.layout_element_tree(&ctx)
resolve_placement(c, p);
update_children_bounds(c, p);
}
// 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);
}
}
}

View File

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

View File

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

View File

@ -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) {
@ -80,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 = {
@ -102,7 +108,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
@ -192,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 = {
@ -212,10 +217,10 @@ 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) {
if ((ctx.mouse_released() & BTN_ANY) && ctx.input.mouse.pos.outside(elem.bounds)) {
return false;
}

View File

@ -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;

View File

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

View File

@ -214,6 +214,8 @@ $case "debug":
debug_app(&ui);
$case "calculator":
calculator(&ui, &te);
$case "popup":
popup(&ui);
$endswitch
// Timings counter
@ -395,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) {
@ -459,5 +462,24 @@ 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;
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!");
}!!;
}