panel-window relocation progress

This commit is contained in:
jacob 2025-12-29 17:27:40 -06:00
parent 4d25eadd40
commit e69aa09212
7 changed files with 368 additions and 187 deletions

View File

@ -863,7 +863,7 @@ u32 LinearU32FromSrgb(Vec4 srgb)
return result; return result;
} }
Vec4 BlendSrgb(Vec4 v0, Vec4 v1, f32 t) Vec4 LerpSrgb(Vec4 v0, Vec4 v1, f32 t)
{ {
Vec4 v0_l = LinearFromSrgb(v0); Vec4 v0_l = LinearFromSrgb(v0);
Vec4 v1_l = LinearFromSrgb(v1); Vec4 v1_l = LinearFromSrgb(v1);

View File

@ -311,7 +311,7 @@ f32 LinearFromSrgbF32(f32 srgb);
Vec4 LinearFromSrgb(Vec4 srgb); Vec4 LinearFromSrgb(Vec4 srgb);
Vec4 SrgbFromLinear(Vec4 lin); Vec4 SrgbFromLinear(Vec4 lin);
u32 LinearU32FromSrgb(Vec4 srgb); u32 LinearU32FromSrgb(Vec4 srgb);
Vec4 BlendSrgb(Vec4 v0, Vec4 v1, f32 t); Vec4 LerpSrgb(Vec4 v0, Vec4 v1, f32 t);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Vec2 //~ Vec2

View File

@ -211,6 +211,7 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
if (ready_glyphs_count > 0) if (ready_glyphs_count > 0)
{ {
// TOOD: Round these too?
GC_Glyph *glyph = ready_glyphs[0]; GC_Glyph *glyph = ready_glyphs[0];
result.font_size = glyph->font_size * scale; result.font_size = glyph->font_size * scale;
result.font_ascent = glyph->font_ascent * scale; result.font_ascent = glyph->font_ascent * scale;

View File

@ -140,7 +140,6 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
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);
Vec2 titlebar_half_dims = MulVec2(DimsFromRng2(titlebar_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_background_color = VEC4(0, 0, 0, 0);
@ -150,18 +149,14 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
Vec4 divider_color = theme.divider_color; Vec4 divider_color = theme.divider_color;
if (titlebar_rep.m1.held) if (titlebar_rep.m1.held)
{ {
widget->pos = AddVec2(SubVec2(cursor_pos, titlebar_rep.last_down_mouse_offset), titlebar_half_dims); widget->pos = SubVec2(cursor_pos, titlebar_rep.last_mouse_down_cursor_offset);
} }
// window_border_color = BlendSrgb(window_border_color, Rgb(0.5, 0.5, 0.5), titlebar_rep.hot); // window_border_color = LerpSrgb(window_border_color, Rgb(0.5, 0.5, 0.5), titlebar_rep.hot);
window_border_color = BlendSrgb(window_border_color, Rgb32(0x0078a6), titlebar_rep.hot); window_border_color = LerpSrgb(window_border_color, Rgb32(0x0078a6), titlebar_rep.hot);
UI_Push(Scale, titlebar_rep.exists); UI_Push(Scale, titlebar_rep.exists);
UI_Push(Tint, VEC4(1, 1, 1, titlebar_rep.exists)); UI_Push(Tint, VEC4(1, 1, 1, titlebar_rep.exists));
// Vec2 pos = LerpVec2(MulVec2(Vec2FromVec(frame->ui_dims), 0.5), widget->pos, titlebar_rep.exists);
Vec2 pos = SubVec2(widget->pos, titlebar_half_dims);
UI_Push(BackgroundColor, window_background_color); UI_Push(BackgroundColor, window_background_color);
UI_Push(BorderColor, window_border_color); UI_Push(BorderColor, window_border_color);
UI_Push(Border, theme.window_border); UI_Push(Border, theme.window_border);
@ -169,7 +164,7 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
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, pos); UI_Push(FloatingPos, widget->pos);
UI_SetNext(Flags, UI_BoxFlag_Floating); UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_PushCP(UI_BuildBoxEx(widget->key)); UI_PushCP(UI_BuildBoxEx(widget->key));
{ {
@ -227,9 +222,9 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
UI_Report btn_rep = UI_ReportFromKey(btn_key); UI_Report btn_rep = UI_ReportFromKey(btn_key);
Vec4 btn_color = theme.window_background_color; Vec4 btn_color = theme.window_background_color;
btn_color = BlendSrgb(btn_color, theme.button_hot_color, btn_rep.hot); btn_color = LerpSrgb(btn_color, theme.button_hot_color, btn_rep.hot);
btn_color = BlendSrgb(btn_color, theme.button_active_color, btn_rep.active); btn_color = LerpSrgb(btn_color, theme.button_active_color, btn_rep.active);
Vec4 btn_border_color = BlendSrgb(VEC4(0, 0, 0, 0), theme.button_active_color, btn_rep.hot); Vec4 btn_border_color = LerpSrgb(VEC4(0, 0, 0, 0), theme.button_active_color, btn_rep.hot);
UI_SetNext(Rounding, 0); UI_SetNext(Rounding, 0);
UI_SetNext(Tint, 0); UI_SetNext(Tint, 0);
@ -272,9 +267,9 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
f32 hotkey_hot = hotkey_rep.hot; f32 hotkey_hot = hotkey_rep.hot;
f32 hotkey_active = hotkey_rep.active; f32 hotkey_active = hotkey_rep.active;
f32 hotkey_hovered = hotkey_rep.hovered; f32 hotkey_hovered = hotkey_rep.hovered;
hotkey_color = BlendSrgb(hotkey_color, hovered_color, hotkey_hot); hotkey_color = LerpSrgb(hotkey_color, hovered_color, hotkey_hot);
hotkey_color = BlendSrgb(hotkey_color, pressed_color, hotkey_active * hotkey_hovered); hotkey_color = LerpSrgb(hotkey_color, pressed_color, hotkey_active * hotkey_hovered);
hotkey_border_color = BlendSrgb(hotkey_border_color, Rgb32(0x0078a6), hotkey_hot); hotkey_border_color = LerpSrgb(hotkey_border_color, Rgb32(0x0078a6), hotkey_hot);
} }
V_Hotkey hotkey = item->desc.hotkeys[i]; V_Hotkey hotkey = item->desc.hotkeys[i];
@ -882,6 +877,7 @@ void V_TickForever(WaveLaneCtx *lane)
panel->pref_ratio = 1; panel->pref_ratio = 1;
panel->is_organizing_panel = 1; panel->is_organizing_panel = 1;
V.root_panel = panel; V.root_panel = panel;
++V.panels_count;
} }
{ {
@ -892,6 +888,7 @@ void V_TickForever(WaveLaneCtx *lane)
panel->pref_ratio = 0.25; panel->pref_ratio = 0.25;
DllQueuePush(panel->parent->first, panel->parent->last, panel); DllQueuePush(panel->parent->first, panel->parent->last, panel);
++panel->parent->count; ++panel->parent->count;
++V.panels_count;
{ {
V_Window *window = PushStruct(perm, V_Window); V_Window *window = PushStruct(perm, V_Window);
@ -900,6 +897,7 @@ void V_TickForever(WaveLaneCtx *lane)
// window->is_tile_window = 1; // window->is_tile_window = 1;
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
++panel->windows_count; ++panel->windows_count;
++V.windows_count;
} }
{ {
V_Window *window = PushStruct(perm, V_Window); V_Window *window = PushStruct(perm, V_Window);
@ -908,6 +906,7 @@ void V_TickForever(WaveLaneCtx *lane)
window->is_tile_window = 1; window->is_tile_window = 1;
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
++panel->windows_count; ++panel->windows_count;
++V.windows_count;
} }
panel->active_window_idx = 1; panel->active_window_idx = 1;
} }
@ -919,6 +918,7 @@ void V_TickForever(WaveLaneCtx *lane)
panel->axis = !panel->parent->axis; panel->axis = !panel->parent->axis;
DllQueuePush(panel->parent->first, panel->parent->last, panel); DllQueuePush(panel->parent->first, panel->parent->last, panel);
++panel->parent->count; ++panel->parent->count;
++V.panels_count;
panel->pref_ratio = 0.75; panel->pref_ratio = 0.75;
panel->is_viewport_panel = 1; panel->is_viewport_panel = 1;
@ -930,6 +930,7 @@ void V_TickForever(WaveLaneCtx *lane)
// window->is_viewport_window = 1; // window->is_viewport_window = 1;
// DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); // DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
// ++panel->windows_count; // ++panel->windows_count;
// ++V.windows_count;
// } // }
} }
@ -940,6 +941,7 @@ void V_TickForever(WaveLaneCtx *lane)
// panel->axis = !panel->parent->axis; // panel->axis = !panel->parent->axis;
// DllQueuePush(panel->parent->first, panel->parent->last, panel); // DllQueuePush(panel->parent->first, panel->parent->last, panel);
// ++panel->parent->count; // ++panel->parent->count;
// ++V.panels_count;
// { // {
// V_Window *window = PushStruct(perm, V_Window); // V_Window *window = PushStruct(perm, V_Window);
@ -948,6 +950,7 @@ void V_TickForever(WaveLaneCtx *lane)
// // window->is_tile_window = 1; // // window->is_tile_window = 1;
// DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); // DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
// ++panel->windows_count; // ++panel->windows_count;
// ++V.windows_count;
// } // }
// { // {
// V_Window *window = PushStruct(perm, V_Window); // V_Window *window = PushStruct(perm, V_Window);
@ -956,6 +959,7 @@ void V_TickForever(WaveLaneCtx *lane)
// window->is_tile_window = 1; // window->is_tile_window = 1;
// DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); // DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
// ++panel->windows_count; // ++panel->windows_count;
// ++V.windows_count;
// } // }
// panel->active_window_idx = 1; // panel->active_window_idx = 1;
// } // }
@ -968,7 +972,12 @@ void V_TickForever(WaveLaneCtx *lane)
first_panel_dfs->panel = V.root_panel; first_panel_dfs->panel = V.root_panel;
f32 divider_size = 10; f32 divider_size = 10;
//- Iterate panels i64 prune_windows_count = 0;
V_Window **prune_windows = PushStructsNoZero(frame->arena, V_Window *, V.windows_count);
//////////////////////////////
//- Walk panel tree
while (first_panel_dfs) while (first_panel_dfs)
{ {
PanelDfsNode *panel_dfs = first_panel_dfs; PanelDfsNode *panel_dfs = first_panel_dfs;
@ -1010,11 +1019,11 @@ void V_TickForever(WaveLaneCtx *lane)
f32 child_pref_size = 0; f32 child_pref_size = 0;
if (panel->axis == Axis_X) if (panel->axis == Axis_X)
{ {
child_pref_size = frame->ui_cursor.x - child_rep.screen_rect.p0.x - divider_rep.last_down_mouse_offset.x; child_pref_size = frame->ui_cursor.x - child_rep.screen_rect.p0.x - divider_rep.last_mouse_down_cursor_offset.x;
} }
else else
{ {
child_pref_size = frame->ui_cursor.y - child_rep.screen_rect.p0.y - divider_rep.last_down_mouse_offset.y; 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;
@ -1066,135 +1075,282 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Push(Tint, VEC4(1, 1, 1, 0.90 * panel_rep.exists)); UI_Push(Tint, VEC4(1, 1, 1, 0.90 * panel_rep.exists));
i64 active_window_idx = ClampI64(panel->active_window_idx, 0, MaxI64(panel->windows_count - 1, 0)); i64 active_window_idx = ClampI64(panel->active_window_idx, 0, MaxI64(panel->windows_count - 1, 0));
//////////////////////////////
//- Build tab row //- Build tab row
f32 tab_spacing = 10; f32 tab_spacing = 10;
V_Window *active_window = 0; V_Window *active_window = 0;
V_Window *close_window = 0; V_Window *close_window = 0;
{ {
i64 window_idx = 0; UI_Key tab_row_key = UI_KeyF("tab row");
UI_Report tab_row_rep = UI_ReportFromKey(tab_row_key);
UI_SetNext(Width, UI_GROW(1, 0)); UI_SetNext(Width, UI_GROW(1, 0));
UI_SetNext(Height, UI_SHRINK(0, 1)); UI_SetNext(Height, UI_SHRINK(0, 1));
UI_PushCP(UI_BuildRow()); UI_SetNext(Flags, UI_BoxFlag_Interactable);
//- Build window tabs UI_PushCP(UI_BuildRowEx(tab_row_key));
//////////////////////////////
//- Prep drawable tabs
Enum(DrawableTabKind)
{ {
DrawableTabKind_Window,
DrawableTabKind_NewTab,
DrawableTabKind_Ghost,
};
Struct(DrawableTab)
{
DrawableTab *next;
DrawableTab *prev;
DrawableTabKind kind;
UI_Key key;
V_Window *window;
i64 window_idx;
};
DrawableTab *first_drawable_tab = 0;
DrawableTab *last_drawable_tab = 0;
{
// Push window tabs
i64 window_idx = 0;
for (V_Window *window = panel->first_window; window; window = window->next_in_panel) for (V_Window *window = panel->first_window; window; window = window->next_in_panel)
{ {
UI_Push(Tag, window->key.hash); DrawableTab *tab = PushStruct(frame->arena, DrawableTab);
tab->key = window->key;
tab->kind = DrawableTabKind_Window;
tab->window = window;
tab->window_idx = window_idx;
DllQueuePush(first_drawable_tab, last_drawable_tab, tab);
window_idx += 1;
}
// Insert ghost tab
if (V.dragging_window && panel_rep.is_hovered)
{
DrawableTab *left = 0;
DrawableTab *right = 0;
for (DrawableTab *sibling = first_drawable_tab; sibling; sibling = sibling->next)
{ {
UI_Report tab_rep = UI_ReportFromKey(window->key); UI_Report sibling_rep = UI_ReportFromKey(sibling->key);
if (tab_rep.m1.downs > 0) f32 zone = CenterFromRng2(sibling_rep.screen_rect).x;
if (frame->ui_cursor.x <= zone)
{ {
new_active_window_idx = window_idx; break;
} }
left = sibling;
right = sibling->next;
}
if (window == panel->first_window) b32 skip = (left && left->window == V.dragging_window) || (right && right->window == V.dragging_window);
{ if (!skip)
UI_BuildSpacer(UI_PIX(tab_spacing, 0), Axis_X); {
} DrawableTab *tab = PushStruct(frame->arena, DrawableTab);
tab->key = UI_KeyF("ghost");
tab->kind = DrawableTabKind_Ghost;
DllQueueInsert(first_drawable_tab, last_drawable_tab, left, tab);
}
}
Vec4 bg_color = theme.window_background_color; // Push new tab button
Vec4 border_color = theme.window_border_color; {
if (window_idx == active_window_idx) DrawableTab *tab = PushStruct(frame->arena, DrawableTab);
{ tab->key = UI_KeyF("new tab");
active_window = window; tab->kind = DrawableTabKind_NewTab;
border_color = theme.button_active_color; DllQueuePush(first_drawable_tab, last_drawable_tab, tab);
} }
}
bg_color = BlendSrgb(bg_color, theme.button_hot_color, tab_rep.hot); //////////////////////////////
bg_color = BlendSrgb(bg_color, theme.button_active_color, tab_rep.active); //- Build tabs
border_color = BlendSrgb(border_color, theme.button_active_color, tab_rep.hot);
String tab_name = Zi; for (DrawableTab *tab = first_drawable_tab; tab; tab = tab->next)
if (window->is_tile_window) {
UI_Push(Tag, tab->key.hash);
UI_Report tab_rep = UI_ReportFromKey(tab->key);
if (tab == first_drawable_tab)
{
UI_BuildSpacer(UI_PIX(tab_spacing, 0), Axis_X);
}
switch (tab->kind)
{
//////////////////////////////
//- Build window tab
case DrawableTabKind_Window:
{
V_Window *window = tab->window;
{ {
tab_name = Lit("Tiles"); if (tab_rep.m1.downs > 0)
{
new_active_window_idx = tab->window_idx;
}
if (V.dragging_window == 0)
{
f32 drag_threshold = 20;
if (tab_rep.m1.held)
{
Vec2 drag_start = AddVec2(tab_rep.screen_rect.p0, tab_rep.last_mouse_down_cursor_offset);
if (Vec2Len(SubVec2(frame->ui_cursor, drag_start)) > drag_threshold)
{
V.dragging_window = window;
}
}
}
b32 is_dragging = window == V.dragging_window;
if (is_dragging && tab_rep.m1.ups > 0)
{
V.dragging_window = 0;
}
Vec4 bg_color = theme.window_background_color;
Vec4 border_color = theme.window_border_color;
if (tab->window_idx == active_window_idx)
{
active_window = window;
border_color = theme.button_active_color;
}
bg_color = LerpSrgb(bg_color, theme.button_hot_color, tab_rep.hot);
bg_color = LerpSrgb(bg_color, theme.button_active_color, tab_rep.active);
border_color = LerpSrgb(border_color, theme.button_active_color, tab_rep.hot);
if (is_dragging)
{
bg_color = Color_Blue;
}
String tab_name = Zi;
if (window->is_tile_window)
{
tab_name = Lit("Tiles");
}
else
{
tab_name = Lit("Unknown");
}
UI_SetNext(BackgroundColor, bg_color);
UI_SetNext(BorderColor, border_color);
UI_SetNext(Border, 1);
UI_SetNext(Width, UI_SHRINK(0, 0));
UI_SetNext(Height, UI_SHRINK(0, 0));
UI_SetNext(ChildAlignment, UI_Alignment_Left);
UI_SetNext(Flags, UI_BoxFlag_Interactable);
UI_SetNext(Text, tab_name);
UI_PushCP(UI_BuildRowEx(tab->key));
{
// Build tab title
{
UI_SetNext(ChildAlignment, UI_Alignment_Center);
UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_SetNext(Text, tab_name);
UI_SetNext(Width, UI_SHRINK(6, 0));
UI_SetNext(Height, UI_SHRINK(2, 0));
UI_BuildRow();
}
// Build tab close button
{
UI_Key close_key = UI_KeyF("close");
UI_Report close_rep = UI_ReportFromKey(close_key);
Vec4 close_color = Zi;
close_color = LerpSrgb(close_color, theme.button_hot_color, close_rep.hot);
close_color = LerpSrgb(close_color, theme.button_active_color, close_rep.active);
Vec4 close_border_color = LerpSrgb(VEC4(0, 0, 0, 0), theme.button_active_color, close_rep.hot);
UI_SetNext(BackgroundColor, close_color);
UI_SetNext(BorderColor, close_border_color);
UI_SetNext(Border, 2);
UI_SetNext(ChildAlignment, UI_Alignment_Center);
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable);
UI_SetNext(Text, Lit("x"));
UI_SetNext(Width, UI_SHRINK(6, 0));
UI_SetNext(Height, UI_SHRINK(2, 0));
UI_BuildRowEx(close_key);
if (close_rep.m1.presses)
{
prune_windows[prune_windows_count] = window;
prune_windows_count += 1;
}
}
}
UI_PopCP(UI_TopCP());
} }
else UI_Pop(Tag);
} break;
//////////////////////////////
//- Build ghost tab
case DrawableTabKind_Ghost:
{
UI_Report rep = UI_ReportFromKey(tab->key);
Vec4 bg_color = Zi;
bg_color = LerpSrgb(bg_color, theme.button_hot_color, rep.exists);
bg_color.w *= 0.5;
Vec4 border_color = LerpSrgb(VEC4(0, 0, 0, 0), theme.button_active_color, rep.exists);
UI_SetNext(Scale, rep.exists);
UI_SetNext(BackgroundColor, bg_color);
UI_SetNext(BorderColor, border_color);
UI_SetNext(Border, 2);
UI_SetNext(Width, UI_PIX(30, 0));
UI_SetNext(Height, UI_GROW(1, 0));
UI_SetNext(ChildAlignment, UI_Alignment_Center);
// UI_SetNext(FontSize, theme.font_size * 1.5);
UI_PushCP(UI_BuildRowEx(tab->key));
{ {
tab_name = Lit("Unknown");
} }
UI_PopCP(UI_TopCP());
} break;
//////////////////////////////
//- Build new tab button
case DrawableTabKind_NewTab:
{
UI_Key key = UI_KeyF("new tab");
UI_Report rep = UI_ReportFromKey(key);
Vec4 bg_color = Zi;
bg_color = LerpSrgb(bg_color, theme.button_hot_color, rep.hot);
bg_color = LerpSrgb(bg_color, theme.button_active_color, rep.active);
bg_color.w *= 0.5;
Vec4 border_color = LerpSrgb(VEC4(0, 0, 0, 0), theme.button_active_color, rep.hot);
UI_SetNext(BackgroundColor, bg_color); UI_SetNext(BackgroundColor, bg_color);
UI_SetNext(BorderColor, border_color); UI_SetNext(BorderColor, border_color);
UI_SetNext(Border, 1); UI_SetNext(Border, 2);
UI_SetNext(Width, UI_SHRINK(0, 0)); UI_SetNext(Width, UI_SHRINK(10, 0));
UI_SetNext(Height, UI_SHRINK(0, 0)); UI_SetNext(Height, UI_SHRINK(2, 0));
UI_SetNext(ChildAlignment, UI_Alignment_Left); UI_SetNext(ChildAlignment, UI_Alignment_Center);
UI_SetNext(Flags, UI_BoxFlag_Interactable); // UI_SetNext(FontSize, theme.font_size * 1.5);
UI_SetNext(Text, tab_name); UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable);
UI_PushCP(UI_BuildRowEx(window->key)); UI_SetNext(Text, Lit("+"));
UI_PushCP(UI_BuildRowEx(key));
{ {
// Build tab title
{
UI_SetNext(ChildAlignment, UI_Alignment_Center);
UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_SetNext(Text, tab_name);
UI_SetNext(Width, UI_SHRINK(6, 0));
UI_SetNext(Height, UI_SHRINK(2, 0));
UI_BuildRow();
}
// Build tab close button
{
UI_Key close_key = UI_KeyF("close");
UI_Report close_rep = UI_ReportFromKey(close_key);
Vec4 close_color = Zi;
close_color = BlendSrgb(close_color, theme.button_hot_color, close_rep.hot);
close_color = BlendSrgb(close_color, theme.button_active_color, close_rep.active);
Vec4 close_border_color = BlendSrgb(VEC4(0, 0, 0, 0), theme.button_active_color, close_rep.hot);
UI_SetNext(BackgroundColor, close_color);
UI_SetNext(BorderColor, close_border_color);
UI_SetNext(Border, 2);
UI_SetNext(ChildAlignment, UI_Alignment_Center);
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable);
UI_SetNext(Text, Lit("x"));
UI_SetNext(Width, UI_SHRINK(6, 0));
UI_SetNext(Height, UI_SHRINK(2, 0));
UI_BuildRowEx(close_key);
if (close_rep.m1.presses)
{
close_window = window;
}
}
} }
UI_PopCP(UI_TopCP()); UI_PopCP(UI_TopCP());
} }
UI_Pop(Tag);
UI_BuildSpacer(UI_PIX(tab_spacing, 0), Axis_X);
window_idx += 1;
} }
} UI_BuildSpacer(UI_PIX(tab_spacing, 0), Axis_X);
//- Build new-tab button
{
UI_Key key = UI_KeyF("new tab");
UI_Report rep = UI_ReportFromKey(key);
Vec4 bg_color = Zi;
bg_color = BlendSrgb(bg_color, theme.button_hot_color, rep.hot);
bg_color = BlendSrgb(bg_color, theme.button_active_color, rep.active);
bg_color.w *= 0.5;
Vec4 border_color = BlendSrgb(VEC4(0, 0, 0, 0), theme.button_active_color, rep.hot);
UI_SetNext(BackgroundColor, bg_color);
UI_SetNext(BorderColor, border_color);
UI_SetNext(Border, 2);
UI_SetNext(Width, UI_SHRINK(10, 0));
UI_SetNext(Height, UI_SHRINK(2, 0));
UI_SetNext(ChildAlignment, UI_Alignment_Center);
// UI_SetNext(FontSize, theme.font_size * 1.5);
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable);
UI_SetNext(Text, Lit("+"));
UI_PushCP(UI_BuildRowEx(key));
{
}
UI_PopCP(UI_TopCP());
} }
UI_PopCP(UI_TopCP()); UI_PopCP(UI_TopCP());
} }
//////////////////////////////
//- Build active window //- Build active window
if (active_window) if (active_window)
{ {
Vec4 window_bg_color = theme.window_background_color; Vec4 window_bg_color = theme.window_background_color;
@ -1224,14 +1380,14 @@ void V_TickForever(WaveLaneCtx *lane)
} }
Vec4 bg_color = Zi; Vec4 bg_color = Zi;
bg_color = BlendSrgb(bg_color, theme.button_hot_color, rep.hot); bg_color = LerpSrgb(bg_color, theme.button_hot_color, rep.hot);
bg_color = BlendSrgb(bg_color, theme.button_active_color, rep.active); bg_color = LerpSrgb(bg_color, theme.button_active_color, rep.active);
b32 is_selected = tile_kind == frame->equipped_tile; b32 is_selected = tile_kind == frame->equipped_tile;
Vec4 border_color = Zi; Vec4 border_color = Zi;
border_color = BlendSrgb(border_color, theme.button_selected_color, rep.selected); border_color = LerpSrgb(border_color, theme.button_selected_color, rep.selected);
border_color = BlendSrgb(border_color, theme.button_active_color, rep.hot); border_color = LerpSrgb(border_color, theme.button_active_color, rep.hot);
UI_SetNext(BackgroundColor, bg_color); UI_SetNext(BackgroundColor, bg_color);
UI_SetNext(BorderColor, border_color); UI_SetNext(BorderColor, border_color);
@ -1254,15 +1410,6 @@ void V_TickForever(WaveLaneCtx *lane)
} }
UI_PopCP(UI_TopCP()); UI_PopCP(UI_TopCP());
} }
//- Close window
if (close_window != 0)
{
V_Window *window = close_window;
// TODO: Add window to free list
// TODO: Remove panel if windowless
DllQueueRemoveNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
panel->windows_count -= 1;
}
} }
UI_PopCP(UI_TopCP()); UI_PopCP(UI_TopCP());
panel->active_window_idx = new_active_window_idx; panel->active_window_idx = new_active_window_idx;
@ -1273,18 +1420,20 @@ void V_TickForever(WaveLaneCtx *lane)
UI_PopCP(panel_dfs->cp); UI_PopCP(panel_dfs->cp);
SllStackPop(first_panel_dfs); SllStackPop(first_panel_dfs);
//- Build divider //////////////////////////////
//- Build panel divider
if (panel->next != 0) if (panel->next != 0)
{ {
panel->divider_key = UI_KeyF("Divider"); panel->divider_key = UI_KeyF("Divider");
UI_Report rep = UI_ReportFromKey(panel->divider_key); UI_Report rep = UI_ReportFromKey(panel->divider_key);
Vec4 active_color = theme.button_active_color; Vec4 active_color = theme.button_active_color;
Vec4 hot_color = BlendSrgb(theme.button_hot_color, theme.button_active_color, 0.25); Vec4 hot_color = LerpSrgb(theme.button_hot_color, theme.button_active_color, 0.25);
Vec4 bg_color = Zi; Vec4 bg_color = Zi;
bg_color = BlendSrgb(bg_color, hot_color, rep.hot); bg_color = LerpSrgb(bg_color, hot_color, rep.hot);
bg_color = BlendSrgb(bg_color, active_color, rep.active); bg_color = LerpSrgb(bg_color, active_color, rep.active);
Vec4 border_color = Zi; Vec4 border_color = Zi;
f32 visible_size = 2.0; f32 visible_size = 2.0;
@ -1318,6 +1467,25 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Pop(Tag); UI_Pop(Tag);
} }
} }
//////////////////////////////
//- Prune windows
for (i64 prune_window_idx = 0; prune_window_idx < prune_windows_count; ++prune_window_idx)
{
V_Window *window = prune_windows[prune_window_idx];
V_Panel *panel = window->panel;
if (window == V.dragging_window)
{
V.dragging_window = 0;
}
// TODO: Add window to free list
// TODO: Remove panel if windowless
DllQueueRemoveNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
panel->windows_count -= 1;
}
} }
////////////////////////////// //////////////////////////////

