correct slider cursor offset

This commit is contained in:
jacob 2025-12-31 23:21:18 -06:00
parent 102bb6dc36
commit 90a674724a
9 changed files with 193 additions and 155 deletions

View File

@ -548,6 +548,20 @@ Vec2I32 DivVec2I32Vec2I32(Vec2I32 a, Vec2I32 b)
////////////////////////////////////////////////////////////
//~ Vec4
//- Mul
Vec4 MulVec4(Vec4 v, f32 s)
{
return VEC4(v.x * s, v.y * s, v.z * s, v.w * s);
}
Vec4 MulVec4Vec4(Vec4 a, Vec4 b)
{
return VEC4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
}
//- Conversion
Vec4 Vec4FromU32(u32 v)
{
Vec4 result = Zi;

View File

@ -371,6 +371,11 @@ Vec2I32 SubVec2I32(Vec2I32 a, Vec2I32 b);
////////////////////////////////////////////////////////////
//~ Vec4
//- Mul
Vec4 MulVec4(Vec4 v, f32 s);
Vec4 MulVec4Vec4(Vec4 a, Vec4 b);
//- Conversion
Vec4 Vec4FromU32(u32 v);
u32 U32FromVec4(Vec4 v);

View File

@ -299,7 +299,7 @@ f64 FloatFromString(String str)
if (ok)
{
result = (f64)whole_part + ((f64)frac_part / PowU64(10, str.len - (frac_start_idx + 1)));
result = ((f64)whole_part + ((f64)frac_part / PowU64(10, str.len - (frac_start_idx + 1)))) * sign;
}
else
{

View File

@ -901,7 +901,7 @@ void P_MessageBox(P_MessageBoxKind kind, String message)
} break;
}
LogDebugF("Showing message box kind %F with text \"%F\"", FmtSint(kind), FmtString(message));
LogInfoF("Showing message box kind %F with text \"%F\"", FmtSint(kind), FmtString(message));
MessageBoxExW(0, message_wstr, title, mbox_type, 0);
EndScratch(scratch);

View File

