floating position anchors

This commit is contained in:
jacob 2025-12-30 02:38:57 -06:00
parent bed51e195e
commit 9b94f02a27
8 changed files with 315 additions and 262 deletions

View File

@ -406,6 +406,9 @@
#define AlignedStruct(name, n) typedef struct name name; struct alignas(n) name #define AlignedStruct(name, n) typedef struct name name; struct alignas(n) name
#define AlignedBlock(n) struct alignas(n) #define AlignedBlock(n) struct alignas(n)
//- Union
#define Union(name) typedef union name name; union name
//- Enum //- Enum
#if IsLanguageC #if IsLanguageC
#define Enum(name) typedef enum name name; enum name #define Enum(name) typedef enum name name; enum name

View File

@ -5,7 +5,6 @@
//- Api //- Api
#include "base.cgh" #include "base.cgh"
#if IsLanguageC #if IsLanguageC
#include "base_tweak.h"
#include "base_intrinsics.h" #include "base_intrinsics.h"
#include "base_memory.h" #include "base_memory.h"
#include "base_arena.h" #include "base_arena.h"
@ -27,6 +26,7 @@
#include "base_resource.h" #include "base_resource.h"
#include "base_controller.h" #include "base_controller.h"
#include "base_async.h" #include "base_async.h"
#include "base_tweak.h"
#include "base_state.h" #include "base_state.h"
#elif IsLanguageG #elif IsLanguageG
#include "base_shader.gh" #include "base_shader.gh"

View File

@ -22,12 +22,12 @@ Enum(Axis)
//- Vec2 //- Vec2
Struct(Vec2) { f32 x, y; }; Union(Vec2) { struct { f32 x, y; }; f32 v[2]; };
Struct(Vec2F64) { f64 x, y; }; Union(Vec2F64) { struct { f64 x, y; }; f64 v[2]; };
Struct(Vec2I32) { i32 x, y; }; Union(Vec2I32) { struct { i32 x, y; }; i32 v[2]; };
Struct(Vec2I64) { i64 x, y; }; Union(Vec2I64) { struct { i64 x, y; }; i64 v[2]; };
Struct(Vec2U32) { i32 x, y; }; Union(Vec2U32) { struct { u32 x, y; }; u32 v[2]; };
Struct(Vec2U64) { u64 x, y; }; Union(Vec2U64) { struct { u64 x, y; }; u64 v[2]; };
Struct(Vec2Array) { Vec2 *points; u64 count; }; Struct(Vec2Array) { Vec2 *points; u64 count; };
@ -47,12 +47,12 @@ Struct(Vec2Array) { Vec2 *points; u64 count; };
//- Vec3 //- Vec3
Struct(Vec3) { f32 x, y, z; }; Union(Vec3) { struct { f32 x, y, z; }; f32 v[3]; };
Struct(Vec3F64) { f64 x, y, z; }; Union(Vec3F64) { struct { f64 x, y, z; }; f64 v[3]; };
Struct(Vec3I32) { i32 x, y, z; }; Union(Vec3I32) { struct { i32 x, y, z; }; i32 v[3]; };
Struct(Vec3I64) { i64 x, y, z; }; Union(Vec3I64) { struct { i64 x, y, z; }; i64 v[3]; };
Struct(Vec3U32) { i32 x, y, z; }; Union(Vec3U32) { struct { u32 x, y, z; }; u32 v[3]; };
Struct(Vec3U64) { u64 x, y, z; }; Union(Vec3U64) { struct { u64 x, y, z; }; u64 v[3]; };
Struct(Vec3Array) { Vec3 *points; u64 count; }; Struct(Vec3Array) { Vec3 *points; u64 count; };
@ -72,12 +72,12 @@ Struct(Vec3Array) { Vec3 *points; u64 count; };
//- Vec4 //- Vec4
Struct(Vec4) { f32 x, y, z, w; }; Union(Vec4) { struct { f32 x, y, z, w; }; f32 v[4]; };
Struct(Vec4F64) { f64 x, y, z, w; }; Union(Vec4F64) { struct { f64 x, y, z, w; }; f64 v[4]; };
Struct(Vec4I32) { i32 x, y, z, w; }; Union(Vec4I32) { struct { i32 x, y, z, w; }; i32 v[4]; };
Struct(Vec4I64) { i64 x, y, z, w; }; Union(Vec4I64) { struct { i64 x, y, z, w; }; i64 v[4]; };
Struct(Vec4U32) { i32 x, y, z, w; }; Union(Vec4U32) { struct { u32 x, y, z, w; }; u32 v[4]; };
Struct(Vec4U64) { u64 x, y, z, w; }; Union(Vec4U64) { struct { u64 x, y, z, w; }; u64 v[4]; };
Struct(Vec4Array) { Vec4 *points; u64 count; }; Struct(Vec4Array) { Vec4 *points; u64 count; };
@ -100,11 +100,11 @@ Struct(Vec4Array) { Vec4 *points; u64 count; };
//- Rng1 //- Rng1
Struct(Rng) { f32 min; f32 max; }; Struct(Rng) { f32 min, max; };
Struct(RngI32) { i32 min; i32 max; }; Struct(RngI32) { i32 min, max; };
Struct(RngI64) { i64 min; i64 max; }; Struct(RngI64) { i64 min, max; };
Struct(RngU32) { u32 min; u32 max; }; Struct(RngU32) { u32 min, max; };
Struct(RngU64) { u64 min; u64 max; }; Struct(RngU64) { u64 min, max; };
#define RNG(min, max) (Rng) { (min), (max) } #define RNG(min, max) (Rng) { (min), (max) }
#define RNGI32(min, max) (RngI32) { (min), (max) } #define RNGI32(min, max) (RngI32) { (min), (max) }
@ -114,11 +114,11 @@ Struct(RngU64) { u64 min; u64 max; };
//- Rng2 //- Rng2
Struct(Rng2) { Vec2 p0; Vec2 p1; }; Struct(Rng2) { Vec2 p0, p1; };
Struct(Rng2I32) { Vec2I32 p0; Vec2I32 p1; }; Struct(Rng2I32) { Vec2I32 p0, p1; };
Struct(Rng2I64) { Vec2I64 p0; Vec2I64 p1; }; Struct(Rng2I64) { Vec2I64 p0, p1; };
Struct(Rng2U32) { Vec2U32 p0; Vec2U32 p1; }; Struct(Rng2U32) { Vec2U32 p0, p1; };
Struct(Rng2U64) { Vec2U64 p0; Vec2U64 p1; }; Struct(Rng2U64) { Vec2U64 p0, p1; };
#define RNG2(p0, p1) (Rng2) { (p0), (p1) } #define RNG2(p0, p1) (Rng2) { (p0), (p1) }
#define RNG2I32(p0, p1) (Rng2I32) { (p0), (p1) } #define RNG2I32(p0, p1) (Rng2I32) { (p0), (p1) }
@ -128,11 +128,11 @@ Struct(Rng2U64) { Vec2U64 p0; Vec2U64 p1; };
//- Rng3 //- Rng3
Struct(Rng3) { Vec3 p0; Vec3 p1; }; Struct(Rng3) { Vec3 p0, p1; };
Struct(Rng3I32) { Vec3I32 p0; Vec3I32 p1; }; Struct(Rng3I32) { Vec3I32 p0, p1; };
Struct(Rng3I64) { Vec3I64 p0; Vec3I64 p1; }; Struct(Rng3I64) { Vec3I64 p0, p1; };
Struct(Rng3U32) { Vec3U32 p0; Vec3U32 p1; }; Struct(Rng3U32) { Vec3U32 p0, p1; };
Struct(Rng3U64) { Vec3U64 p0; Vec3U64 p1; }; Struct(Rng3U64) { Vec3U64 p0, p1; };
#define RNG3(p0, p1) (Rng3) { (p0), (p1) } #define RNG3(p0, p1) (Rng3) { (p0), (p1) }
#define RNG3I32(p0, p1) (Rng3I32) { (p0), (p1) } #define RNG3I32(p0, p1) (Rng3I32) { (p0), (p1) }

