hot & active ui elements

This commit is contained in:
jacob 2025-11-06 12:43:37 -06:00
parent bbbb0f63d3
commit f2316869e2
9 changed files with 275 additions and 142 deletions

View File

@ -779,14 +779,48 @@ f32 LerpAngleF32(f32 a, f32 b, f32 t)
i32 LerpI32(i32 val0, i32 val1, 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 i32 LerpU32(u32 val0, u32 val1, f32 t)
i64 LerpI64(i64 val0, i64 val1, f64 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);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -253,6 +253,14 @@ f32 LerpAngleF32(f32 a, f32 b, f32 t);
i32 LerpI32(i32 val0, i32 val1, f32 t); i32 LerpI32(i32 val0, i32 val1, f32 t);
i64 LerpI64(i64 val0, i64 val1, f64 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 //~ Vec2 operations

View File

@ -785,12 +785,12 @@ void PP_UpdateUser(void)
UI_Box *pp_root_box = 0; UI_Box *pp_root_box = 0;
{ {
UI_PushCP(UI_BuildRow(0)); UI_PushCP(UI_BuildRow(UI_NilKey));
{ {
UI_BuildSpacer(UI_FILL(1, 0)); UI_BuildSpacer(UI_FILL(1, 0));
{ {
UI_SetNext(Width, UI_PIX(g->ui_size.x, 1)); 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)); UI_BuildSpacer(UI_FILL(1, 0));
{ {
@ -801,7 +801,7 @@ void PP_UpdateUser(void)
} }
UI_SetNext(ChildLayoutAxis, Axis_Y); UI_SetNext(ChildLayoutAxis, Axis_Y);
UI_SetNext(Height, UI_PIX(g->ui_size.y, 1)); 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)); 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 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)); 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 color0 = Rgb32F(0.17f, 0.17f, 0.17f);
u32 color1 = Rgba32F(0.15f, 0.15f, 0.15f, 1.f); u32 color1 = Rgb32F(0.15f, 0.15f, 0.15f);
PP_MaterialGrid *grid = PushStruct(g->grids_arena, PP_MaterialGrid); PP_MaterialGrid *grid = PushStruct(g->grids_arena, PP_MaterialGrid);
*grid = PP_DefaultMaterialGrid; *grid = PP_DefaultMaterialGrid;
@ -953,7 +953,7 @@ void PP_UpdateUser(void)
grid->offset = offset; grid->offset = offset;
grid->bg0_srgb = color0; grid->bg0_srgb = color0;
grid->bg1_srgb = color1; 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->x_srgb = Color_Red;
grid->y_srgb = Color_Green; grid->y_srgb = Color_Green;
@ -1966,78 +1966,128 @@ void PP_UpdateUser(void)
{ {
UI_PushCP(pp_root_box); UI_PushCP(pp_root_box);
{ {
Vec2 window_dims = VEC2(400, 500); UI_Push(Tag, HashF("lister"));
u32 window_background_color = 0xfa1a1d1e; UI_Key titlebar_key = UI_KeyF("lister title bar");
u32 window_border_color = 0xff343a3b;
UI_Report rep = UI_ReportFromKey(g->lister_key); u32 base_background_color = 0xff1a1d1e;
if (rep.flags & UI_ReportFlag_Active) 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(BackgroundColor, window_background_color);
UI_Push(BorderColor, window_border_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(Rounding, UI_RPIX(15));
UI_Push(Width, UI_PIX(window_dims.x, 0)); UI_Push(Width, UI_PIX(window_width, 0));
UI_Push(Height, UI_PIX(window_dims.y, 0)); UI_Push(Height, UI_FIT(0));
UI_Push(ChildLayoutAxis, Axis_Y); UI_Push(ChildLayoutAxis, Axis_Y);
UI_Push(FloatingPos, g->lister_pos); UI_Push(FloatingPos, g->lister_pos);
UI_SetNext(Flags, UI_BoxFlag_Floating); UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_PushCP(UI_BuildBox(HashF("lister"))); UI_PushCP(UI_BuildBox(UI_KeyF("lister")));
{ {
/* Title bar */ /* Title bar */
UI_PushCP(0); UI_PushCP(0);
{ {
UI_Push(BackgroundColor, 0); UI_Push(BackgroundColor, titlebar_color);
UI_Push(BorderColor, 0); UI_Push(BorderColor, titlebar_border_color);
UI_Push(Rounding, UI_RPIX(0)); UI_Push(Rounding, UI_RPIX(0));
UI_Push(ChildLayoutAxis, Axis_X); UI_Push(ChildLayoutAxis, Axis_X);
UI_Push(Width, UI_FILL(1, 0)); UI_Push(Width, UI_FILL(1, 0));
UI_Push(Height, UI_FNT(2, 0)); UI_Push(Height, UI_FNT(2, 0));
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_DrawHotEffects | UI_BoxFlag_DrawActiveEffects); UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable);
g->lister_key = UI_PushCP(UI_BuildBox(HashF("title bar")))->key; UI_PushCP(UI_BuildBox(titlebar_key));
{ {
UI_Push(Width, UI_FILL(1, 0)); UI_Push(Width, UI_FILL(1, 0));
UI_Push(BorderColor, 0);
/* Left title box */ /* Left title box */
UI_BuildRow(0); UI_BuildRow(UI_NilKey);
/* Title box */ /* Title box */
UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(ChildAlignment, UI_Alignment_Center);
UI_SetNext(Width, UI_FIT(1)); UI_SetNext(Width, UI_FIT(1));
UI_SetNext(Text, Lit("Titleeeeeeeeeeeeeee")); UI_SetNext(Text, Lit("Titleeeeeeeeeeeeeee"));
UI_SetNext(Flags, UI_BoxFlag_DrawText); UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_BuildBox(0); UI_BuildBox(UI_NilKey);
/* Right title box */ /* Right title box */
UI_BuildRow(0); UI_BuildRow(UI_NilKey);
} }
UI_PopCP(); UI_PopCP();
} }
UI_PopCP(); UI_PopCP();
} }
UI_BuildDivider(UI_PIX(1, 0));
UI_SetNext(Tint, 0); UI_SetNext(Tint, 0);
UI_SetNext(Rounding, 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(Tint, 0);
UI_SetNext(BackgroundColor, 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(Rounding, UI_RPIX(2));
UI_SetNext(Width, UI_FILL(1, 0)); UI_SetNext(Width, UI_FILL(1, 0));
UI_SetNext(Height, UI_FNT(1.5, 0)); UI_SetNext(Height, UI_FNT(1.5, 0));
UI_SetNext(Text, Lit("btn")); UI_SetNext(Text, button_text);
UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(ChildAlignment, UI_Alignment_Center);
UI_BuildBox(HashF("btn%F", FmtSint(i))); 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_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(Width, UI_FIT(1));
UI_SetNext(Height, UI_FIT(1)); UI_SetNext(Height, UI_FIT(1));
UI_SetNext(Tint, 0); UI_SetNext(Tint, 0);
UI_PushCP(UI_BuildBox(HashF("dbg"))); UI_PushCP(UI_BuildBox(UI_KeyF("dbg")));
{ {
UI_Push(BackgroundColor, 0); UI_Push(BackgroundColor, 0);
UI_Push(BorderColor, 0); UI_Push(BorderColor, 0);

View File

@ -251,7 +251,6 @@ Struct(PP_SharedUserState)
b32 lister_active; b32 lister_active;
Vec2 lister_pos; Vec2 lister_pos;
UI_Key lister_key;
b32 debug_draw; b32 debug_draw;
b32 debug_console; b32 debug_console;

View File

@ -54,7 +54,7 @@ UI_Box *PP_BuildDebugConsole(b32 minimized)
UI_SetNext(Width, UI_FILL(1, 0)); UI_SetNext(Width, UI_FILL(1, 0));
UI_SetNext(Height, UI_FIT(1)); 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); UI_PushCP(console_box);
{ {
/* Gather display logs */ /* Gather display logs */
@ -117,7 +117,7 @@ UI_Box *PP_BuildDebugConsole(b32 minimized)
UI_Push(Rounding, UI_RPIX(0)); UI_Push(Rounding, UI_RPIX(0));
UI_Push(Border, 1); UI_Push(Border, 1);
UI_Push(ChildAlignment, UI_Alignment_Left); 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_SetNext(Height, UI_PIX(100, 0));
UI_BuildSpacer(UI_PIX(10, 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(Width, UI_FILL(1, 0));
UI_Push(Height, UI_FIT(1)); UI_Push(Height, UI_FIT(1));
UI_Push(Flags, UI_BoxFlag_DrawText); UI_Push(Flags, UI_BoxFlag_DrawText);
UI_BuildBox(0); UI_BuildBox(UI_NilKey);
} }
UI_PopCP(); UI_PopCP();
} }

View File

@ -6,7 +6,7 @@ UI_Box *UI_BuildLabel(String text)
UI_SetNext(Height, UI_FIT(1)); UI_SetNext(Height, UI_FIT(1));
UI_SetNext(Text, text); UI_SetNext(Text, text);
UI_SetNext(Flags, UI_BoxFlag_DrawText); UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_Box *box = UI_BuildBox(0); UI_Box *box = UI_BuildBox(UI_NilKey);
return box; return box;
} }
@ -39,28 +39,26 @@ UI_Box *UI_BuildSpacer(UI_Size size)
UI_Push(Parent, old_parent); UI_Push(Parent, old_parent);
UI_Push(AxisSize, UI_FILL(1, 0), .axis = !axis); UI_Push(AxisSize, UI_FILL(1, 0), .axis = !axis);
UI_Push(AxisSize, size, .axis = axis); UI_Push(AxisSize, size, .axis = axis);
box = UI_BuildBox(0); box = UI_BuildBox(UI_NilKey);
} }
UI_PopStack(); UI_PopStack();
return box; return box;
} }
UI_Box *UI_BuildDivider(UI_Size size) UI_Box *UI_BuildDivider(UI_Size size, u32 color)
{ {
UI_Box *box = 0; UI_Box *box = 0;
UI_Box *old_parent = UI_UseTop(Parent); UI_Box *old_parent = UI_UseTop(Parent);
u32 old_tint = UI_UseTop(Tint); 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; Axis axis = old_parent->child_layout_axis;
UI_PushEmptyStack(); UI_PushEmptyStack();
{ {
UI_Push(Parent, old_parent); UI_Push(Parent, old_parent);
UI_Push(Tint, old_tint); 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, UI_FILL(1, 0), .axis = !axis);
UI_Push(AxisSize, size, .axis = axis); UI_Push(AxisSize, size, .axis = axis);
box = UI_BuildBox(0); box = UI_BuildBox(UI_NilKey);
} }
UI_PopStack(); UI_PopStack();
return box; return box;
@ -69,16 +67,16 @@ UI_Box *UI_BuildDivider(UI_Size size)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Layout helpers //~ Layout helpers
UI_Box *UI_BuildColumn(u64 seed) UI_Box *UI_BuildColumn(UI_Key key)
{ {
UI_SetNext(ChildLayoutAxis, Axis_Y); UI_SetNext(ChildLayoutAxis, Axis_Y);
UI_Box *box = UI_BuildBox(seed); UI_Box *box = UI_BuildBox(key);
return box; return box;
} }
UI_Box *UI_BuildRow(u64 seed) UI_Box *UI_BuildRow(UI_Key key)
{ {
UI_SetNext(ChildLayoutAxis, Axis_X); UI_SetNext(ChildLayoutAxis, Axis_X);
UI_Box *box = UI_BuildBox(seed); UI_Box *box = UI_BuildBox(key);
return box; return box;
} }

View File

@ -9,10 +9,10 @@ UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...);
//~ Spacing helpers //~ Spacing helpers
UI_Box *UI_BuildSpacer(UI_Size size); 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 //~ Layout helpers
UI_Box *UI_BuildColumn(u64 seed); UI_Box *UI_BuildColumn(UI_Key key);
UI_Box *UI_BuildRow(u64 seed); UI_Box *UI_BuildRow(UI_Key key);

View File

@ -21,6 +21,30 @@ ResourceKey UI_GetDefaultFontResource(void)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Key helpers //~ 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_Box *UI_BackBoxFromKey(UI_Key key)
{ {
UI_SharedState *g = &UI_shared_state; UI_SharedState *g = &UI_shared_state;
@ -59,6 +83,20 @@ UI_Box *UI_FrontBoxFromKey(UI_Key key)
return front_box; 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 //~ 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_Font]->style.Font = UI_GetDefaultFontResource();
stack->style_tops[UI_StyleKind_FontSize]->style.FontSize = 16.0f; stack->style_tops[UI_StyleKind_FontSize]->style.FontSize = 16.0f;
stack->style_tops[UI_StyleKind_Tint]->style.Tint = 0xFFFFFFFF; 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 = HashFnv64(Fnv64Basis, 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_DebugColor]->style.DebugColor = Rgba32F(1, 0, 1, 0.5); 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: case UI_StyleKind_Tag:
{ {
n->style.Tag.name = PushString(g->build_arena, desc.style.Tag.name); n->style.Tag = RandU64FromSeeds(n->next->style.Tag, n->style.Tag);
if (n->style.Tag.hash == 0)
{
n->style.Tag.hash = HashFnv64(stack->style_tops[kind]->style.Tag.hash, n->style.Tag.name);
}
} break; } break;
} }
} }
@ -376,27 +409,14 @@ UI_Style UI_PopStyle(UI_StyleDesc desc)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Box //~ Box
UI_Box *UI_BuildBox(u64 seed) UI_Box *UI_BuildBox(UI_Key key)
{ {
UI_SharedState *g = &UI_shared_state; UI_SharedState *g = &UI_shared_state;
UI_Box *parent = UI_UseTop(Parent); UI_Box *parent = UI_UseTop(Parent);
UI_Tag tag = UI_UseTop(Tag);
//////////////////////////////
//- Create box
UI_Box *box = PushStruct(g->build_arena, UI_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 */ /* Insert into lookup */
if (box->key.hash != 0) if (box->key.hash != 0)
@ -422,9 +442,9 @@ UI_Box *UI_BuildBox(u64 seed)
box->parent = parent; box->parent = parent;
++parent->count; ++parent->count;
/* Persist data from back box */ /* Persist state from back box */
UI_Box *back_box = UI_BackBoxFromKey(box->key); UI_Box *back_box = UI_BackBoxFromKey(key);
if (back_box != 0) if (back_box)
{ {
box->report = back_box->report; box->report = back_box->report;
} }
@ -499,10 +519,10 @@ UI_Report UI_ReportFromKey(UI_Key key)
UI_SharedState *g = &UI_shared_state; UI_SharedState *g = &UI_shared_state;
UI_Report result = ZI; UI_Report result = ZI;
UI_Box *back_box = UI_BackBoxFromKey(key); UI_Box *box = UI_BackBoxFromKey(key);
if (back_box) if (box)
{ {
result = back_box->report; result = box->report;
} }
return result; return result;
@ -532,25 +552,21 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags)
////////////////////////////// //////////////////////////////
//- Process controller events //- 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; ControllerEventsArray controller_events = frame.window_frame.controller_events;
if (g->build_arena != 0 && g->back_build_arena != 0) if (g->build_arena != 0 && g->back_build_arena != 0)
{ {
/* Locate boxes */ /* Locate boxes */
UI_Box *hovered_box = 0; UI_Box *old_active_box = UI_FrontBoxFromKey(g->active_box);
UI_Box *active_box = 0; UI_Box *old_hovered_box = UI_FrontBoxFromKey(g->hovered_box);
for (u64 pre_index = g->boxes_count; pre_index-- > 0;) UI_Box *active_box = old_active_box;
{ UI_Box *hovered_box = active_box;
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;
}
}
/* Update cursor pos */ /* Update cursor pos */
for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index) 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 */ /* Init box reports */
if (hovered_box) for (u64 pre_index = g->boxes_count; pre_index-- > 0;)
{
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;)
{ {
UI_Box *box = g->boxes_pre[pre_index]; 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)) if (UI_IsPointInBox(box, g->cursor_pos))
{ {
box->report.flags |= UI_ReportFlag_Hovered;
hovered_box = box; hovered_box = box;
} }
} }
box->report.m1_presses = 0;
box->report.m1_releases = 0;
} }
/* Update state from controller events */ /* Update state from controller events */
@ -597,8 +608,9 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags)
UI_Box *box = hovered_box; UI_Box *box = hovered_box;
if (box) if (box)
{ {
box->report.flags |= UI_ReportFlag_Active; ++box->report.m1_presses;
box->report.activation_offset = SubVec2(g->cursor_pos, box->p0); box->report.m1_held = 1;
box->report.last_m1_offset = SubVec2(g->cursor_pos, box->p0);
active_box = box; active_box = box;
} }
} }
@ -611,13 +623,46 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags)
UI_Box *box = active_box; UI_Box *box = active_box;
if (box) if (box)
{ {
box->report.flags &= ~UI_ReportFlag_Active; ++box->report.m1_releases;
box->report.m1_held = 0;
active_box = 0; active_box = 0;
} }
} }
} break; } 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); Vec2 ceiled_dims = CeilVec2(dims_vec);
box->p0 = FloorVec2(floored_final_pos); box->p0 = FloorVec2(floored_final_pos);
box->p1 = AddVec2(floored_final_pos, ceiled_dims); box->p1 = AddVec2(floored_final_pos, ceiled_dims);
box->report.screen_p0 = box->p0;
box->report.screen_p1 = box->p1;
} }
/* Rounding */ /* Rounding */
@ -1145,8 +1188,6 @@ i64 UI_EndFrame(UI_Frame frame)
rect->debug_srgb = box->debug_color; rect->debug_srgb = box->debug_color;
rect->tint_srgb = box->tint; rect->tint_srgb = box->tint;
rect->border = box->border; rect->border = box->border;
/* Rounding */
rect->tl_rounding = box->rounding_tl; rect->tl_rounding = box->rounding_tl;
rect->tr_rounding = box->rounding_tr; rect->tr_rounding = box->rounding_tr;
rect->br_rounding = box->rounding_br; rect->br_rounding = box->rounding_br;