View File

@ -281,7 +281,10 @@ Struct(V_Ctx)
S_Lookup lookup; S_Lookup lookup;
S_Key player_key; S_Key player_key;
i64 panels_count;
i64 windows_count;
V_Panel *root_panel; V_Panel *root_panel;
V_Window *dragging_window;
Atomic32 shutdown; Atomic32 shutdown;
Fence shutdown_complete; Fence shutdown_complete;

View File

@ -640,7 +640,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
frame->cursor_pos = last_frame->cursor_pos; frame->cursor_pos = last_frame->cursor_pos;
// Locate boxes // Locate boxes
UI_Box *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);
// Update cursor pos // Update cursor pos
@ -657,39 +657,36 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
for (u64 pre_index = UI.boxes_count; pre_index-- > 0;) for (u64 pre_index = UI.boxes_count; pre_index-- > 0;)
{ {
UI_Box *box = last_frame->boxes_pre[pre_index]; UI_Box *box = last_frame->boxes_pre[pre_index];
if (hovered_box == 0 && box->desc.flags & UI_BoxFlag_Interactable) 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.
Vec2 p0 = box->rect.p0;
Vec2 p1 = box->rect.p1;
Vec2 point = frame->cursor_pos;
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 corner_edge_dist = non_corner_edge_dist;
if (non_corner_edge_dist >= 0)
{ {
// TODO: More efficient test. This logic is just copied from the renderer's SDF function for now. f32 tl_radius = box->rounding_tl;
Vec2 p0 = box->rect.p0; f32 tr_radius = box->rounding_tr;
Vec2 p1 = box->rect.p1; f32 br_radius = box->rounding_br;
Vec2 point = frame->cursor_pos; f32 bl_radius = box->rounding_bl;
b32 is_corner = 0; Vec2 tl = VEC2(p0.x + tl_radius, p0.y + tl_radius);
f32 non_corner_edge_dist = MinF32(MinF32(point.x - p0.x, p1.x - point.x), MinF32(point.y - p0.y, p1.y - point.y)); Vec2 tr = VEC2(p1.x - tr_radius, p0.y + tr_radius);
f32 corner_edge_dist = non_corner_edge_dist; Vec2 br = VEC2(p1.x - br_radius, p1.y - br_radius);
if (non_corner_edge_dist >= 0) Vec2 bl = VEC2(p0.x + bl_radius, p1.y - bl_radius);
{ if (point.x < tl.x && point.y < tl.y) corner_edge_dist = MinF32(corner_edge_dist, tl_radius - Vec2Len(SubVec2(tl, point)));
f32 tl_radius = box->rounding_tl; if (point.x > tr.x && point.y < tr.y) corner_edge_dist = MinF32(corner_edge_dist, tr_radius - Vec2Len(SubVec2(tr, point)));
f32 tr_radius = box->rounding_tr; if (point.x > br.x && point.y > br.y) corner_edge_dist = MinF32(corner_edge_dist, br_radius - Vec2Len(SubVec2(br, point)));
f32 br_radius = box->rounding_br; if (point.x < bl.x && point.y > bl.y) corner_edge_dist = MinF32(corner_edge_dist, bl_radius - Vec2Len(SubVec2(bl, point)));
f32 bl_radius = box->rounding_bl;
Vec2 tl = VEC2(p0.x + tl_radius, p0.y + tl_radius);
Vec2 tr = VEC2(p1.x - tr_radius, p0.y + tr_radius);
Vec2 br = VEC2(p1.x - br_radius, p1.y - br_radius);
Vec2 bl = VEC2(p0.x + bl_radius, p1.y - bl_radius);
if (point.x < tl.x && point.y < tl.y) corner_edge_dist = MinF32(corner_edge_dist, tl_radius - Vec2Len(SubVec2(tl, point)));
if (point.x > tr.x && point.y < tr.y) corner_edge_dist = MinF32(corner_edge_dist, tr_radius - Vec2Len(SubVec2(tr, point)));
if (point.x > br.x && point.y > br.y) corner_edge_dist = MinF32(corner_edge_dist, br_radius - Vec2Len(SubVec2(br, point)));
if (point.x < bl.x && point.y > bl.y) corner_edge_dist = MinF32(corner_edge_dist, bl_radius - Vec2Len(SubVec2(bl, point)));
}
is_cursor_in_box = non_corner_edge_dist >= 0 && corner_edge_dist >= 0;
}
if (is_cursor_in_box)
{
hovered_box = box;
} }
is_cursor_in_box = non_corner_edge_dist >= 0 && corner_edge_dist >= 0;
}
box->report.is_hovered = is_cursor_in_box;
if (top_hovered_box == 0 && box->desc.flags & UI_BoxFlag_Interactable && is_cursor_in_box)
{
top_hovered_box = box;
} }
box->report.m1.ups = 0; box->report.m1.ups = 0;
box->report.m1.downs = 0; box->report.m1.downs = 0;
@ -714,25 +711,25 @@ 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)
{ {
if (hovered_box) if (top_hovered_box && active_box == 0)
{ {
hovered_box->report.last_down_mouse_offset = SubVec2(frame->cursor_pos, hovered_box->rect.p0); 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)
{ {
++hovered_box->report.m1.downs; ++top_hovered_box->report.m1.downs;
hovered_box->report.m1.held = 1; top_hovered_box->report.m1.held = 1;
} }
else if (cev.button == Button_M2) else if (cev.button == Button_M2)
{ {
++hovered_box->report.m2.downs; ++top_hovered_box->report.m2.downs;
hovered_box->report.m2.held = 1; top_hovered_box->report.m2.held = 1;
} }
else if (cev.button == Button_M3) else if (cev.button == Button_M3)
{ {
++hovered_box->report.m3.downs; ++top_hovered_box->report.m3.downs;
hovered_box->report.m3.held = 1; top_hovered_box->report.m3.held = 1;
} }
active_box = hovered_box; active_box = top_hovered_box;
} }
} }
} break; } break;
@ -743,32 +740,45 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
{ {
if (active_box) if (active_box)
{ {
++active_box->report.m1.ups;
if (cev.button == Button_M1) if (cev.button == Button_M1)
{ {
if (active_box == hovered_box) if (active_box == top_hovered_box)
{ {
++active_box->report.m1.presses; ++active_box->report.m1.presses;
} }
active_box->report.m1.held = 0; ++active_box->report.m1.ups;
if (active_box->report.m1.held)
{
active_box->report.m1.held = 0;
active_box = 0;
}
} }
else if (cev.button == Button_M2) else if (cev.button == Button_M2)
{ {
if (active_box == hovered_box) if (active_box == top_hovered_box)
{ {
++active_box->report.m2.presses; ++active_box->report.m2.presses;
} }
active_box->report.m2.held = 0; ++active_box->report.m2.ups;
if (active_box->report.m2.held)
{
active_box->report.m2.held = 0;
active_box = 0;
}
} }
else if (cev.button == Button_M3) else if (cev.button == Button_M3)
{ {
if (active_box == hovered_box) if (active_box == top_hovered_box)
{ {
++active_box->report.m3.presses; ++active_box->report.m3.presses;
} }
active_box->report.m3.held = 0; ++active_box->report.m3.ups;
if (active_box->report.m3.held)
{
active_box->report.m3.held = 0;
active_box = 0;
}
} }
active_box = 0;
} }
} }
} break; } break;
@ -781,9 +791,9 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
} }
UI_Box *hot_box = active_box; UI_Box *hot_box = active_box;
if (hovered_box && !active_box) if (top_hovered_box && !active_box)
{ {
hot_box = hovered_box; hot_box = top_hovered_box;
} }
// Update box reports // Update box reports
@ -791,7 +801,6 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
{ {
UI_Box *box = last_frame->boxes_pre[pre_index]; UI_Box *box = last_frame->boxes_pre[pre_index];
UI_Report *report = &box->report; UI_Report *report = &box->report;
report->is_hovered = box == hovered_box;
report->is_hot = box == hot_box; report->is_hot = box == hot_box;
f32 target_exists = box->last_build_tick >= (frame->tick - 1); f32 target_exists = box->last_build_tick >= (frame->tick - 1);
@ -814,7 +823,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
report->screen_rect = box->rect; report->screen_rect = box->rect;
} }
frame->hovered_box = hovered_box ? hovered_box->key : UI_NilKey; frame->top_hovered_box = top_hovered_box ? top_hovered_box->key : UI_NilKey;
frame->hot_box = hot_box ? hot_box->key : UI_NilKey; frame->hot_box = hot_box ? hot_box->key : UI_NilKey;
frame->active_box = active_box ? active_box->key : UI_NilKey; frame->active_box = active_box ? active_box->key : UI_NilKey;
} }

View File

@ -194,7 +194,7 @@ Struct(UI_Report)
f32 selected; f32 selected;
// Mouse button info // Mouse button info
Vec2 last_down_mouse_offset; Vec2 last_mouse_down_cursor_offset;
UI_MouseReport m1; UI_MouseReport m1;
UI_MouseReport m2; UI_MouseReport m2;
UI_MouseReport m3; UI_MouseReport m3;
@ -363,7 +363,7 @@ Struct(UI_Frame)
// Control // Control
Vec2 cursor_pos; Vec2 cursor_pos;
UI_Key hovered_box; UI_Key top_hovered_box;
UI_Key hot_box; UI_Key hot_box;
UI_Key active_box; UI_Key active_box;