View File

@ -239,7 +239,6 @@ void V_TickForever(WaveLaneCtx *lane)
frame->palette = last_frame->palette; frame->palette = last_frame->palette;
frame->is_editing = last_frame->is_editing; frame->is_editing = last_frame->is_editing;
frame->ui_debug = last_frame->ui_debug; frame->ui_debug = last_frame->ui_debug;
frame->show_palette = last_frame->show_palette;
frame->show_console = last_frame->show_console; frame->show_console = last_frame->show_console;
frame->look = last_frame->look; frame->look = last_frame->look;
frame->edit_mode = last_frame->edit_mode; frame->edit_mode = last_frame->edit_mode;
@ -810,14 +809,9 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Report divider_rep = UI_ReportFromKey(resize_panel->divider_key); UI_Report divider_rep = UI_ReportFromKey(resize_panel->divider_key);
f32 child_pref_size = 0; f32 child_pref_size = 0;
if (panel->axis == Axis_X) child_pref_size += frame->ui_cursor.v[panel->axis];
{ child_pref_size -= child_rep.screen_anchor.v[panel->axis];
child_pref_size = frame->ui_cursor.x - child_rep.screen_rect.p0.x - divider_rep.last_mouse_down_cursor_offset.x; child_pref_size -= divider_rep.last_cursor_down_anchor_offset.v[panel->axis];
}
else
{
child_pref_size = frame->ui_cursor.y - child_rep.screen_rect.p0.y - divider_rep.last_mouse_down_cursor_offset.y;
}
f32 ratio_diff = (child_pref_size / panel_size) - resize_panel->pref_ratio; f32 ratio_diff = (child_pref_size / panel_size) - resize_panel->pref_ratio;
f32 min_ratio = 0.05; f32 min_ratio = 0.05;
@ -988,7 +982,7 @@ void V_TickForever(WaveLaneCtx *lane)
f32 drag_threshold = 20; f32 drag_threshold = 20;
if (tab_rep.m1.held) if (tab_rep.m1.held)
{ {
Vec2 drag_start = AddVec2(tab_rep.screen_rect.p0, tab_rep.last_mouse_down_cursor_offset); Vec2 drag_start = AddVec2(tab_rep.screen_anchor, tab_rep.last_cursor_down_anchor_offset);
if (Vec2Len(SubVec2(frame->ui_cursor, drag_start)) > drag_threshold) if (Vec2Len(SubVec2(frame->ui_cursor, drag_start)) > drag_threshold)
{ {
V.dragging_window = window; V.dragging_window = window;
@ -1034,14 +1028,14 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(Border, 1); UI_SetNext(Border, 1);
UI_SetNext(Width, UI_SHRINK(0, 0)); UI_SetNext(Width, UI_SHRINK(0, 0));
UI_SetNext(Height, UI_SHRINK(0, 0)); UI_SetNext(Height, UI_SHRINK(0, 0));
UI_SetNext(ChildAlignment, UI_Alignment_Left); UI_SetNext(ChildAlignment, UI_Region_Left);
UI_SetNext(Flags, UI_BoxFlag_Interactable | (UI_BoxFlag_Selected * (active_window == window))); UI_SetNext(Flags, UI_BoxFlag_Interactable | (UI_BoxFlag_Selected * (active_window == window)));
UI_SetNext(Text, tab_name); UI_SetNext(Text, tab_name);
UI_PushCP(UI_BuildRowEx(tab->key)); UI_PushCP(UI_BuildRowEx(tab->key));
{ {
// Build tab title // Build tab title
{ {
UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(ChildAlignment, UI_Region_Center);
UI_SetNext(Flags, UI_BoxFlag_DrawText); UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_SetNext(Text, tab_name); UI_SetNext(Text, tab_name);
UI_SetNext(Width, UI_SHRINK(6, 0)); UI_SetNext(Width, UI_SHRINK(6, 0));
@ -1062,7 +1056,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(BackgroundColor, close_color); UI_SetNext(BackgroundColor, close_color);
UI_SetNext(BorderColor, close_border_color); UI_SetNext(BorderColor, close_border_color);
UI_SetNext(Border, 2); UI_SetNext(Border, 2);
UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(ChildAlignment, UI_Region_Center);
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable);
UI_SetNext(Text, Lit("x")); UI_SetNext(Text, Lit("x"));
UI_SetNext(Width, UI_SHRINK(6, 0)); UI_SetNext(Width, UI_SHRINK(6, 0));
@ -1099,7 +1093,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(Border, 2); UI_SetNext(Border, 2);
UI_SetNext(Width, UI_PIX(30, 0)); UI_SetNext(Width, UI_PIX(30, 0));
UI_SetNext(Height, UI_GROW(1, 0)); UI_SetNext(Height, UI_GROW(1, 0));
UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(ChildAlignment, UI_Region_Center);
// UI_SetNext(FontSize, theme.font_size * 1.5); // UI_SetNext(FontSize, theme.font_size * 1.5);
UI_PushCP(UI_BuildRowEx(tab->key)); UI_PushCP(UI_BuildRowEx(tab->key));
{ {
@ -1126,7 +1120,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(Border, 2); UI_SetNext(Border, 2);
UI_SetNext(Width, UI_SHRINK(10, 0)); UI_SetNext(Width, UI_SHRINK(10, 0));
UI_SetNext(Height, UI_SHRINK(2, 0)); UI_SetNext(Height, UI_SHRINK(2, 0));
UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(ChildAlignment, UI_Region_Center);
// UI_SetNext(FontSize, theme.font_size * 1.5); // UI_SetNext(FontSize, theme.font_size * 1.5);
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable);
UI_SetNext(Text, Lit("+")); UI_SetNext(Text, Lit("+"));
@ -1190,7 +1184,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(Flags, UI_BoxFlag_Interactable | (UI_BoxFlag_Selected * is_selected)); UI_SetNext(Flags, UI_BoxFlag_Interactable | (UI_BoxFlag_Selected * is_selected));
UI_PushCP(UI_BuildRowEx(key)); UI_PushCP(UI_BuildRowEx(key));
{ {
UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(ChildAlignment, UI_Region_Center);
UI_SetNext(Text, name); UI_SetNext(Text, name);
UI_SetNext(Flags, UI_BoxFlag_DrawText); UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_SetNext(Width, UI_SHRINK(4, 0)); UI_SetNext(Width, UI_SHRINK(4, 0));
@ -1285,6 +1279,8 @@ void V_TickForever(WaveLaneCtx *lane)
//- Build command palette //- Build command palette
V_Palette *palette = &frame->palette; V_Palette *palette = &frame->palette;
palette->show = LerpF32(palette->show, palette->pref_show, 30.0 * frame->dt);
if (palette->show > 0.001)
{ {
palette->key = UI_KeyF("command palette"); palette->key = UI_KeyF("command palette");
UI_Checkpoint palette_cp = UI_PushCP(UI_NilKey); UI_Checkpoint palette_cp = UI_PushCP(UI_NilKey);
@ -1292,27 +1288,21 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Push(Tag, palette->key.hash); UI_Push(Tag, palette->key.hash);
UI_Key titlebar_key = UI_KeyF("title bar"); UI_Key titlebar_key = UI_KeyF("title bar");
UI_Report titlebar_rep = UI_ReportFromKey(titlebar_key); UI_Report titlebar_rep = UI_ReportFromKey(titlebar_key);
UI_Report widget_rep = UI_ReportFromKey(palette->key); UI_Report palette_rep = UI_ReportFromKey(palette->key);
Vec2 widget_half_dims = MulVec2(DimsFromRng2(widget_rep.screen_rect), 0.5);
Vec4 window_background_color = theme.window_background_color; Vec4 window_background_color = theme.window_background_color;
// Vec4 window_background_color = VEC4(0, 0, 0, 0);
Vec4 window_border_color = theme.window_border_color; Vec4 window_border_color = theme.window_border_color;
Vec4 titlebar_color = Zi; Vec4 titlebar_color = Zi;
Vec4 titlebar_border_color = Zi; Vec4 titlebar_border_color = Zi;
Vec4 divider_color = theme.divider_color; Vec4 divider_color = theme.divider_color;
if (titlebar_rep.m1.held) if (titlebar_rep.m1.held)
{ {
palette->pos = AddVec2(SubVec2(frame->ui_cursor, titlebar_rep.last_mouse_down_cursor_offset), widget_half_dims); palette->pos = SubVec2(frame->ui_cursor, palette_rep.last_cursor_down_anchor_offset);
} }
window_border_color = LerpSrgb(window_border_color, Rgb32(0x0078a6), titlebar_rep.hot); window_border_color = LerpSrgb(window_border_color, Rgb32(0x0078a6), titlebar_rep.hot);
UI_Push(Scale, LerpF32(0.75, 1, widget_rep.selected)); UI_Push(Scale, LerpF32(0.75, 1, palette->show));
UI_Push(Tint, VEC4(1, 1, 1, widget_rep.selected)); UI_Push(Tint, VEC4(1, 1, 1, palette->show));
if (widget_rep.selected < 0.25)
{
UI_Push(OmitFlags, UI_UseTop(OmitFlags) | UI_BoxFlag_Interactable);
}
UI_Push(BackgroundColor, window_background_color); UI_Push(BackgroundColor, window_background_color);
UI_Push(BorderColor, window_border_color); UI_Push(BorderColor, window_border_color);
@ -1321,8 +1311,9 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Push(Width, UI_PIX(theme.window_width, 0)); UI_Push(Width, UI_PIX(theme.window_width, 0));
UI_Push(Height, UI_SHRINK(0, 0)); UI_Push(Height, UI_SHRINK(0, 0));
UI_Push(ChildLayoutAxis, Axis_Y); UI_Push(ChildLayoutAxis, Axis_Y);
UI_Push(FloatingPos, SubVec2(palette->pos, widget_half_dims)); UI_Push(FloatingPos, palette->pos);
UI_SetNext(Flags, UI_BoxFlag_Floating | (UI_BoxFlag_Selected * frame->show_palette)); UI_SetNext(FloatingPosAnchor, UI_Region_Center);
UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_PushCP(UI_BuildBoxEx(palette->key)); UI_PushCP(UI_BuildBoxEx(palette->key));
{ {
// Title bar // Title bar
@ -1345,7 +1336,7 @@ void V_TickForever(WaveLaneCtx *lane)
// Title box // Title box
UI_SetNext(FontSize, theme.window_title_font_size); UI_SetNext(FontSize, theme.window_title_font_size);
UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(ChildAlignment, UI_Region_Center);
UI_SetNext(Width, UI_SHRINK(0, 1)); UI_SetNext(Width, UI_SHRINK(0, 1));
UI_SetNext(Text, Lit("Command Palette")); UI_SetNext(Text, Lit("Command Palette"));
UI_SetNext(Flags, UI_BoxFlag_DrawText); UI_SetNext(Flags, UI_BoxFlag_DrawText);
@ -1460,8 +1451,12 @@ void V_TickForever(WaveLaneCtx *lane)
Vec4 item_color = theme.window_background_color; Vec4 item_color = theme.window_background_color;
item_color = LerpSrgb(item_color, theme.button_hot_color, item_rep.hot); item_color = LerpSrgb(item_color, theme.button_hot_color, item_rep.hot);
Vec4 item_border_color = Zi;
if (item->flags & PaletteItemFlag_IsCmd)
{
item_color = LerpSrgb(item_color, theme.button_active_color, item_rep.active); item_color = LerpSrgb(item_color, theme.button_active_color, item_rep.active);
Vec4 item_border_color = LerpSrgb(VEC4(0, 0, 0, 0), theme.button_active_color, item_rep.hot); item_border_color = LerpSrgb(item_border_color, theme.button_active_color, item_rep.hot);
}
UI_SetNext(BorderColor, 0); UI_SetNext(BorderColor, 0);
UI_SetNext(Rounding, UI_RPIX(0)); UI_SetNext(Rounding, UI_RPIX(0));
@ -1472,7 +1467,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(Rounding, UI_RPIX(5)); UI_SetNext(Rounding, UI_RPIX(5));
UI_SetNext(Width, UI_GROW(1, 0)); UI_SetNext(Width, UI_GROW(1, 0));
UI_SetNext(Height, UI_FNT(1.5, 1)); UI_SetNext(Height, UI_FNT(1.5, 1));
UI_SetNext(ChildAlignment, UI_Alignment_Left); UI_SetNext(ChildAlignment, UI_Region_Left);
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable);
UI_PushCP(UI_BuildRowEx(item->key)); UI_PushCP(UI_BuildRowEx(item->key));
{ {
@ -1482,7 +1477,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_BuildSpacer(UI_PIX(20, 1), Axis_X); UI_BuildSpacer(UI_PIX(20, 1), Axis_X);
// Command label // Command label
UI_SetNext(ChildAlignment, UI_Alignment_Left); UI_SetNext(ChildAlignment, UI_Region_Left);
UI_BuildLabel(item->display_name); UI_BuildLabel(item->display_name);
// Middle spacer // Middle spacer
@ -1568,7 +1563,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(Height, UI_GROW(1, 0)); UI_SetNext(Height, UI_GROW(1, 0));
UI_SetNext(Rounding, UI_RPIX(5)); UI_SetNext(Rounding, UI_RPIX(5));
UI_SetNext(Border, 1); UI_SetNext(Border, 1);
UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(ChildAlignment, UI_Region_Center);
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable);
UI_PushCP(UI_BuildRowEx(hotkey_key)); UI_PushCP(UI_BuildRowEx(hotkey_key));
{ {
@ -1618,7 +1613,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_PushCP(UI_BuildColumn()); UI_PushCP(UI_BuildColumn());
{ {
// UI_BuildSpacer(UI_PIX(10, 1), Axis_X); // UI_BuildSpacer(UI_PIX(10, 1), Axis_X);
// UI_Push(ChildAlignment, UI_Alignment_Center); // UI_Push(ChildAlignment, UI_Region_Center);
// UI_SetNext(Width, UI_SHRINK(0, 1)); // UI_SetNext(Width, UI_SHRINK(0, 1));
// UI_SetNext(Height, UI_SHRINK(0, 1)); // UI_SetNext(Height, UI_SHRINK(0, 1));
UI_SetNext(Width, UI_SHRINK(0, 1)); UI_SetNext(Width, UI_SHRINK(0, 1));
@ -1790,7 +1785,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Push(BorderColor, Rgb(0.25, 0.25, 0.25)); UI_Push(BorderColor, Rgb(0.25, 0.25, 0.25));
UI_Push(Rounding, UI_RPIX(0)); UI_Push(Rounding, UI_RPIX(0));
UI_Push(Border, 1); UI_Push(Border, 1);
UI_Push(ChildAlignment, UI_Alignment_Left); UI_Push(ChildAlignment, UI_Region_Left);
UI_PushCP(UI_BuildRow()); UI_PushCP(UI_BuildRow());
{ {
// UI_SetNext(Height, UI_PIX(100, 0)); // UI_SetNext(Height, UI_PIX(100, 0));
@ -1839,7 +1834,7 @@ void V_TickForever(WaveLaneCtx *lane)
case V_CmdKind_toggle_palette: case V_CmdKind_toggle_palette:
{ {
frame->show_palette = !frame->show_palette; frame->palette.pref_show = !frame->palette.pref_show;
} break; } break;
case V_CmdKind_zoom_in: case V_CmdKind_zoom_in:

View File

@ -120,6 +120,9 @@ Struct(V_Palette)
// Persistent state // Persistent state
Vec2 pos; Vec2 pos;
UI_Key key; UI_Key key;
f32 pref_show;
f32 show;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -197,7 +200,6 @@ Struct(V_Frame)
// Modes // Modes
b32 is_editing; b32 is_editing;
b32 ui_debug; b32 ui_debug;
b32 show_palette;
b32 show_console; b32 show_console;
// Editor state // Editor state

View File

@ -76,6 +76,97 @@ UI_Box *UI_BoxFromKey(UI_Key key)
return box; return box;
} }
////////////////////////////////////////////////////////////
//~ Anchor helpers
UI_Region UI_RegionFromPair(UI_RegionPair pair)
{
UI_Region result = 0;
switch(pair.y)
{
case UI_AxisRegion_Start:
{
switch(pair.x)
{
case UI_AxisRegion_Start: { result = UI_Region_TopLeft; } break;
case UI_AxisRegion_Center: { result = UI_Region_Top; } break;
case UI_AxisRegion_End: { result = UI_Region_TopRight; } break;
}
} break;
case UI_AxisRegion_Center:
{
switch(pair.x)
{
case UI_AxisRegion_Start: { result = UI_Region_Left; } break;
case UI_AxisRegion_Center: { result = UI_Region_Center; } break;
case UI_AxisRegion_End: { result = UI_Region_Right; } break;
}
} break;
case UI_AxisRegion_End:
{
switch(pair.x)
{
case UI_AxisRegion_Start: { result = UI_Region_BottomLeft; } break;
case UI_AxisRegion_Center: { result = UI_Region_Bottom; } break;
case UI_AxisRegion_End: { result = UI_Region_BottomRight; } break;
}
} break;
}
return result;
}
UI_RegionPair UI_PairFromRegion(UI_Region region)
{
UI_RegionPair result = Zi;
// Horizontal
switch(region)
{
default: break;
case UI_Region_TopLeft:
case UI_Region_Left:
case UI_Region_BottomLeft:
{
result.x = UI_AxisRegion_Start;
} break;
case UI_Region_Top:
case UI_Region_Center:
case UI_Region_Bottom:
{
result.x = UI_AxisRegion_Center;
} break;
case UI_Region_TopRight:
case UI_Region_Right:
case UI_Region_BottomRight:
{
result.x = UI_AxisRegion_End;
} break;
}
// Vertical
switch(region)
{
default: break;
case UI_Region_TopLeft:
case UI_Region_Top:
case UI_Region_TopRight:
{
result.y = UI_AxisRegion_Start;
} break;
case UI_Region_Left:
case UI_Region_Center:
case UI_Region_Right:
{
result.y = UI_AxisRegion_Center;
} break;
case UI_Region_BottomLeft:
case UI_Region_Bottom:
case UI_Region_BottomRight:
{
result.y = UI_AxisRegion_End;
} break;
}
return result;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Iteration helpers //~ Iteration helpers
@ -295,57 +386,6 @@ void UI_PushStyle(UI_StyleDesc desc)
UI_PushCopy(Height, desc, desc.style.AxisSize); UI_PushCopy(Height, desc, desc.style.AxisSize);
} }
} break; } break;
case UI_StyleKind_ChildAlignment:
{
UI_Alignment alignment = desc.style.ChildAlignment;
// Alignment -> horizontal alignment
switch(alignment)
{
default: break;
case UI_Alignment_TopLeft:
case UI_Alignment_Left:
case UI_Alignment_BottomLeft:
{
UI_PushCopy(ChildAlignmentX, desc, UI_AxisAlignment_Start);
} break;
case UI_Alignment_Top:
case UI_Alignment_Center:
case UI_Alignment_Bottom:
{
UI_PushCopy(ChildAlignmentX, desc, UI_AxisAlignment_Center);
} break;
case UI_Alignment_TopRight:
case UI_Alignment_Right:
case UI_Alignment_BottomRight:
{
UI_PushCopy(ChildAlignmentX, desc, UI_AxisAlignment_End);
} break;
}
// Alignment -> vertical alignment
switch(alignment)
{
default: break;
case UI_Alignment_TopLeft:
case UI_Alignment_Top:
case UI_Alignment_TopRight:
{
UI_PushCopy(ChildAlignmentY, desc, UI_AxisAlignment_Start);
} break;
case UI_Alignment_Left:
case UI_Alignment_Center:
case UI_Alignment_Right:
{
UI_PushCopy(ChildAlignmentY, desc, UI_AxisAlignment_Center);
} break;
case UI_Alignment_BottomLeft:
case UI_Alignment_Bottom:
case UI_Alignment_BottomRight:
{
UI_PushCopy(ChildAlignmentY, desc, UI_AxisAlignment_End);
} break;
}
} break;
} }
} }
else else
@ -415,7 +455,6 @@ UI_Style UI_PopStyle(UI_StyleDesc desc)
switch(kind) switch(kind)
{ {
default: break; default: break;
case UI_StyleKind_AxisSize: case UI_StyleKind_AxisSize:
{ {
if (desc.axis == Axis_X) if (desc.axis == Axis_X)
@ -429,46 +468,6 @@ UI_Style UI_PopStyle(UI_StyleDesc desc)
result = UI_PopStyle(desc); result = UI_PopStyle(desc);
} }
}; };
case UI_StyleKind_ChildAlignment:
{
UI_StyleDesc x_desc = desc;
UI_StyleDesc y_desc = desc;
x_desc.style.kind = UI_StyleKind_ChildAlignmentX;
y_desc.style.kind = UI_StyleKind_ChildAlignmentY;
UI_AxisAlignment x_alignment = UI_PopStyle(x_desc).ChildAlignmentX;
UI_AxisAlignment y_alignment = UI_PopStyle(y_desc).ChildAlignmentY;
switch(y_alignment)
{
case UI_AxisAlignment_Start:
{
switch(x_alignment)
{
case UI_AxisAlignment_Start: { result.ChildAlignment = UI_Alignment_TopLeft; } break;
case UI_AxisAlignment_Center: { result.ChildAlignment = UI_Alignment_Top; } break;
case UI_AxisAlignment_End: { result.ChildAlignment = UI_Alignment_TopRight; } break;
}
} break;
case UI_AxisAlignment_Center:
{
switch(x_alignment)
{
case UI_AxisAlignment_Start: { result.ChildAlignment = UI_Alignment_Left; } break;
case UI_AxisAlignment_Center: { result.ChildAlignment = UI_Alignment_Center; } break;
case UI_AxisAlignment_End: { result.ChildAlignment = UI_Alignment_Right; } break;
}
} break;
case UI_AxisAlignment_End:
{
switch(x_alignment)
{
case UI_AxisAlignment_Start: { result.ChildAlignment = UI_Alignment_BottomLeft; } break;
case UI_AxisAlignment_Center: { result.ChildAlignment = UI_Alignment_Bottom; } break;
case UI_AxisAlignment_End: { result.ChildAlignment = UI_Alignment_BottomRight; } break;
}
} break;
}
} break;
} }
} }
else else
@ -509,8 +508,7 @@ UI_Key UI_BuildBoxEx(UI_Key semantic_key)
n->cmd.box.pref_semantic_dims[Axis_X] = UI_UseTop(Width); n->cmd.box.pref_semantic_dims[Axis_X] = UI_UseTop(Width);
n->cmd.box.pref_semantic_dims[Axis_Y] = UI_UseTop(Height); n->cmd.box.pref_semantic_dims[Axis_Y] = UI_UseTop(Height);
n->cmd.box.scale = UI_UseTop(Scale); n->cmd.box.scale = UI_UseTop(Scale);
n->cmd.box.child_alignment[Axis_X] = UI_UseTop(ChildAlignmentX); n->cmd.box.child_alignment = UI_UseTop(ChildAlignment);
n->cmd.box.child_alignment[Axis_Y] = UI_UseTop(ChildAlignmentY);
n->cmd.box.child_layout_axis = UI_UseTop(ChildLayoutAxis); n->cmd.box.child_layout_axis = UI_UseTop(ChildLayoutAxis);
n->cmd.box.background_color = UI_UseTop(BackgroundColor); n->cmd.box.background_color = UI_UseTop(BackgroundColor);
n->cmd.box.border_color = UI_UseTop(BorderColor); n->cmd.box.border_color = UI_UseTop(BorderColor);
@ -522,6 +520,7 @@ UI_Key UI_BuildBoxEx(UI_Key semantic_key)
n->cmd.box.font_size = UI_UseTop(FontSize); n->cmd.box.font_size = UI_UseTop(FontSize);
n->cmd.box.rounding = UI_UseTop(Rounding); n->cmd.box.rounding = UI_UseTop(Rounding);
n->cmd.box.text = UI_UseTop(Text); n->cmd.box.text = UI_UseTop(Text);
n->cmd.box.floating_pos_anchor = UI_UseTop(FloatingPosAnchor);
n->cmd.box.floating_pos = UI_UseTop(FloatingPos); n->cmd.box.floating_pos = UI_UseTop(FloatingPos);
} }
++frame->cmds_count; ++frame->cmds_count;
@ -635,12 +634,12 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
////////////////////////////// //////////////////////////////
//- Process controller events //- Process controller events
frame->cursor_pos = last_frame->cursor_pos;
if (last_frame->boxes_pre != 0) if (last_frame->boxes_pre != 0)
{ {
ControllerEventsArray controller_events = frame->window_frame.controller_events; ControllerEventsArray controller_events = frame->window_frame.controller_events;
frame->cursor_pos = last_frame->cursor_pos;
// Locate boxes // Locate boxes
UI_Box *top_hovered_box = 0; UI_Box *top_hovered_box = 0;
UI_Box *active_box = UI_BoxFromKey(last_frame->active_box); UI_Box *active_box = UI_BoxFromKey(last_frame->active_box);
@ -662,8 +661,8 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
b32 is_cursor_in_box = 0; b32 is_cursor_in_box = 0;
{ {
// TODO: More efficient test. This logic is just copied from the renderer's SDF function for now. // TODO: More efficient test. This logic is just copied from the renderer's SDF function for now.
Vec2 p0 = box->rect.p0; Vec2 p0 = box->screen_rect.p0;
Vec2 p1 = box->rect.p1; Vec2 p1 = box->screen_rect.p1;
Vec2 point = frame->cursor_pos; Vec2 point = frame->cursor_pos;
b32 is_corner = 0; b32 is_corner = 0;
f32 non_corner_edge_dist = MinF32(MinF32(point.x - p0.x, p1.x - point.x), MinF32(point.y - p0.y, p1.y - point.y)); f32 non_corner_edge_dist = MinF32(MinF32(point.x - p0.x, p1.x - point.x), MinF32(point.y - p0.y, p1.y - point.y));
@ -702,6 +701,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
} }
// Update state from controller events // Update state from controller events
i32 mouse_downs = 0;
for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index) for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index)
{ {
ControllerEvent cev = controller_events.events[cev_index]; ControllerEvent cev = controller_events.events[cev_index];
@ -713,9 +713,9 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
{ {
if (cev.button == Button_M1 || cev.button == Button_M2 || cev.button == Button_M3) if (cev.button == Button_M1 || cev.button == Button_M2 || cev.button == Button_M3)
{ {
mouse_downs += 1;
if (top_hovered_box && active_box == 0) if (top_hovered_box && active_box == 0)
{ {
top_hovered_box->report.last_mouse_down_cursor_offset = SubVec2(frame->cursor_pos, top_hovered_box->rect.p0);
if (cev.button == Button_M1) if (cev.button == Button_M1)
{ {
++top_hovered_box->report.m1.downs; ++top_hovered_box->report.m1.downs;
@ -823,7 +823,13 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
report->active = LerpF32(report->active, target_active, active_blend_rate); report->active = LerpF32(report->active, target_active, active_blend_rate);
report->hovered = LerpF32(report->hovered, target_hovered, hovered_blend_rate); report->hovered = LerpF32(report->hovered, target_hovered, hovered_blend_rate);
report->selected = LerpF32(report->selected, target_selected, selected_blend_rate); report->selected = LerpF32(report->selected, target_selected, selected_blend_rate);
report->screen_rect = box->rect; report->screen_rect = box->screen_rect;
report->screen_anchor = box->screen_anchor;
if (mouse_downs > 0)
{
report->last_cursor_down_anchor_offset = SubVec2(frame->cursor_pos, box->screen_anchor);
}
} }
frame->top_hovered_box = top_hovered_box ? top_hovered_box->key : UI_NilKey; frame->top_hovered_box = top_hovered_box ? top_hovered_box->key : UI_NilKey;
@ -1075,7 +1081,7 @@ void UI_EndFrame(UI_Frame *frame)
// Reset layout data // Reset layout data
box->cursor = 0; box->cursor = 0;
ZeroStructs(box->final_children_size_accum, countof(box->final_children_size_accum)); ZeroStructs(box->final_children_size_accum, countof(box->final_children_size_accum));
ZeroStructs(box->solved_dims, countof(box->solved_dims)); box->solved_dims = VEC2(0, 0);
} }
else else
{ {
@ -1097,7 +1103,7 @@ void UI_EndFrame(UI_Frame *frame)
UI_Size sem_dims = box->desc.pref_semantic_dims[axis]; UI_Size sem_dims = box->desc.pref_semantic_dims[axis];
if (sem_dims.kind == UI_SizeKind_Pixel) if (sem_dims.kind == UI_SizeKind_Pixel)
{ {
box->solved_dims[axis] = RoundF32(sem_dims.v * box->desc.scale); box->solved_dims.v[axis] = RoundF32(sem_dims.v * box->desc.scale);
} }
else if (sem_dims.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText)) else if (sem_dims.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText))
{ {
@ -1111,7 +1117,7 @@ void UI_EndFrame(UI_Frame *frame)
{ {
text_size = box->glyph_run.font_ascent + box->glyph_run.font_descent; text_size = box->glyph_run.font_ascent + box->glyph_run.font_descent;
} }
box->solved_dims[axis] = RoundF32(text_size + (sem_dims.v * 2 * box->desc.scale)); box->solved_dims.v[axis] = RoundF32(text_size + (sem_dims.v * 2 * box->desc.scale));
} }
} }
} }
@ -1134,11 +1140,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))) if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText)))
{ {
// Match independent ancestor // Match independent ancestor
match_size = ancestor->solved_dims[axis]; match_size = ancestor->solved_dims.v[axis];
found_match = 1; found_match = 1;
} }
} }
box->solved_dims[axis] = RoundF32(match_size * sem_dims.v); box->solved_dims.v[axis] = RoundF32(match_size * sem_dims.v);
} }
} }
} }
@ -1159,15 +1165,15 @@ void UI_EndFrame(UI_Frame *frame)
{ {
if (axis == box->desc.child_layout_axis) if (axis == box->desc.child_layout_axis)
{ {
accum += child->solved_dims[axis]; accum += child->solved_dims.v[axis];
} }
else else
{ {
accum = MaxF32(child->solved_dims[axis], accum); accum = MaxF32(child->solved_dims.v[axis], accum);
} }
} }
} }
box->solved_dims[axis] = CeilF32(accum + (sem_dims.v * 2)); box->solved_dims.v[axis] = CeilF32(accum + (sem_dims.v * 2));
} }
} }
} }
@ -1182,7 +1188,7 @@ void UI_EndFrame(UI_Frame *frame)
UI_Size sem_dims = box->desc.pref_semantic_dims[axis]; UI_Size sem_dims = box->desc.pref_semantic_dims[axis];
if (sem_dims.kind == UI_SizeKind_Grow) if (sem_dims.kind == UI_SizeKind_Grow)
{ {
box->solved_dims[axis] = RoundF32(box->parent->solved_dims[axis] * sem_dims.v); box->solved_dims.v[axis] = RoundF32(box->parent->solved_dims.v[axis] * sem_dims.v);
} }
} }
} }
@ -1193,7 +1199,7 @@ void UI_EndFrame(UI_Frame *frame)
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
for (Axis axis = 0; axis < Axis_COUNTXY; ++axis) for (Axis axis = 0; axis < Axis_COUNTXY; ++axis)
{ {
f32 box_size = box->solved_dims[axis]; f32 box_size = box->solved_dims.v[axis];
// Solve non-floating violations // Solve non-floating violations
{ {
f32 size_accum = 0; f32 size_accum = 0;
@ -1202,7 +1208,7 @@ void UI_EndFrame(UI_Frame *frame)
{ {
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating)) if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
{ {
f32 size = child->solved_dims[axis]; f32 size = child->solved_dims.v[axis];
f32 strictness = child->desc.pref_semantic_dims[axis].strictness; f32 strictness = child->desc.pref_semantic_dims[axis].strictness;
f32 flex = size * (1.0 - strictness); f32 flex = size * (1.0 - strictness);
if (axis == box->desc.child_layout_axis) if (axis == box->desc.child_layout_axis)
@ -1225,7 +1231,7 @@ void UI_EndFrame(UI_Frame *frame)
{ {
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating)) if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
{ {
f32 size = child->solved_dims[axis]; f32 size = child->solved_dims.v[axis];
f32 strictness = child->desc.pref_semantic_dims[axis].strictness; f32 strictness = child->desc.pref_semantic_dims[axis].strictness;
f32 flex = size * (1.0 - strictness); f32 flex = size * (1.0 - strictness);
f32 new_size = size; f32 new_size = size;
@ -1242,7 +1248,7 @@ void UI_EndFrame(UI_Frame *frame)
} }
} }
adjusted_size_accum += new_size; adjusted_size_accum += new_size;
child->solved_dims[axis] = RoundF32(new_size); child->solved_dims.v[axis] = RoundF32(new_size);
} }
} }
size_accum = adjusted_size_accum; size_accum = adjusted_size_accum;
@ -1254,12 +1260,12 @@ void UI_EndFrame(UI_Frame *frame)
{ {
if (AnyBit(child->desc.flags, UI_BoxFlag_Floating) && !AnyBit(child->desc.flags, UI_BoxFlag_NoFloatingClamp)) if (AnyBit(child->desc.flags, UI_BoxFlag_Floating) && !AnyBit(child->desc.flags, UI_BoxFlag_NoFloatingClamp))
{ {
f32 size = child->solved_dims[axis]; f32 size = child->solved_dims.v[axis];
if (size > box_size) if (size > box_size)
{ {
f32 strictness = child->desc.pref_semantic_dims[axis].strictness; f32 strictness = child->desc.pref_semantic_dims[axis].strictness;
f32 flex = size * (1.0 - strictness); f32 flex = size * (1.0 - strictness);
child->solved_dims[axis] = RoundF32(MaxF32(size - flex, box_size)); child->solved_dims.v[axis] = RoundF32(MaxF32(size - flex, box_size));
} }
} }
} }
@ -1272,20 +1278,31 @@ void UI_EndFrame(UI_Frame *frame)
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
UI_Box *parent = box->parent; UI_Box *parent = box->parent;
UI_RegionPair child_alignment = UI_PairFromRegion(box->desc.child_alignment);
UI_RegionPair alignment_in_parent = Zi;
if (parent)
{
alignment_in_parent = UI_PairFromRegion(parent->desc.child_alignment);
}
else
{
alignment_in_parent = UI_PairFromRegion(UI_Region_TopLeft);
}
// Initialize layout cursor based on alignment // Initialize layout cursor based on alignment
{ {
Axis axis = box->desc.child_layout_axis; Axis axis = box->desc.child_layout_axis;
UI_AxisAlignment alignment = box->desc.child_alignment[axis]; UI_AxisRegion alignment = child_alignment.v[axis];
f32 box_size = box->solved_dims[axis]; f32 box_size = box->solved_dims.v[axis];
f32 size_accum = box->final_children_size_accum[axis]; f32 size_accum = box->final_children_size_accum[axis];
switch(alignment) switch(alignment)
{ {
default: break; default: break;
case UI_AxisAlignment_Center: case UI_AxisRegion_Center:
{ {
box->cursor = box_size / 2 - size_accum / 2; box->cursor = box_size / 2 - size_accum / 2;
} break; } break;
case UI_AxisAlignment_End: case UI_AxisRegion_End:
{ {
box->cursor = box_size - size_accum; box->cursor = box_size - size_accum;
} break; } break;
@ -1294,24 +1311,43 @@ void UI_EndFrame(UI_Frame *frame)
// Position // Position
{ {
f32 *dims_arr = box->solved_dims;
Vec2 dims_vec = VEC2(dims_arr[0], dims_arr[1]);
Vec2 final_pos = Zi; Vec2 final_pos = Zi;
Vec2 offset = Zi;
Vec2 anchor_offset = Zi;
// Floating box position // Floating box position
if (AnyBit(box->desc.flags, UI_BoxFlag_Floating)) if (AnyBit(box->desc.flags, UI_BoxFlag_Floating))
{ {
Vec2 offset = box->desc.floating_pos; UI_RegionPair floating_anchor = UI_PairFromRegion(box->desc.floating_pos_anchor);
final_pos = AddVec2(parent->rect.p0, offset);
for (Axis axis = 0; axis < Axis_COUNTXY; ++axis)
{
UI_AxisRegion anchor = floating_anchor.v[axis];
switch (anchor)
{
default: break;
case UI_AxisRegion_Center:
{
anchor_offset.v[axis] = box->solved_dims.v[axis] * 0.5;
} break;
case UI_AxisRegion_End:
{
anchor_offset.v[axis] = box->solved_dims.v[axis];
} break;
}
}
offset = SubVec2(box->desc.floating_pos, anchor_offset);
final_pos = AddVec2(parent->screen_rect.p0, offset);
if (!AnyBit(box->desc.flags, UI_BoxFlag_NoFloatingClamp)) if (!AnyBit(box->desc.flags, UI_BoxFlag_NoFloatingClamp))
{ {
{ {
f32 overshoot = MaxF32(0, (final_pos.x + dims_vec.x) - parent->rect.p1.x); f32 overshoot = MaxF32(0, (final_pos.x + box->solved_dims.x) - parent->screen_rect.p1.x);
final_pos.x = MaxF32(parent->rect.p0.x, final_pos.x - overshoot); final_pos.x = MaxF32(parent->screen_rect.p0.x, final_pos.x - overshoot);
} }
{ {
f32 overshoot = MaxF32((final_pos.y + dims_vec.y) - parent->rect.p1.y, 0); f32 overshoot = MaxF32((final_pos.y + box->solved_dims.y) - parent->screen_rect.p1.y, 0);
final_pos.y = MaxF32(parent->rect.p0.y, final_pos.y - overshoot); final_pos.y = MaxF32(parent->screen_rect.p0.y, final_pos.y - overshoot);
} }
} }
} }
@ -1319,48 +1355,49 @@ void UI_EndFrame(UI_Frame *frame)
else if (parent) else if (parent)
{ {
f32 layout_cursor = parent->cursor; f32 layout_cursor = parent->cursor;
f32 offset[2] = Zi;
// Compute offset in layout direction // Compute offset in layout direction
{ {
Axis axis = parent->desc.child_layout_axis; Axis axis = parent->desc.child_layout_axis;
offset[axis] = layout_cursor; offset.v[axis] = layout_cursor;
} }
// Compute offset in non-layout direction (based on alignment) // Compute offset in non-layout direction (based on alignment)
{ {
Axis axis = !parent->desc.child_layout_axis; Axis axis = !parent->desc.child_layout_axis;
UI_AxisAlignment alignment = parent->desc.child_alignment[axis]; UI_AxisRegion alignment = alignment_in_parent.v[axis];
switch(alignment) switch(alignment)
{ {
default: break; default: break;
case UI_AxisAlignment_Center: case UI_AxisRegion_Center:
{ {
f32 parent_size = parent->solved_dims[axis]; f32 parent_size = parent->solved_dims.v[axis];
f32 box_size = dims_arr[axis]; f32 box_size = box->solved_dims.v[axis];
offset[axis] = parent_size / 2 - box_size / 2; offset.v[axis] = parent_size / 2 - box_size / 2;
} break; } break;
case UI_AxisAlignment_End: case UI_AxisRegion_End:
{ {
f32 parent_size = parent->solved_dims[axis]; f32 parent_size = parent->solved_dims.v[axis];
f32 box_size = dims_arr[axis]; f32 box_size = box->solved_dims.v[axis];
offset[axis] = parent_size - box_size; offset.v[axis] = parent_size - box_size;
} break; } break;
} }
} }
final_pos.x = parent->rect.p0.x + offset[0]; final_pos.x = parent->screen_rect.p0.x + offset.x;
final_pos.y = parent->rect.p0.y + offset[1]; final_pos.y = parent->screen_rect.p0.y + offset.y;
parent->cursor += dims_arr[parent->desc.child_layout_axis]; parent->cursor += box->solved_dims.v[parent->desc.child_layout_axis];
} }
// Submit position // Submit position
Vec2 rounded_final_pos = FloorVec2(final_pos); Vec2 rounded_final_pos = FloorVec2(final_pos);
box->rect.p0 = rounded_final_pos; box->screen_rect.p0 = rounded_final_pos;
box->rect.p1 = AddVec2(rounded_final_pos, dims_vec); box->screen_rect.p1 = AddVec2(rounded_final_pos, box->solved_dims);
box->screen_anchor = AddVec2(box->screen_rect.p0, anchor_offset);
} }
// Rounding // Rounding
{ {
UI_Round rounding = box->desc.rounding; UI_Round rounding = box->desc.rounding;
Vec2 half_dims = MulVec2(SubVec2(box->rect.p1, box->rect.p0), 0.5); Vec2 half_dims = MulVec2(SubVec2(box->screen_rect.p1, box->screen_rect.p0), 0.5);
f32 min_half_dims = MinF32(half_dims.x, half_dims.y); f32 min_half_dims = MinF32(half_dims.x, half_dims.y);
f32 final_rounding_tl = 0; f32 final_rounding_tl = 0;
f32 final_rounding_tr = 0; f32 final_rounding_tr = 0;
@ -1388,10 +1425,10 @@ void UI_EndFrame(UI_Frame *frame)
if (parent && !AllBits(box->desc.flags, UI_BoxFlag_Floating | UI_BoxFlag_NoFloatingClamp)) if (parent && !AllBits(box->desc.flags, UI_BoxFlag_Floating | UI_BoxFlag_NoFloatingClamp))
{ {
Vec2 vtl = SubVec2(VEC2(parent->rect.p0.x, parent->rect.p0.y), VEC2(box->rect.p0.x, box->rect.p0.y)); Vec2 vtl = SubVec2(VEC2(parent->screen_rect.p0.x, parent->screen_rect.p0.y), VEC2(box->screen_rect.p0.x, box->screen_rect.p0.y));
Vec2 vtr = SubVec2(VEC2(parent->rect.p1.x, parent->rect.p0.y), VEC2(box->rect.p1.x, box->rect.p0.y)); Vec2 vtr = SubVec2(VEC2(parent->screen_rect.p1.x, parent->screen_rect.p0.y), VEC2(box->screen_rect.p1.x, box->screen_rect.p0.y));
Vec2 vbr = SubVec2(VEC2(parent->rect.p1.x, parent->rect.p1.y), VEC2(box->rect.p1.x, box->rect.p1.y)); Vec2 vbr = SubVec2(VEC2(parent->screen_rect.p1.x, parent->screen_rect.p1.y), VEC2(box->screen_rect.p1.x, box->screen_rect.p1.y));
Vec2 vbl = SubVec2(VEC2(parent->rect.p0.x, parent->rect.p1.y), VEC2(box->rect.p0.x, box->rect.p1.y)); Vec2 vbl = SubVec2(VEC2(parent->screen_rect.p0.x, parent->screen_rect.p1.y), VEC2(box->screen_rect.p0.x, box->screen_rect.p1.y));
final_rounding_tl = MaxF32(final_rounding_tl, parent->rounding_tl - Vec2Len(vtl)); final_rounding_tl = MaxF32(final_rounding_tl, parent->rounding_tl - Vec2Len(vtl));
final_rounding_tr = MaxF32(final_rounding_tr, parent->rounding_tr - Vec2Len(vtr)); final_rounding_tr = MaxF32(final_rounding_tr, parent->rounding_tr - Vec2Len(vtr));
final_rounding_br = MaxF32(final_rounding_br, parent->rounding_br - Vec2Len(vbr)); final_rounding_br = MaxF32(final_rounding_br, parent->rounding_br - Vec2Len(vbr));
@ -1420,10 +1457,12 @@ void UI_EndFrame(UI_Frame *frame)
for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index) for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index)
{ {
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
UI_RegionPair child_alignment = UI_PairFromRegion(box->desc.child_alignment);
b32 is_visible = 1; b32 is_visible = 1;
is_visible = is_visible && (box->desc.tint.w >= 0.001); is_visible = is_visible && (box->desc.tint.w >= 0.001);
is_visible = is_visible && (box->rect.p1.x - box->rect.p0.x >= 1); is_visible = is_visible && (box->screen_rect.p1.x - box->screen_rect.p0.x >= 1);
is_visible = is_visible && (box->rect.p1.y - box->rect.p0.y >= 1); is_visible = is_visible && (box->screen_rect.p1.y - box->screen_rect.p0.y >= 1);
if (is_visible || AnyBit(frame->frame_flags, UI_FrameFlag_Debug)) if (is_visible || AnyBit(frame->frame_flags, UI_FrameFlag_Debug))
{ {
Vec4 debug_lin = is_visible ? LinearFromSrgb(box->desc.debug_color) : LinearFromSrgb(box->desc.invisible_debug_color); Vec4 debug_lin = is_visible ? LinearFromSrgb(box->desc.debug_color) : LinearFromSrgb(box->desc.invisible_debug_color);
@ -1431,7 +1470,7 @@ void UI_EndFrame(UI_Frame *frame)
// Box rect // Box rect
{ {
UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect); UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect);
rect->bounds = box->rect; rect->bounds = box->screen_rect;
rect->background_lin = LinearFromSrgb(box->desc.background_color); rect->background_lin = LinearFromSrgb(box->desc.background_color);
rect->border_lin = LinearFromSrgb(box->desc.border_color); rect->border_lin = LinearFromSrgb(box->desc.border_color);
rect->debug_lin = debug_lin; rect->debug_lin = debug_lin;
@ -1449,7 +1488,7 @@ void UI_EndFrame(UI_Frame *frame)
GC_Run raw_run = box->glyph_run; GC_Run raw_run = box->glyph_run;
if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && raw_run.ready) if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && raw_run.ready)
{ {
f32 max_baseline = DimsFromRng2(box->rect).x; f32 max_baseline = DimsFromRng2(box->screen_rect).x;
b32 should_truncate = raw_run.baseline_length > max_baseline && !AnyBit(box->desc.flags, UI_BoxFlag_NoTextTruncation); b32 should_truncate = raw_run.baseline_length > max_baseline && !AnyBit(box->desc.flags, UI_BoxFlag_NoTextTruncation);
// Truncate run // Truncate run
@ -1497,48 +1536,48 @@ void UI_EndFrame(UI_Frame *frame)
final_baseline_length = raw_run.baseline_length; final_baseline_length = raw_run.baseline_length;
} }
UI_AxisAlignment x_alignment = box->desc.child_alignment[Axis_X]; UI_AxisRegion x_alignment = child_alignment.v[Axis_X];
UI_AxisAlignment y_alignment = box->desc.child_alignment[Axis_Y]; UI_AxisRegion y_alignment = child_alignment.v[Axis_Y];
// Compute baseline // Compute baseline
f32 ascent = raw_run.font_ascent; f32 ascent = raw_run.font_ascent;
f32 font_descent = raw_run.font_descent; f32 font_descent = raw_run.font_descent;
f32 cap = raw_run.font_cap; f32 cap = raw_run.font_cap;
f32 baseline_height = ascent + font_descent; f32 baseline_height = ascent + font_descent;
Vec2 box_dims = DimsFromRng2(box->rect); Vec2 box_dims = DimsFromRng2(box->screen_rect);
Vec2 baseline = Zi; Vec2 baseline = Zi;
switch (x_alignment) switch (x_alignment)
{ {
case UI_AxisAlignment_Start: case UI_AxisRegion_Start:
{ {
baseline.x = box->rect.p0.x; baseline.x = box->screen_rect.p0.x;
} break; } break;
case UI_AxisAlignment_End: case UI_AxisRegion_End:
{ {
baseline.x = box->rect.p1.x; baseline.x = box->screen_rect.p1.x;
baseline.x -= final_baseline_length; baseline.x -= final_baseline_length;
} break; } break;
case UI_AxisAlignment_Center: case UI_AxisRegion_Center:
{ {
baseline.x = box->rect.p0.x; baseline.x = box->screen_rect.p0.x;
baseline.x += (box_dims.x - final_baseline_length) / 2; baseline.x += (box_dims.x - final_baseline_length) / 2;
} break; } break;
} }
switch (y_alignment) switch (y_alignment)
{ {
case UI_AxisAlignment_Start: case UI_AxisRegion_Start:
{ {
baseline.y = box->rect.p0.y; baseline.y = box->screen_rect.p0.y;
baseline.y += ascent; baseline.y += ascent;
} break; } break;
case UI_AxisAlignment_End: case UI_AxisRegion_End:
{ {
baseline.y = box->rect.p1.y; baseline.y = box->screen_rect.p1.y;
baseline.y -= font_descent; baseline.y -= font_descent;
} break; } break;
case UI_AxisAlignment_Center: case UI_AxisRegion_Center:
{ {
baseline.y = box->rect.p0.y; baseline.y = box->screen_rect.p0.y;
baseline.y += box_dims.y / 2; baseline.y += box_dims.y / 2;
baseline.y += cap / 2; baseline.y += cap / 2;
} break; } break;

View File

@ -42,28 +42,34 @@ Struct(UI_Round)
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Alignment types //~ Region types
Enum(UI_Alignment) Enum(UI_Region)
{ {
UI_Alignment_TopLeft, UI_Region_TopLeft,
UI_Alignment_Top, UI_Region_Top,
UI_Alignment_TopRight, UI_Region_TopRight,
UI_Alignment_Left, UI_Region_Left,
UI_Alignment_Center, UI_Region_Center,
UI_Alignment_Right, UI_Region_Right,
UI_Alignment_BottomLeft, UI_Region_BottomLeft,
UI_Alignment_Bottom, UI_Region_Bottom,
UI_Alignment_BottomRight, UI_Region_BottomRight,
}; };
Enum(UI_AxisAlignment) Enum(UI_AxisRegion)
{ {
UI_AxisAlignment_Start, UI_AxisRegion_Start,
UI_AxisAlignment_Center, UI_AxisRegion_Center,
UI_AxisAlignment_End, UI_AxisRegion_End,
};
Union(UI_RegionPair)
{
struct { UI_AxisRegion x, y; };
UI_AxisRegion v[2];
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -98,8 +104,7 @@ Enum(UI_BoxFlag)
X(Parent, UI_Key) \ X(Parent, UI_Key) \
X(Tag, u64) \ X(Tag, u64) \
X(ChildLayoutAxis, Axis) \ X(ChildLayoutAxis, Axis) \
X(ChildAlignmentX, UI_AxisAlignment) \ X(ChildAlignment, UI_Region) \
X(ChildAlignmentY, UI_AxisAlignment) \
X(Width, UI_Size) \ X(Width, UI_Size) \
X(Height, UI_Size) \ X(Height, UI_Size) \
X(Scale, f32) \ X(Scale, f32) \
@ -109,6 +114,7 @@ Enum(UI_BoxFlag)
X(InvisibleDebugColor, Vec4) \ X(InvisibleDebugColor, Vec4) \
X(Tint, Vec4) \ X(Tint, Vec4) \
X(Border, f32) \ X(Border, f32) \
X(FloatingPosAnchor, UI_Region) \
X(FloatingPos, Vec2) \ X(FloatingPos, Vec2) \
X(Rounding, UI_Round) \ X(Rounding, UI_Round) \
X(Font, GC_FontKey) \ X(Font, GC_FontKey) \
@ -121,7 +127,6 @@ Enum(UI_BoxFlag)
/* --------------------------------------------- */ \ /* --------------------------------------------- */ \
X(BeginVirtualStyles_, i8) \ X(BeginVirtualStyles_, i8) \
/* --------------------------------------------- */ \ /* --------------------------------------------- */ \
X(ChildAlignment, UI_Alignment) \
X(AxisSize, UI_Size) \ X(AxisSize, UI_Size) \
/* ------------------------------------------------- */ /* ------------------------------------------------- */
@ -199,13 +204,14 @@ Struct(UI_Report)
f32 selected; f32 selected;
// Mouse button info // Mouse button info
Vec2 last_mouse_down_cursor_offset; Vec2 last_cursor_down_anchor_offset;
UI_MouseReport m1; UI_MouseReport m1;
UI_MouseReport m2; UI_MouseReport m2;
UI_MouseReport m3; UI_MouseReport m3;
// Where was this box last rendered in screen coordinates // Where was this box last rendered in screen coordinates
Rng2 screen_rect; Rng2 screen_rect;
Vec2 screen_anchor;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -241,7 +247,8 @@ Struct(UI_BoxDesc)
GC_FontKey font; GC_FontKey font;
f32 font_size; f32 font_size;
Axis child_layout_axis; Axis child_layout_axis;
UI_AxisAlignment child_alignment[Axis_COUNTXY]; UI_Region child_alignment;
UI_Region floating_pos_anchor;
}; };
Struct(UI_Cmd) Struct(UI_Cmd)
@ -302,10 +309,11 @@ Struct(UI_Box)
//- Layout data //- Layout data
f32 cursor; f32 cursor;
f32 final_children_size_accum[Axis_COUNTXY]; f32 final_children_size_accum[Axis_COUNTXY];
f32 solved_dims[Axis_COUNTXY]; Vec2 solved_dims;
//- Layout results //- Layout results
Rng2 rect; Rng2 screen_rect;
Vec2 screen_anchor;
f32 rounding_tl; f32 rounding_tl;
f32 rounding_tr; f32 rounding_tr;
f32 rounding_br; f32 rounding_br;
@ -426,6 +434,12 @@ UI_Key UI_KeyF_(String fmt, ...);
UI_Key UI_RandKey(void); UI_Key UI_RandKey(void);
UI_Box *UI_BoxFromKey(UI_Key key); 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 //~ Iteration helpers

View File

@ -8,7 +8,7 @@ UI_Key UI_BuildLabel(String text)
f32 font_size = UI_UseTop(FontSize); f32 font_size = UI_UseTop(FontSize);
f32 scale = UI_UseTop(Scale); f32 scale = UI_UseTop(Scale);
Vec4 tint = UI_UseTop(Tint); Vec4 tint = UI_UseTop(Tint);
UI_Alignment alignment = UI_UseTop(ChildAlignment); UI_Region alignment = UI_UseTop(ChildAlignment);
UI_Key key = Zi; UI_Key key = Zi;
UI_PushCP(UI_NilKey); UI_PushCP(UI_NilKey);