From 67ba54274f458656ecf6589b1e5d983a5d696267 Mon Sep 17 00:00:00 2001 From: jacob Date: Mon, 3 Nov 2025 00:34:13 -0600 Subject: [PATCH] ui control testing --- src/base/base.h | 1 + src/base/base_controller.h | 3 - src/pp/pp.c | 47 +++-- src/pp/pp.h | 5 +- src/pp/pp_widgets.c | 6 +- src/ui/ui_common.c | 5 +- src/ui/ui_core.c | 393 ++++++++++++++++++++++++++----------- src/ui/ui_core.h | 86 +++++--- 8 files changed, 381 insertions(+), 165 deletions(-) diff --git a/src/base/base.h b/src/base/base.h index b200cb65..7683c719 100644 --- a/src/base/base.h +++ b/src/base/base.h @@ -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 }) diff --git a/src/base/base_controller.h b/src/base/base_controller.h index 61b4dd9b..9f44e008 100644 --- a/src/base/base_controller.h +++ b/src/base/base_controller.h @@ -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) diff --git a/src/pp/pp.c b/src/pp/pp.c index 1044be26..5643602b 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -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 diff --git a/src/pp/pp.h b/src/pp/pp.h index f0256141..a7633a49 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -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; diff --git a/src/pp/pp_widgets.c b/src/pp/pp_widgets.c index 9f3fef42..0ff42917 100644 --- a/src/pp/pp_widgets.c +++ b/src/pp/pp_widgets.c @@ -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(); diff --git a/src/ui/ui_common.c b/src/ui/ui_common.c index 63170097..21948838 100644 --- a/src/ui/ui_common.c +++ b/src/ui/ui_common.c @@ -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; } diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 61ac7d64..094b52ac 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -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); diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index e422d21f..8d1fb969 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -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);