ui control testing

This commit is contained in:
jacob 2025-11-03 00:34:13 -06:00
parent 687cc88a64
commit 67ba54274f
8 changed files with 381 additions and 165 deletions

View File

@ -614,6 +614,7 @@ ForceInline void UnlockTicketMutex(TicketMutex *tm)
#if LanguageIsC
#define STRING(size, data) ((String) { (size), (data) })
#define Zstr ((String) { 0, 0})
#define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) }
#define LitNoCast(cstr_lit) { .len = (sizeof((cstr_lit)) - 1), .text = (u8 *)(cstr_lit) }
#define StringFromPointers(p0, p1) ((String) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 })

View File

@ -146,9 +146,6 @@ Struct(ControllerEvent)
/* ControllerEventKind_MouseMove */
Vec2I32 mouse_delta;
/* Should be incremented by systems that want to consume the input */
u32 consumed;
};
Struct(ControllerEventsArray)

View File

@ -395,14 +395,14 @@ void PP_UpdateUser(void)
g->screen_size.y = MaxI32(g->screen_size.y, 1);
//- Begin UI
UI_BeginBuild(&controller_events);
UI_BeginBuild(controller_events);
UI_Push(LayoutAxis, Axis_Y);
if (window_frame.forced_top)
{
UI_SetNext(Border, 10);
UI_SetNext(BorderColor, Rgba32F(1, 0, 0, 0.5));
}
UI_Box *pp_root_box = UI_BuildBox(UI_NilKey);
UI_Box *pp_root_box = UI_BuildBox(Lit("pp root"));
PP_PushGameUiStyle();
UI_Push(Parent, pp_root_box);
@ -679,7 +679,7 @@ void PP_UpdateUser(void)
if (g->bind_states[PP_BindKind_DebugLister].num_presses > 0)
{
g->debug_lister = !g->debug_lister;
g->lister_active = !g->lister_active;
}
{
@ -1938,21 +1938,32 @@ void PP_UpdateUser(void)
}
/* Draw lister */
if (g->debug_lister)
if (g->lister_active)
{
Vec2 size = VEC2(400, 500);
UI_PushCheckpoint();
{
Vec2 size = VEC2(400, 500);
UI_SetNext(LayoutAxis, Axis_Y);
UI_SetNext(BackgroundColor, Rgba32F(0.075, 0.075, 0.075, 0.99));
UI_SetNext(BorderColor, Rgba32F(0.2, 0.2, 0.2, 1));
UI_SetNext(Border, 2);
UI_SetNext(Rounding, 0.1);
UI_SetNext(Parent, pp_root_box);
UI_SetNext(Flags, UI_BoxFlag_Floating | UI_BoxFlag_ClampFloatingX | UI_BoxFlag_ClampFloatingY);
UI_SetNext(FloatingPos, g->debug_lister_pos);
UI_SetNext(Width, UI_PIX(size.x, 0));
UI_SetNext(Height, UI_PIX(size.y, 0));
UI_Box *lister_box = UI_BuildBox(UI_NilKey);
UI_Event ev = UI_EventFromKey(g->lister_key);
if (ev.flags & UI_EventFlag_Active)
{
g->lister_pos = SubVec2(g->ui_cursor, ev.activation_offset);
}
UI_SetNext(LayoutAxis, Axis_Y);
UI_SetNext(BackgroundColor, Rgba32F(0.075, 0.075, 0.075, 0.99));
UI_SetNext(BorderColor, Rgba32F(0.2, 0.2, 0.2, 1));
UI_SetNext(Border, 2);
UI_SetNext(Rounding, 0.1);
UI_SetNext(Parent, pp_root_box);
UI_SetNext(Flags, UI_BoxFlag_Floating | UI_BoxFlag_ClampFloatingX | UI_BoxFlag_ClampFloatingY);
UI_SetNext(FloatingPos, g->lister_pos);
UI_SetNext(Width, UI_PIX(size.x, 0));
UI_SetNext(Height, UI_PIX(size.y, 0));
UI_Box *lister_box = UI_BuildBox(Lit("lister"));
g->lister_key = lister_box->key;
}
UI_PopCheckpoint();
}
/* Draw debug info */
@ -1968,7 +1979,7 @@ void PP_UpdateUser(void)
UI_SetNext(Width, UI_FIT(0));
UI_SetNext(Height, UI_FIT(1));
UI_SetNext(Tint, 0);
UI_Box *dbg_box = UI_BuildBox(UI_NilKey);
UI_Box *dbg_box = UI_BuildBox(Lit("dbg"));
UI_PushCheckpoint();
{
UI_Push(Parent, dbg_box);
@ -2272,7 +2283,7 @@ void PP_UpdateUser(void)
}
/* Render UI */
g->gpu_submit_fence_target = UI_EndBuild(g->ui_target);
g->gpu_submit_fence_target = UI_EndBuild(g->ui_target, g->ui_to_screen_xf);
//////////////////////////////
//- Present & end frame

