From e69aa09212e5c79c182e55f0decd8abf0c9547f3 Mon Sep 17 00:00:00 2001 From: jacob Date: Mon, 29 Dec 2025 17:27:40 -0600 Subject: [PATCH] panel-window relocation progress --- src/base/base_math.c | 2 +- src/base/base_math.h | 2 +- src/glyph_cache/glyph_cache.c | 1 + src/pp/pp_vis/pp_vis_core.c | 430 +++++++++++++++++++++++----------- src/pp/pp_vis/pp_vis_core.h | 3 + src/ui/ui_core.c | 113 +++++---- src/ui/ui_core.h | 4 +- 7 files changed, 368 insertions(+), 187 deletions(-) diff --git a/src/base/base_math.c b/src/base/base_math.c index 7366e71b..c201cda5 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -863,7 +863,7 @@ u32 LinearU32FromSrgb(Vec4 srgb) return result; } -Vec4 BlendSrgb(Vec4 v0, Vec4 v1, f32 t) +Vec4 LerpSrgb(Vec4 v0, Vec4 v1, f32 t) { Vec4 v0_l = LinearFromSrgb(v0); Vec4 v1_l = LinearFromSrgb(v1); diff --git a/src/base/base_math.h b/src/base/base_math.h index f1d655fe..b396652d 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -311,7 +311,7 @@ f32 LinearFromSrgbF32(f32 srgb); Vec4 LinearFromSrgb(Vec4 srgb); Vec4 SrgbFromLinear(Vec4 lin); u32 LinearU32FromSrgb(Vec4 srgb); -Vec4 BlendSrgb(Vec4 v0, Vec4 v1, f32 t); +Vec4 LerpSrgb(Vec4 v0, Vec4 v1, f32 t); //////////////////////////////////////////////////////////// //~ Vec2 diff --git a/src/glyph_cache/glyph_cache.c b/src/glyph_cache/glyph_cache.c index fe0ebaa9..7e74fab1 100644 --- a/src/glyph_cache/glyph_cache.c +++ b/src/glyph_cache/glyph_cache.c @@ -211,6 +211,7 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size if (ready_glyphs_count > 0) { + // TOOD: Round these too? GC_Glyph *glyph = ready_glyphs[0]; result.font_size = glyph->font_size * scale; result.font_ascent = glyph->font_ascent * scale; diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index d8d8cc3f..b6f54f1a 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -140,7 +140,6 @@ void V_EndCommandsWidget(V_CommandsWidget *widget) UI_Key titlebar_key = UI_KeyF("title bar"); 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 = VEC4(0, 0, 0, 0); @@ -150,18 +149,14 @@ void V_EndCommandsWidget(V_CommandsWidget *widget) Vec4 divider_color = theme.divider_color; 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 = BlendSrgb(window_border_color, Rgb32(0x0078a6), titlebar_rep.hot); - + // window_border_color = LerpSrgb(window_border_color, Rgb(0.5, 0.5, 0.5), titlebar_rep.hot); + window_border_color = LerpSrgb(window_border_color, Rgb32(0x0078a6), titlebar_rep.hot); UI_Push(Scale, 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(BorderColor, window_border_color); 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(Height, UI_SHRINK(0, 0)); UI_Push(ChildLayoutAxis, Axis_Y); - UI_Push(FloatingPos, pos); + UI_Push(FloatingPos, widget->pos); UI_SetNext(Flags, UI_BoxFlag_Floating); UI_PushCP(UI_BuildBoxEx(widget->key)); { @@ -227,9 +222,9 @@ void V_EndCommandsWidget(V_CommandsWidget *widget) UI_Report btn_rep = UI_ReportFromKey(btn_key); Vec4 btn_color = theme.window_background_color; - btn_color = BlendSrgb(btn_color, theme.button_hot_color, btn_rep.hot); - btn_color = BlendSrgb(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); + btn_color = LerpSrgb(btn_color, theme.button_hot_color, btn_rep.hot); + btn_color = LerpSrgb(btn_color, theme.button_active_color, btn_rep.active); + Vec4 btn_border_color = LerpSrgb(VEC4(0, 0, 0, 0), theme.button_active_color, btn_rep.hot); UI_SetNext(Rounding, 0); UI_SetNext(Tint, 0); @@ -272,9 +267,9 @@ void V_EndCommandsWidget(V_CommandsWidget *widget) f32 hotkey_hot = hotkey_rep.hot; f32 hotkey_active = hotkey_rep.active; f32 hotkey_hovered = hotkey_rep.hovered; - hotkey_color = BlendSrgb(hotkey_color, hovered_color, hotkey_hot); - hotkey_color = BlendSrgb(hotkey_color, pressed_color, hotkey_active * hotkey_hovered); - hotkey_border_color = BlendSrgb(hotkey_border_color, Rgb32(0x0078a6), hotkey_hot); + hotkey_color = LerpSrgb(hotkey_color, hovered_color, hotkey_hot); + hotkey_color = LerpSrgb(hotkey_color, pressed_color, hotkey_active * hotkey_hovered); + hotkey_border_color = LerpSrgb(hotkey_border_color, Rgb32(0x0078a6), hotkey_hot); } V_Hotkey hotkey = item->desc.hotkeys[i]; @@ -882,6 +877,7 @@ void V_TickForever(WaveLaneCtx *lane) panel->pref_ratio = 1; panel->is_organizing_panel = 1; V.root_panel = panel; + ++V.panels_count; } { @@ -892,6 +888,7 @@ void V_TickForever(WaveLaneCtx *lane) panel->pref_ratio = 0.25; DllQueuePush(panel->parent->first, panel->parent->last, panel); ++panel->parent->count; + ++V.panels_count; { V_Window *window = PushStruct(perm, V_Window); @@ -900,6 +897,7 @@ void V_TickForever(WaveLaneCtx *lane) // window->is_tile_window = 1; DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); ++panel->windows_count; + ++V.windows_count; } { V_Window *window = PushStruct(perm, V_Window); @@ -908,6 +906,7 @@ void V_TickForever(WaveLaneCtx *lane) window->is_tile_window = 1; DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); ++panel->windows_count; + ++V.windows_count; } panel->active_window_idx = 1; } @@ -919,6 +918,7 @@ void V_TickForever(WaveLaneCtx *lane) panel->axis = !panel->parent->axis; DllQueuePush(panel->parent->first, panel->parent->last, panel); ++panel->parent->count; + ++V.panels_count; panel->pref_ratio = 0.75; panel->is_viewport_panel = 1; @@ -930,6 +930,7 @@ void V_TickForever(WaveLaneCtx *lane) // window->is_viewport_window = 1; // DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); // ++panel->windows_count; + // ++V.windows_count; // } } @@ -940,6 +941,7 @@ void V_TickForever(WaveLaneCtx *lane) // panel->axis = !panel->parent->axis; // DllQueuePush(panel->parent->first, panel->parent->last, panel); // ++panel->parent->count; + // ++V.panels_count; // { // V_Window *window = PushStruct(perm, V_Window); @@ -948,6 +950,7 @@ void V_TickForever(WaveLaneCtx *lane) // // window->is_tile_window = 1; // DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); // ++panel->windows_count; + // ++V.windows_count; // } // { // V_Window *window = PushStruct(perm, V_Window); @@ -956,6 +959,7 @@ void V_TickForever(WaveLaneCtx *lane) // window->is_tile_window = 1; // DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); // ++panel->windows_count; + // ++V.windows_count; // } // panel->active_window_idx = 1; // } @@ -968,7 +972,12 @@ void V_TickForever(WaveLaneCtx *lane) first_panel_dfs->panel = V.root_panel; 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) { PanelDfsNode *panel_dfs = first_panel_dfs; @@ -1010,11 +1019,11 @@ void V_TickForever(WaveLaneCtx *lane) f32 child_pref_size = 0; 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 { - 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; @@ -1066,135 +1075,282 @@ void V_TickForever(WaveLaneCtx *lane) 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)); + + ////////////////////////////// //- Build tab row + f32 tab_spacing = 10; V_Window *active_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(Height, UI_SHRINK(0, 1)); - UI_PushCP(UI_BuildRow()); - //- Build window tabs + UI_SetNext(Flags, UI_BoxFlag_Interactable); + 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) { - 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); - if (tab_rep.m1.downs > 0) + UI_Report sibling_rep = UI_ReportFromKey(sibling->key); + 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) - { - UI_BuildSpacer(UI_PIX(tab_spacing, 0), Axis_X); - } + b32 skip = (left && left->window == V.dragging_window) || (right && right->window == V.dragging_window); + if (!skip) + { + 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; - Vec4 border_color = theme.window_border_color; - if (window_idx == active_window_idx) - { - active_window = window; - border_color = theme.button_active_color; - } + // Push new tab button + { + DrawableTab *tab = PushStruct(frame->arena, DrawableTab); + tab->key = UI_KeyF("new tab"); + tab->kind = DrawableTabKind_NewTab; + 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); - border_color = BlendSrgb(border_color, theme.button_active_color, tab_rep.hot); + ////////////////////////////// + //- Build tabs - String tab_name = Zi; - if (window->is_tile_window) + for (DrawableTab *tab = first_drawable_tab; tab; tab = tab->next) + { + 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(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(window->key)); + 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)); { - // 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_Pop(Tag); - UI_BuildSpacer(UI_PIX(tab_spacing, 0), Axis_X); - window_idx += 1; } - } - //- 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_BuildSpacer(UI_PIX(tab_spacing, 0), Axis_X); } UI_PopCP(UI_TopCP()); } + + ////////////////////////////// //- Build active window + if (active_window) { Vec4 window_bg_color = theme.window_background_color; @@ -1224,14 +1380,14 @@ void V_TickForever(WaveLaneCtx *lane) } 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 = LerpSrgb(bg_color, theme.button_hot_color, rep.hot); + bg_color = LerpSrgb(bg_color, theme.button_active_color, rep.active); b32 is_selected = tile_kind == frame->equipped_tile; Vec4 border_color = Zi; - border_color = BlendSrgb(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_selected_color, rep.selected); + border_color = LerpSrgb(border_color, theme.button_active_color, rep.hot); UI_SetNext(BackgroundColor, bg_color); UI_SetNext(BorderColor, border_color); @@ -1254,15 +1410,6 @@ void V_TickForever(WaveLaneCtx *lane) } 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()); panel->active_window_idx = new_active_window_idx; @@ -1273,18 +1420,20 @@ void V_TickForever(WaveLaneCtx *lane) UI_PopCP(panel_dfs->cp); SllStackPop(first_panel_dfs); - //- Build divider + ////////////////////////////// + //- Build panel divider + if (panel->next != 0) { panel->divider_key = UI_KeyF("Divider"); UI_Report rep = UI_ReportFromKey(panel->divider_key); 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; - bg_color = BlendSrgb(bg_color, hot_color, rep.hot); - bg_color = BlendSrgb(bg_color, active_color, rep.active); + bg_color = LerpSrgb(bg_color, hot_color, rep.hot); + bg_color = LerpSrgb(bg_color, active_color, rep.active); Vec4 border_color = Zi; f32 visible_size = 2.0; @@ -1318,6 +1467,25 @@ void V_TickForever(WaveLaneCtx *lane) 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; + } } ////////////////////////////// diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index 550dd94f..45f03355 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -281,7 +281,10 @@ Struct(V_Ctx) S_Lookup lookup; S_Key player_key; + i64 panels_count; + i64 windows_count; V_Panel *root_panel; + V_Window *dragging_window; Atomic32 shutdown; Fence shutdown_complete; diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 0fdc97d1..57ae198f 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -640,7 +640,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) frame->cursor_pos = last_frame->cursor_pos; // Locate boxes - UI_Box *hovered_box = 0; + UI_Box *top_hovered_box = 0; UI_Box *active_box = UI_BoxFromKey(last_frame->active_box); // 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;) { 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. - 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) - { - f32 tl_radius = box->rounding_tl; - f32 tr_radius = box->rounding_tr; - f32 br_radius = box->rounding_br; - 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; + f32 tl_radius = box->rounding_tl; + f32 tr_radius = box->rounding_tr; + f32 br_radius = box->rounding_br; + 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; + } + 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.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 (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) { - ++hovered_box->report.m1.downs; - hovered_box->report.m1.held = 1; + ++top_hovered_box->report.m1.downs; + top_hovered_box->report.m1.held = 1; } else if (cev.button == Button_M2) { - ++hovered_box->report.m2.downs; - hovered_box->report.m2.held = 1; + ++top_hovered_box->report.m2.downs; + top_hovered_box->report.m2.held = 1; } else if (cev.button == Button_M3) { - ++hovered_box->report.m3.downs; - hovered_box->report.m3.held = 1; + ++top_hovered_box->report.m3.downs; + top_hovered_box->report.m3.held = 1; } - active_box = hovered_box; + active_box = top_hovered_box; } } } break; @@ -743,32 +740,45 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) { if (active_box) { - ++active_box->report.m1.ups; 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.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) { - if (active_box == hovered_box) + if (active_box == top_hovered_box) { ++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) { - if (active_box == hovered_box) + if (active_box == top_hovered_box) { ++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; @@ -781,9 +791,9 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) } 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 @@ -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_Report *report = &box->report; - report->is_hovered = box == hovered_box; report->is_hot = box == hot_box; 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; } - 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->active_box = active_box ? active_box->key : UI_NilKey; } diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index 389b0a57..c80cc599 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -194,7 +194,7 @@ Struct(UI_Report) f32 selected; // Mouse button info - Vec2 last_down_mouse_offset; + Vec2 last_mouse_down_cursor_offset; UI_MouseReport m1; UI_MouseReport m2; UI_MouseReport m3; @@ -363,7 +363,7 @@ Struct(UI_Frame) // Control Vec2 cursor_pos; - UI_Key hovered_box; + UI_Key top_hovered_box; UI_Key hot_box; UI_Key active_box;