diff --git a/src/base/base.h b/src/base/base.h index dff562c7..aab6e04a 100644 --- a/src/base/base.h +++ b/src/base/base.h @@ -378,6 +378,7 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); #define Color_Yellow Rgb32(0xFF, 0xFF, 0x00) #define Color_Orange Rgb32(0xFF, 0xA5, 0x00) #define Color_Purple Rgb32(0xFF, 0x00, 0XFF) +#define Color_Cyan Rgb32(0x00, 0xFF, 0XFF) //////////////////////////////////////////////////////////// //~ Intrinsic headers diff --git a/src/config.h b/src/config.h index 580ea6fa..19d12830 100644 --- a/src/config.h +++ b/src/config.h @@ -72,8 +72,6 @@ #define GPU_DEBUG 1 #define GPU_DEBUG_VALIDATION 0 -#define UI_DEBUG 0 - /* If virtual fibers are enabled, each fiber will get its own OS thread, * and fiber suspend/resume will be emulated using OS thread primitives. * This is slow but allows for easier debugging in tricky cases diff --git a/src/pp/pp.c b/src/pp/pp.c index 621a166e..e0168bd7 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -394,7 +394,13 @@ void PP_UpdateUser(void) g->screen_size.y = MaxI32(g->screen_size.y, 1); //- Begin UI - UI_BeginBuild(controller_events); + UI_BuildFlag ui_build_flags = 0; + if (g->ui_debug) + { + ui_build_flags |= UI_BuildFlag_Debug; + } + + UI_BeginBuild(controller_events, ui_build_flags); UI_Push(LayoutAxis, Axis_Y); if (window_frame.forced_top) { @@ -676,6 +682,11 @@ void PP_UpdateUser(void) g->debug_camera = !g->debug_camera; } + if (g->bind_states[PP_BindKind_DebugUi].num_presses > 0) + { + g->ui_debug = !g->ui_debug; + } + if (g->bind_states[PP_BindKind_DebugLister].num_presses > 0) { g->lister_active = !g->lister_active; @@ -1953,22 +1964,28 @@ void PP_UpdateUser(void) UI_Push(BorderColor, Rgba32F(0.2, 0.2, 0.2, 1)); UI_Push(Border, 2); - UI_SetNext(FloatingPos, g->lister_pos); - UI_SetNext(LayoutAxis, Axis_Y); - UI_SetNext(Rounding, UI_RPIX(10)); + // UI_Size padding = UI_FILL(1, 0); + // UI_Size padding = UI_PIX(10, 0); + UI_Push(Width, UI_PIX(size.x, 0)); + UI_Push(Height, UI_PIX(size.y, 0)); + + UI_Push(LayoutAxis, Axis_Y); + UI_Push(FloatingPos, g->lister_pos); UI_SetNext(Flags, UI_BoxFlag_Floating); - UI_SetNext(Width, UI_PIX(size.x, 0)); - UI_SetNext(Height, UI_PIX(size.y, 0)); + UI_SetNext(Rounding, UI_RPIX(50)); UI_Box *lister_box = UI_BuildBox(Lit("lister")); - UI_PushCP(lister_box); + UI_Box *lister_pad = lister_box; + UI_PushCP(lister_pad); { - UI_Push(BackgroundColor, 0); // UI_BuildSpacer(UI_PIX(10, 0)); + UI_Push(BackgroundColor, 0); + UI_Push(LayoutAxis, Axis_X); + UI_Push(Width, UI_FILL(1, 0)); + UI_Push(Height, UI_FNT(5, 0)); { - UI_SetNext(LayoutAxis, Axis_X); - UI_SetNext(Width, UI_FILL(1, 0)); - UI_SetNext(Height, UI_FNT(1, 0)); - // UI_SetNext(Border, 0); + UI_Push(BackgroundColor, Color_Orange); + UI_Push(Border, 2); + UI_Box *title_bar = UI_BuildBox(Zstr); UI_PushCP(title_bar); { @@ -1976,19 +1993,27 @@ void PP_UpdateUser(void) UI_Push(Padding, 0); UI_Push(BackgroundColor, 0); UI_Push(Border, 0); - { - UI_Box *left_box = UI_BuildBox(Zstr); - } + + UI_Box *left_box = UI_BuildBox(Zstr); + // UI_SetNext(LeftPadding, UI_PIX(10, 1)); + // UI_SetNext(Padding, UI_PAD(UI_FILL(1, 0))); + UI_Box *center_box = UI_BuildBox(Zstr); + UI_Box *right_box = UI_BuildBox(Zstr); + + // UI_Pad title_padding = UI_PADEX(.left = UI_PIX(50, 0), .right = UI_PIX(50, 0), .bottom = UI_PIX(10, 0)); + // UI_Pad title_padding = UI_PAD(UI_FILL(1, 0)); + // UI_Box *center_pad = UI_BuildPad(center_box, title_padding); + // UI_Box *center_pad = center_box; + UI_PushCP(center_box); { UI_SetNext(Text, Lit("Title")); UI_SetNext(Flags, UI_BoxFlag_DrawText); - UI_SetNext(Width, UI_FIT(1)); + // UI_SetNext(Padding, UI_PADEX(.left = UI_PIX(100, 0), .right = UI_PIX(50, 0), .bottom = UI_PIX(10, 0))); + // UI_SetNext(Padding, UI_PADEX(.left = UI_PIX(1, 0))); + UI_SetNext(Padding, UI_PADALL(UI_FILL(1, 0))); UI_Box *title_box = UI_BuildBox(Zstr); } - { - UI_Box *right_box = UI_BuildBox(Zstr); - - } + UI_PopCP(); } UI_PopCP(); } @@ -2017,7 +2042,7 @@ void PP_UpdateUser(void) { UI_Push(BackgroundColor, 0); UI_Push(BorderColor, 0); - UI_Push(Padding, 2); + // UI_Push(Padding, UI_PIX(5, 0)); UI_BuildLabelF("Blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved)); UI_BuildLabelF("Blended world tick: %F", FmtUint(g->ss_blended->tick)); diff --git a/src/pp/pp.h b/src/pp/pp.h index a7633a49..f21488ad 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -33,6 +33,7 @@ Enum(PP_BindKind) PP_BindKind_DebugTeleport, PP_BindKind_DebugExplode, PP_BindKind_DebugToggleTopmost, + PP_BindKind_DebugUi, PP_BindKind_FullscreenMod, PP_BindKind_Fullscreen, PP_BindKind_ZoomIn, @@ -83,6 +84,7 @@ Global Readonly PP_BindKind g_binds[Btn_Count] = { [Btn_F3] = PP_BindKind_DebugDraw, [Btn_Tab] = PP_BindKind_DebugLister, [Btn_F4] = PP_BindKind_DebugToggleTopmost, + [Btn_F5] = PP_BindKind_DebugUi, [Btn_GraveAccent] = PP_BindKind_DebugConsole, [Btn_Alt] = PP_BindKind_FullscreenMod, [Btn_Enter] = PP_BindKind_Fullscreen, @@ -245,6 +247,8 @@ Struct(PP_SharedUserState) //- Debug ui + b32 ui_debug; + PP_EntKey debug_following; Vec2 debug_camera_pan_start; b32 debug_camera_panning; diff --git a/src/pp/pp_widgets.c b/src/pp/pp_widgets.c index 6b0a8456..45372202 100644 --- a/src/pp/pp_widgets.c +++ b/src/pp/pp_widgets.c @@ -124,9 +124,9 @@ UI_Box *PP_BuildDebugConsole(b32 minimized) UI_Box *log_box = UI_BuildBox(Zstr); UI_PushCP(log_box); { + UI_SetNext(Padding, UI_PADALL(UI_FNT(0.25, 0))); UI_SetNext(BackgroundColor, 0); UI_SetNext(Border, 0); - UI_SetNext(Padding, 6); UI_SetNext(Text, text); UI_SetNext(Width, UI_FILL(1, 0)); UI_SetNext(Height, UI_FIT(1)); diff --git a/src/ui/ui_common.c b/src/ui/ui_common.c index ba3e8208..a207effc 100644 --- a/src/ui/ui_common.c +++ b/src/ui/ui_common.c @@ -1,6 +1,5 @@ //////////////////////////////////////////////////////////// -//~ Label widget - +//~ Label helpers UI_Box *UI_BuildLabel(String text) { UI_SetNext(Width, UI_FIT(0)); @@ -27,19 +26,32 @@ UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...) } //////////////////////////////////////////////////////////// -//~ Spacing widgets +//~ Spacing helpers UI_Box *UI_BuildSpacer(UI_Size size) { - UI_SetNext(Tint, 0); - if (UI_PeekTop(Parent)->layout_axis == Axis_X) + UI_Box *box = 0; + + UI_Size old_width = UI_PeekTop(Width); + UI_Size old_height = UI_PeekTop(Height); + UI_Box *old_parent = UI_PeekTop(Parent); + + UI_PushStack(); { - UI_SetNext(Width, size); + UI_SetNext(Tint, 0); + UI_SetNext(Parent, old_parent); + if (old_parent->layout_axis == Axis_X) + { + UI_SetNext(Width, size); + UI_SetNext(Height, old_height); + } + else + { + UI_SetNext(Width, old_width); + UI_SetNext(Height, size); + } + box = UI_BuildBox(Zstr); } - else - { - UI_SetNext(Height, size); - } - UI_Box *box = UI_BuildBox(Zstr); + UI_PopStack(); return box; } diff --git a/src/ui/ui_common.h b/src/ui/ui_common.h index faeb3b1e..ccb37579 100644 --- a/src/ui/ui_common.h +++ b/src/ui/ui_common.h @@ -1,11 +1,11 @@ //////////////////////////////////////////////////////////// -//~ Label widget +//~ Label helpers UI_Box *UI_BuildLabel(String text); #define UI_BuildLabelF(fmt_cstr, ...) UI_BuildLabelF_(fmt_cstr, __VA_ARGS__, FmtEnd) UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...); //////////////////////////////////////////////////////////// -//~ Spacing widgets +//~ Spacing helpers UI_Box *UI_BuildSpacer(UI_Size size); diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 9189f21c..505b1df4 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -65,6 +65,7 @@ UI_Box *UI_FrontBoxFromKey(UI_Key key) void UI_PushCP(UI_Box *parent) { UI_SharedState *g = &UI_shared_state; + UI_Stack *stack = g->top_stack; UI_Checkpoint *cp = g->first_free_checkpoint; if (cp) { @@ -75,9 +76,9 @@ void UI_PushCP(UI_Box *parent) { cp = PushStruct(g->build_arena, UI_Checkpoint); } - cp->next = g->top_checkpoint; - cp->v = g->top_checkpoint->v + 1; - g->top_checkpoint = cp; + cp->next = stack->top_checkpoint; + cp->v = stack->top_checkpoint->v + 1; + stack->top_checkpoint = cp; if (parent != 0) { UI_Push(Parent, parent); @@ -87,22 +88,23 @@ void UI_PushCP(UI_Box *parent) void UI_PopCP(void) { UI_SharedState *g = &UI_shared_state; - UI_Checkpoint *cp = g->top_checkpoint; + UI_Stack *stack = g->top_stack; + UI_Checkpoint *cp = stack->top_checkpoint; u64 v = cp->v; /* Pop styles */ for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind) { - UI_StyleNode *n = g->style_tops[kind]; + UI_StyleNode *n = stack->style_tops[kind]; while (n && n->checkpoint >= v) { UI_StyleNode *next = n->next; n->next = g->first_free_style_node; g->first_free_style_node = n; - g->style_tops[kind] = next; + stack->style_tops[kind] = next; n = next; } } - g->top_checkpoint = cp->next; + stack->top_checkpoint = cp->next; cp->next = g->first_free_checkpoint; g->first_free_checkpoint = cp; } @@ -110,101 +112,321 @@ void UI_PopCP(void) //////////////////////////////////////////////////////////// //~ Style stack helpers -UI_StyleNode *UI_PushStyleNode(UI_Style desc) +void UI_PushStack(void) { UI_SharedState *g = &UI_shared_state; - UI_StyleNode *n = g->style_tops[desc.kind]; - b32 cancel = 0; - if (!n->style.forced) + UI_Stack *stack = PushStruct(g->build_arena, UI_Stack); + + /* Init checkpoint */ { + UI_Checkpoint *cp = g->first_free_checkpoint; + if (cp) { - if (n->style.pop_when_used) + g->first_free_checkpoint = cp->next; + ZeroStruct(cp); + } + else + { + cp = PushStruct(g->build_arena, UI_Checkpoint); + } + stack->top_checkpoint = cp; + } + + /* Init styles */ + { + for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind) + { + UI_StyleNode *n = g->first_free_style_node; + if (n) { + g->first_free_style_node = n->next; ZeroStruct(n); } else { - 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 = PushStruct(g->build_arena, UI_StyleNode); } - n->style = desc; - n->checkpoint = g->top_checkpoint->v; + n->style.kind = kind; + stack->style_tops[kind] = n; } + stack->style_tops[UI_StyleKind_Parent]->style.Parent = g->root_box; + stack->style_tops[UI_StyleKind_Width]->style.Width = UI_FILL(1, 0); + stack->style_tops[UI_StyleKind_Height]->style.Height = UI_FILL(1, 0); + stack->style_tops[UI_StyleKind_Font]->style.Font = UI_GetDefaultFontResource(); + stack->style_tops[UI_StyleKind_FontSize]->style.FontSize = 16.0f; + stack->style_tops[UI_StyleKind_Tint]->style.Tint = 0xFFFFFFFF; + stack->style_tops[UI_StyleKind_Tag]->style.Tag.name = Lit("root"); + stack->style_tops[UI_StyleKind_Tag]->style.Tag.hash = HashFnv64(Fnv64Basis, stack->style_tops[UI_StyleKind_Tag]->style.Tag.name); + } - /* Initialize style data from desc */ - switch (desc.kind) + stack->next = g->top_stack; + g->top_stack = stack; +} + +void UI_PopStack(void) +{ + UI_SharedState *g = &UI_shared_state; + UI_Stack *stack = g->top_stack; + + /* Free checkpoints */ + { + UI_Checkpoint *cp = stack->top_checkpoint; + while (cp) + { + UI_Checkpoint *next = cp->next; + cp->next = g->first_free_checkpoint; + g->first_free_checkpoint = cp; + cp = next; + } + } + + /* Free style nodes */ + for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind) + { + UI_StyleNode *n = stack->style_tops[kind]; + while (n) + { + UI_StyleNode *next = n->next; + n->next = g->first_free_style_node; + g->first_free_style_node = n; + n = next; + } + } + + g->top_stack = stack->next; + stack->next = g->first_free_stack; + g->first_free_stack = stack; +} + +void UI_PushStyle(UI_Style desc) +{ + UI_SharedState *g = &UI_shared_state; + UI_Stack *stack = g->top_stack; + + if (desc.kind >= UI_StyleKind_BeginVirtualStyles_) + { + switch(desc.kind) { default: break; - case UI_StyleKind_Text: + case UI_StyleKind_Padding: { - 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); - } + UI_Pad pad = desc.Padding; + UI_PushCopy(TopPadding, desc, pad.top); + UI_PushCopy(BottomPadding, desc, pad.bottom); + UI_PushCopy(LeftPadding, desc, pad.left); + UI_PushCopy(RightPadding, desc, pad.right); } break; } } - g->style_tops[desc.kind] = n; - return n; + else + { + UI_StyleNode *n = stack->style_tops[desc.kind]; + if (!n->style.forced) + { + { + if (n->style.pop_when_used) + { + UI_StyleNode *next = n->next; + ZeroStruct(n); + n->next = next; + } + else + { + 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 = stack->style_tops[desc.kind]; + stack->style_tops[desc.kind] = n; + } + n->style = desc; + n->checkpoint = stack->top_checkpoint->v; + } + + /* Initialize style data from desc */ + switch (desc.kind) + { + default: break; + + case UI_StyleKind_Text: + { + 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(stack->style_tops[desc.kind]->style.Tag.hash, n->style.Tag.name); + } + } break; + } + } + } } -UI_Style UI_PopStyleNode(UI_StyleKind kind) +UI_Style UI_PopStyle(UI_StyleKind kind) { UI_SharedState *g = &UI_shared_state; - UI_StyleNode *n = g->style_tops[kind]; + UI_Stack *stack = g->top_stack; + UI_StyleNode *n = stack->style_tops[kind]; UI_Style style = n->style; - g->style_tops[kind] = n->next; + stack->style_tops[kind] = n->next; n->next = g->first_free_style_node; g->first_free_style_node = n; return style; } -UI_StyleNode *UI_PeekStyleNode(UI_StyleKind kind) +UI_Style UI_FetchStyle(UI_StyleKind kind, b32 use) { UI_SharedState *g = &UI_shared_state; - UI_StyleNode *n = g->style_tops[kind]; - return n; -} - -UI_Style UI_StyleFromTopNode(UI_StyleKind kind, b32 use) -{ - UI_SharedState *g = &UI_shared_state; - UI_StyleNode *n = g->style_tops[kind]; - UI_Style style = n->style; - if (use && n->style.pop_when_used) + UI_Stack *stack = g->top_stack; + UI_Style result = ZI; + result.kind = kind; + if (kind >= UI_StyleKind_BeginVirtualStyles_) { - g->style_tops[kind] = n->next; - n->next = g->first_free_style_node; - g->first_free_style_node = n; + switch(kind) + { + default: break; + + case UI_StyleKind_Padding: + { + result.Padding.top = UI_FetchTop(TopPadding, use); + result.Padding.bottom = UI_FetchTop(BottomPadding, use); + result.Padding.left = UI_FetchTop(LeftPadding, use); + result.Padding.right = UI_FetchTop(RightPadding, use); + } break; + } } - return style; + else + { + UI_StyleNode *n = stack->style_tops[kind]; + result = n->style; + if (use && n->style.pop_when_used) + { + stack->style_tops[kind] = n->next; + n->next = g->first_free_style_node; + g->first_free_style_node = n; + } + + } + return result; } //////////////////////////////////////////////////////////// -//~ Box helpers +//~ Padding helpers + +UI_Box *UI_BuildPadAlongAxis(UI_Box *parent, UI_Size start, UI_Size end, Axis final_layout_axis) +{ + UI_Box *pad = parent; + b32 has_start_padding = !(start.kind == UI_SizeKind_Pixel && start.v == 0); + b32 has_end_padding = !(end.kind == UI_SizeKind_Pixel && end.v == 0); + UI_Size old_width = UI_PeekTop(Width); + UI_Size old_height = UI_PeekTop(Height); + { + UI_PushStack(); + { + UI_PushCP(parent); + { + UI_ForcePush(Padding, UI_PIX(0, 0)); + UI_Push(Tint, 0); + /* Start */ + if (has_start_padding) + { + if (parent->layout_axis == Axis_X) + { + UI_SetNext(Width, start); + UI_SetNext(Height, old_height); + } + else + { + UI_SetNext(Width, old_width); + UI_SetNext(Height, start); + } + UI_BuildBox(Zstr); + } + /* Pad */ + { + UI_SetNext(Width, old_width); + UI_SetNext(Height, old_height); + UI_SetNext(LayoutAxis, final_layout_axis); + pad = UI_BuildBox(Zstr); + } + /* End */ + if (has_end_padding) + { + if (parent->layout_axis == Axis_X) + { + UI_SetNext(Width, end); + UI_SetNext(Height, old_height); + } + else + { + UI_SetNext(Width, old_width); + UI_SetNext(Height, end); + } + UI_BuildBox(Zstr); + } + } + UI_PopCP(); + } + UI_PopStack(); + } + return pad; +} + +UI_Box *UI_BuildPad(UI_Box *parent, UI_Pad padding) +{ + UI_Box *pad = parent; + b32 has_top_padding = !(padding.top.kind == UI_SizeKind_Pixel && padding.top.v == 0); + b32 has_bottom_padding = !(padding.bottom.kind == UI_SizeKind_Pixel && padding.bottom.v == 0); + b32 has_left_padding = !(padding.left.kind == UI_SizeKind_Pixel && padding.left.v == 0); + b32 has_right_padding = !(padding.right.kind == UI_SizeKind_Pixel && padding.right.v == 0); + if (has_top_padding || has_bottom_padding || has_left_padding || has_right_padding) + { + if (parent->layout_axis == Axis_X) + { + b32 needs_second_pass = has_top_padding || has_bottom_padding; + pad = UI_BuildPadAlongAxis(pad, padding.left, padding.right, needs_second_pass ? Axis_Y : Axis_X); + if (needs_second_pass) + { + pad = UI_BuildPadAlongAxis(pad, padding.top, padding.bottom, Axis_X); + } + } + else + { + b32 needs_second_pass = has_left_padding || has_right_padding; + pad = UI_BuildPadAlongAxis(pad, padding.top, padding.bottom, needs_second_pass ? Axis_X : Axis_Y); + if (needs_second_pass) + { + pad = UI_BuildPadAlongAxis(pad, padding.left, padding.right, Axis_Y); + } + } + } + return pad; +} + +//////////////////////////////////////////////////////////// +//~ Box UI_Box *UI_BuildBox(String seed) { UI_SharedState *g = &UI_shared_state; + UI_Box *parent = UI_UseTop(Parent); + + /* Create padding */ + UI_Pad padding = UI_UseTop(Padding); + parent = UI_BuildPad(parent, padding); /* Calculate key */ - UI_Box *parent = UI_UseTop(Parent); UI_Tag tag = UI_UseTop(Tag); UI_Key key = ZI; if (seed.len > 0) @@ -259,7 +481,6 @@ UI_Box *UI_BuildBox(String seed) box->border = UI_UseTop(Border); box->font_resource = UI_UseTop(Font); box->font_size = UI_UseTop(FontSize); - box->padding = UI_UseTop(Padding); box->rounding = UI_UseTop(Rounding); box->text = UI_UseTop(Text); box->floating_pos = UI_UseTop(FloatingPos); @@ -304,7 +525,7 @@ UI_Event UI_EventFromKey(UI_Key key) //////////////////////////////////////////////////////////// //~ Begin build -void UI_BeginBuild(ControllerEventsArray controller_events) +void UI_BeginBuild(ControllerEventsArray controller_events, UI_BuildFlag build_flags) { UI_SharedState *g = &UI_shared_state; @@ -409,6 +630,7 @@ void UI_BeginBuild(ControllerEventsArray controller_events) g->back_boxes_count = g->boxes_count; g->back_boxes_pre = g->boxes_pre; g->back_boxes_post = g->boxes_post; + g->back_build_flags = g->build_flags; } ////////////////////////////// @@ -423,6 +645,9 @@ void UI_BeginBuild(ControllerEventsArray controller_events) g->boxes_count = 0; g->first_free_style_node = 0; g->first_free_checkpoint = 0; + g->first_free_stack = 0; + + g->build_flags = build_flags; /* Init bins */ g->box_bins = PushStructs(g->build_arena, UI_BoxBin, UI_NumBoxLookupBins); @@ -437,38 +662,14 @@ void UI_BeginBuild(ControllerEventsArray controller_events) if (!g->back_build_arena) { /* Back buffer not initialized, swap again */ - UI_BeginBuild(controller_events); + UI_BeginBuild(controller_events, build_flags); } } - ////////////////////////////// //- 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); - } - } + UI_PushStack(); } //////////////////////////////////////////////////////////// @@ -594,7 +795,7 @@ i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf) text_size = box->font->ascent + box->font->descent; } } - box->solved_dims[axis] = text_size + box->padding * 2; + box->solved_dims[axis] = text_size; } } } @@ -840,7 +1041,7 @@ i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf) is_visible = is_visible && ((box->tint & 0xFF000000) != 0); is_visible = is_visible && (box->p1.x > box->p0.x); is_visible = is_visible && (box->p1.y > box->p0.y); - if (is_visible || UI_DEBUG) + if (is_visible || AnyBit(g->build_flags, UI_BuildFlag_Debug)) { /* Box rect */ { @@ -905,13 +1106,12 @@ i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf) f32 ascent = box->font->ascent; f32 descent = box->font->descent; - f32 padding = box->padding; Vec2 baseline = box->p0; - baseline = AddVec2(baseline, VEC2(padding, padding + ascent)); + baseline.y += ascent; F_Run run = box->glyph_run; - f32 max_baseline = box->p1.x - (padding * 2); + f32 max_baseline = box->p1.x; b32 should_truncate = run.count > 0 && (run.rects[run.count - 1].pos + run.rects[run.count - 1].advance) > max_baseline; /* Truncate run */ @@ -1021,7 +1221,7 @@ i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf) } /* Render rect wireframes */ - if (UI_DEBUG) + if (AnyBit(g->build_flags, UI_BuildFlag_Debug)) { UI_RectSig sig = ZI; sig.viewport_size = RoundVec2ToVec2I32(render_viewport.size); diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index eaafe53c..ebe70b57 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -9,14 +9,23 @@ Struct(UI_Key) u64 hash; }; +//////////////////////////////////////////////////////////// +//~ Build flags + +Enum(UI_BuildFlag) +{ + UI_BuildFlag_None = 0, + UI_BuildFlag_Debug = (1 << 0), +}; + //////////////////////////////////////////////////////////// //~ Size types Enum(UI_SizeKind) { - UI_SizeKind_Fit, /* Size to contents */ - UI_SizeKind_Fill, /* Size as percent of parent size */ UI_SizeKind_Pixel, /* Exact size */ + UI_SizeKind_Fill, /* Size as percent of parent size */ + UI_SizeKind_Fit, /* Size to contents */ }; Struct(UI_Size) @@ -42,7 +51,27 @@ Struct(UI_Round) }; //////////////////////////////////////////////////////////// -//~ Box flag types +//~ Padding types + +Struct(UI_Pad) +{ + UI_Size top; + UI_Size bottom; + UI_Size left; + UI_Size right; +}; + +//////////////////////////////////////////////////////////// +//~ Checkpoint types + +Struct(UI_Checkpoint) +{ + UI_Checkpoint *next; + u64 v; +}; + +//////////////////////////////////////////////////////////// +//~ Box flags Enum(UI_BoxFlag) { @@ -68,12 +97,20 @@ Enum(UI_BoxFlag) x(BorderColor, u32) \ x(Tint, u32) \ x(Border, f32) \ + x(FloatingPos, Vec2) \ + x(Rounding, UI_Round) \ x(Font, ResourceKey) \ x(FontSize, u32) \ x(Text, String) \ - x(Padding, f32) \ - x(Rounding, UI_Round) \ - x(FloatingPos, Vec2) \ + x(LeftPadding, UI_Size) \ + x(RightPadding, UI_Size) \ + x(TopPadding, UI_Size) \ + x(BottomPadding, UI_Size) \ + /* ----------------------------------- */ \ + /* --------- Virtual styles --------- */ \ + /* ----------------------------------- */ \ + x(BeginVirtualStyles_, i8) \ + x(Padding, UI_Pad) \ /* ------------------------------------------- */ Struct(UI_Tag) @@ -112,13 +149,12 @@ Struct(UI_StyleNode) UI_Style style; }; -//////////////////////////////////////////////////////////// -//~ Checkpoint types - -Struct(UI_Checkpoint) +Struct(UI_Stack) { - UI_Checkpoint *next; - u64 v; + UI_Stack *next; + + UI_Checkpoint *top_checkpoint; + UI_StyleNode *style_tops[UI_StyleKind_Count]; }; //////////////////////////////////////////////////////////// @@ -174,10 +210,9 @@ Struct(UI_Box) f32 border; Vec2 floating_pos; String text; - Axis layout_axis; ResourceKey font_resource; f32 font_size; - f32 padding; + Axis layout_axis; //- Pre-layout data u64 pre_index; @@ -219,6 +254,9 @@ Struct(UI_SharedState) Arena *build_arena; Arena *back_build_arena; + UI_BuildFlag build_flags; + UI_BuildFlag back_build_flags; + UI_BoxBin *box_bins; UI_BoxBin *back_box_bins; @@ -228,8 +266,8 @@ Struct(UI_SharedState) u64 boxes_count; u64 back_boxes_count; - UI_Checkpoint *top_checkpoint; - UI_StyleNode *style_tops[UI_StyleKind_Count]; + UI_Stack *top_stack; + UI_Stack *first_free_stack; UI_Checkpoint *first_free_checkpoint; UI_StyleNode *first_free_style_node; @@ -269,20 +307,30 @@ void UI_PushCP(UI_Box *parent); void UI_PopCP(void); //////////////////////////////////////////////////////////// -//~ Style helpers +//~ Style stack helpers -UI_StyleNode *UI_PushStyleNode(UI_Style desc); -UI_Style UI_PopStyleNode(UI_StyleKind kind); -UI_StyleNode *UI_PeekTopStyleNode(UI_StyleKind kind); -UI_Style UI_StyleFromTopNode(UI_StyleKind kind, b32 use); +void UI_PushStack(void); +void UI_PopStack(void); -#define UI_SetNext(name, ...) UI_PushStyleNode((UI_Style) { .kind = UI_StyleKind_##name, .name = __VA_ARGS__, .pop_when_used = 1 }) -#define UI_Push(name, ...) UI_PushStyleNode((UI_Style) { .kind = UI_StyleKind_##name, .name = __VA_ARGS__ }) -#define UI_ForceNext(name, ...) UI_PushStyleNode((UI_Style) { .kind = UI_StyleKind_##name, .name = __VA_ARGS__, .pop_when_used = 1, .forced = 1 }) -#define UI_ForcePush(name, ...) UI_PushStyleNode((UI_Style) { .kind = UI_StyleKind_##name, .name = __VA_ARGS__, .forced = 1 }) -#define UI_Pop(name) UI_PopStyleNode(UI_StyleKind_##name).name -#define UI_UseTop(name) UI_StyleFromTopNode(UI_StyleKind_##name, 1).name -#define UI_PeekTop(name) UI_StyleFromTopNode(UI_StyleKind_##name, 0).name +void UI_PushStyle(UI_Style desc); +UI_Style UI_PopStyle(UI_StyleKind kind); +UI_Style UI_FetchStyle(UI_StyleKind kind, b32 use); + +#define UI_SetNext(name, ...) UI_PushStyle((UI_Style) { .kind = UI_StyleKind_##name, .name = __VA_ARGS__, .pop_when_used = 1 }) +#define UI_Push(name, ...) UI_PushStyle((UI_Style) { .kind = UI_StyleKind_##name, .name = __VA_ARGS__ }) +#define UI_ForceNext(name, ...) UI_PushStyle((UI_Style) { .kind = UI_StyleKind_##name, .name = __VA_ARGS__, .pop_when_used = 1, .forced = 1 }) +#define UI_ForcePush(name, ...) UI_PushStyle((UI_Style) { .kind = UI_StyleKind_##name, .name = __VA_ARGS__, .forced = 1 }) +#define UI_Pop(name) UI_PopStyle(UI_StyleKind_##name).name +#define UI_FetchTop(name, use) UI_FetchStyle(UI_StyleKind_##name, use).name +#define UI_PeekTop(name) UI_FetchTop(name, 0) +#define UI_UseTop(name) UI_FetchTop(name, 1) + +#define UI_PushCopy(name, src, ...) do { \ + UI_Style _new = src; \ + _new.kind = UI_StyleKind_##name; \ + _new.name = __VA_ARGS__; \ + UI_PushStyle(_new); \ +} while (0) //////////////////////////////////////////////////////////// //~ Size helpers @@ -302,6 +350,15 @@ UI_Style UI_StyleFromTopNode(UI_StyleKind kind, b32 use); #define UI_RPIX(_v) UI_ROUND(UI_RoundKind_Pixel, (_v)) #define UI_RFILL(_v) UI_ROUND(UI_RoundKind_Fill, (_v)) +//////////////////////////////////////////////////////////// +//~ Padding helpers + +#define UI_PAD(...) ((UI_Pad) { __VA_ARGS__ }) +#define UI_PADALL(size) ((UI_Pad) { .top = size, .bottom = size, .left = size, .right = size }) + +UI_Box *UI_BuildPadAlongAxis(UI_Box *parent, UI_Size start, UI_Size end, Axis final_layout_axis); +UI_Box *UI_BuildPad(UI_Box *parent, UI_Pad padding); + //////////////////////////////////////////////////////////// //~ Box @@ -317,7 +374,7 @@ UI_Event UI_EventFromKey(UI_Key key); //////////////////////////////////////////////////////////// //~ Begin build -void UI_BeginBuild(ControllerEventsArray controller_events); +void UI_BeginBuild(ControllerEventsArray controller_events, UI_BuildFlag flags); //////////////////////////////////////////////////////////// //~ End build