retain box state cache within ui core
This commit is contained in:
parent
ad56fafeff
commit
fbf7882db2
@ -277,7 +277,7 @@ Inline void RemoveDictEntry(Dict *dict, DictEntry *entry)
|
||||
dict->last = prev;
|
||||
}
|
||||
}
|
||||
/* Insert into free list */
|
||||
/* Add to free list */
|
||||
{
|
||||
entry->next = dict->first_free;
|
||||
dict->first_free = entry;
|
||||
|
||||
@ -31,6 +31,8 @@ u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc)
|
||||
GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size)
|
||||
{
|
||||
GC_Run result = Zi;
|
||||
if (str.len > 0)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
Arena *perm = PermArena();
|
||||
|
||||
@ -208,10 +210,12 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
|
||||
result.font_cap = glyph->font_cap;
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
// result.ready = uncached_codepoints_count == 0 && pending_glyphs_count == 0;
|
||||
result.ready = 1;
|
||||
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -286,7 +286,7 @@ N_MsgAssembler *N_AcquireMsgAssembler(N_Channel *channel, u64 msg_id, u64 chunk_
|
||||
/* FIXME: Ensure chunk_count > 0 */
|
||||
ma->is_reliable = is_reliable;
|
||||
|
||||
/* Insert into channel list */
|
||||
/* Add to channel list */
|
||||
ma->touched_ns = now_ns;
|
||||
if (channel->most_recent_msg_assembler)
|
||||
{
|
||||
@ -299,7 +299,7 @@ N_MsgAssembler *N_AcquireMsgAssembler(N_Channel *channel, u64 msg_id, u64 chunk_
|
||||
}
|
||||
channel->most_recent_msg_assembler = ma;
|
||||
|
||||
/* Insert into lookup table */
|
||||
/* Add to lookup table */
|
||||
u64 hash = N_HashFromMsg(channel->id, msg_id);
|
||||
ma->hash = hash;
|
||||
N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[hash % host->num_msg_assembler_lookup_bins];
|
||||
|
||||
@ -19,7 +19,12 @@ void V_Shutdown(void)
|
||||
|
||||
V_Frame *V_CurrentFrame(void)
|
||||
{
|
||||
return &V.frames[V.current_frame_idx];
|
||||
return &V.frames[V.current_frame_tick % countof(V.frames)];
|
||||
}
|
||||
|
||||
V_Frame *V_LastFrame(void)
|
||||
{
|
||||
return &V.frames[(V.current_frame_tick - 1) % countof(V.frames)];
|
||||
}
|
||||
|
||||
S_Cmd *V_PushSimCmd(S_CmdKind kind)
|
||||
@ -421,19 +426,13 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
b32 shutdown = 0;
|
||||
while (!shutdown)
|
||||
{
|
||||
u64 last_frame_idx = V.current_frame_idx;
|
||||
u64 frame_idx = last_frame_idx + 1;
|
||||
if (frame_idx >= countof(V.frames))
|
||||
{
|
||||
frame_idx = 0;
|
||||
}
|
||||
V.current_frame_idx = frame_idx;
|
||||
V_Frame *last_frame = &V.frames[last_frame_idx];
|
||||
V_Frame *frame = &V.frames[frame_idx];
|
||||
|
||||
//////////////////////////////
|
||||
//- Begin frame
|
||||
|
||||
V.current_frame_tick += 1;
|
||||
V_Frame *last_frame = V_LastFrame();
|
||||
V_Frame *frame = V_CurrentFrame();
|
||||
|
||||
{
|
||||
Arena *old_arena = frame->arena;
|
||||
Arena *old_dverts_arena = frame->dverts_arena;
|
||||
@ -462,8 +461,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
frame->edit_camera_zoom = last_frame->edit_camera_zoom;
|
||||
frame->look = last_frame->look;
|
||||
|
||||
frame->tick = V.current_frame_tick;
|
||||
frame->time_ns = TimeNs();
|
||||
frame->tick = last_frame->tick + 1;
|
||||
frame->dt_ns = frame->time_ns - last_frame->time_ns;
|
||||
frame->dt = SecondsFromNs(frame->dt_ns);
|
||||
|
||||
@ -790,20 +789,29 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
/* TODO: Remove this (testing) */
|
||||
//- Init test layout
|
||||
if (!V.root_space)
|
||||
if (!V.root_panel)
|
||||
{
|
||||
V_Space *space = PushStruct(perm, V_Space);
|
||||
space->axis = Axis_X;
|
||||
V.root_space = space;
|
||||
|
||||
space->pref_size[Axis_X] = UI_GROW(1, 0);
|
||||
space->pref_size[Axis_Y] = UI_GROW(1, 0);
|
||||
{
|
||||
V_Panel *panel = PushStruct(perm, V_Panel);
|
||||
panel->axis = Axis_X;
|
||||
// panel->pref_size[Axis_X] = UI_PIX(frame->ui_dims.x, 0);
|
||||
// panel->pref_size[Axis_Y] = UI_PIX(frame->ui_dims.y, 0);
|
||||
panel->key = UI_TransKey(); /* TODO: Don't use transient keys for panels */
|
||||
panel->pref_size[Axis_X] = UI_GROW(1, 0);
|
||||
panel->pref_size[Axis_Y] = UI_GROW(1, 0);
|
||||
panel->is_organizing_panel = 1;
|
||||
V.root_panel = panel;
|
||||
}
|
||||
|
||||
{
|
||||
V_Panel *panel = PushStruct(perm, V_Panel);
|
||||
panel->space = space;
|
||||
DllQueuePushNP(space->first_panel, space->last_panel, panel, next_in_space, prev_in_space);
|
||||
++space->panels_count;
|
||||
panel->parent = V.root_panel;
|
||||
panel->axis = !panel->parent->axis;
|
||||
panel->key = UI_TransKey(); /* TODO: Don't use transient keys for panels */
|
||||
panel->pref_size[Axis_X] = UI_GROW(1, 0);
|
||||
panel->pref_size[Axis_Y] = UI_GROW(1, 0);
|
||||
DllQueuePush(panel->parent->first, panel->parent->last, panel);
|
||||
++panel->parent->count;
|
||||
|
||||
{
|
||||
V_Window *window = PushStruct(perm, V_Window);
|
||||
@ -824,9 +832,13 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
{
|
||||
V_Panel *panel = PushStruct(perm, V_Panel);
|
||||
panel->space = space;
|
||||
DllQueuePushNP(space->first_panel, space->last_panel, panel, next_in_space, prev_in_space);
|
||||
++space->panels_count;
|
||||
panel->parent = V.root_panel;
|
||||
panel->axis = !panel->parent->axis;
|
||||
panel->key = UI_TransKey(); /* TODO: Don't use transient keys for panels */
|
||||
panel->pref_size[Axis_X] = UI_GROW(1, 0);
|
||||
panel->pref_size[Axis_Y] = UI_GROW(1, 0);
|
||||
DllQueuePush(panel->parent->first, panel->parent->last, panel);
|
||||
++panel->parent->count;
|
||||
|
||||
{
|
||||
V_Window *window = PushStruct(perm, V_Window);
|
||||
@ -837,6 +849,29 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
}
|
||||
|
||||
// {
|
||||
// V_Space *space = PushStruct(perm, V_Space);
|
||||
// space->parent = V.root_space;
|
||||
// space->axis = !space->parent->axis;
|
||||
// space->pref_size[Axis_X] = UI_GROW(1, 0);
|
||||
// space->pref_size[Axis_Y] = UI_GROW(1, 0);
|
||||
// DllQueuePush(space->parent->first, space->parent->last, space);
|
||||
// ++space->parent->count;
|
||||
|
||||
// V_Panel *panel = PushStruct(perm, V_Panel);
|
||||
// panel->space = space;
|
||||
// DllQueuePushNP(space->first_panel, space->last_panel, panel, next_in_space, prev_in_space);
|
||||
// ++space->panels_count;
|
||||
|
||||
// {
|
||||
// V_Window *window = PushStruct(perm, V_Window);
|
||||
// window->panel = panel;
|
||||
// window->is_viewport_window = 1;
|
||||
// DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
|
||||
// ++panel->windows_count;
|
||||
// }
|
||||
// }
|
||||
|
||||
// {
|
||||
// V_Panel *panel = PushStruct(perm, V_Panel);
|
||||
// panel->space = space;
|
||||
@ -855,55 +890,53 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
if (frame->is_editing)
|
||||
{
|
||||
Struct(SpaceDfsNode) { SpaceDfsNode *next; b32 visited; V_Space *space; UI_Checkpoint cp; };
|
||||
SpaceDfsNode *first_space_dfs = PushStruct(frame->arena, SpaceDfsNode);
|
||||
first_space_dfs->space = V.root_space;
|
||||
Struct(PanelDfsNode) { PanelDfsNode *next; b32 visited; V_Panel *panel; UI_Checkpoint cp; };
|
||||
PanelDfsNode *first_panel_dfs = PushStruct(frame->arena, PanelDfsNode);
|
||||
first_panel_dfs->panel = V.root_panel;
|
||||
|
||||
//- Iterate spaces
|
||||
while (first_space_dfs)
|
||||
//- Iterate panels
|
||||
while (first_panel_dfs)
|
||||
{
|
||||
SpaceDfsNode *space_dfs = first_space_dfs;
|
||||
V_Space *space = space_dfs->space;
|
||||
if (!space_dfs->visited)
|
||||
PanelDfsNode *panel_dfs = first_panel_dfs;
|
||||
V_Panel *panel = panel_dfs->panel;
|
||||
if (!panel_dfs->visited)
|
||||
{
|
||||
space_dfs->visited = 1;
|
||||
for (V_Space *child = space->last; child; child = child->prev)
|
||||
panel_dfs->visited = 1;
|
||||
for (V_Panel *child = panel->last; child; child = child->prev)
|
||||
{
|
||||
SpaceDfsNode *n = PushStruct(frame->arena, SpaceDfsNode);
|
||||
n->space = child;
|
||||
SllStackPush(first_space_dfs, n);
|
||||
PanelDfsNode *n = PushStruct(frame->arena, PanelDfsNode);
|
||||
n->panel = child;
|
||||
SllStackPush(first_panel_dfs, n);
|
||||
}
|
||||
|
||||
UI_Key space_key = UI_TransKey();
|
||||
UI_SetNext(Width, space->pref_size[Axis_X]);
|
||||
UI_SetNext(Width, space->pref_size[Axis_Y]);
|
||||
if (space->axis == Axis_X)
|
||||
UI_SetNext(Width, panel->pref_size[Axis_X]);
|
||||
UI_SetNext(Height, panel->pref_size[Axis_Y]);
|
||||
if (panel->axis == Axis_X)
|
||||
{
|
||||
UI_BuildRowEx(space_key);
|
||||
UI_BuildRowEx(panel->key);
|
||||
}
|
||||
else
|
||||
{
|
||||
UI_BuildColumnEx(space_key);
|
||||
UI_BuildColumnEx(panel->key);
|
||||
}
|
||||
space_dfs->cp = UI_PushCP(space_key);
|
||||
panel_dfs->cp = UI_PushCP(panel->key);
|
||||
|
||||
//- Build space panels
|
||||
for (V_Panel *panel = space->first_panel; panel; panel = panel->next_in_space)
|
||||
if (!panel->is_organizing_panel)
|
||||
{
|
||||
// UI_SetNext(Width, UI_SHRINK(0, 1));
|
||||
UI_SetNext(Width, UI_GROW(1, 0));
|
||||
UI_SetNext(Height, UI_GROW(1, 0));
|
||||
// UI_SetNext(Width, UI_GROW(1, 0));
|
||||
// UI_SetNext(Height, UI_GROW(1, 0));
|
||||
UI_PushCP(UI_BuildColumn());
|
||||
{
|
||||
i64 active_window_idx = ClampI64(panel->active_window_idx, 0, MaxI64(panel->windows_count - 1, 0));
|
||||
//- Build panel window tabs
|
||||
//- Build window tabs
|
||||
f32 tab_spacing = 10;
|
||||
V_Window *active_window = 0;
|
||||
{
|
||||
UI_SetNext(Width, UI_SHRINK(0, 0));
|
||||
UI_SetNext(Height, UI_SHRINK(0, 0));
|
||||
UI_PushCP(UI_BuildRow());
|
||||
i64 window_idx = 0;
|
||||
UI_SetNext(Width, UI_SHRINK(0, 1));
|
||||
UI_SetNext(Height, UI_SHRINK(0, 1));
|
||||
UI_PushCP(UI_BuildRow());
|
||||
for (V_Window *window = panel->first_window; window; window = window->next_in_panel)
|
||||
{
|
||||
if (!window->is_viewport_window)
|
||||
@ -920,8 +953,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
UI_SetNext(BackgroundColor, VEC4(0.2, 0.2, 0.2, 1));
|
||||
UI_SetNext(Border, 1);
|
||||
UI_SetNext(Width, UI_SHRINK(theme.text_padding_x, 0));
|
||||
UI_SetNext(Height, UI_SHRINK(theme.text_padding_y, 0));
|
||||
UI_SetNext(Width, UI_SHRINK(theme.text_padding_x, 1));
|
||||
UI_SetNext(Height, UI_SHRINK(theme.text_padding_y, 1));
|
||||
UI_SetNext(ChildAlignment, UI_Alignment_Center);
|
||||
UI_PushCP(UI_BuildRow());
|
||||
{
|
||||
@ -940,7 +973,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
UI_PopCP(UI_TopCP());
|
||||
}
|
||||
//- Build active panel active_window
|
||||
//- Build active window
|
||||
if (active_window && !active_window->is_viewport_window)
|
||||
{
|
||||
V_Window *window = active_window;
|
||||
@ -968,13 +1001,24 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
}
|
||||
UI_PopCP(UI_TopCP());
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UI_PopCP(space_dfs->cp);
|
||||
SllStackPop(first_space_dfs);
|
||||
UI_PopCP(panel_dfs->cp);
|
||||
SllStackPop(first_panel_dfs);
|
||||
|
||||
//- Build divider
|
||||
if (panel->next != 0)
|
||||
{
|
||||
UI_Key divider_key = UI_TransKey();
|
||||
UI_SetNext(BackgroundColor, Color_Cyan);
|
||||
// UI_SetNext(Border, 2);
|
||||
UI_SetNext(AxisSize, UI_GROW(1, 1), .axis = panel->axis);
|
||||
UI_SetNext(AxisSize, UI_PIX(5, 1), .axis = !panel->axis);
|
||||
/* FIXME: Non-transient key */
|
||||
UI_BuildBoxEx(divider_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,28 +149,21 @@ Struct(V_CommandsWidget)
|
||||
|
||||
/* TODO: Move boolean fields into bitwise property flags */
|
||||
|
||||
Struct(V_Space)
|
||||
{
|
||||
V_Space *parent;
|
||||
V_Space *next;
|
||||
V_Space *prev;
|
||||
V_Space *first;
|
||||
V_Space *last;
|
||||
|
||||
i64 panels_count;
|
||||
struct V_Panel *first_panel;
|
||||
struct V_Panel *last_panel;
|
||||
|
||||
UI_Size pref_size[Axis_CountXY];
|
||||
|
||||
Axis axis;
|
||||
};
|
||||
|
||||
Struct(V_Panel)
|
||||
{
|
||||
V_Space *space;
|
||||
V_Panel *next_in_space;
|
||||
V_Panel *prev_in_space;
|
||||
V_Panel *parent;
|
||||
V_Panel *next;
|
||||
V_Panel *prev;
|
||||
V_Panel *first;
|
||||
V_Panel *last;
|
||||
i64 count;
|
||||
|
||||
UI_Key key;
|
||||
|
||||
UI_Size pref_size[Axis_CountXY];
|
||||
Axis axis;
|
||||
|
||||
b32 is_organizing_panel;
|
||||
|
||||
i64 active_window_idx;
|
||||
i64 windows_count;
|
||||
@ -277,12 +270,12 @@ Struct(V_Ctx)
|
||||
S_Lookup lookup;
|
||||
S_Key player_key;
|
||||
|
||||
V_Space *root_space;
|
||||
V_Panel *root_panel;
|
||||
|
||||
Atomic32 shutdown;
|
||||
Fence shutdown_complete;
|
||||
|
||||
u64 current_frame_idx;
|
||||
i64 current_frame_tick;
|
||||
V_Frame frames[2];
|
||||
};
|
||||
|
||||
@ -298,6 +291,7 @@ void V_Shutdown(void);
|
||||
//~ Helpers
|
||||
|
||||
V_Frame *V_CurrentFrame(void);
|
||||
V_Frame *V_LastFrame(void);
|
||||
S_Cmd *V_PushSimCmd(S_CmdKind kind);
|
||||
String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey);
|
||||
|
||||
|
||||
447
src/ui/ui_core.c
447
src/ui/ui_core.c
@ -1,4 +1,4 @@
|
||||
UI_State UI_state = Zi;
|
||||
UI_Ctx UI = Zi;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Bootstrap
|
||||
@ -18,6 +18,11 @@ GC_FontKey UI_GetDefaultFont(void)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
b32 UI_MatchKey(UI_Key a, UI_Key b)
|
||||
{
|
||||
return a.hash == b.hash;
|
||||
}
|
||||
|
||||
UI_Key UI_KeyFromString(String str)
|
||||
{
|
||||
u64 top_tag = UI_UseTop(Tag);
|
||||
@ -43,8 +48,7 @@ UI_Key UI_KeyF_(String fmt, ...)
|
||||
|
||||
UI_Key UI_TransKey(void)
|
||||
{
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
u64 seed = ++frame->transient_key_seed;
|
||||
u64 seed = ++UI.transient_key_seed;
|
||||
UI_Key key = Zi;
|
||||
key.hash = RandU64FromSeed(seed);
|
||||
return key;
|
||||
@ -52,16 +56,14 @@ UI_Key UI_TransKey(void)
|
||||
|
||||
UI_Box *UI_BoxFromKey(UI_Key key)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
UI_Box *box = 0;
|
||||
if (key.hash != 0)
|
||||
{
|
||||
UI_BoxBin *bin = &g->box_bins[key.hash % UI_NumBoxLookupBins];
|
||||
for (UI_Box *tmp = bin->first; tmp; tmp = tmp->next_in_bin)
|
||||
UI_BoxBin *bin = &UI.box_bins[key.hash % countof(UI.box_bins)];
|
||||
for (box = bin->first; box; box = box->next_in_bin)
|
||||
{
|
||||
if (tmp->key.hash == key.hash)
|
||||
if (UI_MatchKey(box->key, key))
|
||||
{
|
||||
box = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -69,6 +71,105 @@ UI_Box *UI_BoxFromKey(UI_Key key)
|
||||
return box;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Iteration helpers
|
||||
|
||||
UI_BoxIterResult UI_FirstBox(Arena *arena, UI_BoxIter *iter, UI_Key start_key)
|
||||
{
|
||||
/* Free old stack */
|
||||
if (iter->first)
|
||||
{
|
||||
if (iter->last_free)
|
||||
{
|
||||
iter->last_free->next = iter->first;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->first_free = iter->first;
|
||||
}
|
||||
iter->last_free = iter->first;
|
||||
iter->first = 0;
|
||||
}
|
||||
/* Create root dfs node */
|
||||
UI_BoxIterDfsNode *dfs = iter->first_free;
|
||||
if (dfs)
|
||||
{
|
||||
SllQueuePop(iter->first_free, iter->last_free);
|
||||
ZeroStruct(dfs);
|
||||
}
|
||||
else
|
||||
{
|
||||
dfs = PushStruct(arena, UI_BoxIterDfsNode);
|
||||
}
|
||||
dfs->box = UI_BoxFromKey(start_key);
|
||||
iter->first = dfs;
|
||||
return UI_NextBox(arena, iter);
|
||||
}
|
||||
|
||||
UI_BoxIterResult UI_NextBox(Arena *arena, UI_BoxIter *iter)
|
||||
{
|
||||
UI_BoxIterResult result = Zi;
|
||||
if (iter->first)
|
||||
{
|
||||
UI_BoxIterDfsNode *dfs = iter->first;
|
||||
UI_Box *box = dfs->box;
|
||||
if (!dfs->visited)
|
||||
{
|
||||
/* Pre order */
|
||||
dfs->visited = 1;
|
||||
result.box = box;
|
||||
result.pre = 1;
|
||||
/* Push floating children to dfs stack */
|
||||
for (UI_Box *child = box->last; child; child = child->prev)
|
||||
{
|
||||
if (AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
||||
{
|
||||
UI_BoxIterDfsNode *child_dfs = iter->first_free;
|
||||
if (child_dfs)
|
||||
{
|
||||
SllQueuePop(iter->first_free, iter->last_free);
|
||||
ZeroStruct(child_dfs);
|
||||
}
|
||||
else
|
||||
{
|
||||
child_dfs = PushStruct(arena, UI_BoxIterDfsNode);
|
||||
}
|
||||
child_dfs->box = child;
|
||||
SllStackPush(iter->first, child_dfs);
|
||||
}
|
||||
}
|
||||
/* Push non-floating children to dfs stack */
|
||||
for (UI_Box *child = box->last; child; child = child->prev)
|
||||
{
|
||||
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
||||
{
|
||||
UI_BoxIterDfsNode *child_dfs = iter->first_free;
|
||||
if (child_dfs)
|
||||
{
|
||||
SllQueuePop(iter->first_free, iter->last_free);
|
||||
ZeroStruct(child_dfs);
|
||||
}
|
||||
else
|
||||
{
|
||||
child_dfs = PushStruct(arena, UI_BoxIterDfsNode);
|
||||
}
|
||||
child_dfs->box = child;
|
||||
SllStackPush(iter->first, child_dfs);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Post order */
|
||||
result.box = box;
|
||||
result.pre = 0;
|
||||
SllStackPop(iter->first);
|
||||
SllQueuePush(iter->first_free, iter->last_free, dfs);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ String helpers
|
||||
|
||||
@ -410,7 +511,6 @@ UI_Key UI_BuildBoxEx(UI_Key key)
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Rng2 uv)
|
||||
{
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
@ -430,7 +530,6 @@ void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Rng2 uv)
|
||||
|
||||
UI_Report UI_ReportFromKey(UI_Key key)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
UI_Report result = Zi;
|
||||
|
||||
UI_Box *box = UI_BoxFromKey(key);
|
||||
@ -447,38 +546,39 @@ UI_Report UI_ReportFromKey(UI_Key key)
|
||||
|
||||
UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
|
||||
//////////////////////////////
|
||||
//- Init persistent state
|
||||
|
||||
if (!g->box_arena)
|
||||
if (!UI.box_arena)
|
||||
{
|
||||
g->box_arena = AcquireArena(Gibi(64));
|
||||
g->box_bins = PushStructs(g->box_arena, UI_BoxBin, UI_NumBoxLookupBins);
|
||||
|
||||
for (u64 i = 0; i < countof(g->frames); ++i)
|
||||
UI.box_arena = AcquireArena(Gibi(64));
|
||||
/* Init frames */
|
||||
for (u64 i = 0; i < countof(UI.frames); ++i)
|
||||
{
|
||||
UI_Frame *frame = &g->frames[i];
|
||||
UI_Frame *frame = &UI.frames[i];
|
||||
frame->arena = AcquireArena(Gibi(64));
|
||||
frame->rects_arena = AcquireArena(Gibi(64));
|
||||
frame->gpu_arena = G_AcquireArena();
|
||||
}
|
||||
/* Init root box */
|
||||
{
|
||||
UI_Box *box = PushStruct(UI.box_arena, UI_Box);
|
||||
box->key = UI_RootKey;
|
||||
UI.boxes_count += 1;
|
||||
UI_BoxBin *bin = &UI.box_bins[box->key.hash % countof(UI.box_bins)];
|
||||
bin->first = box;
|
||||
bin->last = box;
|
||||
UI.root_box = box;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Begin frame
|
||||
|
||||
u64 last_frame_idx = g->current_frame_idx;
|
||||
u64 frame_idx = last_frame_idx + 1;
|
||||
if (frame_idx >= countof(g->frames))
|
||||
{
|
||||
frame_idx = 0;
|
||||
}
|
||||
g->current_frame_idx = frame_idx;
|
||||
|
||||
UI_Frame *last_frame = &g->frames[last_frame_idx];
|
||||
UI_Frame *frame = &g->frames[frame_idx];
|
||||
UI.current_frame_tick += 1;
|
||||
UI_Frame *last_frame = UI_LastFrame();
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
|
||||
{
|
||||
Arena *old_arena = frame->arena;
|
||||
@ -500,7 +600,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
||||
i64 dt_ns = now_ns - last_frame->time_ns;
|
||||
frame->time_ns = now_ns;
|
||||
frame->dt_ns = dt_ns;
|
||||
frame->tick = last_frame->tick + 1;
|
||||
frame->tick = UI.current_frame_tick;
|
||||
}
|
||||
|
||||
/* Init style stack */
|
||||
@ -538,7 +638,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
||||
}
|
||||
|
||||
/* Init box reports */
|
||||
for (u64 pre_index = g->boxes_count; pre_index-- > 0;)
|
||||
for (u64 pre_index = UI.boxes_count; pre_index-- > 0;)
|
||||
{
|
||||
UI_Box *box = last_frame->boxes_pre[pre_index];
|
||||
if (hovered_box == 0 && box->desc.flags & UI_BoxFlag_Interactable)
|
||||
@ -627,7 +727,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
||||
}
|
||||
|
||||
/* Update box hot & active states */
|
||||
for (u64 pre_index = 0; pre_index < g->boxes_count; ++pre_index)
|
||||
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;
|
||||
@ -666,8 +766,12 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
||||
|
||||
UI_Frame *UI_CurrentFrame(void)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
return &g->frames[g->current_frame_idx];
|
||||
return &UI.frames[UI.current_frame_tick % countof(UI.frames)];
|
||||
};
|
||||
|
||||
UI_Frame *UI_LastFrame(void)
|
||||
{
|
||||
return &UI.frames[(UI.current_frame_tick - 1) % countof(UI.frames)];
|
||||
};
|
||||
|
||||
Arena *UI_FrameArena(void)
|
||||
@ -686,7 +790,7 @@ Vec2 UI_CursorPos(void)
|
||||
void UI_EndFrame(UI_Frame *frame)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
UI_State *g = &UI_state;
|
||||
UI_BoxIter box_iter = Zi;
|
||||
|
||||
Vec2I32 monitor_size = frame->window_frame.monitor_size;
|
||||
Rng3 monitor_viewport = RNG3(VEC3(0, 0, 0), VEC3(monitor_size.x, monitor_size.y, 1));
|
||||
@ -699,7 +803,51 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
//////////////////////////////
|
||||
//- Process commands
|
||||
|
||||
g->boxes_count = 0;
|
||||
{
|
||||
//////////////////////////////
|
||||
//- Create boxes from build cmds
|
||||
|
||||
for (UI_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
||||
{
|
||||
UI_Cmd cmd = cmd_node->cmd;
|
||||
if (cmd.kind == UI_CmdKind_BuildBox)
|
||||
{
|
||||
UI_Key key = cmd.box.key;
|
||||
UI_Box *box = 0;
|
||||
{
|
||||
UI_BoxBin *bin = &UI.box_bins[key.hash % countof(UI.box_bins)];
|
||||
for (box = bin->first; box; box = box->next_in_bin)
|
||||
{
|
||||
if (UI_MatchKey(box->key, key))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Allocate new box */
|
||||
if (box == 0)
|
||||
{
|
||||
/* Allocate new box */
|
||||
box = UI.first_free_box;
|
||||
if (box)
|
||||
{
|
||||
SllStackPop(UI.first_free_box);
|
||||
ZeroStruct(box);
|
||||
}
|
||||
else
|
||||
{
|
||||
box = PushStruct(UI.box_arena, UI_Box);
|
||||
}
|
||||
box->key = key;
|
||||
DllQueuePushNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
|
||||
++UI.boxes_count;
|
||||
}
|
||||
}
|
||||
box->last_build_tick = frame->tick;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Update boxes from cmds
|
||||
|
||||
for (UI_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
||||
{
|
||||
@ -710,93 +858,45 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
case UI_CmdKind_BuildBox:
|
||||
{
|
||||
UI_Key key = cmd.box.key;
|
||||
if (key.hash == 0)
|
||||
if (UI_MatchKey(key, UI_NilKey))
|
||||
{
|
||||
key = UI_TransKey();
|
||||
}
|
||||
UI_Box *box = UI_BoxFromKey(key);
|
||||
|
||||
b32 is_root = frame->root_box == 0;
|
||||
UI_Box *parent = 0;
|
||||
if (!is_root)
|
||||
if (box != UI.root_box)
|
||||
{
|
||||
parent = UI_BoxFromKey(cmd.box.parent);
|
||||
if (!parent)
|
||||
{
|
||||
parent = frame->root_box;
|
||||
parent = UI.root_box;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate box */
|
||||
UI_Box *box = 0;
|
||||
/* Update parent */
|
||||
if (box->parent != parent)
|
||||
{
|
||||
UI_BoxBin *bin = &g->box_bins[key.hash % UI_NumBoxLookupBins];
|
||||
for (UI_Box *tmp = bin->first; tmp && !box; tmp = tmp->next_in_bin)
|
||||
{
|
||||
if (tmp->key.hash == key.hash)
|
||||
{
|
||||
box = tmp;
|
||||
}
|
||||
}
|
||||
if (box)
|
||||
{
|
||||
/* Remove box from old parent */
|
||||
if (box->parent)
|
||||
{
|
||||
/* Remove from old parent */
|
||||
DllQueueRemove(box->parent->first, box->parent->last, box);
|
||||
--box->parent->count;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (parent)
|
||||
{
|
||||
box = g->first_free_box;
|
||||
if (box)
|
||||
{
|
||||
SllStackPop(g->first_free_box);
|
||||
ZeroStruct(box);
|
||||
/* Add to new parent */
|
||||
DllQueuePush(parent->first, parent->last, box);
|
||||
++parent->count;
|
||||
}
|
||||
else
|
||||
{
|
||||
box = PushStruct(g->box_arena, UI_Box);
|
||||
box->parent = parent;
|
||||
}
|
||||
DllQueuePushNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
|
||||
}
|
||||
}
|
||||
++g->boxes_count;
|
||||
|
||||
/* Reset box */
|
||||
UI_Box old_box = *box;
|
||||
{
|
||||
ZeroStruct(box);
|
||||
box->next_in_bin = old_box.next_in_bin;
|
||||
box->prev_in_bin = old_box.prev_in_bin;
|
||||
box->report = old_box.report;
|
||||
}
|
||||
box->key = key;
|
||||
box->last_updated_tick = frame->tick;
|
||||
|
||||
/* Update box */
|
||||
{
|
||||
box->desc = cmd.box;
|
||||
|
||||
/* Insert box into parent */
|
||||
if (parent)
|
||||
{
|
||||
DllQueuePush(parent->first, parent->last, box);
|
||||
box->parent = parent;
|
||||
++parent->count;
|
||||
}
|
||||
|
||||
/* Fetch run */
|
||||
if (box->desc.text.len > 0)
|
||||
{
|
||||
box->glyph_run = GC_RunFromString(frame->arena, box->desc.text, box->desc.font, box->desc.font_size);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_root)
|
||||
{
|
||||
frame->root_box = box;
|
||||
}
|
||||
} break;
|
||||
|
||||
case UI_CmdKind_SetRawTexture:
|
||||
@ -810,73 +910,90 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Prune boxes
|
||||
//- Prune cached boxes
|
||||
|
||||
// {
|
||||
// u64 cur_tick = frame->tick;
|
||||
// UI_BoxIter it = UI_ITER(g->root_box);
|
||||
// UI_Box *box = UI_NextBox(&it);
|
||||
// while (box != 0)
|
||||
// {
|
||||
// UI_Box *next = UI_NextBox(&it);
|
||||
// box = next;
|
||||
// }
|
||||
// }
|
||||
{
|
||||
u64 prunes_count = 0;
|
||||
UI_Box **prunes = PushStructsNoZero(scratch.arena, UI_Box *, UI.boxes_count);
|
||||
for (UI_BoxIterResult ir = UI_FirstBox(scratch.arena, &box_iter, UI_RootKey); ir.box; ir = UI_NextBox(scratch.arena, &box_iter))
|
||||
{
|
||||
if (ir.pre)
|
||||
{
|
||||
UI_Box *box = ir.box;
|
||||
if (box->last_build_tick < frame->tick)
|
||||
{
|
||||
prunes[prunes_count++] = box;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (u64 prune_idx = 0; prune_idx < prunes_count; ++prune_idx)
|
||||
{
|
||||
UI_Box *box = prunes[prune_idx];
|
||||
UI_Box *parent = box->parent;
|
||||
UI_BoxBin *bin = &UI.box_bins[box->key.hash % countof(UI.box_bins)];
|
||||
/* Re-parent children */
|
||||
if (box->first)
|
||||
{
|
||||
for (UI_Box *child = box->first; child; child = child->next)
|
||||
{
|
||||
child->parent = parent;
|
||||
}
|
||||
if (parent->last)
|
||||
{
|
||||
parent->last->next = box->first;
|
||||
box->first->prev = parent->last;
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->first = box->first;
|
||||
}
|
||||
parent->last = box->last;
|
||||
parent->count += box->count;
|
||||
}
|
||||
/* Remove from parent */
|
||||
DllQueueRemove(parent->first, parent->last, box);
|
||||
--parent->count;
|
||||
/* Remove from lookup table */
|
||||
DllQueueRemoveNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
|
||||
/* Add to free list */
|
||||
SllStackPush(UI.first_free_box, box);
|
||||
--UI.boxes_count;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Layout
|
||||
|
||||
/* Build pre-order & post-order box arrays */
|
||||
u64 boxes_count = g->boxes_count;
|
||||
/* Prepare layout data */
|
||||
u64 boxes_count = UI.boxes_count;
|
||||
UI_Box **boxes_pre = PushStructsNoZero(frame->arena, UI_Box *, boxes_count);
|
||||
UI_Box **boxes_post = PushStructsNoZero(frame->arena, UI_Box *, boxes_count);
|
||||
frame->boxes_pre = boxes_pre;
|
||||
frame->boxes_post = boxes_post;
|
||||
{
|
||||
Struct(BoxNode) { BoxNode *next; b32 visited; UI_Box *box; };
|
||||
BoxNode *first_dfs = PushStruct(scratch.arena, BoxNode);
|
||||
u64 pre_index = 0;
|
||||
u64 post_index = 0;
|
||||
first_dfs->box = frame->root_box;
|
||||
while (first_dfs)
|
||||
for (UI_BoxIterResult ir = UI_FirstBox(scratch.arena, &box_iter, UI_RootKey); ir.box; ir = UI_NextBox(scratch.arena, &box_iter))
|
||||
{
|
||||
BoxNode *n = first_dfs;
|
||||
UI_Box *box = n->box;
|
||||
if (!n->visited)
|
||||
UI_Box *box = ir.box;
|
||||
if (ir.pre)
|
||||
{
|
||||
/* Push floating children to dfs stack */
|
||||
for (UI_Box *child = box->last; child; child = child->prev)
|
||||
{
|
||||
if (AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
||||
{
|
||||
BoxNode *child_n = PushStruct(scratch.arena, BoxNode);
|
||||
child_n->box = child;
|
||||
SllStackPush(first_dfs, child_n);
|
||||
}
|
||||
}
|
||||
/* Push non-floating children to dfs stack */
|
||||
for (UI_Box *child = box->last; child; child = child->prev)
|
||||
{
|
||||
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
||||
{
|
||||
BoxNode *child_n = PushStruct(scratch.arena, BoxNode);
|
||||
child_n->box = child;
|
||||
SllStackPush(first_dfs, child_n);
|
||||
}
|
||||
}
|
||||
box->pre_index = pre_index++;
|
||||
boxes_pre[box->pre_index] = box;
|
||||
n->visited = 1;
|
||||
box->pre_index = pre_index;
|
||||
boxes_pre[pre_index] = box;
|
||||
pre_index += 1;
|
||||
|
||||
/* Reset layout data */
|
||||
ZeroStruct(&box->layout);
|
||||
}
|
||||
else
|
||||
{
|
||||
SllStackPop(first_dfs);
|
||||
box->post_index = post_index++;
|
||||
boxes_post[box->post_index] = box;
|
||||
box->post_index = post_index;
|
||||
boxes_post[post_index] = box;
|
||||
post_index += 1;
|
||||
}
|
||||
}
|
||||
Assert(pre_index == boxes_count);
|
||||
@ -892,7 +1009,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
UI_Size pref_size = box->desc.pref_size[axis];
|
||||
if (pref_size.kind == UI_SizeKind_Pixel)
|
||||
{
|
||||
box->solved_dims[axis] = pref_size.v;
|
||||
box->layout.solved_dims[axis] = pref_size.v;
|
||||
}
|
||||
else if (pref_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText))
|
||||
{
|
||||
@ -906,7 +1023,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
{
|
||||
text_size = box->glyph_run.font_ascent + box->glyph_run.font_descent;
|
||||
}
|
||||
box->solved_dims[axis] = text_size + (pref_size.v * 2);
|
||||
box->layout.solved_dims[axis] = text_size + (pref_size.v * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -929,11 +1046,11 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText)))
|
||||
{
|
||||
/* Match independent ancestor */
|
||||
match_size = ancestor->solved_dims[axis];
|
||||
match_size = ancestor->layout.solved_dims[axis];
|
||||
found_match = 1;
|
||||
}
|
||||
}
|
||||
box->solved_dims[axis] = match_size * pref_size.v;
|
||||
box->layout.solved_dims[axis] = match_size * pref_size.v;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -954,15 +1071,15 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
{
|
||||
if (axis == box->desc.child_layout_axis)
|
||||
{
|
||||
accum += child->solved_dims[axis];
|
||||
accum += child->layout.solved_dims[axis];
|
||||
}
|
||||
else
|
||||
{
|
||||
accum = MaxF32(child->solved_dims[axis], accum);
|
||||
accum = MaxF32(child->layout.solved_dims[axis], accum);
|
||||
}
|
||||
}
|
||||
}
|
||||
box->solved_dims[axis] = accum + (pref_size.v * 2);
|
||||
box->layout.solved_dims[axis] = accum + (pref_size.v * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -977,7 +1094,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
UI_Size pref_size = box->desc.pref_size[axis];
|
||||
if (pref_size.kind == UI_SizeKind_Grow)
|
||||
{
|
||||
box->solved_dims[axis] = box->parent->solved_dims[axis] * pref_size.v;
|
||||
box->layout.solved_dims[axis] = box->parent->layout.solved_dims[axis] * pref_size.v;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -988,7 +1105,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
UI_Box *box = boxes_pre[pre_index];
|
||||
for (Axis axis = 0; axis < Axis_CountXY; ++axis)
|
||||
{
|
||||
f32 box_size = box->solved_dims[axis];
|
||||
f32 box_size = box->layout.solved_dims[axis];
|
||||
/* Solve non-floating violations */
|
||||
{
|
||||
f32 size_accum = 0;
|
||||
@ -997,7 +1114,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
{
|
||||
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
||||
{
|
||||
f32 size = child->solved_dims[axis];
|
||||
f32 size = child->layout.solved_dims[axis];
|
||||
f32 strictness = child->desc.pref_size[axis].strictness;
|
||||
f32 flex = size * (1.0 - strictness);
|
||||
if (axis == box->desc.child_layout_axis)
|
||||
@ -1020,7 +1137,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
{
|
||||
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
||||
{
|
||||
f32 size = child->solved_dims[axis];
|
||||
f32 size = child->layout.solved_dims[axis];
|
||||
f32 strictness = child->desc.pref_size[axis].strictness;
|
||||
f32 flex = size * (1.0 - strictness);
|
||||
f32 new_size = size;
|
||||
@ -1037,24 +1154,24 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
}
|
||||
}
|
||||
adjusted_size_accum += new_size;
|
||||
child->solved_dims[axis] = new_size;
|
||||
child->layout.solved_dims[axis] = new_size;
|
||||
}
|
||||
}
|
||||
size_accum = adjusted_size_accum;
|
||||
}
|
||||
box->final_children_size_accum[axis] = size_accum;
|
||||
box->layout.final_children_size_accum[axis] = size_accum;
|
||||
}
|
||||
/* Solve floating violations */
|
||||
for (UI_Box *child = box->first; child; child = child->next)
|
||||
{
|
||||
if (AnyBit(child->desc.flags, UI_BoxFlag_Floating) && !AnyBit(child->desc.flags, UI_BoxFlag_NoFloatingClamp))
|
||||
{
|
||||
f32 size = child->solved_dims[axis];
|
||||
f32 size = child->layout.solved_dims[axis];
|
||||
if (size > box_size)
|
||||
{
|
||||
f32 strictness = child->desc.pref_size[axis].strictness;
|
||||
f32 flex = size * (1.0 - strictness);
|
||||
child->solved_dims[axis] = MaxF32(size - flex, box_size);
|
||||
child->layout.solved_dims[axis] = MaxF32(size - flex, box_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1071,25 +1188,25 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
{
|
||||
Axis axis = box->desc.child_layout_axis;
|
||||
UI_AxisAlignment alignment = box->desc.child_alignment[axis];
|
||||
f32 box_size = box->solved_dims[axis];
|
||||
f32 size_accum = box->final_children_size_accum[axis];
|
||||
f32 box_size = box->layout.solved_dims[axis];
|
||||
f32 size_accum = box->layout.final_children_size_accum[axis];
|
||||
switch(alignment)
|
||||
{
|
||||
default: break;
|
||||
case UI_AxisAlignment_Center:
|
||||
{
|
||||
box->layout_cursor = box_size / 2 - size_accum / 2;
|
||||
box->layout.cursor = box_size / 2 - size_accum / 2;
|
||||
} break;
|
||||
case UI_AxisAlignment_End:
|
||||
{
|
||||
box->layout_cursor = box_size - size_accum;
|
||||
box->layout.cursor = box_size - size_accum;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Position */
|
||||
{
|
||||
f32 *dims_arr = box->solved_dims;
|
||||
f32 *dims_arr = box->layout.solved_dims;
|
||||
Vec2 dims_vec = VEC2(dims_arr[0], dims_arr[1]);
|
||||
Vec2 final_pos = Zi;
|
||||
|
||||
@ -1113,7 +1230,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
/* Non-floating box position */
|
||||
else if (parent)
|
||||
{
|
||||
f32 layout_cursor = parent->layout_cursor;
|
||||
f32 layout_cursor = parent->layout.cursor;
|
||||
f32 offset[2] = Zi;
|
||||
/* Compute offset in layout direction */
|
||||
{
|
||||
@ -1129,13 +1246,13 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
default: break;
|
||||
case UI_AxisAlignment_Center:
|
||||
{
|
||||
f32 parent_size = parent->solved_dims[axis];
|
||||
f32 parent_size = parent->layout.solved_dims[axis];
|
||||
f32 box_size = dims_arr[axis];
|
||||
offset[axis] = parent_size / 2 - box_size / 2;
|
||||
} break;
|
||||
case UI_AxisAlignment_End:
|
||||
{
|
||||
f32 parent_size = parent->solved_dims[axis];
|
||||
f32 parent_size = parent->layout.solved_dims[axis];
|
||||
f32 box_size = dims_arr[axis];
|
||||
offset[axis] = parent_size - box_size;
|
||||
} break;
|
||||
@ -1143,7 +1260,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
}
|
||||
final_pos.x = parent->rect.p0.x + offset[0];
|
||||
final_pos.y = parent->rect.p0.y + offset[1];
|
||||
parent->layout_cursor += dims_arr[parent->desc.child_layout_axis];
|
||||
parent->layout.cursor += dims_arr[parent->desc.child_layout_axis];
|
||||
}
|
||||
|
||||
/* Submit position */
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
//~ Key types
|
||||
|
||||
#define UI_NilKey ((UI_Key) { 0 })
|
||||
#define UI_RootKey ((UI_Key) { 0xa3deb3749ef35a7aUll })
|
||||
#define UI_RootKey ((UI_Key) { 0xaaaaaaaaaaaaaaaaUll })
|
||||
|
||||
Struct(UI_Key)
|
||||
{
|
||||
@ -253,7 +253,7 @@ Struct(UI_Box)
|
||||
UI_Box *next_in_bin;
|
||||
UI_Box *prev_in_bin;
|
||||
UI_Report report;
|
||||
u64 last_updated_tick;
|
||||
i64 last_build_tick;
|
||||
|
||||
//- Tree links
|
||||
UI_Box *parent;
|
||||
@ -267,16 +267,19 @@ Struct(UI_Box)
|
||||
UI_BoxDesc desc;
|
||||
G_Texture2DRef raw_texture;
|
||||
Rng2 raw_texture_slice_uv;
|
||||
GC_Run glyph_run;
|
||||
|
||||
//- Pre-layout data
|
||||
u64 pre_index;
|
||||
u64 post_index;
|
||||
|
||||
//- Layout data
|
||||
GC_Run glyph_run;
|
||||
f32 layout_cursor;
|
||||
struct
|
||||
{
|
||||
f32 cursor;
|
||||
f32 solved_dims[Axis_CountXY];
|
||||
f32 final_children_size_accum[Axis_CountXY];
|
||||
} layout;
|
||||
|
||||
//- Layout results
|
||||
Rng2 rect;
|
||||
@ -293,9 +296,30 @@ Struct(UI_BoxBin)
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ State types
|
||||
//~ Iterator types
|
||||
|
||||
#define UI_NumBoxLookupBins 16384
|
||||
Struct(UI_BoxIterDfsNode)
|
||||
{
|
||||
UI_BoxIterDfsNode *next;
|
||||
UI_Box *box;
|
||||
b32 visited;
|
||||
};
|
||||
|
||||
Struct(UI_BoxIter)
|
||||
{
|
||||
UI_BoxIterDfsNode *first;
|
||||
UI_BoxIterDfsNode *first_free;
|
||||
UI_BoxIterDfsNode *last_free;
|
||||
};
|
||||
|
||||
Struct(UI_BoxIterResult)
|
||||
{
|
||||
UI_Box *box;
|
||||
b32 pre;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Context types
|
||||
|
||||
Enum(UI_FrameFlag)
|
||||
{
|
||||
@ -314,10 +338,8 @@ Struct(UI_Frame)
|
||||
G_ResourceHandle backbuffer;
|
||||
G_CommandListHandle cl;
|
||||
|
||||
u64 transient_key_seed;
|
||||
|
||||
/* Time */
|
||||
u64 tick;
|
||||
i64 tick;
|
||||
i64 time_ns;
|
||||
i64 dt_ns;
|
||||
|
||||
@ -338,21 +360,25 @@ Struct(UI_Frame)
|
||||
UI_StyleNode *first_free_style_node;
|
||||
|
||||
/* Layout */
|
||||
UI_Box *root_box;
|
||||
UI_Box **boxes_pre;
|
||||
UI_Box **boxes_post;
|
||||
};
|
||||
|
||||
Struct(UI_State)
|
||||
Struct(UI_Ctx)
|
||||
{
|
||||
Arena *box_arena;
|
||||
UI_BoxBin *box_bins;
|
||||
u64 boxes_count;
|
||||
Arena *box_arena;
|
||||
UI_Box *root_box;
|
||||
UI_BoxBin box_bins[Kibi(256)];
|
||||
UI_Box *first_free_box;
|
||||
|
||||
u64 current_frame_idx;
|
||||
u64 transient_key_seed;
|
||||
|
||||
i64 current_frame_tick;
|
||||
UI_Frame frames[2];
|
||||
} extern UI_state;
|
||||
};
|
||||
|
||||
extern UI_Ctx UI;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Bootstrap
|
||||
@ -367,14 +393,19 @@ GC_FontKey UI_GetDefaultFont(void);
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
b32 UI_MatchKey(UI_Key a, UI_Key b);
|
||||
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_Key UI_TransKey(void);
|
||||
|
||||
UI_Box *UI_BoxFromKey(UI_Key key);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Iteration helpers
|
||||
|
||||
UI_BoxIterResult UI_FirstBox(Arena *arena, UI_BoxIter *iter, UI_Key start_key);
|
||||
UI_BoxIterResult UI_NextBox(Arena *arena, UI_BoxIter *iter);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ String helpers
|
||||
|
||||
@ -454,6 +485,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color);
|
||||
//~ Frame helpers
|
||||
|
||||
UI_Frame *UI_CurrentFrame(void);
|
||||
UI_Frame *UI_LastFrame(void);
|
||||
Arena *UI_FrameArena(void);
|
||||
Vec2 UI_CursorPos(void);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user