497 lines
12 KiB
C
497 lines
12 KiB
C
////////////////////////////////////////////////////////////
|
|
//~ Key types
|
|
|
|
#define UI_NilKey ((UI_Key) { 0 })
|
|
#define UI_RootKey ((UI_Key) { 0xa3deb3749ef35a7aUll })
|
|
|
|
Struct(UI_Key)
|
|
{
|
|
u64 hash;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ 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;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Alignment types
|
|
|
|
Enum(UI_Alignment)
|
|
{
|
|
UI_Alignment_TopLeft,
|
|
UI_Alignment_Top,
|
|
UI_Alignment_TopRight,
|
|
|
|
UI_Alignment_Left,
|
|
UI_Alignment_Center,
|
|
UI_Alignment_Right,
|
|
|
|
UI_Alignment_BottomLeft,
|
|
UI_Alignment_Bottom,
|
|
UI_Alignment_BottomRight,
|
|
};
|
|
|
|
Enum(UI_AxisAlignment)
|
|
{
|
|
UI_AxisAlignment_Start,
|
|
UI_AxisAlignment_Center,
|
|
UI_AxisAlignment_End,
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Checkpoint types
|
|
|
|
Struct(UI_Checkpoint)
|
|
{
|
|
u64 v;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Box flags
|
|
|
|
Enum(UI_BoxFlag)
|
|
{
|
|
UI_BoxFlag_None = 0,
|
|
UI_BoxFlag_DrawText = (1 << 0),
|
|
UI_BoxFlag_Interactable = (1 << 1),
|
|
UI_BoxFlag_NoTextTruncation = (1 << 2),
|
|
UI_BoxFlag_Floating = (1 << 3),
|
|
UI_BoxFlag_NoFloatingClamp = (1 << 4),
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Style types
|
|
|
|
#define UI_StyleKindsXMacro(X) \
|
|
X(Flags, UI_BoxFlag) \
|
|
X(Parent, UI_Key) \
|
|
X(Tag, u64) \
|
|
X(ChildLayoutAxis, Axis) \
|
|
X(ChildAlignmentX, UI_AxisAlignment) \
|
|
X(ChildAlignmentY, UI_AxisAlignment) \
|
|
X(Width, UI_Size) \
|
|
X(Height, UI_Size) \
|
|
X(BackgroundColor, Vec4) \
|
|
X(BorderColor, Vec4) \
|
|
X(DebugColor, Vec4) \
|
|
X(Tint, Vec4) \
|
|
X(Border, f32) \
|
|
X(FloatingPos, Vec2) \
|
|
X(Rounding, UI_Round) \
|
|
X(Font, ResourceKey) \
|
|
X(FontSize, u32) \
|
|
X(Text, String) \
|
|
X(BackgroundTexture, GPU_Resource *) \
|
|
X(BackgroundTextureUv0, Vec2) \
|
|
X(BackgroundTextureUv1, Vec2) \
|
|
/* --------------------------------------- */ \
|
|
/* ----------- Virtual styles ----------- */ \
|
|
/* --------------------------------------- */ \
|
|
X(BeginVirtualStyles_, i8) \
|
|
X(ChildAlignment, UI_Alignment) \
|
|
X(AxisSize, UI_Size) \
|
|
/* -------------------------------------------------- */
|
|
|
|
Enum(UI_StyleKind)
|
|
{
|
|
#define X(name, type) UI_StyleKind_##name,
|
|
UI_StyleKind_None,
|
|
UI_StyleKindsXMacro(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_StyleKindsXMacro(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;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Report types
|
|
|
|
Struct(UI_Report)
|
|
{
|
|
b32 m1_held;
|
|
|
|
f32 hovered;
|
|
f32 hot;
|
|
f32 active;
|
|
|
|
i32 m1_downs;
|
|
i32 m1_ups;
|
|
i32 m1_presses;
|
|
Vec2 last_m1_offset;
|
|
|
|
/* Where was this box last rendered in screen coordinates */
|
|
Vec2 screen_p0;
|
|
Vec2 screen_p1;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Command types
|
|
|
|
Enum(UI_CmdKind)
|
|
{
|
|
UI_CmdKind_None,
|
|
UI_CmdKind_BuildBox,
|
|
UI_CmdKind_SetRawTexture,
|
|
};
|
|
|
|
Struct(UI_BoxDesc)
|
|
{
|
|
UI_BoxFlag flags;
|
|
|
|
UI_Key key;
|
|
UI_Key parent;
|
|
|
|
UI_Size pref_size[Axis_CountXY];
|
|
UI_Round rounding;
|
|
Vec4 background_color;
|
|
Vec4 border_color;
|
|
Vec4 debug_color;
|
|
Vec4 tint;
|
|
f32 border;
|
|
Vec2 floating_pos;
|
|
String text;
|
|
ResourceKey font_resource;
|
|
f32 font_size;
|
|
Axis child_layout_axis;
|
|
UI_AxisAlignment child_alignment[Axis_CountXY];
|
|
};
|
|
|
|
Struct(UI_Cmd)
|
|
{
|
|
UI_CmdKind kind;
|
|
union
|
|
{
|
|
UI_BoxDesc box;
|
|
struct
|
|
{
|
|
UI_Key key;
|
|
GPU_Resource *texture;
|
|
Vec2 uv0;
|
|
Vec2 uv1;
|
|
} 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;
|
|
UI_Report report;
|
|
u64 last_updated_tick;
|
|
|
|
//- Tree links
|
|
UI_Box *parent;
|
|
UI_Box *first;
|
|
UI_Box *last;
|
|
UI_Box *next;
|
|
UI_Box *prev;
|
|
u64 count;
|
|
|
|
//- Cmd data
|
|
UI_BoxDesc desc;
|
|
GPU_Resource *raw_texture;
|
|
Vec2 raw_texture_uv0;
|
|
Vec2 raw_texture_uv1;
|
|
|
|
//- Pre-layout data
|
|
u64 pre_index;
|
|
u64 post_index;
|
|
|
|
//- Layout data
|
|
F_Run glyph_run;
|
|
F_Font *font;
|
|
f32 layout_cursor;
|
|
f32 solved_dims[Axis_CountXY];
|
|
f32 final_children_size_accum[Axis_CountXY];
|
|
|
|
//- Layout results
|
|
Vec2 p0;
|
|
Vec2 p1;
|
|
f32 rounding_tl;
|
|
f32 rounding_tr;
|
|
f32 rounding_br;
|
|
f32 rounding_bl;
|
|
};
|
|
|
|
Struct(UI_BoxBin)
|
|
{
|
|
UI_Box *first;
|
|
UI_Box *last;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Frame types
|
|
|
|
Enum(UI_FrameFlag)
|
|
{
|
|
UI_FrameFlag_None = 0,
|
|
UI_FrameFlag_Debug = (1 << 0),
|
|
UI_FrameFlag_Vsync = (1 << 1),
|
|
};
|
|
|
|
Struct(UI_Frame)
|
|
{
|
|
WND_Frame window_frame;
|
|
Vec2 cursor_pos;
|
|
UI_Key hovered_box;
|
|
UI_Key active_box;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ State types
|
|
|
|
#define UI_NumBoxLookupBins 16384
|
|
|
|
Struct(UI_BFrameState);
|
|
Struct(UI_EFrameState);
|
|
|
|
Struct(UI_State)
|
|
{
|
|
//////////////////////////////
|
|
//- Persistent sate
|
|
|
|
Arena *box_arena;
|
|
UI_BoxBin *box_bins;
|
|
u64 boxes_count;
|
|
UI_Box *first_free_box;
|
|
|
|
//////////////////////////////
|
|
//- Frame-begin state
|
|
|
|
struct UI_BFrameState
|
|
{
|
|
Arena *cmds_arena;
|
|
WND_Frame window_frame;
|
|
|
|
u64 transient_key_seed;
|
|
|
|
/* Time */
|
|
u64 tick;
|
|
i64 time_ns;
|
|
i64 dt_ns;
|
|
|
|
/* Control */
|
|
Vec2 cursor_pos;
|
|
UI_Key hovered_box;
|
|
UI_Key active_box;
|
|
|
|
/* Cmds */
|
|
Vec4 swapchain_color;
|
|
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;
|
|
} bframe;
|
|
|
|
//////////////////////////////
|
|
//- Frame-end state
|
|
|
|
struct UI_EFrameState
|
|
{
|
|
Arena *layout_arena;
|
|
Arena *rects_arena;
|
|
u64 tick;
|
|
|
|
/* Render */
|
|
GPU_Resource *draw_target;
|
|
GPU_Swapchain *swapchain;
|
|
i64 gpu_submit_fence_target;
|
|
GPU_TransientBuffer draw_rects_tbuff;
|
|
|
|
/* Layout */
|
|
UI_Box *root_box;
|
|
UI_Box **boxes_pre;
|
|
UI_Box **boxes_post;
|
|
} eframe;
|
|
} extern UI_state;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Startup
|
|
|
|
void UI_Startup(void);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Font helpers
|
|
|
|
ResourceKey UI_GetDefaultFontResource(void);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Key helpers
|
|
|
|
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);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ String helpers
|
|
|
|
String UI_StringF_(String fmt, ...);
|
|
#define UI_StringF(fmt_cstr, ...) UI_StringF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd)
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Checkpoint helpers
|
|
|
|
UI_Checkpoint UI_PushCP(UI_Key parent);
|
|
void UI_PopCP(UI_Checkpoint pop_to);
|
|
|
|
UI_Checkpoint UI_TopCP(void);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ 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 = 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_UseTop(name, ...) UI_PopStyle(UI_STYLEDESC(name, .use = 1, __VA_ARGS__)).name
|
|
|
|
#define UI_PushCopy(name, src, ...) do { \
|
|
UI_StyleDesc _new = src; \
|
|
_new.style.kind = UI_StyleKind_##name; \
|
|
_new.style.name = __VA_ARGS__; \
|
|
UI_PushStyle(_new); \
|
|
} while (0)
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Size helpers
|
|
|
|
#define UI_SIZE(_kind, _v, _s) (UI_Size) { .kind = (_kind), .v = (_v), .strictness = (_s) }
|
|
|
|
#define UI_PIX(_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_RPIX(_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 key);
|
|
#define UI_BuildBox() UI_BuildBoxEx(UI_TransKey())
|
|
|
|
void UI_SetRawTexture(UI_Key key, GPU_Resource *texture, Vec2 uv0, Vec2 uv1);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Report
|
|
|
|
UI_Report UI_ReportFromKey(UI_Key key);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Begin frame
|
|
|
|
UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Frame helpers
|
|
|
|
Arena *UI_FrameArena(void);
|
|
Vec2 UI_CursorPos(void);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ End frame
|
|
|
|
i64 UI_EndFrame(UI_Frame frame);
|