diff --git a/src/main.c3 b/src/main.c3 index 350e05b..0d961d6 100644 --- a/src/main.c3 +++ b/src/main.c3 @@ -65,6 +65,10 @@ fn int main(String[] args) if (ctx.button("button2", ugui::Rect{0,0,30,30})!!.mouse_release) { io::printn("release button2"); } + if (ctx.slider_hor("slider", ugui::Rect{0,0,100,30})!!.update) { + ugui::Elem* e = ctx.get_elem_by_label("slider")!!; + io::printfn("slider: %f", e.slider.value); + } |}; ctx.div_end()!!; diff --git a/src/ugui_button.c3 b/src/ugui_button.c3 index 20d4d9e..87f9d0f 100644 --- a/src/ugui_button.c3 +++ b/src/ugui_button.c3 @@ -23,9 +23,6 @@ fn ElemEvents! Ctx.button(&ctx, String label, Rect size) // TODO: 3. Fill the button specific fields } - // TODO: Check for interactions - // FIXME: this is not how normal buttons work, usually focus follows both - // mouse hover and mouse down c_elem.events = ctx.get_elem_events(c_elem); if (parent.flags.has_focus) { if (c_elem.events.mouse_hover) { diff --git a/src/ugui_data.c3 b/src/ugui_data.c3 index 178be3b..7abf1e7 100644 --- a/src/ugui_data.c3 +++ b/src/ugui_data.c3 @@ -23,6 +23,7 @@ enum ElemType { ETYPE_NONE, ETYPE_DIV, ETYPE_BUTTON, + ETYPE_SLIDER, } bitstruct ElemFlags : uint { @@ -39,6 +40,7 @@ bitstruct ElemEvents : uint { bool mouse_press : 4; bool mouse_release : 5; bool mouse_hold : 6; + bool update : 7; } enum DivLayout { @@ -54,6 +56,12 @@ struct Div { Color color_bg; } +// slider element +struct Slider { + float value; + Rect handle; +} + // element structure struct Elem { Id id; @@ -63,6 +71,7 @@ struct Elem { ElemType type; union { Div div; + Slider slider; } } diff --git a/src/ugui_impl.c3 b/src/ugui_impl.c3 index 27b9efe..da6e210 100644 --- a/src/ugui_impl.c3 +++ b/src/ugui_impl.c3 @@ -24,6 +24,14 @@ macro Ctx.get_elem(&ctx, Id id) return c_elem; } +// this searches an element in the cache by label, it does not create a new element +// if it does't find one +macro Ctx.get_elem_by_label(&ctx, String label) +{ + Id id = hash(label); + return ctx.cache.search(id); +} + fn void! Ctx.init(&ctx) { ctx.tree.init(MAX_ELEMENTS)!; diff --git a/src/ugui_input.c3 b/src/ugui_input.c3 index 886865f..b68cbfc 100644 --- a/src/ugui_input.c3 +++ b/src/ugui_input.c3 @@ -83,11 +83,13 @@ macro Ctx.is_mouse_down(&ctx, MouseButtons btn) macro ElemEvents Ctx.get_elem_events(&ctx, Elem *elem) { // TODO: add the other events + // FIXME: active should be elsewhere + bool active = elem.events.mouse_hold || ctx.is_hovered(elem); ElemEvents ev = { .mouse_hover = ctx.is_hovered(elem), - .mouse_press = ctx.is_mouse_pressed(BTN_ANY), - .mouse_release = ctx.is_mouse_released(BTN_ANY), - .mouse_hold = ctx.is_mouse_down(BTN_ANY), + .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; } @@ -101,8 +103,20 @@ fn void Ctx.input_mouse_button(&ctx, MouseButtons buttons) } // Mouse was moved, report absolute position -// TODO: implement this -fn void Ctx.input_mouse_abs(&ctx, short x, short y) { return; } +fn void Ctx.input_mouse_abs(&ctx, short x, short y) +{ + ctx.input.mouse.pos.x = clamp(x, 0u16, ctx.width); + ctx.input.mouse.pos.y = clamp(y, 0u16, ctx.height); + + short dx, dy; + dx = x - ctx.input.mouse.pos.x; + dy = y - ctx.input.mouse.pos.y; + + ctx.input.mouse.delta.x = dx; + ctx.input.mouse.delta.y = dy; + + ctx.input.events.mouse_move = true; +} // Mouse was moved, report relative motion fn void Ctx.input_mouse_delta(&ctx, short dx, short dy) diff --git a/src/ugui_slider.c3 b/src/ugui_slider.c3 new file mode 100644 index 0000000..3fea39d --- /dev/null +++ b/src/ugui_slider.c3 @@ -0,0 +1,66 @@ +module ugui; + +fn ElemEvents! Ctx.slider_hor(&ctx, String label, Rect size) +{ + Id id = hash(label); + + Elem *parent = ctx.get_parent()!; + Elem *c_elem = ctx.get_elem(id)!; + // add it to the tree + ctx.tree.add(id, ctx.active_div)!; + + // 1. Fill the element fields + c_elem.type = ETYPE_SLIDER; + + // if the element is new or the parent was updated then redo layout + if (c_elem.flags.is_new || parent.flags.updated) { + // 2. Layout + c_elem.rect = ctx.position_element(parent, size, true); + /* handle + * +----+-----+---------------------+ + * | |#####| | + * +----+-----+---------------------+ + */ + c_elem.slider.handle = Rect{ + .x = (short)(c_elem.rect.x + (int)(c_elem.rect.w * c_elem.slider.value)), + .y = c_elem.rect.y, + .w = (short)(c_elem.rect.w * 0.25), + .h = c_elem.rect.h, + }; + } + + c_elem.events = ctx.get_elem_events(c_elem); + if (parent.flags.has_focus && c_elem.events.mouse_hover) { + if (point_in_rect(ctx.input.mouse.pos, c_elem.slider.handle) && c_elem.events.mouse_hold) { + short x = (short)clamp(ctx.input.mouse.pos.x - c_elem.slider.handle.w/2, c_elem.rect.x, c_elem.rect.x + c_elem.rect.w - c_elem.slider.handle.w); + float v = (float)(c_elem.slider.handle.x-c_elem.rect.x) / (float)(c_elem.rect.w-c_elem.slider.handle.w); + c_elem.slider.handle.x = x; + c_elem.slider.value = v; + c_elem.events.update = true; + } + } + + // Draw the button + Color bg_color = uint_to_rgba(0x0000ffff); + Color handle_color = uint_to_rgba(0x0ff000ff); + + Cmd cmd = { + .type = CMD_RECT, + .rect = { + .rect = c_elem.rect, + .color = bg_color, + }, + }; + ctx.cmd_queue.enqueue(&cmd)!; + + cmd = Cmd{ + .type = CMD_RECT, + .rect = { + .rect = c_elem.slider.handle, + .color = handle_color, + }, + }; + ctx.cmd_queue.enqueue(&cmd)!; + + return c_elem.events; +}