View File

@ -250,8 +250,9 @@ Struct(PP_SharedUserState)
b32 debug_camera_panning;
b32 debug_camera;
b32 debug_lister;
Vec2 debug_lister_pos;
b32 lister_active;
Vec2 lister_pos;
UI_Key lister_key;
b32 debug_draw;
b32 debug_console;

View File

@ -60,7 +60,7 @@ UI_Box *PP_BuildDebugConsole(b32 minimized)
// UI_SetNext(Height, UI_FILL(0.33, 1));
UI_SetNext(Height, UI_FIT(1));
}
console_box = UI_BuildBox(UI_NilKey);
console_box = UI_BuildBox(Lit("Console box"));
UI_Push(Parent, console_box);
}
{
@ -124,7 +124,7 @@ UI_Box *PP_BuildDebugConsole(b32 minimized)
UI_SetNext(BorderColor, Rgba32F(0.25, 0.25, 0.25, 1));
UI_SetNext(Rounding, 0);
UI_SetNext(Border, 1);
UI_Box *log_box = UI_BuildBox(UI_NilKey);
UI_Box *log_box = UI_BuildBox(Zstr);
UI_Push(Parent, log_box);
}
{
@ -135,7 +135,7 @@ UI_Box *PP_BuildDebugConsole(b32 minimized)
UI_SetNext(Width, UI_FILL(1, 0));
UI_SetNext(Height, UI_TXT(1));
UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_Box *log_textbox = UI_BuildBox(UI_NilKey);
UI_Box *log_textbox = UI_BuildBox(Zstr);
}
}
UI_PopCheckpoint();

View File

@ -3,12 +3,11 @@
UI_Box *UI_BuildLabel(String text)
{
UI_Key key = UI_KeyFromString(0, text);
UI_SetNext(Width, UI_TXT(0));
UI_SetNext(Height, UI_TXT(0));
UI_SetNext(Text, text);
UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_Box *box = UI_BuildBox(UI_NilKey);
UI_Box *box = UI_BuildBox(Zstr);
return box;
}
@ -41,6 +40,6 @@ UI_Box *UI_BuildSpacer(UI_Size size)
{
UI_SetNext(Height, size);
}
UI_Box *box = UI_BuildBox(UI_NilKey);
UI_Box *box = UI_BuildBox(Zstr);
return box;
}

View File