View File

@ -82,11 +82,10 @@ Enum(UI_BoxFlag)
{ {
UI_BoxFlag_None = 0, UI_BoxFlag_None = 0,
UI_BoxFlag_DrawText = (1 << 0), UI_BoxFlag_DrawText = (1 << 0),
UI_BoxFlag_DrawHotEffects = (1 << 1), UI_BoxFlag_Interactable = (1 << 1),
UI_BoxFlag_DrawActiveEffects = (1 << 2), UI_BoxFlag_NoTextTruncation = (1 << 2),
UI_BoxFlag_NoTextTruncation = (1 << 3), UI_BoxFlag_Floating = (1 << 3),
UI_BoxFlag_Floating = (1 << 4), UI_BoxFlag_NoFloatingClamp = (1 << 4),
UI_BoxFlag_NoFloatingClamp = (1 << 5),
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -95,7 +94,7 @@ Enum(UI_BoxFlag)
#define UI_StyleKindsXMacro(x) \ #define UI_StyleKindsXMacro(x) \
x(Flags, UI_BoxFlag) \ x(Flags, UI_BoxFlag) \
x(Parent, struct UI_Box *) \ x(Parent, struct UI_Box *) \
x(Tag, UI_Tag) \ x(Tag, u64) \
x(ChildLayoutAxis, Axis) \ x(ChildLayoutAxis, Axis) \
x(ChildAlignmentX, UI_AxisAlignment) \ x(ChildAlignmentX, UI_AxisAlignment) \
x(ChildAlignmentY, UI_AxisAlignment) \ x(ChildAlignmentY, UI_AxisAlignment) \
@ -119,12 +118,6 @@ Enum(UI_BoxFlag)
x(AxisSize, UI_Size) \ x(AxisSize, UI_Size) \
/* ------------------------------------------- */ /* ------------------------------------------- */
Struct(UI_Tag)
{
String name;
u64 hash;
};
Enum(UI_StyleKind) Enum(UI_StyleKind)
{ {
#define X(name, type) UI_StyleKind_##name, #define X(name, type) UI_StyleKind_##name,
@ -180,21 +173,18 @@ Struct(UI_Stack)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Report types //~ Report types
Enum(UI_ReportFlag)
{
UI_ReportFlag_None = 0,
UI_ReportFlag_Active = (1 << 0),
UI_ReportFlag_Hovered = (1 << 1),
};
Struct(UI_Report) Struct(UI_Report)
{ {
UI_ReportFlag flags; b32 m1_held;
Vec2 activation_offset;
f32 hot_ratio; f32 hot;
f32 active_ratio; 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_p0;
Vec2 screen_p1; Vec2 screen_p1;
}; };
@ -291,7 +281,10 @@ Struct(UI_Frame)
Struct(UI_SharedState) Struct(UI_SharedState)
{ {
//- Control state //- Control state
i64 last_frame_begin_ns;
Vec2 cursor_pos; Vec2 cursor_pos;
UI_Key hovered_box;
UI_Key active_box;
//- Build state //- Build state
Arena *build_arena; Arena *build_arena;
@ -342,9 +335,19 @@ ResourceKey UI_GetDefaultFontResource(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Key helpers //~ 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_BackBoxFromKey(UI_Key key);
UI_Box *UI_FrontBoxFromKey(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 //~ Checkpoint helpers
@ -398,7 +401,7 @@ UI_Style UI_PopStyle(UI_StyleDesc desc);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Box //~ 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); void UI_SetBackgroundTexture(UI_Box *box, GPU_Resource *texture, Vec2 uv0, Vec2 uv1);
b32 UI_IsPointInBox(UI_Box *box, Vec2 point); b32 UI_IsPointInBox(UI_Box *box, Vec2 point);