From f2316869e224d2c85151f994b1d48c9593a055c5 Mon Sep 17 00:00:00 2001 From: jacob Date: Thu, 6 Nov 2025 12:43:37 -0600 Subject: [PATCH] hot & active ui elements --- src/base/base_math.c | 42 ++++++++++-- src/base/base_math.h | 8 +++ src/pp/pp.c | 124 +++++++++++++++++++++++---------- src/pp/pp.h | 1 - src/pp/pp_widgets.c | 6 +- src/ui/ui_common.c | 20 +++--- src/ui/ui_common.h | 6 +- src/ui/ui_core.c | 159 +++++++++++++++++++++++++++---------------- src/ui/ui_core.h | 51 +++++++------- 9 files changed, 275 insertions(+), 142 deletions(-) diff --git a/src/base/base_math.c b/src/base/base_math.c index f2b33758..6c2c1e5b 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -779,14 +779,48 @@ f32 LerpAngleF32(f32 a, f32 b, f32 t) i32 LerpI32(i32 val0, i32 val1, f32 t) { - return val0 + RoundF32ToI32(((f32)(val1 - val0) * t)); + return val0 + RoundF32ToI32(((f32)val1 - (f32)val0 * t)); +} + +i64 LerpI64(i64 val0, i64 val1, f64 t) +{ + return val0 + RoundF64ToI64(((f64)val1 - (f64)val0 * t)); } -//- Lerp i64 -i64 LerpI64(i64 val0, i64 val1, f64 t) +i32 LerpU32(u32 val0, u32 val1, f32 t) { - return val0 + RoundF64ToI64(((f64)(val1 - val0) * t)); + return val0 + (u64)RoundF32ToI32(((f32)val1 - (f32)val0 * t)); +} + +i64 LerpU64(u64 val0, u64 val1, f64 t) +{ + return val0 + (u64)RoundF64ToI64(((f64)val1 - (f64)val0 * t)); +} + +//////////////////////////////////////////////////////////// +//~ Color operations + +Vec4 Vec4NormFromU32(u32 v) +{ + Vec4 result; + result.x = ((v >> 0) & 0xFF) / 255.0; + result.y = ((v >> 8) & 0xFF) / 255.0; + result.z = ((v >> 16) & 0xFF) / 255.0; + result.w = ((v >> 24) & 0xFF) / 255.0; + return result; +} + +u32 LerpSrgbU32(u32 v0, u32 v1, f32 t) +{ + Vec4 norm0 = Vec4NormFromU32(v0); + Vec4 norm1 = Vec4NormFromU32(v1); + Vec4 norm = ZI; + norm.x = LerpF32(norm0.x, norm1.x, t); + norm.y = LerpF32(norm0.y, norm1.y, t); + norm.z = LerpF32(norm0.z, norm1.z, t); + norm.w = LerpF32(norm0.w, norm1.w, t); + return Rgba32F(norm.x, norm.y, norm.z, norm.w); } //////////////////////////////////////////////////////////// diff --git a/src/base/base_math.h b/src/base/base_math.h index e1332ad7..dcd3ff5b 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -253,6 +253,14 @@ f32 LerpAngleF32(f32 a, f32 b, f32 t); i32 LerpI32(i32 val0, i32 val1, f32 t); i64 LerpI64(i64 val0, i64 val1, f64 t); +i32 LerpU32(u32 val0, u32 val1, f32 t); +i64 LerpU64(u64 val0, u64 val1, f64 t); + +//////////////////////////////////////////////////////////// +//~ Color operations + +Vec4 Vec4NormFromU32(u32 v); +u32 LerpSrgbU32(u32 v0, u32 v1, f32 t); //////////////////////////////////////////////////////////// //~ Vec2 operations diff --git a/src/pp/pp.c b/src/pp/pp.c index 6a9f8fa1..f619fc31 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -785,12 +785,12 @@ void PP_UpdateUser(void) UI_Box *pp_root_box = 0; { - UI_PushCP(UI_BuildRow(0)); + UI_PushCP(UI_BuildRow(UI_NilKey)); { UI_BuildSpacer(UI_FILL(1, 0)); { UI_SetNext(Width, UI_PIX(g->ui_size.x, 1)); - UI_PushCP(UI_BuildColumn(0)); + UI_PushCP(UI_BuildColumn(UI_NilKey)); { UI_BuildSpacer(UI_FILL(1, 0)); { @@ -801,7 +801,7 @@ void PP_UpdateUser(void) } UI_SetNext(ChildLayoutAxis, Axis_Y); UI_SetNext(Height, UI_PIX(g->ui_size.y, 1)); - pp_root_box = UI_BuildBox(HashF("pp root")); + pp_root_box = UI_BuildBox(UI_KeyF("pp root")); } UI_BuildSpacer(UI_FILL(1, 0)); } @@ -943,8 +943,8 @@ void PP_UpdateUser(void) Vec2 pos = InvertXformMulV2(g->world_to_render_xf, VEC2(0, 0)); Vec2 size = InvertXformBasisMulV2(g->world_to_render_xf, VEC2(g->render_size.x, g->render_size.y)); - u32 color0 = Rgba32F(0.17f, 0.17f, 0.17f, 1.f); - u32 color1 = Rgba32F(0.15f, 0.15f, 0.15f, 1.f); + u32 color0 = Rgb32F(0.17f, 0.17f, 0.17f); + u32 color1 = Rgb32F(0.15f, 0.15f, 0.15f); PP_MaterialGrid *grid = PushStruct(g->grids_arena, PP_MaterialGrid); *grid = PP_DefaultMaterialGrid; @@ -953,7 +953,7 @@ void PP_UpdateUser(void) grid->offset = offset; grid->bg0_srgb = color0; grid->bg1_srgb = color1; - grid->line_srgb = Rgba32(0x3f, 0x3f, 0x3f, 0xFF); + grid->line_srgb = Rgb32(0x3f, 0x3f, 0x3f); grid->x_srgb = Color_Red; grid->y_srgb = Color_Green; @@ -1966,80 +1966,130 @@ void PP_UpdateUser(void) { UI_PushCP(pp_root_box); { - Vec2 window_dims = VEC2(400, 500); - u32 window_background_color = 0xfa1a1d1e; - u32 window_border_color = 0xff343a3b; + UI_Push(Tag, HashF("lister")); + UI_Key titlebar_key = UI_KeyF("lister title bar"); - UI_Report rep = UI_ReportFromKey(g->lister_key); - if (rep.flags & UI_ReportFlag_Active) + u32 base_background_color = 0xff1a1d1e; + u32 base_border_color = 0xff343a3b; + + f32 window_border = 1; + f32 window_width = 300; + u32 window_background_color = base_background_color; + u32 window_border_color = base_border_color; + u32 titlebar_color = 0; + u32 titlebar_border_color = 0; + u32 divider_color = base_border_color; { - g->lister_pos = SubVec2(g->ui_cursor, rep.activation_offset); + UI_Report rep = UI_ReportFromKey(titlebar_key); + if (rep.m1_held) + { + g->lister_pos = SubVec2(g->ui_cursor, rep.last_m1_offset); + } + { + // titlebar_color = LerpSrgbU32(window_background_color, Color_White, 0.1); + // titlebar_border_color = LerpSrgbU32(window_background_color, Color_White, 0.1); + // titlebar_border_color = Color_White; + // window_border_color = Color_White; + // window_border_color = LerpSrgbU32(base_border_color, Color_White, 0.25); + + // u32 highlight = LerpSrgbU32(base_border_color, Rgb32F(0.25, 0.25, 0.25), rep.hot); + u32 highlight = LerpSrgbU32(base_border_color, Rgb32F(0.5, 0.5, 0.5), rep.hot); + window_border_color = highlight; + } } + UI_Push(BackgroundColor, window_background_color); UI_Push(BorderColor, window_border_color); - UI_Push(Border, 1); + UI_Push(Border, window_border); + // UI_Push(Rounding, UI_RPIX(15)); UI_Push(Rounding, UI_RPIX(15)); - UI_Push(Width, UI_PIX(window_dims.x, 0)); - UI_Push(Height, UI_PIX(window_dims.y, 0)); + UI_Push(Width, UI_PIX(window_width, 0)); + UI_Push(Height, UI_FIT(0)); UI_Push(ChildLayoutAxis, Axis_Y); UI_Push(FloatingPos, g->lister_pos); UI_SetNext(Flags, UI_BoxFlag_Floating); - UI_PushCP(UI_BuildBox(HashF("lister"))); + UI_PushCP(UI_BuildBox(UI_KeyF("lister"))); { /* Title bar */ UI_PushCP(0); { - UI_Push(BackgroundColor, 0); - UI_Push(BorderColor, 0); + UI_Push(BackgroundColor, titlebar_color); + UI_Push(BorderColor, titlebar_border_color); UI_Push(Rounding, UI_RPIX(0)); UI_Push(ChildLayoutAxis, Axis_X); UI_Push(Width, UI_FILL(1, 0)); UI_Push(Height, UI_FNT(2, 0)); - UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_DrawHotEffects | UI_BoxFlag_DrawActiveEffects); - g->lister_key = UI_PushCP(UI_BuildBox(HashF("title bar")))->key; + UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); + UI_PushCP(UI_BuildBox(titlebar_key)); { UI_Push(Width, UI_FILL(1, 0)); + UI_Push(BorderColor, 0); /* Left title box */ - UI_BuildRow(0); + UI_BuildRow(UI_NilKey); /* Title box */ UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(Width, UI_FIT(1)); UI_SetNext(Text, Lit("Titleeeeeeeeeeeeeee")); UI_SetNext(Flags, UI_BoxFlag_DrawText); - UI_BuildBox(0); + UI_BuildBox(UI_NilKey); /* Right title box */ - UI_BuildRow(0); + UI_BuildRow(UI_NilKey); } UI_PopCP(); } UI_PopCP(); } - UI_BuildDivider(UI_PIX(1, 0)); UI_SetNext(Tint, 0); UI_SetNext(Rounding, 0); - UI_PushCP(UI_BuildColumn(0)); + UI_PushCP(UI_BuildRow(UI_NilKey)); { - for (u32 i = 0; i < 10; ++i) + UI_BuildSpacer(UI_PIX(window_border + 1, 0)); { - UI_SetNext(BorderColor, 0); - UI_SetNext(BackgroundColor, 0); - UI_SetNext(Rounding, UI_RPIX(2)); - UI_SetNext(Width, UI_FILL(1, 0)); - UI_SetNext(Height, UI_FNT(1.5, 0)); - UI_SetNext(Text, Lit("btn")); - UI_SetNext(Flags, UI_BoxFlag_DrawText); - UI_SetNext(ChildAlignment, UI_Alignment_Center); - UI_BuildBox(HashF("btn%F", FmtSint(i))); - } + UI_SetNext(Tint, 0); + UI_SetNext(Rounding, 0); + UI_PushCP(UI_BuildColumn(UI_NilKey)); + { + u32 count = 10; + for (u32 i = 0; i < count; ++i) + { + UI_BuildDivider(UI_PIX(1, 0), divider_color); + UI_Key btn_key = UI_KeyF("btn%F", FmtSint(i)); + UI_Report rep = UI_ReportFromKey(btn_key); + u32 color = LerpSrgbU32(0, Rgb32(0x10, 0x3c, 0x4c), rep.hot); + u32 border_color = LerpSrgbU32(0, Rgb32(0x00, 0x79, 0xa6), rep.hot); + + String button_text = UI_StringF("Button %F", FmtSint(i)); + + UI_SetNext(BorderColor, border_color); + UI_SetNext(BackgroundColor, color); + UI_SetNext(Rounding, UI_RPIX(2)); + UI_SetNext(Width, UI_FILL(1, 0)); + UI_SetNext(Height, UI_FNT(1.5, 0)); + UI_SetNext(Text, button_text); + UI_SetNext(ChildAlignment, UI_Alignment_Center); + UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); + UI_BuildBox(btn_key); + + if (rep.m1_presses) + { + LogInfoF("%F pressed", FmtString(button_text)); + } + } + + } + UI_PopCP(); + } + UI_BuildSpacer(UI_PIX(window_border + 1, 0)); } UI_PopCP(); + UI_PopCP(); } UI_PopCP(); @@ -2058,7 +2108,7 @@ void PP_UpdateUser(void) UI_SetNext(Width, UI_FIT(1)); UI_SetNext(Height, UI_FIT(1)); UI_SetNext(Tint, 0); - UI_PushCP(UI_BuildBox(HashF("dbg"))); + UI_PushCP(UI_BuildBox(UI_KeyF("dbg"))); { UI_Push(BackgroundColor, 0); UI_Push(BorderColor, 0); diff --git a/src/pp/pp.h b/src/pp/pp.h index 09cb3049..0af2b11a 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -251,7 +251,6 @@ Struct(PP_SharedUserState) b32 lister_active; Vec2 lister_pos; - UI_Key lister_key; b32 debug_draw; b32 debug_console; diff --git a/src/pp/pp_widgets.c b/src/pp/pp_widgets.c index c5261388..ce5c0954 100644 --- a/src/pp/pp_widgets.c +++ b/src/pp/pp_widgets.c @@ -54,7 +54,7 @@ UI_Box *PP_BuildDebugConsole(b32 minimized) UI_SetNext(Width, UI_FILL(1, 0)); UI_SetNext(Height, UI_FIT(1)); } - console_box = UI_BuildColumn(HashF("Console box")); + console_box = UI_BuildColumn(UI_KeyF("Console box")); UI_PushCP(console_box); { /* Gather display logs */ @@ -117,7 +117,7 @@ UI_Box *PP_BuildDebugConsole(b32 minimized) UI_Push(Rounding, UI_RPIX(0)); UI_Push(Border, 1); UI_Push(ChildAlignment, UI_Alignment_Left); - UI_PushCP(UI_BuildRow(0)); + UI_PushCP(UI_BuildRow(UI_NilKey)); { // UI_SetNext(Height, UI_PIX(100, 0)); UI_BuildSpacer(UI_PIX(10, 0)); @@ -127,7 +127,7 @@ UI_Box *PP_BuildDebugConsole(b32 minimized) UI_Push(Width, UI_FILL(1, 0)); UI_Push(Height, UI_FIT(1)); UI_Push(Flags, UI_BoxFlag_DrawText); - UI_BuildBox(0); + UI_BuildBox(UI_NilKey); } UI_PopCP(); } diff --git a/src/ui/ui_common.c b/src/ui/ui_common.c index bec6e695..179aeba0 100644 --- a/src/ui/ui_common.c +++ b/src/ui/ui_common.c @@ -6,7 +6,7 @@ UI_Box *UI_BuildLabel(String text) UI_SetNext(Height, UI_FIT(1)); UI_SetNext(Text, text); UI_SetNext(Flags, UI_BoxFlag_DrawText); - UI_Box *box = UI_BuildBox(0); + UI_Box *box = UI_BuildBox(UI_NilKey); return box; } @@ -39,28 +39,26 @@ UI_Box *UI_BuildSpacer(UI_Size size) UI_Push(Parent, old_parent); UI_Push(AxisSize, UI_FILL(1, 0), .axis = !axis); UI_Push(AxisSize, size, .axis = axis); - box = UI_BuildBox(0); + box = UI_BuildBox(UI_NilKey); } UI_PopStack(); return box; } -UI_Box *UI_BuildDivider(UI_Size size) +UI_Box *UI_BuildDivider(UI_Size size, u32 color) { UI_Box *box = 0; UI_Box *old_parent = UI_UseTop(Parent); u32 old_tint = UI_UseTop(Tint); - f32 old_border = UI_UseTop(Border); - u32 old_border_color = UI_UseTop(BorderColor); Axis axis = old_parent->child_layout_axis; UI_PushEmptyStack(); { UI_Push(Parent, old_parent); UI_Push(Tint, old_tint); - UI_Push(BackgroundColor, old_border_color); + UI_Push(BackgroundColor, color); UI_Push(AxisSize, UI_FILL(1, 0), .axis = !axis); UI_Push(AxisSize, size, .axis = axis); - box = UI_BuildBox(0); + box = UI_BuildBox(UI_NilKey); } UI_PopStack(); return box; @@ -69,16 +67,16 @@ UI_Box *UI_BuildDivider(UI_Size size) //////////////////////////////////////////////////////////// //~ Layout helpers -UI_Box *UI_BuildColumn(u64 seed) +UI_Box *UI_BuildColumn(UI_Key key) { UI_SetNext(ChildLayoutAxis, Axis_Y); - UI_Box *box = UI_BuildBox(seed); + UI_Box *box = UI_BuildBox(key); return box; } -UI_Box *UI_BuildRow(u64 seed) +UI_Box *UI_BuildRow(UI_Key key) { UI_SetNext(ChildLayoutAxis, Axis_X); - UI_Box *box = UI_BuildBox(seed); + UI_Box *box = UI_BuildBox(key); return box; } diff --git a/src/ui/ui_common.h b/src/ui/ui_common.h index a4dd3829..569fe073 100644 --- a/src/ui/ui_common.h +++ b/src/ui/ui_common.h @@ -9,10 +9,10 @@ UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...); //~ Spacing helpers UI_Box *UI_BuildSpacer(UI_Size size); -UI_Box *UI_BuildDivider(UI_Size size); +UI_Box *UI_BuildDivider(UI_Size size, u32 color); //////////////////////////////////////////////////////////// //~ Layout helpers -UI_Box *UI_BuildColumn(u64 seed); -UI_Box *UI_BuildRow(u64 seed); +UI_Box *UI_BuildColumn(UI_Key key); +UI_Box *UI_BuildRow(UI_Key key); diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index a3fd51fe..264ecb36 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -21,6 +21,30 @@ ResourceKey UI_GetDefaultFontResource(void) //////////////////////////////////////////////////////////// //~ Key helpers +UI_Key UI_KeyFromString(String str) +{ + u64 top_tag = UI_UseTop(Tag); + UI_Key key = ZI; + key.hash = RandU64FromSeeds(key.hash, top_tag); + key.hash = HashFnv64(key.hash, str); + return key; +} + +UI_Key UI_KeyF_(String fmt, ...) +{ + TempArena scratch = BeginScratchNoConflict(); + UI_Key key = ZI; + va_list args; + va_start(args, fmt); + { + String name = FormatStringV(scratch.arena, fmt, args); + key = UI_KeyFromString(name); + } + va_end(args); + EndScratch(scratch); + return key; +} + UI_Box *UI_BackBoxFromKey(UI_Key key) { UI_SharedState *g = &UI_shared_state; @@ -59,6 +83,20 @@ UI_Box *UI_FrontBoxFromKey(UI_Key key) return front_box; } + +//////////////////////////////////////////////////////////// +//~ String helpers + +String UI_StringF_(String fmt, ...) +{ + UI_SharedState *g = &UI_shared_state; + va_list args; + va_start(args, fmt); + String str = FormatStringV(g->build_arena, fmt, args); + va_end(args); + return str; +} + //////////////////////////////////////////////////////////// //~ Checkpoint helpers @@ -156,8 +194,7 @@ void UI_PushEmptyStack(void) stack->style_tops[UI_StyleKind_Font]->style.Font = UI_GetDefaultFontResource(); stack->style_tops[UI_StyleKind_FontSize]->style.FontSize = 16.0f; stack->style_tops[UI_StyleKind_Tint]->style.Tint = 0xFFFFFFFF; - stack->style_tops[UI_StyleKind_Tag]->style.Tag.name = Lit("root"); - stack->style_tops[UI_StyleKind_Tag]->style.Tag.hash = HashFnv64(Fnv64Basis, stack->style_tops[UI_StyleKind_Tag]->style.Tag.name); + stack->style_tops[UI_StyleKind_Tag]->style.Tag = HashFnv64(Fnv64Basis, Lit("root")); stack->style_tops[UI_StyleKind_DebugColor]->style.DebugColor = Rgba32F(1, 0, 1, 0.5); } @@ -320,11 +357,7 @@ void UI_PushStyle(UI_StyleDesc desc) case UI_StyleKind_Tag: { - n->style.Tag.name = PushString(g->build_arena, desc.style.Tag.name); - if (n->style.Tag.hash == 0) - { - n->style.Tag.hash = HashFnv64(stack->style_tops[kind]->style.Tag.hash, n->style.Tag.name); - } + n->style.Tag = RandU64FromSeeds(n->next->style.Tag, n->style.Tag); } break; } } @@ -376,27 +409,14 @@ UI_Style UI_PopStyle(UI_StyleDesc desc) //////////////////////////////////////////////////////////// //~ Box -UI_Box *UI_BuildBox(u64 seed) +UI_Box *UI_BuildBox(UI_Key key) { UI_SharedState *g = &UI_shared_state; UI_Box *parent = UI_UseTop(Parent); - UI_Tag tag = UI_UseTop(Tag); - - ////////////////////////////// - //- Create box UI_Box *box = PushStruct(g->build_arena, UI_Box); - - /* Calculate key */ - if (seed != 0) - { - UI_Key key = ZI; - key.hash = RandU64FromSeeds(key.hash, parent->key.hash); - key.hash = RandU64FromSeeds(key.hash, tag.hash); - key.hash = RandU64FromSeeds(key.hash, seed); - box->key = key; - } + box->key = key; /* Insert into lookup */ if (box->key.hash != 0) @@ -422,9 +442,9 @@ UI_Box *UI_BuildBox(u64 seed) box->parent = parent; ++parent->count; - /* Persist data from back box */ - UI_Box *back_box = UI_BackBoxFromKey(box->key); - if (back_box != 0) + /* Persist state from back box */ + UI_Box *back_box = UI_BackBoxFromKey(key); + if (back_box) { box->report = back_box->report; } @@ -499,10 +519,10 @@ UI_Report UI_ReportFromKey(UI_Key key) UI_SharedState *g = &UI_shared_state; UI_Report result = ZI; - UI_Box *back_box = UI_BackBoxFromKey(key); - if (back_box) + UI_Box *box = UI_BackBoxFromKey(key); + if (box) { - result = back_box->report; + result = box->report; } return result; @@ -532,25 +552,21 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) ////////////////////////////// //- Process controller events + i64 now_ns = TimeNs(); + i64 dt_ns = now_ns - g->last_frame_begin_ns; + f64 dt = SecondsFromNs(dt_ns); + f64 inv_dt = 1.0 / dt; + g->last_frame_begin_ns = now_ns; + ControllerEventsArray controller_events = frame.window_frame.controller_events; if (g->build_arena != 0 && g->back_build_arena != 0) { /* Locate boxes */ - UI_Box *hovered_box = 0; - UI_Box *active_box = 0; - for (u64 pre_index = g->boxes_count; pre_index-- > 0;) - { - UI_Box *box = g->boxes_pre[pre_index]; - if (hovered_box == 0 && box->report.flags & UI_ReportFlag_Hovered) - { - hovered_box = box; - } - if (active_box == 0 && box->report.flags & UI_ReportFlag_Active) - { - active_box = box; - } - } + UI_Box *old_active_box = UI_FrontBoxFromKey(g->active_box); + UI_Box *old_hovered_box = UI_FrontBoxFromKey(g->hovered_box); + UI_Box *active_box = old_active_box; + UI_Box *hovered_box = active_box; /* Update cursor pos */ for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index) @@ -562,24 +578,19 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) } } - /* Update hovered box */ - if (hovered_box) - { - hovered_box->report.flags &= ~UI_ReportFlag_Hovered; - hovered_box = 0; - } - /* Iterate boxes in reverse render order */ - for (u64 pre_index = g->boxes_count; pre_index-- > 0 && hovered_box == 0;) + /* Init box reports */ + for (u64 pre_index = g->boxes_count; pre_index-- > 0;) { UI_Box *box = g->boxes_pre[pre_index]; - if (box->key.hash != 0) + if (hovered_box == 0 && box->flags & UI_BoxFlag_Interactable) { if (UI_IsPointInBox(box, g->cursor_pos)) { - box->report.flags |= UI_ReportFlag_Hovered; hovered_box = box; } } + box->report.m1_presses = 0; + box->report.m1_releases = 0; } /* Update state from controller events */ @@ -597,8 +608,9 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) UI_Box *box = hovered_box; if (box) { - box->report.flags |= UI_ReportFlag_Active; - box->report.activation_offset = SubVec2(g->cursor_pos, box->p0); + ++box->report.m1_presses; + box->report.m1_held = 1; + box->report.last_m1_offset = SubVec2(g->cursor_pos, box->p0); active_box = box; } } @@ -611,13 +623,46 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) UI_Box *box = active_box; if (box) { - box->report.flags &= ~UI_ReportFlag_Active; + ++box->report.m1_releases; + box->report.m1_held = 0; active_box = 0; } } } break; } } + + /* Update box hot & active states */ + for (u64 pre_index = 0; pre_index < g->boxes_count; ++pre_index) + { + UI_Box *box = g->boxes_pre[pre_index]; + UI_Report *report = &box->report; + f32 target_hot = 0; + f32 target_active = 0; + f32 hot_blend_rate = 1; + f32 active_blend_rate = 1; + if (box == hovered_box) + { + target_hot = 1; + } + else + { + hot_blend_rate = 15 * dt; + } + if (box == active_box) + { + target_active = 1; + } + else + { + active_blend_rate = 15 * dt; + } + report->hot = LerpF32(report->hot, target_hot, hot_blend_rate); + report->active = LerpF32(report->active, target_active, active_blend_rate); + } + + g->hovered_box = hovered_box ? hovered_box->key : UI_NilKey; + g->active_box = active_box ? active_box->key : UI_NilKey; } ////////////////////////////// @@ -1056,8 +1101,6 @@ i64 UI_EndFrame(UI_Frame frame) Vec2 ceiled_dims = CeilVec2(dims_vec); box->p0 = FloorVec2(floored_final_pos); box->p1 = AddVec2(floored_final_pos, ceiled_dims); - box->report.screen_p0 = box->p0; - box->report.screen_p1 = box->p1; } /* Rounding */ @@ -1145,8 +1188,6 @@ i64 UI_EndFrame(UI_Frame frame) rect->debug_srgb = box->debug_color; rect->tint_srgb = box->tint; rect->border = box->border; - - /* Rounding */ rect->tl_rounding = box->rounding_tl; rect->tr_rounding = box->rounding_tr; rect->br_rounding = box->rounding_br; diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index a6c1220a..e345470a 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -82,11 +82,10 @@ Enum(UI_BoxFlag) { UI_BoxFlag_None = 0, UI_BoxFlag_DrawText = (1 << 0), - UI_BoxFlag_DrawHotEffects = (1 << 1), - UI_BoxFlag_DrawActiveEffects = (1 << 2), - UI_BoxFlag_NoTextTruncation = (1 << 3), - UI_BoxFlag_Floating = (1 << 4), - UI_BoxFlag_NoFloatingClamp = (1 << 5), + UI_BoxFlag_Interactable = (1 << 1), + UI_BoxFlag_NoTextTruncation = (1 << 2), + UI_BoxFlag_Floating = (1 << 3), + UI_BoxFlag_NoFloatingClamp = (1 << 4), }; //////////////////////////////////////////////////////////// @@ -95,7 +94,7 @@ Enum(UI_BoxFlag) #define UI_StyleKindsXMacro(x) \ x(Flags, UI_BoxFlag) \ x(Parent, struct UI_Box *) \ - x(Tag, UI_Tag) \ + x(Tag, u64) \ x(ChildLayoutAxis, Axis) \ x(ChildAlignmentX, UI_AxisAlignment) \ x(ChildAlignmentY, UI_AxisAlignment) \ @@ -119,12 +118,6 @@ Enum(UI_BoxFlag) x(AxisSize, UI_Size) \ /* ------------------------------------------- */ -Struct(UI_Tag) -{ - String name; - u64 hash; -}; - Enum(UI_StyleKind) { #define X(name, type) UI_StyleKind_##name, @@ -180,21 +173,18 @@ Struct(UI_Stack) //////////////////////////////////////////////////////////// //~ Report types -Enum(UI_ReportFlag) -{ - UI_ReportFlag_None = 0, - UI_ReportFlag_Active = (1 << 0), - UI_ReportFlag_Hovered = (1 << 1), -}; - Struct(UI_Report) { - UI_ReportFlag flags; - Vec2 activation_offset; + b32 m1_held; - f32 hot_ratio; - f32 active_ratio; + f32 hot; + f32 active; + b32 m1_presses; + b32 m1_releases; + Vec2 last_m1_offset; + + /* Where was this box last rendered in screen coordinates */ Vec2 screen_p0; Vec2 screen_p1; }; @@ -291,7 +281,10 @@ Struct(UI_Frame) Struct(UI_SharedState) { //- Control state + i64 last_frame_begin_ns; Vec2 cursor_pos; + UI_Key hovered_box; + UI_Key active_box; //- Build state Arena *build_arena; @@ -342,9 +335,19 @@ ResourceKey UI_GetDefaultFontResource(void); //////////////////////////////////////////////////////////// //~ Key helpers +UI_Key UI_KeyFromString(String str); +UI_Key UI_KeyF_(String fmt, ...); +#define UI_KeyF(fmt_cstr, ...) UI_KeyF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd) + UI_Box *UI_BackBoxFromKey(UI_Key key); UI_Box *UI_FrontBoxFromKey(UI_Key key); +//////////////////////////////////////////////////////////// +//~ String helpers + +String UI_StringF_(String fmt, ...); +#define UI_StringF(fmt_cstr, ...) UI_StringF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd) + //////////////////////////////////////////////////////////// //~ Checkpoint helpers @@ -398,7 +401,7 @@ UI_Style UI_PopStyle(UI_StyleDesc desc); //////////////////////////////////////////////////////////// //~ Box -UI_Box *UI_BuildBox(u64 seed); +UI_Box *UI_BuildBox(UI_Key key); void UI_SetBackgroundTexture(UI_Box *box, GPU_Resource *texture, Vec2 uv0, Vec2 uv1); b32 UI_IsPointInBox(UI_Box *box, Vec2 point);