@ -21,27 +21,42 @@ ResourceKey UI_GetDefaultFontResource(void)
////////////////////////////////////////////////////////////
//~ Key helpers
u64 UI_HashFromTop(void)
UI_Box *UI_BackBoxFromKey(UI_Key key)
{
UI_Box *parent_box = UI_PeekTop(Parent);
u64 tag_hash = UI_PeekTop(Tag);
return RandU64FromSeeds(parent_box->key.hash, tag_hash);
}
u64 UI_HashFromString(u64 seed, String str)
{
if (seed == 0)
UI_SharedState *g = &UI_shared_state;
UI_Box *back_box = 0;
if (key.hash != 0)
{
seed = UI_HashFromTop();
UI_BoxBin *back_bin = &g->back_box_bins[key.hash % UI_NumBoxLookupBins];
for (UI_Box *tmp = back_bin->first; tmp; tmp = tmp->next_in_bin)
{
if (tmp->key.hash == key.hash)
{
back_box = tmp;
break;
}
}
}
return HashFnv64(seed, str);
return back_box;
}
UI_Key UI_KeyFromString(u64 seed, String str)
UI_Box *UI_FrontBoxFromKey(UI_Key key)
{
UI_Key result = ZI;
result.hash = UI_HashFromString(seed, str);
return result;
UI_SharedState *g = &UI_shared_state;
UI_Box *front_box = 0;
if (key.hash != 0)
{
UI_BoxBin *front_bin = &g->box_bins[key.hash % UI_NumBoxLookupBins];
for (UI_Box *tmp = front_bin->first; tmp; tmp = tmp->next_in_bin)
{
if (tmp->key.hash == key.hash)
{
front_box = tmp;
break;
}
}
}
return front_box;
}
////////////////////////////////////////////////////////////
@ -70,10 +85,7 @@ void UI_PopCheckpoint(void)
UI_SharedState *g = &UI_shared_state;
UI_Checkpoint *cp = g->top_checkpoint;
u64 v = cp->v;
if (v == 0)
{
DEBUGBREAKABLE;
}
/* Pop styles */
for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind)
{
UI_StyleNode *n = g->style_tops[kind];
@ -100,26 +112,30 @@ UI_StyleNode *UI_PushStyleNode(UI_Style desc)
UI_StyleNode *n = g->style_tops[desc.kind];
if (!n->style.forced)
{
if (n->style.pop_when_used)
{
ZeroStruct(n);
}
else
{
n = g->first_free_style_node;
if (n)
if (n->style.pop_when_used)
{
g->first_free_style_node = n->next;
ZeroStruct(n);
}
else
{
n = PushStruct(g->build_arena, UI_StyleNode);
n = g->first_free_style_node;
if (n)
{
g->first_free_style_node = n->next;
ZeroStruct(n);
}
else
{
n = PushStruct(g->build_arena, UI_StyleNode);
}
n->next = g->style_tops[desc.kind];
}
n->next = g->style_tops[desc.kind];
n->style = desc;
n->checkpoint = g->top_checkpoint->v;
}
n->style = desc;
n->checkpoint = g->top_checkpoint->v;
/* Initialize style data from desc */
switch (desc.kind)
{
default: break;
@ -128,6 +144,15 @@ UI_StyleNode *UI_PushStyleNode(UI_Style desc)
{
n->style.Text = PushString(g->build_arena, desc.Text);
} break;
case UI_StyleKind_Tag:
{
n->style.Tag.name = PushString(g->build_arena, desc.Tag.name);
if (n->style.Tag.hash == 0)
{
n->style.Tag.hash = HashFnv64(g->style_tops[desc.kind]->style.Tag.hash, n->style.Tag.name);
}
} break;
}
}
g->style_tops[desc.kind] = n;
@ -169,13 +194,25 @@ UI_Style UI_StyleFromTopNode(UI_StyleKind kind, b32 use)
////////////////////////////////////////////////////////////
//~ Box helpers
UI_Box *UI_BuildBox(UI_Key key)
UI_Box *UI_BuildBox(String seed)
{
UI_SharedState *g = &UI_shared_state;
UI_BoxBin *bin = &g->box_bins[key.hash % UI_NumBoxLookupBins];
UI_BoxBin *back_bin = &g->back_box_bins[key.hash % UI_NumBoxLookupBins];
/* Calculate key */
UI_Box *parent = UI_UseTop(Parent);
UI_Tag tag = UI_UseTop(Tag);
UI_Key key = ZI;
if (seed.len > 0)
{
key.hash = RandU64FromSeeds(key.hash, parent->key.hash);
key.hash = RandU64FromSeeds(key.hash, tag.hash);
key.hash = HashFnv64(key.hash, seed);
}
/* Insert into lookup */
UI_BoxBin *bin = &g->box_bins[key.hash % UI_NumBoxLookupBins];
UI_Box *box = PushStruct(g->build_arena, UI_Box);
UI_Box *back_box = 0;
if (key.hash != 0)
{
#if RtcIsEnabled
@ -190,33 +227,20 @@ UI_Box *UI_BuildBox(UI_Key key)
}
#endif
DllPushBackNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
back_box = UI_BackBoxFromKey(key);
}
/* Find previous build's box from hash */
UI_Box *back_box = 0;
if (key.hash != 0)
{
for (UI_Box *tmp = back_bin->first; tmp; tmp = tmp->next_in_bin)
{
if (tmp->key.hash == key.hash)
{
back_box = tmp;
break;
}
}
}
if (back_box)
{
*box = *back_box;
}
box->parent = parent;
box->key = key;
++g->boxes_count;
box->key = key;
/* Persist data from back box */
if (back_box != 0)
{
box->event = back_box->event;
}
/* Pull from style stack */
box->flags = UI_UseTop(Flags);
box->parent = UI_UseTop(Parent);
box->pref_size[Axis_X] = UI_UseTop(Width);
box->pref_size[Axis_Y] = UI_UseTop(Height);
box->layout_axis = UI_UseTop(LayoutAxis);
@ -237,8 +261,8 @@ UI_Box *UI_BuildBox(UI_Key key)
box->font = F_LoadFontAsync(box->font_resource, box->font_size);
}
DllPushBack(box->parent->first, box->parent->last, box);
++box->parent->count;
DllPushBack(parent->first, parent->last, box);
++parent->count;
return box;
}
@ -250,69 +274,209 @@ void UI_SetBackgroundTexture(UI_Box *box, GPU_Resource *texture, Vec2 uv0, Vec2
box->background_texture_uv1 = uv1;
}
////////////////////////////////////////////////////////////
//~ Event
UI_Event UI_EventFromKey(UI_Key key)
{
UI_SharedState *g = &UI_shared_state;
UI_Event result = ZI;
UI_Box *back_box = UI_BackBoxFromKey(key);
if (back_box)
{
result = back_box->event;
}
return result;
}
////////////////////////////////////////////////////////////
//~ Begin build
void UI_BeginBuild(ControllerEventsArray *controller_events)
void UI_BeginBuild(ControllerEventsArray controller_events)
{
UI_SharedState *g = &UI_shared_state;
/* Swap front & back build states */
//////////////////////////////
//- Process controller events
if (g->build_arena != 0 && g->back_build_arena != 0)
{
Arena *swp = g->build_arena;
g->build_arena = g->back_build_arena;
g->back_build_arena = swp;
}
g->back_box_bins = g->box_bins;
g->back_root_box = g->root_box;
g->back_boxes_count = g->boxes_count;
Xform screen_to_ui_xf = InvertXform(g->ui_to_screen_xf);
/* Reset front build state */
if (!g->build_arena)
{
g->build_arena = AcquireArena(Gibi(64));
}
ResetArena(g->build_arena);
g->boxes_count = 0;
g->first_free_style_node = 0;
g->first_free_checkpoint = 0;
/* Init bins */
g->box_bins = PushStructs(g->build_arena, UI_BoxBin, UI_NumBoxLookupBins);
/* Init root box */
g->root_box = PushStruct(g->build_arena, UI_Box);
g->root_box->key = UI_RootKey;
UI_BoxBin *bin = &g->box_bins[g->root_box->key.hash % UI_NumBoxLookupBins];
DllPushBackNP(bin->first, bin->last, g->root_box, next_in_bin, prev_in_bin);
++g->boxes_count;
/* Init checkpoints */
g->top_checkpoint = PushStruct(g->build_arena, UI_Checkpoint);
/* Init styles */
{
UI_StyleNode *nodes = PushStructs(g->build_arena, UI_StyleNode, UI_StyleKind_Count);
for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind)
/* Locate boxes */
UI_Box *hovered_box = 0;
UI_Box *active_box = 0;
for (u64 pre_index = g->boxes_count; pre_index-- > 0;)
{
UI_StyleNode *n = &nodes[kind];
UI_Style *style = &n->style;
style->kind = kind;
g->style_tops[kind] = n;
UI_Box *box = g->boxes_pre[pre_index];
if (hovered_box == 0 && box->event.flags & UI_EventFlag_Hovered)
{
hovered_box = box;
}
if (active_box == 0 && box->event.flags & UI_EventFlag_Active)
{
active_box = box;
}
}
// /* Refresh initial box events */
// for (u64 pre_index = g->boxes_count; pre_index-- > 0;)
// {
// UI_Box *box = g->boxes_pre[pre_index];
// if (g->cursor_pos.x > box->p0.x && g->cursor_pos.x < box->p1.x &&
// g->cursor_pos.y > box->p0.y && g->cursor_pos.y < box->p1.y)
// {
// box->event.flags |= UI_EventFlag_Hovered;
// hovered_box = box;
// }
// else
// {
// box->event.flags &= ~UI_EventFlag_Hovered;
// hovered_box = 0;
// }
// if (box->event.flags & UI_EventFlag_Active)
// {
// active_box = box;
// }
// }
/* Update state from controller events */
for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index)
{
ControllerEvent cev = controller_events.events[cev_index];
switch (cev.kind)
{
default: break;
case ControllerEventKind_CursorMove:
{
g->cursor_pos = MulXformV2(screen_to_ui_xf, Vec2FromFields(cev.cursor_pos));
/* Iterate boxes in reverse render order */
for (u64 pre_index = g->boxes_count; pre_index-- > 0;)
{
UI_Box *box = g->boxes_pre[pre_index];
if (g->cursor_pos.x > box->p0.x && g->cursor_pos.x < box->p1.x &&
g->cursor_pos.y > box->p0.y && g->cursor_pos.y < box->p1.y)
{
if (hovered_box)
{
hovered_box->event.flags &= ~UI_EventFlag_Hovered;
}
box->event.flags |= UI_EventFlag_Hovered;
hovered_box = box;
break;
}
}
} break;
case ControllerEventKind_ButtonDown:
{
if (cev.button == Btn_M1)
{
UI_Box *box = hovered_box;
if (box)
{
box->event.flags |= UI_EventFlag_Active;
box->event.activation_offset = SubVec2(g->cursor_pos, box->p0);
active_box = box;
}
}
} break;
case ControllerEventKind_ButtonUp:
{
if (cev.button == Btn_M1)
{
UI_Box *box = active_box;
if (box)
{
box->event.flags &= ~UI_EventFlag_Active;
active_box = 0;
}
}
} break;
}
}
g->style_tops[UI_StyleKind_Tag]->style.Tag = HashFnv64(Fnv64Basis, Lit("root"));
g->style_tops[UI_StyleKind_Parent]->style.Parent = g->root_box;
g->style_tops[UI_StyleKind_Width]->style.Width = UI_FILL(1, 0);
g->style_tops[UI_StyleKind_Height]->style.Height = UI_FILL(1, 0);
g->style_tops[UI_StyleKind_Font]->style.Font = UI_GetDefaultFontResource();
g->style_tops[UI_StyleKind_FontSize]->style.FontSize = 16.0f;
g->style_tops[UI_StyleKind_Tint]->style.Tint = 0xFFFFFFFF;
}
if (!g->back_build_arena)
//////////////////////////////
//- Swap front & back
{
/* Back buffer not initialized, swap again */
UI_BeginBuild(controller_events);
{
Arena *swp = g->build_arena;
g->build_arena = g->back_build_arena;
g->back_build_arena = swp;
}
g->back_box_bins = g->box_bins;
g->back_root_box = g->root_box;
g->back_boxes_count = g->boxes_count;
g->back_boxes_pre = g->boxes_pre;
g->back_boxes_post = g->boxes_post;
}
//////////////////////////////
//- Reset build state
{
if (!g->build_arena)
{
g->build_arena = AcquireArena(Gibi(64));
}
ResetArena(g->build_arena);
g->boxes_count = 0;
g->first_free_style_node = 0;
g->first_free_checkpoint = 0;
/* Init bins */
g->box_bins = PushStructs(g->build_arena, UI_BoxBin, UI_NumBoxLookupBins);
/* Init root box */
g->root_box = PushStruct(g->build_arena, UI_Box);
g->root_box->key = UI_RootKey;
UI_BoxBin *bin = &g->box_bins[g->root_box->key.hash % UI_NumBoxLookupBins];
DllPushBackNP(bin->first, bin->last, g->root_box, next_in_bin, prev_in_bin);
++g->boxes_count;
if (!g->back_build_arena)
{
/* Back buffer not initialized, swap again */
UI_BeginBuild(controller_events);
}
}
//////////////////////////////
//- Init style stack
{
/* Init checkpoints */
g->top_checkpoint = PushStruct(g->build_arena, UI_Checkpoint);
/* Init styles */
{
UI_StyleNode *nodes = PushStructs(g->build_arena, UI_StyleNode, UI_StyleKind_Count);
for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind)
{
UI_StyleNode *n = &nodes[kind];
UI_Style *style = &n->style;
style->kind = kind;
g->style_tops[kind] = n;
}
g->style_tops[UI_StyleKind_Parent]->style.Parent = g->root_box;
g->style_tops[UI_StyleKind_Width]->style.Width = UI_FILL(1, 0);
g->style_tops[UI_StyleKind_Height]->style.Height = UI_FILL(1, 0);
g->style_tops[UI_StyleKind_Font]->style.Font = UI_GetDefaultFontResource();
g->style_tops[UI_StyleKind_FontSize]->style.FontSize = 16.0f;
g->style_tops[UI_StyleKind_Tint]->style.Tint = 0xFFFFFFFF;
g->style_tops[UI_StyleKind_Tag]->style.Tag.name = Lit("root");
g->style_tops[UI_StyleKind_Tag]->style.Tag.hash = HashFnv64(Fnv64Basis, g->style_tops[UI_StyleKind_Tag]->style.Tag.name);
}
}
}
@ -329,10 +493,11 @@ GPU_ResourceDesc UI_GetRenderTargetDesc(Vec2I32 size)
return desc;
}
i64 UI_EndBuild(GPU_Resource *render_target)
i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf)
{
TempArena scratch = BeginScratchNoConflict();
UI_SharedState *g = &UI_shared_state;
g->ui_to_screen_xf = ui_to_screen_xf;
Vec2I32 render_target_size = GPU_GetTextureSize2D(render_target);
Rect render_viewport = ZI;
@ -352,8 +517,10 @@ i64 UI_EndBuild(GPU_Resource *render_target)
/* Build pre-order & post-order box arrays */
u64 boxes_count = g->boxes_count;
UI_Box **boxes_pre = PushStructsNoZero(scratch.arena, UI_Box *, boxes_count);
UI_Box **boxes_post = PushStructsNoZero(scratch.arena, UI_Box *, boxes_count);
UI_Box **boxes_pre = PushStructsNoZero(g->build_arena, UI_Box *, boxes_count);
UI_Box **boxes_post = PushStructsNoZero(g->build_arena, UI_Box *, boxes_count);
g->boxes_pre = boxes_pre;
g->boxes_post = boxes_post;
{
Struct(BoxNode) { BoxNode *next; b32 visited; UI_Box *box; };
BoxNode *first_dfs = 0;
@ -390,13 +557,15 @@ i64 UI_EndBuild(GPU_Resource *render_target)
StackPush(first_dfs, child_n);
}
}
boxes_pre[pre_index++] = box;
box->pre_index = pre_index++;
boxes_pre[box->pre_index] = box;
n->visited = 1;
}
else
{
StackPop(first_dfs);
boxes_post[post_index++] = box;
box->post_index = post_index++;
boxes_post[box->post_index] = box;
}
}
Assert(pre_index == boxes_count);