@ -94,6 +94,7 @@ V_WidgetTheme V_GetWidgetTheme(void)
// theme.rounding = 1;
theme.rounding = TweakFloat(Lit("Rounding"), 1, 0, 1);
theme.text_color = Rgb32(0xffdddee0);
theme.text_padding_x = 5;
theme.text_padding_y = 5;
@ -120,6 +121,7 @@ void V_PushWidgetThemeStyles(V_WidgetTheme theme)
{
UI_Push(Font, theme.font);
UI_Push(FontSize, theme.font_size);
UI_Push(TextColor, theme.text_color);
}
////////////////////////////////////////////////////////////
@ -343,7 +345,7 @@ void V_TickForever(WaveLaneCtx *lane)
V_PushWidgetThemeStyles(theme);
UI_Key vis_box = UI_KeyF("vis box");
UI_Report vis_box_rep = UI_ReportFromKey(vis_box);
UI_BoxReports vis_box_reps = UI_ReportsFromKey(vis_box);
{
UI_Push(ChildLayoutAxis, Axis_Y);
UI_Push(Width, UI_GROW(1, 0));
@ -353,7 +355,7 @@ void V_TickForever(WaveLaneCtx *lane)
}
// TODO: Don't rely on ui report for draw size since it introduces one frame of delay when resizing
frame->ui_dims = RoundVec2(DimsFromRng2(vis_box_rep.screen_rect));
frame->ui_dims = RoundVec2(DimsFromRng2(vis_box_reps.draw.screen_rect));
frame->ui_dims.x = MaxF32(frame->ui_dims.x, 64);
frame->ui_dims.y = MaxF32(frame->ui_dims.y, 64);
frame->draw_dims = frame->ui_dims;
@ -784,7 +786,7 @@ void V_TickForever(WaveLaneCtx *lane)
{
panel_dfs->visited = 1;
UI_Report panel_rep = UI_ReportFromKey(panel->key);
UI_BoxReport panel_rep = UI_ReportsFromKey(panel->key).draw;
f32 panel_size = 0;
if (panel->axis == Axis_X)
{
@ -811,10 +813,10 @@ void V_TickForever(WaveLaneCtx *lane)
// Apply resize
if (resize_panel)
{
UI_Report child_rep = UI_ReportFromKey(resize_panel->key);
UI_Report divider_rep = UI_ReportFromKey(resize_panel->divider_key);
UI_BoxReport child_rep = UI_ReportsFromKey(resize_panel->key).draw;
UI_BoxReports divider_reps = UI_ReportsFromKey(resize_panel->divider_key);
f32 drag_offset = ui_frame->last_mouse_down_cursor_pos.v[panel->axis] - divider_rep.last_mouse_down_screen_anchor.v[panel->axis];
f32 drag_offset = ui_frame->drag_cursor_pos.v[panel->axis] - divider_reps.drag.screen_anchor.v[panel->axis];
f32 child_pref_size = 0;
child_pref_size += frame->ui_cursor.v[panel->axis];
@ -880,7 +882,7 @@ void V_TickForever(WaveLaneCtx *lane)
V_Window *close_window = 0;
{
UI_Key tab_row_key = UI_KeyF("tab row");
UI_Report tab_row_rep = UI_ReportFromKey(tab_row_key);
UI_BoxReport tab_row_rep = UI_ReportsFromKey(tab_row_key).draw;
UI_SetNext(Width, UI_GROW(1, 0));
UI_SetNext(Height, UI_SHRINK(0, 1));
@ -930,7 +932,7 @@ void V_TickForever(WaveLaneCtx *lane)
DrawableTab *right = first_drawable_tab;
for (DrawableTab *sibling = first_drawable_tab; sibling; sibling = sibling->next)
{
UI_Report sibling_rep = UI_ReportFromKey(sibling->key);
UI_BoxReport sibling_rep = UI_ReportsFromKey(sibling->key).draw;
f32 zone = CenterFromRng2(sibling_rep.screen_rect).x;
if (frame->ui_cursor.x <= zone)
{
@ -965,7 +967,7 @@ void V_TickForever(WaveLaneCtx *lane)
for (DrawableTab *tab = first_drawable_tab; tab; tab = tab->next)
{
UI_Push(Tag, tab->key.hash);
UI_Report tab_rep = UI_ReportFromKey(tab->key);
UI_BoxReport tab_rep = UI_ReportsFromKey(tab->key).draw;
if (tab == first_drawable_tab)
{
@ -991,7 +993,7 @@ void V_TickForever(WaveLaneCtx *lane)
f32 drag_threshold = 20;
if (tab_rep.m1.held)
{
Vec2 drag_start = ui_frame->last_mouse_down_cursor_pos;
Vec2 drag_start = ui_frame->drag_cursor_pos;
if (Vec2Len(SubVec2(frame->ui_cursor, drag_start)) > drag_threshold)
{
V.dragging_window = window;
@ -1013,14 +1015,9 @@ void V_TickForever(WaveLaneCtx *lane)
border_color = theme.button_active_color;
}
bg_color = LerpSrgb(bg_color, theme.button_hot_color, tab_rep.hot * (1.0 - tab_rep.selected));
bg_color = LerpSrgb(bg_color, theme.button_hot_color, tab_rep.hot);
bg_color = LerpSrgb(bg_color, theme.button_active_color, tab_rep.active * is_dragging);
border_color = LerpSrgb(border_color, theme.button_active_color, tab_rep.selected);
// if (is_dragging)
// {
// bg_color = Color_Blue;
// }
border_color = LerpSrgb(border_color, theme.button_active_color, tab_rep.misc);
String tab_name = Zi;
if (window->is_tile_window)
@ -1038,7 +1035,8 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(Width, UI_SHRINK(0, 0));
UI_SetNext(Height, UI_SHRINK(0, 0));
UI_SetNext(ChildAlignment, UI_Region_Left);
UI_SetNext(Flags, UI_BoxFlag_Interactable | (UI_BoxFlag_Selected * (active_window == window)));
UI_SetNext(Misc, window == active_window);
UI_SetNext(Flags, UI_BoxFlag_Interactable);
UI_SetNext(Text, tab_name);
UI_PushCP(UI_BuildRowEx(tab->key));
{
@ -1055,7 +1053,7 @@ void V_TickForever(WaveLaneCtx *lane)
// Build tab close button
{
UI_Key close_key = UI_KeyF("close");
UI_Report close_rep = UI_ReportFromKey(close_key);
UI_BoxReport close_rep = UI_ReportsFromKey(close_key).draw;
Vec4 close_color = Zi;
close_color = LerpSrgb(close_color, theme.button_hot_color, close_rep.hot);
@ -1089,7 +1087,7 @@ void V_TickForever(WaveLaneCtx *lane)
case DrawableTabKind_Ghost:
{
UI_Report rep = UI_ReportFromKey(tab->key);
UI_BoxReport rep = UI_ReportsFromKey(tab->key).draw;
Vec4 bg_color = Zi;
bg_color = LerpSrgb(bg_color, theme.button_hot_color, rep.exists);
@ -1120,7 +1118,7 @@ void V_TickForever(WaveLaneCtx *lane)
case DrawableTabKind_NewTab:
{
UI_Key key = UI_KeyF("new tab");
UI_Report rep = UI_ReportFromKey(key);
UI_BoxReport rep = UI_ReportsFromKey(key).draw;
Vec4 bg_color = Zi;
bg_color = LerpSrgb(bg_color, theme.button_hot_color, rep.hot);
@ -1172,7 +1170,7 @@ void V_TickForever(WaveLaneCtx *lane)
{
String name = S_NameFromTileKind(tile_kind);
UI_Key key = UI_KeyF("Tile %F", FmtString(name));
UI_Report rep = UI_ReportFromKey(key);
UI_BoxReport rep = UI_ReportsFromKey(key).draw;
if (rep.m1.downs)
{
@ -1186,7 +1184,7 @@ void V_TickForever(WaveLaneCtx *lane)
b32 is_selected = tile_kind == frame->equipped_tile;
Vec4 border_color = Zi;
border_color = LerpSrgb(border_color, theme.button_selected_color, rep.selected);
border_color = LerpSrgb(border_color, theme.button_selected_color, rep.misc);
border_color = LerpSrgb(border_color, theme.button_active_color, rep.hot);
UI_SetNext(BackgroundColor, bg_color);
@ -1194,7 +1192,8 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(Border, 1);
UI_SetNext(Width, UI_GROW(1, 0));
UI_SetNext(Height, UI_SHRINK(0, 0));
UI_SetNext(Flags, UI_BoxFlag_Interactable | (UI_BoxFlag_Selected * is_selected));
UI_SetNext(Misc, is_selected);
UI_SetNext(Flags, UI_BoxFlag_Interactable);
UI_PushCP(UI_BuildRowEx(key));
{
UI_SetNext(ChildAlignment, UI_Region_Center);
@ -1226,7 +1225,7 @@ void V_TickForever(WaveLaneCtx *lane)
if (panel->next != 0)
{
panel->divider_key = UI_KeyF("Divider");
UI_Report rep = UI_ReportFromKey(panel->divider_key);
UI_BoxReport rep = UI_ReportsFromKey(panel->divider_key).draw;
Vec4 active_color = theme.button_active_color;
Vec4 hot_color = LerpSrgb(theme.button_hot_color, theme.button_active_color, 0.25);
@ -1307,20 +1306,20 @@ void V_TickForever(WaveLaneCtx *lane)
{
UI_Push(Tag, palette->key.hash);
UI_Key titlebar_key = UI_KeyF("title bar");
UI_Report titlebar_rep = UI_ReportFromKey(titlebar_key);
UI_Report palette_rep = UI_ReportFromKey(palette->key);
UI_BoxReports titlebar_reps = UI_ReportsFromKey(titlebar_key);
UI_BoxReports palette_reps = UI_ReportsFromKey(palette->key);
Vec4 window_background_color = theme.window_background_color;
Vec4 window_border_color = theme.window_border_color;
Vec4 titlebar_color = Zi;
Vec4 titlebar_border_color = Zi;
Vec4 divider_color = theme.divider_color;
if (titlebar_rep.m1.held)
if (titlebar_reps.draw.m1.held)
{
Vec2 drag_offset = SubVec2(ui_frame->last_mouse_down_cursor_pos, palette_rep.last_mouse_down_screen_anchor);
Vec2 drag_offset = SubVec2(ui_frame->drag_cursor_pos, palette_reps.drag.screen_anchor);
palette->pos = SubVec2(frame->ui_cursor, drag_offset);
}
window_border_color = LerpSrgb(window_border_color, Rgb32(0x0078a6), titlebar_rep.hot);
window_border_color = LerpSrgb(window_border_color, Rgb32(0x0078a6), titlebar_reps.draw.hot);
f32 scale = LerpF32(0.85, 1, palette->show);
UI_Push(Tint, VEC4(1, 1, 1, palette->show));
@ -1464,7 +1463,7 @@ void V_TickForever(WaveLaneCtx *lane)
// Divider
UI_BuildDivider(UI_PIX(1, 1), divider_color, Axis_Y);
UI_Report item_rep = UI_ReportFromKey(item->key);
UI_BoxReport item_rep = UI_ReportsFromKey(item->key).draw;
if (item_rep.m1.presses)
{
if (item->flags & PaletteItemFlag_IsCmd)
@ -1483,6 +1482,9 @@ void V_TickForever(WaveLaneCtx *lane)
item_border_color = LerpSrgb(item_border_color, theme.button_active_color, item_rep.hot);
}
UI_Size item_height = UI_FNT(1.5, 1);
UI_Size tweak_height = UI_FNT(1.25, 1);
UI_SetNext(BorderColor, 0);
UI_SetNext(Rounding, UI_RPIX(0));
UI_PushCP(UI_BuildRow());
@ -1491,7 +1493,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(BackgroundColor, item_color);
UI_SetNext(Rounding, UI_RPIX(5));
UI_SetNext(Width, UI_GROW(1, 0));
UI_SetNext(Height, UI_FNT(1.5, 1));
UI_SetNext(Height, item_height);
UI_SetNext(ChildAlignment, UI_Region_Left);
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable);
UI_PushCP(UI_BuildRowEx(item->key));
@ -1525,7 +1527,7 @@ void V_TickForever(WaveLaneCtx *lane)
{
UI_BuildSpacer(UI_PIX(spacing * 0.5, 1), Axis_X);
UI_Key reset_key = UI_KeyF("reset");
UI_Report reset_rep = UI_ReportFromKey(reset_key);
UI_BoxReport reset_rep = UI_ReportsFromKey(reset_key).draw;
if (reset_rep.m1.presses > 0)
{
@ -1551,13 +1553,15 @@ void V_TickForever(WaveLaneCtx *lane)
UI_PopCP(UI_TopCP());
}
TweakFloat(Lit("Test"), 0, -50, 50);
switch (tweak_desc.kind)
{
// Boolean tweak
case TweakKind_Bool:
{
UI_Key cb_key = UI_KeyF("tweak checkbox");
UI_Report cb_rep = UI_ReportFromKey(cb_key);
UI_BoxReport cb_rep = UI_ReportsFromKey(cb_key).draw;
b32 tweak_bool = BoolFromString(new_tweak_str);
if (cb_rep.m1.downs)
@ -1593,11 +1597,13 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Key slider_key = UI_KeyF("tweak slider");
UI_Key marker_key = UI_KeyF("tweak slider marker");
UI_Report slider_rep = UI_ReportFromKey(slider_key);
UI_Report marker_rep = UI_ReportFromKey(marker_key);
UI_BoxReports slider_reps = UI_ReportsFromKey(slider_key);
UI_BoxReports marker_reps = UI_ReportsFromKey(marker_key);
Vec2 slider_pos = slider_rep.screen_rect.p0;
Vec2 slider_dims = DimsFromRng2(slider_rep.screen_rect);
Vec2 slider_pos = slider_reps.draw.screen_rect.p0;
Vec2 slider_dims = DimsFromRng2(slider_reps.draw.screen_rect);
Vec2 marker_dims = DimsFromRng2(marker_reps.draw.screen_rect);
Vec2 half_marker_dims = MulVec2(marker_dims, 0.5);
f64 range_min = tweak_desc.range.min;
f64 range_max = tweak_desc.range.max;
@ -1606,76 +1612,83 @@ void V_TickForever(WaveLaneCtx *lane)
range_max = range_min + 1;
}
if (TweakFloat(Lit("Test"), 0.5, 0, 1))
{
}
f64 tweak_float = FloatFromString(new_tweak_str);
{
Axis slider_axis = Axis_X;
if (slider_rep.m1.held)
if (slider_reps.draw.m1.held)
{
f64 initial_marker_width = DimsFromRng2(marker_reps.drag.screen_rect).x;
f64 initial_slider_pos = slider_reps.drag.screen_rect.p0.x;
f64 initial_slider_width = DimsFromRng2(slider_reps.drag.screen_rect).x - initial_marker_width;
f64 initial_cursor = ui_frame->drag_cursor_pos.x;
f64 initial_ratio = slider_reps.drag.misc;
Vec2 initial_start = slider_rep.last_mouse_down_screen_rect.p0;
Vec2 initial_end = slider_rep.last_mouse_down_screen_rect.p1;
Vec2 initial_dims = SubVec2(initial_end, initial_start);
f64 virtual_slider_start = initial_cursor - (initial_slider_width * initial_ratio);
f64 virtual_slider_end = virtual_slider_start + initial_slider_width;
Vec2 initial_marker_offset = SubVec2(marker_rep.last_mouse_down_screen_anchor, initial_start);
Vec2 initial_cursor = ui_frame->last_mouse_down_cursor_pos;
f64 virtual_cursor = ClampF32(frame->ui_cursor.x, virtual_slider_start, virtual_slider_end);
f64 virtual_cursor_ratio = (virtual_cursor - virtual_slider_start) / (virtual_slider_end - virtual_slider_start);
Vec2 virtual_start = SubVec2(initial_cursor, initial_marker_offset);
Vec2 virtual_end = AddVec2(virtual_start, initial_dims);
Vec2 virtual_cursor_offset = SubVec2(frame->ui_cursor, virtual_start);
Vec2 virtual_cursor_ratio = DivVec2Vec2(virtual_cursor_offset, initial_dims);
virtual_cursor_ratio = ClampVec2(virtual_cursor_ratio, RNG2(VEC2(0, 0), VEC2(1, 1)));
tweak_float = LerpF64(range_min, range_max, virtual_cursor_ratio);
tweak_float = ClampF64(tweak_float, range_min, range_max);
f32 precision = 3; // FIXME: Remove this
tweak_float = LerpF64(range_min, range_max, virtual_cursor_ratio.v[slider_axis]);
f64 precision = 6; // FIXME: Remove this
new_tweak_str = StringFromFloat(frame->arena, tweak_float, precision);
}
if (slider_rep.is_hot)
if (slider_reps.draw.is_hot)
{
WND_PushCmd(
window_frame,
.kind = WND_CmdKind_SetCursor,
slider_axis == Axis_X ? WND_CursorKind_HorizontalResize : WND_CursorKind_VerticalResize
);
WND_PushCmd(window_frame, .kind = WND_CmdKind_SetCursor, WND_CursorKind_HorizontalResize);
}
}
f32 ratio = 0;
ratio = (tweak_float - range_min) / (range_max - range_min);
ratio = ClampF32(ratio, 0, 1);
UI_BuildSpacer(UI_PIX(spacing, 1), Axis_X);
// Tweak slider
Vec4 slider_bg_color = Zi;
Vec4 slider_bg_color = theme.window_background_color;
Vec4 slider_border_color = theme.window_border_color;
slider_border_color = LerpSrgb(slider_border_color, theme.button_active_color, slider_rep.hot);
Vec4 slider_progress_color = theme.color_positive;
Vec4 marker_bg_color = slider_bg_color;
slider_border_color = LerpSrgb(slider_border_color, theme.button_active_color, slider_reps.draw.hot);
marker_bg_color = LerpSrgb(marker_bg_color, theme.text_color, slider_reps.draw.hot);
UI_SetNext(BackgroundColor, slider_bg_color);
UI_SetNext(BorderColor, slider_border_color);
UI_SetNext(Rounding, UI_RGROW(theme.rounding));
UI_SetNext(Border, 2);
UI_SetNext(Border, 1);
UI_SetNext(Width, UI_FNT(10, 1));
UI_SetNext(Height, UI_FNT(1.25, 1));
UI_SetNext(Height, tweak_height);
UI_SetNext(Flags, UI_BoxFlag_Interactable);
UI_SetNext(Misc, ratio);
UI_PushCP(UI_BuildRowEx(slider_key));
{
// FIXME: Marker pos should account for marker width
f32 ratio = 0;
ratio = (tweak_float - range_min) / (range_max - range_min);
ratio = ClampF32(ratio, 0, 1);
f32 marker_pos = ratio * slider_dims.x;
f32 marker_pos = ratio * (slider_dims.x - marker_dims.x);
UI_SetNext(BackgroundColor, slider_bg_color);
UI_SetNext(BorderColor, slider_border_color);
UI_SetNext(Rounding, UI_RGROW(theme.rounding));
UI_SetNext(Border, 2);
UI_SetNext(Width, UI_FNT(1.25, 1));
UI_SetNext(Height, UI_FNT(1.25, 1));
UI_SetNext(Anchor, UI_Region_Center);
UI_SetNext(FloatingPos, VEC2(marker_pos, 0));
UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_BuildBoxEx(marker_key);
// Slider progress
{
UI_SetNext(BackgroundColor, slider_progress_color);
// UI_SetNext(Rounding, UI_RGROW(theme.rounding));
UI_SetNext(Rounding, 0);
UI_SetNext(BorderColor, 0);
UI_SetNext(Border, 1);
UI_SetNext(Width, UI_PIX(marker_pos + half_marker_dims.x, 0));
UI_SetNext(Height, tweak_height);
UI_BuildBox();
}
// Slider marker
{
UI_SetNext(BackgroundColor, marker_bg_color);
UI_SetNext(BorderColor, slider_border_color);
UI_SetNext(Rounding, UI_RGROW(theme.rounding));
UI_SetNext(Border, 1);
UI_SetNext(Width, tweak_height);
UI_SetNext(Height, tweak_height);
// UI_SetNext(Anchor, UI_Region_Center);
UI_SetNext(FloatingPos, VEC2(marker_pos, 0));
UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_BuildBoxEx(marker_key);
}
}
UI_PopCP(UI_TopCP());
} break;
@ -1691,7 +1704,7 @@ void V_TickForever(WaveLaneCtx *lane)
for (u64 i = 0; i < countof(item->hotkeys); ++i)
{
UI_Key hotkey_key = UI_KeyF("hotkey%F", FmtUint(i));
UI_Report hotkey_rep = UI_ReportFromKey(hotkey_key);
UI_BoxReport hotkey_rep = UI_ReportsFromKey(hotkey_key).draw;
Vec4 hotkey_color = Zi;
Vec4 hotkey_border_color = Zi;
@ -1759,7 +1772,7 @@ void V_TickForever(WaveLaneCtx *lane)
if (frame->show_console)
{
UI_Key dbg_box = UI_KeyF("Debug box");
UI_Report dbg_rep = UI_ReportFromKey(dbg_box);
UI_BoxReport dbg_rep = UI_ReportsFromKey(dbg_box).draw;
Vec2 dbg_dims = DimsFromRng2(dbg_rep.screen_rect);
f32 padding = 20;

View File

@ -46,6 +46,7 @@ Struct(V_WidgetTheme)
Vec4 color_positive;
Vec4 color_negative;
Vec4 text_color;
f32 text_padding_x;
f32 text_padding_y;
};

View File

@ -341,23 +341,18 @@ void UI_PushDefaults(void)
switch (kind)
{
default: break;
case UI_StyleKind_Parent: { desc.style.Parent = UI_RootKey; } break;
case UI_StyleKind_Width: { desc.style.Width = UI_GROW(1, 0); } break;
case UI_StyleKind_Height: { desc.style.Height = UI_GROW(1, 0); }
case UI_StyleKind_Scale: { desc.style.Scale = VEC2(1, 1); } break;
case UI_StyleKind_Font: { desc.style.Font = UI_GetDefaultFont(); } break;
u8 prefetch[127] = Zi;
for (u64 idx = 0; idx < countof(prefetch); ++idx)
{
prefetch[idx] = idx;
}
case UI_StyleKind_Parent: { desc.style.Parent = UI_RootKey; } break;
case UI_StyleKind_Width: { desc.style.Width = UI_GROW(1, 0); } break;
case UI_StyleKind_Height: { desc.style.Height = UI_GROW(1, 0); }
case UI_StyleKind_Scale: { desc.style.Scale = VEC2(1, 1); } break;
case UI_StyleKind_Font: { desc.style.Font = UI_GetDefaultFont(); } break;
case UI_StyleKind_FontSize: { desc.style.FontSize = 16.0f; } break;
case UI_StyleKind_Tint: { desc.style.Tint = Color_White; } break;
case UI_StyleKind_TextColor: { desc.style.TextColor = Color_White; } break;
case UI_StyleKind_Tag: { desc.style.Tag = HashFnv64(Fnv64Basis, Lit("root")); } break;
case UI_StyleKind_DebugColor: { desc.style.DebugColor = Rgba(1, 0, 1, 0.5); } break;
case UI_StyleKind_InvisibleDebugColor: { desc.style.InvisibleDebugColor = Rgba(0, 1, 1, 0.25); } break;
case UI_StyleKind_BackgroundTextureSliceUv: { desc.style.BackgroundTextureSliceUv = RNG2(VEC2(0, 0), VEC2(1, 1)); } break;
case UI_StyleKind_InvisibleDebugColor: { desc.style.InvisibleDebugColor = Rgba(0, 1, 1, 0.25); } break;
case UI_StyleKind_BackgroundTextureSliceUv: { desc.style.BackgroundTextureSliceUv = RNG2(VEC2(0, 0), VEC2(1, 1)); } break;
};
UI_PushStyle(desc);
}
@ -518,11 +513,12 @@ UI_Key UI_BuildBoxEx(UI_Key semantic_key)
n->cmd.box.border = UI_Top(Border);
n->cmd.box.font = UI_Top(Font);
n->cmd.box.font_size = UI_Top(FontSize);
n->cmd.box.rounding = UI_Top(Rounding);
n->cmd.box.text_color = UI_Top(TextColor);
n->cmd.box.text = UI_Top(Text);
n->cmd.box.anchor = UI_Top(Anchor);
n->cmd.box.floating_pos = UI_Top(FloatingPos);
n->cmd.box.misc = UI_Top(Misc);
}
++frame->cmds_count;
SllQueuePush(frame->first_cmd_node, frame->last_cmd_node, n);
@ -546,14 +542,14 @@ void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Rng2 uv)
////////////////////////////////////////////////////////////
//~ Report
UI_Report UI_ReportFromKey(UI_Key key)
UI_BoxReports UI_ReportsFromKey(UI_Key key)
{
UI_Report result = Zi;
UI_BoxReports result = Zi;
UI_Box *box = UI_BoxFromKey(key);
if (box)
{
result = box->report;
result = box->reports;
}
return result;
@ -636,7 +632,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
//- Process controller events
frame->cursor_pos = last_frame->cursor_pos;
frame->last_mouse_down_cursor_pos = last_frame->last_mouse_down_cursor_pos;
frame->drag_cursor_pos = last_frame->drag_cursor_pos;
if (last_frame->boxes_pre != 0)
{
@ -660,6 +656,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
for (u64 pre_index = UI.boxes_count; pre_index-- > 0;)
{
UI_Box *box = last_frame->boxes_pre[pre_index];
UI_BoxReport *report = &box->reports.draw;
b32 is_cursor_in_box = 0;
{
// TODO: More efficient test. This logic is just copied from the renderer's SDF function for now.
@ -686,20 +683,20 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
}
is_cursor_in_box = non_corner_edge_dist >= 0 && corner_edge_dist >= 0;
}
box->report.is_hovered = is_cursor_in_box;
report->is_hovered = is_cursor_in_box;
if (top_hovered_box == 0 && box->desc.flags & UI_BoxFlag_Interactable && is_cursor_in_box)
{
top_hovered_box = box;
}
box->report.m1.ups = 0;
box->report.m1.downs = 0;
box->report.m1.presses = 0;
box->report.m2.ups = 0;
box->report.m2.downs = 0;
box->report.m2.presses = 0;
box->report.m3.ups = 0;
box->report.m3.downs = 0;
box->report.m3.presses = 0;
report->m1.ups = 0;
report->m1.downs = 0;
report->m1.presses = 0;
report->m2.ups = 0;
report->m2.downs = 0;
report->m2.presses = 0;
report->m3.ups = 0;
report->m3.downs = 0;
report->m3.presses = 0;
}
// Update state from controller events
@ -720,18 +717,18 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
{
if (cev.button == Button_M1)
{
++top_hovered_box->report.m1.downs;
top_hovered_box->report.m1.held = 1;
++top_hovered_box->reports.draw.m1.downs;
top_hovered_box->reports.draw.m1.held = 1;
}
else if (cev.button == Button_M2)
{
++top_hovered_box->report.m2.downs;
top_hovered_box->report.m2.held = 1;
++top_hovered_box->reports.draw.m2.downs;
top_hovered_box->reports.draw.m2.held = 1;
}
else if (cev.button == Button_M3)
{
++top_hovered_box->report.m3.downs;
top_hovered_box->report.m3.held = 1;
++top_hovered_box->reports.draw.m3.downs;
top_hovered_box->reports.draw.m3.held = 1;
}
active_box = top_hovered_box;
}
@ -748,12 +745,12 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
{
if (active_box == top_hovered_box)
{
++active_box->report.m1.presses;
++active_box->reports.draw.m1.presses;
}
++active_box->report.m1.ups;
if (active_box->report.m1.held)
++active_box->reports.draw.m1.ups;
if (active_box->reports.draw.m1.held)
{
active_box->report.m1.held = 0;
active_box->reports.draw.m1.held = 0;
active_box = 0;
}
}
@ -761,12 +758,12 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
{
if (active_box == top_hovered_box)
{
++active_box->report.m2.presses;
++active_box->reports.draw.m2.presses;
}
++active_box->report.m2.ups;
if (active_box->report.m2.held)
++active_box->reports.draw.m2.ups;
if (active_box->reports.draw.m2.held)
{
active_box->report.m2.held = 0;
active_box->reports.draw.m2.held = 0;
active_box = 0;
}
}
@ -774,12 +771,12 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
{
if (active_box == top_hovered_box)
{
++active_box->report.m3.presses;
++active_box->reports.draw.m3.presses;
}
++active_box->report.m3.ups;
if (active_box->report.m3.held)
++active_box->reports.draw.m3.ups;
if (active_box->reports.draw.m3.held)
{
active_box->report.m3.held = 0;
active_box->reports.draw.m3.held = 0;
active_box = 0;
}
}
@ -804,40 +801,40 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
for (u64 pre_index = 0; pre_index < UI.boxes_count; ++pre_index)
{
UI_Box *box = last_frame->boxes_pre[pre_index];
UI_Report *report = &box->report;
UI_BoxReport *report = &box->reports.draw;
report->is_hot = box == hot_box;
report->is_selected = !!(box->desc.flags & UI_BoxFlag_Selected);
f32 target_exists = box->last_build_tick >= (frame->tick - 1);
f32 target_hovered = report->is_hovered;
f32 target_hot = report->is_hot;
f32 target_active = box == active_box;
f32 target_selected = report->is_selected;
f64 target_misc = box->desc.misc;
// TODO: Configurable per-box blend rates
f32 exists_blend_rate = (30 * frame->dt);
f32 hot_blend_rate = target_hot == 1 ? 1 : (15 * frame->dt);
f32 active_blend_rate = target_active == 1 ? 1 : (15 * frame->dt);
f32 hovered_blend_rate = target_hovered == 1 ? 1 : (15 * frame->dt);
f32 selected_blend_rate = (30 * frame->dt);
f64 misc_blend_rate = (30 * frame->dt);
report->exists = LerpF32(report->exists, target_exists, exists_blend_rate);
report->hot = LerpF32(report->hot, target_hot, hot_blend_rate);
report->active = LerpF32(report->active, target_active, active_blend_rate);
report->hovered = LerpF32(report->hovered, target_hovered, hovered_blend_rate);
report->selected = LerpF32(report->selected, target_selected, selected_blend_rate);
// report->misc = LerpF32(report->misc, target_misc, misc_blend_rate);
report->misc = target_misc;
report->screen_rect = box->screen_rect;
report->screen_anchor = box->screen_anchor;
if (mouse_downs > 0)
{
report->last_mouse_down_screen_rect = box->screen_rect;
report->last_mouse_down_screen_anchor = box->screen_anchor;
box->reports.drag = *report;
}
}
if (mouse_downs > 0)
{
frame->last_mouse_down_cursor_pos = frame->cursor_pos;
frame->drag_cursor_pos = frame->cursor_pos;
}
frame->top_hovered_box = top_hovered_box ? top_hovered_box->key : UI_NilKey;
@ -1540,6 +1537,7 @@ void UI_EndFrame(UI_Frame *frame)
if (is_visible || AnyBit(frame->frame_flags, UI_FrameFlag_Debug))
{
Vec4 debug_lin = is_visible ? LinearFromSrgb(box->desc.debug_color) : LinearFromSrgb(box->desc.invisible_debug_color);
Vec4 tint_lin = LinearFromSrgb(box->desc.tint);
// Box rect
{
@ -1548,7 +1546,7 @@ void UI_EndFrame(UI_Frame *frame)
rect->background_lin = LinearFromSrgb(box->desc.background_color);
rect->border_lin = LinearFromSrgb(box->desc.border_color);
rect->debug_lin = debug_lin;
rect->tint_lin = LinearFromSrgb(box->desc.tint);
rect->tint_lin = tint_lin;
rect->border = box->desc.border;
rect->tl_rounding = box->rounding_tl;
rect->tr_rounding = box->rounding_tr;
@ -1661,6 +1659,8 @@ void UI_EndFrame(UI_Frame *frame)
baseline = CeilVec2(baseline);
// Push text rects
Vec4 text_color_lin = LinearFromSrgb(box->desc.text_color);
text_color_lin = MulVec4Vec4(text_color_lin, tint_lin);
for (u64 rect_idx = 0; rect_idx < final_rects_count; ++rect_idx)
{
GC_RunRect rr = final_rects[rect_idx];
@ -1669,7 +1669,7 @@ void UI_EndFrame(UI_Frame *frame)
{
UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect);
rect->debug_lin = debug_lin;
rect->tint_lin = LinearFromSrgb(box->desc.tint);
rect->tint_lin = text_color_lin;
rect->tex = rr.tex;
rect->tex_slice_uv = rr.tex_slice_uv;
rect->bounds = rr.bounds;

View File

@ -91,7 +91,6 @@ Enum(UI_BoxFlag)
UI_BoxFlag_NoTextTruncation = (1 << 2),
UI_BoxFlag_Floating = (1 << 3),
UI_BoxFlag_NoFloatingClamp = (1 << 4),
UI_BoxFlag_Selected = (1 << 5),
};
////////////////////////////////////////////////////////////
@ -119,9 +118,11 @@ Enum(UI_BoxFlag)
X(Rounding, UI_Round) \
X(Font, GC_FontKey) \
X(FontSize, f32) \
X(TextColor, Vec4) \
X(Text, String) \
X(BackgroundTexture, G_Texture2DRef) \
X(BackgroundTextureSliceUv, Rng2) \
X(Misc, f64) \
/* --------------------------------------------- */ \
/* --------------- Virtual styles -------------- */ \
/* --------------------------------------------- */ \
@ -191,29 +192,29 @@ Struct(UI_MouseReport)
i32 presses; // Mouse button events while box is active and hovered
};
Struct(UI_Report)
Struct(UI_BoxReport)
{
b32 is_hovered;
b32 is_hot;
b32 is_selected;
f32 exists;
f32 hovered;
f32 hot;
f32 active;
f32 selected;
f64 misc;
UI_MouseReport m1;
UI_MouseReport m2;
UI_MouseReport m3;
// Where was this box rendered in screen coordinates
Rng2 screen_rect;
Vec2 screen_anchor;
};
// Where was this box rendered during the last mouse press
Rng2 last_mouse_down_screen_rect;
Vec2 last_mouse_down_screen_anchor;
Struct(UI_BoxReports)
{
UI_BoxReport draw; // Box data used for last render
UI_BoxReport drag; // Box data during last mouse button down event
};
////////////////////////////////////////////////////////////
@ -244,6 +245,7 @@ Struct(UI_BoxDesc)
Vec4 tint;
f32 border;
Vec2 scale;
Vec4 text_color;
String text;
GC_FontKey font;
f32 font_size;
@ -251,6 +253,7 @@ Struct(UI_BoxDesc)
UI_Region child_alignment;
UI_Region anchor;
Vec2 floating_pos;
f64 misc;
};
Struct(UI_Cmd)
@ -284,7 +287,7 @@ Struct(UI_Box)
//- Persistent data
UI_Box *next_in_bin;
UI_Box *prev_in_bin;
UI_Report report;
UI_BoxReports reports;
i64 last_build_tick;
i64 old_gen;
@ -380,7 +383,7 @@ Struct(UI_Frame)
// Control
Vec2 cursor_pos;
Vec2 last_mouse_down_cursor_pos;
Vec2 drag_cursor_pos;
UI_Key top_hovered_box;
UI_Key hot_box;
UI_Key active_box;
@ -518,7 +521,7 @@ void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Rng2 uv);
////////////////////////////////////////////////////////////
//~ Report
UI_Report UI_ReportFromKey(UI_Key key);
UI_BoxReports UI_ReportsFromKey(UI_Key key);
////////////////////////////////////////////////////////////
//~ Begin frame

View File

@ -8,6 +8,7 @@ UI_Key UI_BuildLabel(String text)
f32 font_size = UI_Top(FontSize);
Vec2 scale = UI_Top(Scale);
Vec4 tint = UI_Top(Tint);
Vec4 text_color = UI_Top(TextColor);
UI_Region alignment = UI_Top(ChildAlignment);
UI_Key key = Zi;
@ -19,6 +20,7 @@ UI_Key UI_BuildLabel(String text)
UI_Push(Tint, tint);
UI_Push(Font, font);
UI_Push(FontSize, font_size);
UI_Push(TextColor, text_color);
UI_Push(Width, UI_SHRINK(0, 1));
UI_Push(Height, UI_SHRINK(0, 1));
UI_Push(Text, text);