From 90b908ff9899d07dae46391b8c5761f998a1ddf2 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 28 Dec 2019 13:02:19 -0800 Subject: [PATCH] Removed all reliance on external factors from the foldhaus_panel.h system --- src/foldhaus_app.cpp | 195 +++++++++++-- src/foldhaus_app.h | 6 +- src/foldhaus_panel.h | 265 ++++++------------ .../foldhaus_panel_animation_timeline.h | 4 +- 4 files changed, 260 insertions(+), 210 deletions(-) diff --git a/src/foldhaus_app.cpp b/src/foldhaus_app.cpp index 848da6b..8c3b351 100644 --- a/src/foldhaus_app.cpp +++ b/src/foldhaus_app.cpp @@ -13,18 +13,18 @@ SetPanelDefinitionExternal(panel* Panel, s32 OldPanelDefinitionIndex, s32 NewPan internal void -DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, v2 FooterMin, v2 FooterMax, interface_config Interface, mouse_state Mouse) +DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect FooterBounds, interface_config Interface, mouse_state Mouse) { - PushRenderQuad2D(RenderBuffer, FooterMin, v2{FooterMax.x, FooterMin.y + 25}, v4{.5f, .5f, .5f, 1.f}); - PushRenderQuad2D(RenderBuffer, FooterMin, FooterMin + v2{25, 25}, WhiteV4); + PushRenderQuad2D(RenderBuffer, FooterBounds.Min, v2{FooterBounds.Max.x, FooterBounds.Min.y + 25}, v4{.5f, .5f, .5f, 1.f}); + PushRenderQuad2D(RenderBuffer, FooterBounds.Min, FooterBounds.Min + v2{25, 25}, WhiteV4); - v2 PanelSelectButtonMin = FooterMin + v2{30, 1}; + v2 PanelSelectButtonMin = FooterBounds.Min + v2{30, 1}; v2 PanelSelectButtonMax = PanelSelectButtonMin + v2{100, 23}; if (Panel->PanelSelectionMenuOpen) { v2 ButtonDimension = v2{100, 25}; - v2 ButtonMin = v2{PanelSelectButtonMin.x, FooterMax.y}; + v2 ButtonMin = v2{PanelSelectButtonMin.x, FooterBounds.Max.y}; v2 MenuMin = ButtonMin; v2 MenuMax = v2{ButtonMin.x + ButtonDimension.x, ButtonMin.y + (ButtonDimension.y * GlobalPanelDefsCount)}; @@ -64,24 +64,24 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, v2 FooterMin, } internal void -RenderPanel(panel* Panel, v2 PanelMin, v2 PanelMax, v2 WindowMin, v2 WindowMax, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) +RenderPanel(panel* Panel, rect PanelBounds, rect WindowBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) { Assert(Panel->PanelDefinitionIndex >= 0); - v2 FooterMin = PanelMin; - v2 FooterMax = v2{PanelMax.x, PanelMin.y + 25}; - rect PanelBounds = rect{ - v2{PanelMin.x, FooterMax.y}, - PanelMax, + rect FooterBounds = rect{ + PanelBounds.Min, + v2{PanelBounds.Max.x, PanelBounds.Min.y + 25}, + }; + rect PanelViewBounds = rect{ + v2{PanelBounds.Min.x, FooterBounds.Max.y}, + PanelBounds.Max, }; panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex]; + Definition.Render(*Panel, PanelViewBounds, RenderBuffer, State, Context, Mouse); - - Definition.Render(*Panel, PanelBounds, RenderBuffer, State, Context, Mouse); - - PushRenderOrthographic(RenderBuffer, WindowMin.x, WindowMin.y, WindowMax.x, WindowMax.y); - DrawPanelFooter(Panel, RenderBuffer, FooterMin, FooterMax, State->Interface, Mouse); + PushRenderOrthographic(RenderBuffer, WindowBounds.Min.x, WindowBounds.Min.y, WindowBounds.Max.x, WindowBounds.Max.y); + DrawPanelFooter(Panel, RenderBuffer, FooterBounds, State->Interface, Mouse); } internal v4 @@ -287,8 +287,8 @@ INITIALIZE_APPLICATION(InitializeApplication) } // End Animation Playground - InitializePanelLayout(&State->PanelLayout); - panel* Panel = TakeNewPanel(&State->PanelLayout); + InitializePanelSystem(&State->PanelSystem); + panel* Panel = TakeNewPanel(&State->PanelSystem); SetPanelDefinition(Panel, 0); } @@ -304,7 +304,7 @@ HandleInput (app_state* State, rect WindowBounds, input_queue InputQueue, mouse_ } else { - panel_and_bounds PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, &State->PanelLayout, WindowBounds); + panel_and_bounds PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, WindowBounds); if (!PanelWithMouseOverIt.Panel) { return; } panel_definition PanelDefinition = GlobalPanelDefs[PanelWithMouseOverIt.Panel->PanelDefinitionIndex]; @@ -394,6 +394,152 @@ CreateDMXBuffers(assembly Assembly, s32 BufferHeaderSize, memory_arena* Arena) return Result; } +#define PANEL_EDGE_CLICK_MAX_DISTANCE 6 + +internal void +HandleMousePanelInteractionOrRecurse(panel* Panel, rect PanelBounds, panel_system* PanelLayout, mouse_state Mouse) +{ + // TODO(Peter): Need a way to calculate this button's position more systemically + if (Panel->SplitDirection == PanelSplit_NoSplit + && PointIsInRange(Mouse.DownPos, PanelBounds.Min, PanelBounds.Min + v2{25, 25})) + { + r32 XDistance = GSAbs(Mouse.Pos.x - Mouse.DownPos.x); + r32 YDistance = GSAbs(Mouse.Pos.y - Mouse.DownPos.y); + + if (XDistance > YDistance) + { + r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / Width(PanelBounds); + SplitPanelVertically(Panel, XPercent, PanelBounds, PanelLayout); + } + else + { + r32 YPercent = (Mouse.Pos.y - PanelBounds.Min.y) / Height(PanelBounds); + SplitPanelHorizontally(Panel, YPercent, PanelBounds, PanelLayout); + } + } + else if (Panel->SplitDirection == PanelSplit_Horizontal) + { + r32 SplitY = GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, Panel->SplitPercent); + r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.y - SplitY); + if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + r32 NewSplitY = Mouse.Pos.y; + if (NewSplitY <= PanelBounds.Min.y) + { + ConsolidatePanelsKeepOne(Panel, Panel->Top, PanelLayout); + } + else if (NewSplitY >= PanelBounds.Max.y) + { + ConsolidatePanelsKeepOne(Panel, Panel->Bottom, PanelLayout); + } + else + { + Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Height(PanelBounds); + } + } + else + { + rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); + rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); + HandleMousePanelInteractionOrRecurse(&Panel->Bottom->Panel, BottomPanelBounds, PanelLayout, Mouse); + HandleMousePanelInteractionOrRecurse(&Panel->Top->Panel, TopPanelBounds, PanelLayout, Mouse); + } + } + else if (Panel->SplitDirection == PanelSplit_Vertical) + { + r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, Panel->SplitPercent); + r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.x - SplitX); + if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + r32 NewSplitX = Mouse.Pos.x; + if (NewSplitX <= PanelBounds.Min.x) + { + ConsolidatePanelsKeepOne(Panel, Panel->Right, PanelLayout); + } + else if (NewSplitX >= PanelBounds.Max.x) + { + ConsolidatePanelsKeepOne(Panel, Panel->Left, PanelLayout); + } + else + { + Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Width(PanelBounds); + } + } + else + { + rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); + rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); + HandleMousePanelInteractionOrRecurse(&Panel->Left->Panel, LeftPanelBounds, PanelLayout, Mouse); + HandleMousePanelInteractionOrRecurse(&Panel->Right->Panel, RightPanelBounds, PanelLayout, Mouse); + } + } +} + +internal void +HandleMousePanelInteraction(panel_system* PanelSystem, rect WindowBounds,mouse_state Mouse) +{ + if (MouseButtonTransitionedUp(Mouse.LeftButtonState)) + { + Assert(PanelSystem->PanelsUsed > 0); + panel* FirstPanel = &PanelSystem->Panels[0].Panel; + HandleMousePanelInteractionOrRecurse(FirstPanel, WindowBounds, PanelSystem, Mouse); + } +} + +internal void +DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state Mouse, render_command_buffer* RenderBuffer) +{ + r32 MouseLeftEdgeDistance = GSAbs(Mouse.Pos.x - PanelMin.x); + r32 MouseRightEdgeDistance = GSAbs(Mouse.Pos.x - PanelMax.x); + r32 MouseTopEdgeDistance = GSAbs(Mouse.Pos.y - PanelMax.y); + r32 MouseBottomEdgeDistance = GSAbs(Mouse.Pos.y - PanelMin.y); + + PushRenderBoundingBox2D(RenderBuffer, PanelMin, PanelMax, 1, Color); + v4 HighlightColor = v4{.3f, .3f, .3f, 1.f}; + r32 HighlightThickness = 1; + if (MouseLeftEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + v2 LeftEdgeMin = PanelMin; + v2 LeftEdgeMax = v2{PanelMin.x + HighlightThickness, PanelMax.y}; + PushRenderQuad2D(RenderBuffer, LeftEdgeMin, LeftEdgeMax, HighlightColor); + } + else if (MouseRightEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + v2 RightEdgeMin = v2{PanelMax.x - HighlightThickness, PanelMin.y}; + v2 RightEdgeMax = PanelMax; + PushRenderQuad2D(RenderBuffer, RightEdgeMin, RightEdgeMax, HighlightColor); + } + else if (MouseTopEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + v2 TopEdgeMin = v2{PanelMin.x, PanelMax.y - HighlightThickness}; + v2 TopEdgeMax = PanelMax; + PushRenderQuad2D(RenderBuffer, TopEdgeMin, TopEdgeMax, HighlightColor); + } + else if (MouseBottomEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + v2 BottomEdgeMin = PanelMin; + v2 BottomEdgeMax = v2{PanelMax.x, PanelMin.y + HighlightThickness}; + PushRenderQuad2D(RenderBuffer, BottomEdgeMin, BottomEdgeMax, HighlightColor); + } +} + +internal void +DrawAllPanels(panel_layout PanelLayout, render_command_buffer* RenderBuffer, mouse_state Mouse, app_state* State, context Context) +{ + for (u32 i = 0; i < PanelLayout.PanelsCount; i++) + { + panel_with_layout PanelWithLayout = PanelLayout.Panels[i]; + panel* Panel = PanelWithLayout.Panel; + rect PanelBounds = PanelWithLayout.Bounds; + + RenderPanel(Panel, PanelBounds, State->WindowBounds, RenderBuffer, State, Context, Mouse); + v4 BorderColor = v4{0, 0, 0, 1}; + + PushRenderOrthographic(RenderBuffer, State->WindowBounds.Min.x, State->WindowBounds.Min.y, State->WindowBounds.Max.x, State->WindowBounds.Max.y); + DrawPanelBorder(*Panel, PanelBounds.Min, PanelBounds.Max, BorderColor, Mouse, RenderBuffer); + } +} + UPDATE_AND_RENDER(UpdateAndRender) { DEBUG_TRACK_FUNCTION; @@ -444,11 +590,6 @@ UPDATE_AND_RENDER(UpdateAndRender) s32 HeaderSize = State->NetworkProtocolHeaderSize; dmx_buffer_list* DMXBuffers = 0; - if (State->ActiveAssemblyIndecies.Used > 1) - { - s32 f = 4; - } - for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) { array_entry_handle* AssemblyHandle = GetElementAtIndex(i, State->ActiveAssemblyIndecies); @@ -490,9 +631,11 @@ UPDATE_AND_RENDER(UpdateAndRender) PushRenderOrthographic(RenderBuffer, 0, 0, Width(State->WindowBounds), Height(State->WindowBounds)); PushRenderClearScreen(RenderBuffer); - HandleMousePanelInteraction(&State->PanelLayout, State->WindowBounds, Mouse); - DrawAllPanels(&State->PanelLayout, State->WindowBounds, RenderBuffer, State->Interface, Mouse, State, Context); + HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse); + + panel_layout PanelsToRender = GetPanelLayout(&State->PanelSystem, State->WindowBounds, &State->Transient); + DrawAllPanels(PanelsToRender, RenderBuffer, Mouse, State, Context); for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) { diff --git a/src/foldhaus_app.h b/src/foldhaus_app.h index fe8f9e2..f93d7ea 100644 --- a/src/foldhaus_app.h +++ b/src/foldhaus_app.h @@ -14,13 +14,13 @@ #include "assembly_parser.cpp" #include "test_patterns.h" -typedef struct app_state app_state; - // TODO(Peter): something we can do later is to remove all reliance on app_state and context // from foldhaus_pane.h. It should just emit lists of things that the app can iterate over and // perform operations on, like panel_draw_requests = { bounds, panel* } etc. #include "foldhaus_panel.h" +typedef struct app_state app_state; + #include "foldhaus_command_dispatch.h" #include "foldhaus_operation_mode.h" @@ -66,7 +66,7 @@ struct app_state animation_system AnimationSystem; animation_block_handle SelectedAnimationBlockHandle; - panel_layout PanelLayout; + panel_system PanelSystem; }; internal void OpenColorPicker(app_state* State, v4* Address); diff --git a/src/foldhaus_panel.h b/src/foldhaus_panel.h index f6a9ea0..65153b9 100644 --- a/src/foldhaus_panel.h +++ b/src/foldhaus_panel.h @@ -6,7 +6,7 @@ Creation Date: 2019-12-26 Usage: Include this file in ONE file in your project. -Define both RenderPanel and SetPanelDefinitionExternal +Define SetPanelDefinitionExternal */ @@ -56,7 +56,7 @@ struct panel_entry }; #define PANELS_MAX 16 -struct panel_layout +struct panel_system { panel_entry Panels[PANELS_MAX]; u32 PanelsUsed; @@ -64,9 +64,23 @@ struct panel_layout panel_entry FreeList; }; -internal void SetPanelDefinitionExternal(panel* Panel, s32 OldPanelDefinitionIndex, s32 NewPanelDefinitionIndex); -internal void RenderPanel(panel* Panel, v2 PanelMin, v2 PanelMax, v2 WindowMin, v2 WindowMax, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse); +// NOTE(Peter): This representation is used to let external code render and interact +// with panels. It shouldn't be stored across frame boundaries as the pointers to +// Panel's are liable to change. +struct panel_with_layout +{ + panel* Panel; + rect Bounds; +}; +struct panel_layout +{ + panel_with_layout* Panels; + u32 PanelsCount; + u32 PanelsMax; +}; + +internal void SetPanelDefinitionExternal(panel* Panel, s32 OldPanelDefinitionIndex, s32 NewPanelDefinitionIndex); ///////////////////////////////// // @@ -75,33 +89,33 @@ internal void RenderPanel(panel* Panel, v2 PanelMin, v2 PanelMax, v2 WindowMin, ///////////////////////////////// internal void -InitializePanelLayout(panel_layout* Layout) +InitializePanelSystem(panel_system* PanelSystem) { - Layout->FreeList.Free.Next = &Layout->FreeList; + PanelSystem->FreeList.Free.Next = &PanelSystem->FreeList; } internal panel_entry* -TakeNewPanelEntry(panel_layout* Layout) +TakeNewPanelEntry(panel_system* PanelSystem) { panel_entry* FreeEntry = 0; - if (Layout->FreeList.Free.Next != &Layout->FreeList) + if (PanelSystem->FreeList.Free.Next != &PanelSystem->FreeList) { - FreeEntry = Layout->FreeList.Free.Next; - Layout->FreeList.Free.Next = FreeEntry->Free.Next; + FreeEntry = PanelSystem->FreeList.Free.Next; + PanelSystem->FreeList.Free.Next = FreeEntry->Free.Next; } else { - Assert(Layout->PanelsUsed < PANELS_MAX); - FreeEntry = Layout->Panels + Layout->PanelsUsed++; + Assert(PanelSystem->PanelsUsed < PANELS_MAX); + FreeEntry = PanelSystem->Panels + PanelSystem->PanelsUsed++; } return FreeEntry; } internal panel* -TakeNewPanel(panel_layout* Layout) +TakeNewPanel(panel_system* PanelSystem) { panel* Result = 0; - panel_entry* FreeEntry = TakeNewPanelEntry(Layout); + panel_entry* FreeEntry = TakeNewPanelEntry(PanelSystem); Result = &FreeEntry->Panel; *Result = {0}; @@ -111,25 +125,25 @@ TakeNewPanel(panel_layout* Layout) } internal void -FreePanelEntry(panel_entry* Entry, panel_layout* Layout) +FreePanelEntry(panel_entry* Entry, panel_system* PanelSystem) { - Assert(Entry >= Layout->Panels && Entry <= Layout->Panels + PANELS_MAX); + Assert(Entry >= PanelSystem->Panels && Entry <= PanelSystem->Panels + PANELS_MAX); Entry->Panel = {0}; - Entry->Free.Next = Layout->FreeList.Free.Next; - Layout->FreeList.Free.Next = Entry; + Entry->Free.Next = PanelSystem->FreeList.Free.Next; + PanelSystem->FreeList.Free.Next = Entry; } internal void -FreePanelAtIndex(s32 Index, panel_layout* Layout) +FreePanelAtIndex(s32 Index, panel_system* PanelSystem) { - Assert(Index > 0 && Index < (s32)Layout->PanelsUsed); - panel_entry* EntryToFree = Layout->Panels + Index; - EntryToFree->Free.Next = Layout->FreeList.Free.Next; - Layout->FreeList.Free.Next = EntryToFree; + Assert(Index > 0 && Index < (s32)PanelSystem->PanelsUsed); + panel_entry* EntryToFree = PanelSystem->Panels + Index; + EntryToFree->Free.Next = PanelSystem->FreeList.Free.Next; + PanelSystem->FreeList.Free.Next = EntryToFree; } internal void -SplitPanelVertically(panel* Parent, r32 Percent, rect ParentBounds, panel_layout* Layout) +SplitPanelVertically(panel* Parent, r32 Percent, rect ParentBounds, panel_system* PanelSystem) { r32 SplitX = GSLerp(ParentBounds.Min.x, ParentBounds.Max.x, Percent); if (SplitX > ParentBounds.Min.x && SplitX < ParentBounds.Max.x) @@ -137,16 +151,16 @@ SplitPanelVertically(panel* Parent, r32 Percent, rect ParentBounds, panel_layout Parent->SplitDirection = PanelSplit_Vertical; Parent->SplitPercent = Percent; - Parent->Left = TakeNewPanelEntry(Layout); + Parent->Left = TakeNewPanelEntry(PanelSystem); Parent->Left->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex; - Parent->Right = TakeNewPanelEntry(Layout); + Parent->Right = TakeNewPanelEntry(PanelSystem); Parent->Right->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex; } } internal void -SplitPanelHorizontally(panel* Parent, r32 Percent, rect ParentBounds, panel_layout* Layout) +SplitPanelHorizontally(panel* Parent, r32 Percent, rect ParentBounds, panel_system* PanelSystem) { r32 SplitY = GSLerp(ParentBounds.Min.y, ParentBounds.Max.y, Percent); if (SplitY > ParentBounds.Min.y && SplitY < ParentBounds.Max.y) @@ -154,16 +168,16 @@ SplitPanelHorizontally(panel* Parent, r32 Percent, rect ParentBounds, panel_layo Parent->SplitDirection = PanelSplit_Horizontal; Parent->SplitPercent = Percent; - Parent->Bottom = TakeNewPanelEntry(Layout); + Parent->Bottom = TakeNewPanelEntry(PanelSystem); Parent->Bottom->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex; - Parent->Top = TakeNewPanelEntry(Layout); + Parent->Top = TakeNewPanelEntry(PanelSystem); Parent->Top->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex; } } internal void -ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_layout* Layout) +ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_system* PanelSystem) { panel_entry* LeftChild = Parent->Left; panel_entry* RightChild = Parent->Right; @@ -171,8 +185,8 @@ ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_lay *Parent = PanelEntryToKeep->Panel; Parent->SplitDirection = PanelSplit_NoSplit; - FreePanelEntry(LeftChild, Layout); - FreePanelEntry(RightChild, Layout); + FreePanelEntry(LeftChild, PanelSystem); + FreePanelEntry(RightChild, PanelSystem); } internal void @@ -237,6 +251,43 @@ GetLeftPanelBounds(panel* Panel, rect PanelBounds) return Result; } +internal void +LayoutPanel(panel* Panel, rect PanelBounds, panel_layout* Layout) +{ + if (Panel->SplitDirection == PanelSplit_NoSplit) + { + panel_with_layout* WithLayout = Layout->Panels + Layout->PanelsCount++; + WithLayout->Panel = Panel; + WithLayout->Bounds = PanelBounds; + } + else if (Panel->SplitDirection == PanelSplit_Horizontal) + { + rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); + rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); + LayoutPanel(&Panel->Top->Panel, TopPanelBounds, Layout); + LayoutPanel(&Panel->Bottom->Panel, BottomPanelBounds, Layout); + } + else if (Panel->SplitDirection == PanelSplit_Vertical) + { + rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); + rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); + LayoutPanel(&Panel->Left->Panel, LeftPanelBounds, Layout); + LayoutPanel(&Panel->Right->Panel, RightPanelBounds, Layout); + } +} + +internal panel_layout +GetPanelLayout(panel_system* System, rect WindowBounds, memory_arena* Storage) +{ + panel_layout Result = {}; + Result.PanelsMax = System->PanelsUsed; + Result.Panels = PushArray(Storage, panel_with_layout, Result.PanelsMax); + + LayoutPanel(&System->Panels[0].Panel, WindowBounds, &Result); + + return Result; +} + struct panel_and_bounds { panel* Panel; @@ -286,156 +337,12 @@ GetPanelContainingPoint(v2 Point, panel* Panel, rect PanelBounds) } internal panel_and_bounds -GetPanelContainingPoint(v2 Point, panel_layout* Layout, rect WindowBounds) +GetPanelContainingPoint(v2 Point, panel_system* PanelSystem, rect WindowBounds) { panel_and_bounds Result = {0}; - if (Layout->PanelsUsed > 0) + if (PanelSystem->PanelsUsed > 0) { - Result = GetPanelContainingPoint(Point, &Layout->Panels[0].Panel, WindowBounds); + Result = GetPanelContainingPoint(Point, &PanelSystem->Panels[0].Panel, WindowBounds); } return Result; } - -internal void -HandleMousePanelInteractionOrRecurse(panel* Panel, rect PanelBounds, panel_layout* PanelLayout, mouse_state Mouse) -{ - r32 PanelEdgeClickMaxDistance = 4; - - // TODO(Peter): Need a way to calculate this button's position more systemically - if (Panel->SplitDirection == PanelSplit_NoSplit - && PointIsInRange(Mouse.DownPos, PanelBounds.Min, PanelBounds.Min + v2{25, 25})) - { - r32 XDistance = GSAbs(Mouse.Pos.x - Mouse.DownPos.x); - r32 YDistance = GSAbs(Mouse.Pos.y - Mouse.DownPos.y); - - if (XDistance > YDistance) - { - r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / Width(PanelBounds); - SplitPanelVertically(Panel, XPercent, PanelBounds, PanelLayout); - } - else - { - r32 YPercent = (Mouse.Pos.y - PanelBounds.Min.y) / Height(PanelBounds); - SplitPanelHorizontally(Panel, YPercent, PanelBounds, PanelLayout); - } - } - else if (Panel->SplitDirection == PanelSplit_Horizontal) - { - r32 SplitY = GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, Panel->SplitPercent); - r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.y - SplitY); - if (ClickDistanceFromSplit < PanelEdgeClickMaxDistance) - { - r32 NewSplitY = Mouse.Pos.y; - if (NewSplitY <= PanelBounds.Min.y) - { - ConsolidatePanelsKeepOne(Panel, Panel->Top, PanelLayout); - } - else if (NewSplitY >= PanelBounds.Max.y) - { - ConsolidatePanelsKeepOne(Panel, Panel->Bottom, PanelLayout); - } - else - { - Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Height(PanelBounds); - } - } - else - { - rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); - rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); - HandleMousePanelInteractionOrRecurse(&Panel->Bottom->Panel, BottomPanelBounds, PanelLayout, Mouse); - HandleMousePanelInteractionOrRecurse(&Panel->Top->Panel, TopPanelBounds, PanelLayout, Mouse); - } - } - else if (Panel->SplitDirection == PanelSplit_Vertical) - { - r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, Panel->SplitPercent); - r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.x - SplitX); - if (ClickDistanceFromSplit < PanelEdgeClickMaxDistance) - { - r32 NewSplitX = Mouse.Pos.x; - if (NewSplitX <= PanelBounds.Min.x) - { - ConsolidatePanelsKeepOne(Panel, Panel->Right, PanelLayout); - } - else if (NewSplitX >= PanelBounds.Max.x) - { - ConsolidatePanelsKeepOne(Panel, Panel->Left, PanelLayout); - } - else - { - Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Width(PanelBounds); - } - } - else - { - rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); - rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); - HandleMousePanelInteractionOrRecurse(&Panel->Left->Panel, LeftPanelBounds, PanelLayout, Mouse); - HandleMousePanelInteractionOrRecurse(&Panel->Right->Panel, RightPanelBounds, PanelLayout, Mouse); - } - } -} - -internal void -HandleMousePanelInteraction(panel_layout* PanelLayout, rect WindowBounds, mouse_state Mouse) -{ - r32 PanelEdgeClickMaxDistance = 4; - - if (MouseButtonTransitionedUp(Mouse.LeftButtonState)) - { - Assert(PanelLayout->PanelsUsed > 0); - panel* FirstPanel = &PanelLayout->Panels[0].Panel; - HandleMousePanelInteractionOrRecurse(FirstPanel, WindowBounds, PanelLayout, Mouse); - } -} - -internal void -DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, render_command_buffer* RenderBuffer) -{ - PushRenderBoundingBox2D(RenderBuffer, PanelMin, PanelMax, 1, Color); -} - -internal void -DrawPanelOrRecurse(panel* Panel, rect PanelBounds, rect WindowRect, render_command_buffer* RenderBuffer, interface_config Interface, mouse_state Mouse, app_state* State, context Context) -{ - if (Panel->SplitDirection == PanelSplit_NoSplit) - { - RenderPanel(Panel, PanelBounds.Min, PanelBounds.Max, WindowRect.Min, WindowRect.Max, RenderBuffer, State, Context, Mouse); - v4 BorderColor = v4{0, 0, 0, 1}; - -#if 0 - if (PointIsInRange(Mouse.Pos, PanelMin, PanelMax)) - { - BorderColor = v4{1, 0, 1, 1}; - } -#endif - - PushRenderOrthographic(RenderBuffer, WindowRect.Min.x, WindowRect.Min.y, WindowRect.Max.x, WindowRect.Max.y); - DrawPanelBorder(*Panel, PanelBounds.Min, PanelBounds.Max, BorderColor, RenderBuffer); - } - else if (Panel->SplitDirection == PanelSplit_Horizontal) - { - rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); - rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); - - DrawPanelOrRecurse(&Panel->Bottom->Panel, BottomPanelBounds, WindowRect, RenderBuffer, Interface, Mouse, State, Context); - DrawPanelOrRecurse(&Panel->Top->Panel, TopPanelBounds, WindowRect, RenderBuffer, Interface, Mouse, State, Context); - } - else if (Panel->SplitDirection == PanelSplit_Vertical) - { - rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); - rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); - - DrawPanelOrRecurse(&Panel->Left->Panel, LeftPanelBounds, WindowRect, RenderBuffer, Interface, Mouse, State, Context); - DrawPanelOrRecurse(&Panel->Right->Panel, RightPanelBounds, WindowRect, RenderBuffer, Interface, Mouse, State, Context); - } -} - -internal void -DrawAllPanels(panel_layout* PanelLayout, rect WindowBounds, render_command_buffer* RenderBuffer, interface_config Interface, mouse_state Mouse, app_state* State, context Context) -{ - Assert(PanelLayout->PanelsUsed > 0); - panel* FirstPanel = &PanelLayout->Panels[0].Panel; - DrawPanelOrRecurse(FirstPanel, WindowBounds, WindowBounds, RenderBuffer, Interface, Mouse, State, Context); -} diff --git a/src/panels/foldhaus_panel_animation_timeline.h b/src/panels/foldhaus_panel_animation_timeline.h index 4c6bbc4..9faa0de 100644 --- a/src/panels/foldhaus_panel_animation_timeline.h +++ b/src/panels/foldhaus_panel_animation_timeline.h @@ -78,7 +78,7 @@ OPERATION_RENDER_PROC(UpdateDragAnimationClip) { drag_animation_clip_state* OpState = (drag_animation_clip_state*)Operation.OpStateMemory; - panel_and_bounds AnimationPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelLayout, State->WindowBounds); + panel_and_bounds AnimationPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds); Assert(AnimationPanel.Panel); s32 ClipInitialStartTimeXPosition = GetXPositionFromTimeInAnimationPanel(OpState->SelectedClip_InitialStartTime, AnimationPanel.Bounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame, State->AnimationSystem.SecondsPerFrame); @@ -136,7 +136,7 @@ SelectAndBeginDragAnimationBlock(animation_block_handle BlockHandle, s32 PanelSt FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand) { - panel_and_bounds ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelLayout, State->WindowBounds); + panel_and_bounds ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, State->WindowBounds); r32 MouseDownPositionPercent = (Mouse.Pos.x - ActivePanel.Bounds.Min.x) / Width(ActivePanel.Bounds); r32 NewBlockTimeStart = MouseDownPositionPercent * State->AnimationSystem.AnimationEnd; #define NEW_BLOCK_DURATION 1