View File

@ -44,9 +44,9 @@ Enum(UI_BoxFlag)
//~ Style types
#define UI_StyleKindsXMacro(x) \
x(Tag, u64) \
x(Flags, UI_BoxFlag) \
x(Parent, struct UI_Box *) \
x(Tag, UI_Tag) \
x(LayoutAxis, Axis) \
x(Width, UI_Size) \
x(Height, UI_Size) \
@ -63,6 +63,12 @@ Enum(UI_BoxFlag)
x(FloatingPos, Vec2) \
/* ------------------------------------------- */
Struct(UI_Tag)
{
String name;
u64 hash;
};
Enum(UI_StyleKind)
{
#define X(name, type) UI_StyleKind_##name,
@ -93,6 +99,31 @@ Struct(UI_StyleNode)
UI_Style style;
};
////////////////////////////////////////////////////////////
//~ Checkpoint types
Struct(UI_Checkpoint)
{
UI_Checkpoint *next;
u64 v;
};
////////////////////////////////////////////////////////////
//~ Event types
Enum(UI_EventFlag)
{
UI_EventFlag_None = 0,
UI_EventFlag_Active = (1 << 0),
UI_EventFlag_Hovered = (1 << 1),
};
Struct(UI_Event)
{
UI_EventFlag flags;
Vec2 activation_offset;
};
////////////////////////////////////////////////////////////
//~ Box types
@ -112,18 +143,15 @@ Struct(UI_Box)
//- Persistent data
UI_Key key;
UI_Event event;
//- Per-build data
UI_BoxFlag flags;
String display_text;
GPU_Resource *background_texture;
Vec2 background_texture_uv0;
Vec2 background_texture_uv1;
Axis layout_axis;
UI_Size pref_size[Axis_CountXY];
u32 background_color;
u32 border_color;
@ -133,35 +161,32 @@ Struct(UI_Box)
f32 text_padding;
f32 rounding;
Vec2 floating_pos;
String display_text;
Axis layout_axis;
ResourceKey font_resource;
f32 font_size;
//- Pre-layout data
u64 pre_index;
u64 post_index;
//- Layout data
F_Run glyph_run;
F_Font *font;
f32 solved_dims[Axis_CountXY];
f32 layout_cursor;
//- Post-solve data
//- Post-layout data
Vec2 p0;
Vec2 p1;
};
Struct(UI_BoxBin)
{
UI_Box *first;
UI_Box *last;
};
////////////////////////////////////////////////////////////
//~ Checkpoint types
Struct(UI_Checkpoint)
{
UI_Checkpoint *next;
u64 v;
};
////////////////////////////////////////////////////////////
//~ State types
@ -169,6 +194,10 @@ Struct(UI_Checkpoint)
Struct(UI_SharedState)
{
//- Control state
Vec2 cursor_pos;
Xform ui_to_screen_xf;
//- Build state
Arena *build_arena;
Arena *back_build_arena;
@ -183,11 +212,16 @@ Struct(UI_SharedState)
u64 back_boxes_count;
UI_Checkpoint *top_checkpoint;
UI_Checkpoint *first_free_checkpoint;
UI_StyleNode *style_tops[UI_StyleKind_Count];
UI_Checkpoint *first_free_checkpoint;
UI_StyleNode *first_free_style_node;
//- Layout state
UI_Box **boxes_pre;
UI_Box **boxes_post;
UI_Box **back_boxes_pre;
UI_Box **back_boxes_post;
//- Render state
i64 gpu_submit_fence_target;
GPU_TransientBuffer draw_rects_tbuff;
@ -208,9 +242,8 @@ ResourceKey UI_GetDefaultFontResource(void);
////////////////////////////////////////////////////////////
//~ Key helpers
u64 UI_HashFromTop(void);
u64 UI_HashFromString(u64 seed, String str);
UI_Key UI_KeyFromString(u64 seed, String str);
UI_Box *UI_BackBoxFromKey(UI_Key key);
UI_Box *UI_FrontBoxFromKey(UI_Key key);
////////////////////////////////////////////////////////////
//~ Checkpoint helpers
@ -248,17 +281,22 @@ UI_Style UI_StyleFromTopNode(UI_StyleKind kind, b32 use);
////////////////////////////////////////////////////////////
//~ Box
UI_Box *UI_BuildBox(UI_Key key);
UI_Box *UI_BuildBox(String seed);
void UI_SetBackgroundTexture(UI_Box *box, GPU_Resource *texture, Vec2 uv0, Vec2 uv1);
////////////////////////////////////////////////////////////
//~ Event
UI_Event UI_EventFromKey(UI_Key key);
////////////////////////////////////////////////////////////
//~ Begin build
void UI_BeginBuild(ControllerEventsArray *controller_events);
void UI_BeginBuild(ControllerEventsArray controller_events);
////////////////////////////////////////////////////////////
//~ End build
GPU_ResourceDesc UI_GetRenderTargetDesc(Vec2I32 size);
i64 UI_EndBuild(GPU_Resource *render_target);
i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf);