//////////////////////////////////////////////////////////// //~ Key types #define UI_NilKey ((UI_Key) { 0 }) #define UI_RootKey ((UI_Key) { 0xaaaaaaaaaaaaaaaaUll }) Struct(UI_Key) { u64 v; }; //////////////////////////////////////////////////////////// //~ Size types Enum(UI_SizeKind) { UI_SizeKind_Pixel, // Exact size UI_SizeKind_Grow, // Size as percent of parent size UI_SizeKind_Shrink, // Size of children + padding in pixels }; Struct(UI_Size) { UI_SizeKind kind; f32 v; f32 strictness; }; //////////////////////////////////////////////////////////// //~ Rounding types Enum(UI_RoundKind) { UI_RoundKind_Pixel, // Exact radius UI_RoundKind_Grow, // Radius as percent of size }; Struct(UI_Round) { UI_RoundKind kind; f32 v; }; //////////////////////////////////////////////////////////// //~ Region types Enum(UI_Region) { UI_Region_TopLeft, UI_Region_Top, UI_Region_TopRight, UI_Region_Left, UI_Region_Center, UI_Region_Right, UI_Region_BottomLeft, UI_Region_Bottom, UI_Region_BottomRight, }; Enum(UI_AxisRegion) { UI_AxisRegion_Start, UI_AxisRegion_Center, UI_AxisRegion_End, }; Union(UI_RegionPair) { struct { UI_AxisRegion x, y; }; UI_AxisRegion v[2]; }; //////////////////////////////////////////////////////////// //~ Checkpoint types Struct(UI_Checkpoint) { u64 v; }; //////////////////////////////////////////////////////////// //~ Box flags Enum(UI_BoxFlag) { UI_BoxFlag_None = 0, UI_BoxFlag_DrawText = (1 << 0), UI_BoxFlag_CaptureMouse = (1 << 1), UI_BoxFlag_CaptureThroughChildren = (1 << 2), UI_BoxFlag_DontTruncateText = (1 << 3), UI_BoxFlag_Floating = (1 << 4), UI_BoxFlag_DontClampFloatingX = (1 << 5), UI_BoxFlag_DontClampFloatingY = (1 << 6), UI_BoxFlag_Scissor = (1 << 7), }; //////////////////////////////////////////////////////////// //~ Debug breakpoint flags Enum(UI_DebugBreakFlag) { UI_DebugBreakFlag_None = 0, UI_DebugBreakFlag_CheckCursorHover = (1 << 0), UI_DebugBreakFlag_BuildFeedback = (1 << 1), UI_DebugBreakFlag_PrepLayout = (1 << 2), UI_DebugBreakFlag_IndependentSolve = (1 << 3), UI_DebugBreakFlag_UpwardsDependentSolveLayoutAxis = (1 << 4), UI_DebugBreakFlag_DownwardsDependentSolve = (1 << 5), UI_DebugBreakFlag_UpwardsDependentSolveNonLayoutAxis = (1 << 6), UI_DebugBreakFlag_SolveViolations = (1 << 7), UI_DebugBreakFlag_FinalSolve = (1 << 8), UI_DebugBreakFlag_BuildGpuData = (1 << 9), UI_DebugBreakFlag_All = 0xFFFFFFFF }; //////////////////////////////////////////////////////////// //~ Style types #define UI_StyleKindsXList(X) \ X(OmitFlags, UI_BoxFlag) \ X(OrFlags, UI_BoxFlag) \ X(Flags, UI_BoxFlag) \ X(DebugBreakFlags, UI_DebugBreakFlag) \ X(Parent, UI_Key) \ X(Tag, u64) \ X(ChildLayoutAxis, Axis) \ X(ChildAlignment, UI_Region) \ X(Width, UI_Size) \ X(Height, UI_Size) \ X(Scale, Vec2) \ X(BackgroundColor, Vec4) \ X(BorderColor, Vec4) \ X(DebugColor, Vec4) \ X(InvisibleDebugColor, Vec4) \ X(Tint, Vec4) \ X(Opacity, f32) \ X(BorderSize, f32) \ X(Anchor, UI_Region) \ X(FloatingPos, Vec2) \ X(Rounding, UI_Round) \ X(Font, GC_FontKey) \ X(FontSize, f32) \ X(TextColor, Vec4) \ X(Text, String) \ X(Icon, UI_Icon) \ X(SpriteSheet, SPR_SheetKey) \ X(SpriteSpan, SPR_SpanKey) \ X(SpriteSeq, i64) \ X(BackgroundTexture, G_TextureRef) \ X(BackgroundTextureSliceUv, Rng2) \ X(Misc, f64) \ X(ZagColor, Vec4) \ X(ZagPeriod, f32) \ X(ZagAmplitude, f32) \ X(ZagThickness, f32) \ X(ZagRoundness, f32) \ /* --------------------------------------------- */ \ /* --------------- Virtual styles -------------- */ \ /* --------------------------------------------- */ \ X(BeginVirtualStyles_, i8) \ /* --------------------------------------------- */ \ X(AxisSize, UI_Size) \ /* ------------------------------------------------- */ Enum(UI_StyleKind) { #define X(name, type) CAT(UI_StyleKind_,name), UI_StyleKind_None, UI_StyleKindsXList(X) UI_StyleKind_COUNT, #undef X }; Struct(UI_Style) { UI_StyleKind kind; // Union of all style fields union { #define X(name, type) type name; UI_StyleKindsXList(X) #undef X }; }; Struct(UI_StyleDesc) { Axis axis; UI_Style style; // Push b32 pop_when_used; b32 override; // Pop b32 force_pop; b32 use; }; Struct(UI_StyleNode) { UI_StyleNode *next; UI_Style style; UI_Checkpoint checkpoint; b32 pop_when_used; b32 override; }; Struct(UI_Stack) { UI_StyleNode *style_tops[UI_StyleKind_COUNT]; UI_Checkpoint top_checkpoint; }; //////////////////////////////////////////////////////////// //~ Input types Struct(UI_ButtonState) { b32 held; // Persistent i32 downs; // Mouse button down events over box causing activation i32 ups; // Mouse button up events while box is active i32 presses; // Mouse button events while box is active and hovered }; Struct(UI_InputState) { UI_ButtonState buttons[Button_COUNT]; }; //////////////////////////////////////////////////////////// //~ Feedback types Struct(UI_Feedback) { Rng2 screen_rect; Vec2 screen_anchor; b32 active_absolute; b32 hot_absolute; b32 hovered_absolute; b32 exists_absolute; f32 active_smooth; f32 hot_smooth; f32 hovered_smooth; f32 exists_smooth; f64 misc_smooth; }; //////////////////////////////////////////////////////////// //~ Command types Enum(UI_CmdKind) { UI_CmdKind_None, UI_CmdKind_BuildBox, UI_CmdKind_SetRawTexture, }; Struct(UI_BoxDesc) { UI_BoxFlag flags; UI_DebugBreakFlag debug_break_flags; UI_Key key; UI_Key parent; b32 is_transient; UI_Size pref_semantic_dims[Axis_COUNTXY]; UI_Round rounding; Vec4 background_color; Vec4 border_color; Vec4 debug_color; Vec4 invisible_debug_color; Vec4 tint; f32 opacity; f32 border_size; Vec2 scale; Vec4 text_color; String text; UI_Icon icon; GC_FontKey font; f32 font_size; Axis child_layout_axis; UI_Region child_alignment; UI_Region anchor; Vec2 floating_pos; SPR_SheetKey sprite_sheet; SPR_SpanKey sprite_span; i64 sprite_seq; f64 misc; Vec4 zag_color; f32 zag_period; f32 zag_amplitude; f32 zag_thickness; f32 zag_roundness; }; Struct(UI_Cmd) { UI_CmdKind kind; union { UI_BoxDesc box; struct { UI_Key key; G_TextureRef tex; Rng2 slice_uv; } set_raw_texture; }; }; Struct(UI_CmdNode) { UI_CmdNode *next; UI_Cmd cmd; }; //////////////////////////////////////////////////////////// //~ Box types Struct(UI_Box) { UI_Key key; //- Persistent data UI_Box *next_in_bin; UI_Box *prev_in_bin; i64 last_build_tick; i64 old_gen; i64 gen; //- Tree links UI_Box *parent; UI_Box *first; UI_Box *last; UI_Box *next; UI_Box *prev; u64 count; //- Cmd data UI_BoxDesc desc; G_TextureRef raw_texture; Rng2 raw_texture_slice_uv; GC_Run glyph_run; SPR_Sprite sprite; //- Pre-layout data u64 pre_index; u64 post_index; //- Layout data f32 solved_opacity; Vec2 solved_scale; Rng2 solved_scissor; Vec2 final_children_size_accum; Vec2 solved_dims; f32 cursor; //- Layout results Rng2 screen_rect; Vec2 screen_anchor; f32 rounding_tl; f32 rounding_tr; f32 rounding_br; f32 rounding_bl; //- Feedback b32 mouse_hovered; b32 mouse_captured; UI_Feedback feedback; UI_Feedback drag_feedback; }; Struct(UI_BoxBin) { UI_Box *first; UI_Box *last; }; //////////////////////////////////////////////////////////// //~ Iterator types 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; }; //////////////////////////////////////////////////////////// //~ State types Enum(UI_FrameFlag) { UI_FrameFlag_None = 0, UI_FrameFlag_Debug = (1 << 0), }; Struct(UI_Frame) { Arena *arena; Arena *rects_arena; WND_Frame window_frame; // Time i64 tick; i64 time_ns; i64 dt_ns; f32 dt; // Input Vec2 cursor_pos; Vec2 drag_cursor_pos; UI_InputState input; UI_InputState drag_input; UI_Key top_hovered_box; UI_Key top_hot_box; UI_Key top_active_box; // Cmds UI_FrameFlag frame_flags; UI_CmdNode *first_cmd_node; UI_CmdNode *last_cmd_node; u64 cmds_count; // Style stack UI_Stack *top_stack; UI_StyleNode *first_free_style_node; // Layout UI_Box **boxes_pre; UI_Box **boxes_post; }; Struct(UI_Ctx) { u64 boxes_count; Arena *box_arena; UI_Box *root_box; UI_BoxBin box_bins[Kibi(256)]; UI_Box *first_free_box; RandState rand; G_ArenaHandle gpu_frame_arena; G_CommandListHandle cl; i64 cur_frame_tick; UI_Frame frames[2]; }; extern UI_Ctx UI; //////////////////////////////////////////////////////////// //~ Key helpers b32 UI_MatchKey(UI_Key a, UI_Key b); b32 UI_IsKeyNil(UI_Key key); 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_RandKey(void); UI_Box *UI_BoxFromKey(UI_Key key); //////////////////////////////////////////////////////////// //~ Region helpers UI_Region UI_RegionFromPair(UI_RegionPair pair); UI_RegionPair UI_PairFromRegion(UI_Region region); //////////////////////////////////////////////////////////// //~ 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 String UI_StringF_(String fmt, ...); #define UI_StringF(fmt_cstr, ...) UI_StringF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd) //////////////////////////////////////////////////////////// //~ Style stack helpers void UI_PushDefaults(void); void UI_PushStyle(UI_StyleDesc desc); UI_Style UI_PopStyle(UI_StyleDesc desc); #define UI_STYLEDESC(name, ...) (UI_StyleDesc) { .style.kind = CAT(UI_StyleKind_,name), __VA_ARGS__ } #define UI_SetNext(name, ...) UI_PushStyle(UI_STYLEDESC(name, .pop_when_used = 1, .style.name = __VA_ARGS__)) #define UI_Push(name, ...) UI_PushStyle(UI_STYLEDESC(name, .style.name = __VA_ARGS__)) #define UI_ForceNext(name, ...) UI_PushStyle(UI_STYLEDESC(name, .pop_when_used = 1, .override = 1, .style.name = __VA_ARGS__)) #define UI_ForcePush(name, ...) UI_PushStyle(UI_STYLEDESC(name, .override = 1, .style.name = __VA_ARGS__)) #define UI_Pop(name, ...) UI_PopStyle(UI_STYLEDESC(name, .force_pop = 1, __VA_ARGS__)).name #define UI_PeekTop(name, ...) UI_PopStyle(UI_STYLEDESC(name, __VA_ARGS__)).name #define UI_Top(name, ...) UI_PopStyle(UI_STYLEDESC(name, .use = 1, __VA_ARGS__)).name #define UI_SetDF(name, ...) DeferFor(UI_Push(name, __VA_ARGS__), UI_Pop(name)) #define UI_PushCopy(name, src, ...) do { \ UI_StyleDesc _new = src; \ _new.style.kind = CAT(UI_StyleKind_,name); \ _new.style.name = __VA_ARGS__; \ UI_PushStyle(_new); \ } while (0) //////////////////////////////////////////////////////////// //~ Checkpoint helpers UI_Checkpoint UI_PushCp(UI_Key parent); void UI_PopCp(UI_Checkpoint pop_to); UI_Checkpoint UI_TopCp(void); //////////////////////////////////////////////////////////// //~ Size helpers #define UI_SIZE(_kind, _v, _s) (UI_Size) { .kind = (_kind), .v = (_v), .strictness = (_s) } #define UI_Px(_v, _s) UI_SIZE(UI_SizeKind_Pixel, (_v), (_s)) #define UI_Shrink(_v, _s) UI_SIZE(UI_SizeKind_Shrink, (_v), (_s)) #define UI_Grow(_v, _s) UI_SIZE(UI_SizeKind_Grow, (_v), (_s)) #define UI_Fnt(_v, _s) UI_SIZE(UI_SizeKind_Pixel, (f32)UI_PeekTop(FontSize) * (_v), (_s)) //////////////////////////////////////////////////////////// //~ Rounding helpers #define UI_ROUND(_kind, _v) (UI_Round) { .kind = (_kind), .v = (_v)} #define UI_Rpx(_v) UI_ROUND(UI_RoundKind_Pixel, (_v)) #define UI_Rgrow(_v) UI_ROUND(UI_RoundKind_Grow, (_v)) //////////////////////////////////////////////////////////// //~ Command helpers UI_Key UI_BuildBoxEx(UI_Key semantic_key); #define UI_BuildBox() UI_BuildBoxEx(UI_NilKey) void UI_SetRawTexture(UI_Key key, G_TextureRef tex, Rng2 uv); #if IsRtcEnabled #define UI_DebugBreak(box, target_flags) do { if (box->desc.debug_break_flags & target_flags) { DEBUGBREAK; } } while (0) #else #define UI_DebugBreak(...) #endif //////////////////////////////////////////////////////////// //~ Begin frame UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags); //////////////////////////////////////////////////////////// //~ Frame helpers UI_Frame *UI_CurrentFrame(void); UI_Frame *UI_PrevFrame(void); Arena *UI_FrameArena(void); //////////////////////////////////////////////////////////// //~ Feedback //- Passive b32 UI_IsButtonPassive(Button button); //- Input b32 UI_Held(UI_Key key, Button button); i32 UI_Downs(UI_Key key, Button button); i32 UI_Ups(UI_Key key, Button button); i32 UI_Presses(UI_Key key, Button button); //- Interaction f32 UI_Active(UI_Key key); b32 UI_ActiveAbsolute(UI_Key key); f32 UI_Hot(UI_Key key); b32 UI_HotAbsolute(UI_Key key); f32 UI_Hovered(UI_Key key); f32 UI_HoveredAbsolute(UI_Key key); f32 UI_Exists(UI_Key key); b32 UI_ExistsAbsolute(UI_Key); f64 UI_Misc(UI_Key key); f64 UI_DragMisc(UI_Key key); //- Layout Vec2 UI_Anchor(UI_Key key); Vec2 UI_DragAnchor(UI_Key key); Rng2 UI_Rect(UI_Key key); Rng2 UI_DragRect(UI_Key key); Vec2 UI_CursorPos(void); Vec2 UI_DragCursorPos(void); //////////////////////////////////////////////////////////// //~ Layout helpers GC_Run UI_ScaleRun(Arena *arena, GC_Run unscaled_run, Vec2 scale); //////////////////////////////////////////////////////////// //~ End frame void UI_EndFrame(UI_Frame *frame, i32 vsync);