Removed all reliance on external factors from the foldhaus_panel.h system

This commit is contained in:
Peter Slattery 2019-12-28 13:02:19 -08:00
parent 27ae65fb0c
commit 90b908ff98
4 changed files with 260 additions and 210 deletions

View File

@ -13,18 +13,18 @@ SetPanelDefinitionExternal(panel* Panel, s32 OldPanelDefinitionIndex, s32 NewPan
internal void 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, FooterBounds.Min, v2{FooterBounds.Max.x, FooterBounds.Min.y + 25}, v4{.5f, .5f, .5f, 1.f});
PushRenderQuad2D(RenderBuffer, FooterMin, FooterMin + v2{25, 25}, WhiteV4); 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}; v2 PanelSelectButtonMax = PanelSelectButtonMin + v2{100, 23};
if (Panel->PanelSelectionMenuOpen) if (Panel->PanelSelectionMenuOpen)
{ {
v2 ButtonDimension = v2{100, 25}; v2 ButtonDimension = v2{100, 25};
v2 ButtonMin = v2{PanelSelectButtonMin.x, FooterMax.y}; v2 ButtonMin = v2{PanelSelectButtonMin.x, FooterBounds.Max.y};
v2 MenuMin = ButtonMin; v2 MenuMin = ButtonMin;
v2 MenuMax = v2{ButtonMin.x + ButtonDimension.x, ButtonMin.y + (ButtonDimension.y * GlobalPanelDefsCount)}; 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 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); Assert(Panel->PanelDefinitionIndex >= 0);
v2 FooterMin = PanelMin; rect FooterBounds = rect{
v2 FooterMax = v2{PanelMax.x, PanelMin.y + 25}; PanelBounds.Min,
rect PanelBounds = rect{ v2{PanelBounds.Max.x, PanelBounds.Min.y + 25},
v2{PanelMin.x, FooterMax.y}, };
PanelMax, rect PanelViewBounds = rect{
v2{PanelBounds.Min.x, FooterBounds.Max.y},
PanelBounds.Max,
}; };
panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex]; panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex];
Definition.Render(*Panel, PanelViewBounds, RenderBuffer, State, Context, Mouse);
PushRenderOrthographic(RenderBuffer, WindowBounds.Min.x, WindowBounds.Min.y, WindowBounds.Max.x, WindowBounds.Max.y);
Definition.Render(*Panel, PanelBounds, RenderBuffer, State, Context, Mouse); DrawPanelFooter(Panel, RenderBuffer, FooterBounds, State->Interface, Mouse);
PushRenderOrthographic(RenderBuffer, WindowMin.x, WindowMin.y, WindowMax.x, WindowMax.y);
DrawPanelFooter(Panel, RenderBuffer, FooterMin, FooterMax, State->Interface, Mouse);
} }
internal v4 internal v4
@ -287,8 +287,8 @@ INITIALIZE_APPLICATION(InitializeApplication)
} // End Animation Playground } // End Animation Playground
InitializePanelLayout(&State->PanelLayout); InitializePanelSystem(&State->PanelSystem);
panel* Panel = TakeNewPanel(&State->PanelLayout); panel* Panel = TakeNewPanel(&State->PanelSystem);
SetPanelDefinition(Panel, 0); SetPanelDefinition(Panel, 0);
} }
@ -304,7 +304,7 @@ HandleInput (app_state* State, rect WindowBounds, input_queue InputQueue, mouse_
} }
else 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; } if (!PanelWithMouseOverIt.Panel) { return; }
panel_definition PanelDefinition = GlobalPanelDefs[PanelWithMouseOverIt.Panel->PanelDefinitionIndex]; panel_definition PanelDefinition = GlobalPanelDefs[PanelWithMouseOverIt.Panel->PanelDefinitionIndex];
@ -394,6 +394,152 @@ CreateDMXBuffers(assembly Assembly, s32 BufferHeaderSize, memory_arena* Arena)
return Result; 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) UPDATE_AND_RENDER(UpdateAndRender)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
@ -444,11 +590,6 @@ UPDATE_AND_RENDER(UpdateAndRender)
s32 HeaderSize = State->NetworkProtocolHeaderSize; s32 HeaderSize = State->NetworkProtocolHeaderSize;
dmx_buffer_list* DMXBuffers = 0; dmx_buffer_list* DMXBuffers = 0;
if (State->ActiveAssemblyIndecies.Used > 1)
{
s32 f = 4;
}
for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++)
{ {
array_entry_handle* AssemblyHandle = GetElementAtIndex(i, State->ActiveAssemblyIndecies); 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)); PushRenderOrthographic(RenderBuffer, 0, 0, Width(State->WindowBounds), Height(State->WindowBounds));
PushRenderClearScreen(RenderBuffer); 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++) for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
{ {

View File

@ -14,13 +14,13 @@
#include "assembly_parser.cpp" #include "assembly_parser.cpp"
#include "test_patterns.h" #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 // 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 // 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. // perform operations on, like panel_draw_requests = { bounds, panel* } etc.
#include "foldhaus_panel.h" #include "foldhaus_panel.h"
typedef struct app_state app_state;
#include "foldhaus_command_dispatch.h" #include "foldhaus_command_dispatch.h"
#include "foldhaus_operation_mode.h" #include "foldhaus_operation_mode.h"
@ -66,7 +66,7 @@ struct app_state
animation_system AnimationSystem; animation_system AnimationSystem;
animation_block_handle SelectedAnimationBlockHandle; animation_block_handle SelectedAnimationBlockHandle;
panel_layout PanelLayout; panel_system PanelSystem;
}; };
internal void OpenColorPicker(app_state* State, v4* Address); internal void OpenColorPicker(app_state* State, v4* Address);

View File

@ -6,7 +6,7 @@ Creation Date: 2019-12-26
Usage: Usage:
Include this file in ONE file in your project. 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 #define PANELS_MAX 16
struct panel_layout struct panel_system
{ {
panel_entry Panels[PANELS_MAX]; panel_entry Panels[PANELS_MAX];
u32 PanelsUsed; u32 PanelsUsed;
@ -64,9 +64,23 @@ struct panel_layout
panel_entry FreeList; panel_entry FreeList;
}; };
internal void SetPanelDefinitionExternal(panel* Panel, s32 OldPanelDefinitionIndex, s32 NewPanelDefinitionIndex); // NOTE(Peter): This representation is used to let external code render and interact
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); // 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 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* internal panel_entry*
TakeNewPanelEntry(panel_layout* Layout) TakeNewPanelEntry(panel_system* PanelSystem)
{ {
panel_entry* FreeEntry = 0; panel_entry* FreeEntry = 0;
if (Layout->FreeList.Free.Next != &Layout->FreeList) if (PanelSystem->FreeList.Free.Next != &PanelSystem->FreeList)
{ {
FreeEntry = Layout->FreeList.Free.Next; FreeEntry = PanelSystem->FreeList.Free.Next;
Layout->FreeList.Free.Next = FreeEntry->Free.Next; PanelSystem->FreeList.Free.Next = FreeEntry->Free.Next;
} }
else else
{ {
Assert(Layout->PanelsUsed < PANELS_MAX); Assert(PanelSystem->PanelsUsed < PANELS_MAX);
FreeEntry = Layout->Panels + Layout->PanelsUsed++; FreeEntry = PanelSystem->Panels + PanelSystem->PanelsUsed++;
} }
return FreeEntry; return FreeEntry;
} }
internal panel* internal panel*
TakeNewPanel(panel_layout* Layout) TakeNewPanel(panel_system* PanelSystem)
{ {
panel* Result = 0; panel* Result = 0;
panel_entry* FreeEntry = TakeNewPanelEntry(Layout); panel_entry* FreeEntry = TakeNewPanelEntry(PanelSystem);
Result = &FreeEntry->Panel; Result = &FreeEntry->Panel;
*Result = {0}; *Result = {0};
@ -111,25 +125,25 @@ TakeNewPanel(panel_layout* Layout)
} }
internal void 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->Panel = {0};
Entry->Free.Next = Layout->FreeList.Free.Next; Entry->Free.Next = PanelSystem->FreeList.Free.Next;
Layout->FreeList.Free.Next = Entry; PanelSystem->FreeList.Free.Next = Entry;
} }
internal void internal void
FreePanelAtIndex(s32 Index, panel_layout* Layout) FreePanelAtIndex(s32 Index, panel_system* PanelSystem)
{ {
Assert(Index > 0 && Index < (s32)Layout->PanelsUsed); Assert(Index > 0 && Index < (s32)PanelSystem->PanelsUsed);
panel_entry* EntryToFree = Layout->Panels + Index; panel_entry* EntryToFree = PanelSystem->Panels + Index;
EntryToFree->Free.Next = Layout->FreeList.Free.Next; EntryToFree->Free.Next = PanelSystem->FreeList.Free.Next;
Layout->FreeList.Free.Next = EntryToFree; PanelSystem->FreeList.Free.Next = EntryToFree;
} }
internal void 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); r32 SplitX = GSLerp(ParentBounds.Min.x, ParentBounds.Max.x, Percent);
if (SplitX > ParentBounds.Min.x && SplitX < ParentBounds.Max.x) 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->SplitDirection = PanelSplit_Vertical;
Parent->SplitPercent = Percent; Parent->SplitPercent = Percent;
Parent->Left = TakeNewPanelEntry(Layout); Parent->Left = TakeNewPanelEntry(PanelSystem);
Parent->Left->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex; Parent->Left->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex;
Parent->Right = TakeNewPanelEntry(Layout); Parent->Right = TakeNewPanelEntry(PanelSystem);
Parent->Right->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex; Parent->Right->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex;
} }
} }
internal void 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); r32 SplitY = GSLerp(ParentBounds.Min.y, ParentBounds.Max.y, Percent);
if (SplitY > ParentBounds.Min.y && SplitY < ParentBounds.Max.y) 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->SplitDirection = PanelSplit_Horizontal;
Parent->SplitPercent = Percent; Parent->SplitPercent = Percent;
Parent->Bottom = TakeNewPanelEntry(Layout); Parent->Bottom = TakeNewPanelEntry(PanelSystem);
Parent->Bottom->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex; Parent->Bottom->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex;
Parent->Top = TakeNewPanelEntry(Layout); Parent->Top = TakeNewPanelEntry(PanelSystem);
Parent->Top->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex; Parent->Top->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex;
} }
} }
internal void 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* LeftChild = Parent->Left;
panel_entry* RightChild = Parent->Right; panel_entry* RightChild = Parent->Right;
@ -171,8 +185,8 @@ ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_lay
*Parent = PanelEntryToKeep->Panel; *Parent = PanelEntryToKeep->Panel;
Parent->SplitDirection = PanelSplit_NoSplit; Parent->SplitDirection = PanelSplit_NoSplit;
FreePanelEntry(LeftChild, Layout); FreePanelEntry(LeftChild, PanelSystem);
FreePanelEntry(RightChild, Layout); FreePanelEntry(RightChild, PanelSystem);
} }
internal void internal void
@ -237,6 +251,43 @@ GetLeftPanelBounds(panel* Panel, rect PanelBounds)
return Result; 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 struct panel_and_bounds
{ {
panel* Panel; panel* Panel;
@ -286,156 +337,12 @@ GetPanelContainingPoint(v2 Point, panel* Panel, rect PanelBounds)
} }
internal panel_and_bounds 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}; 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; 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);
}

View File

@ -78,7 +78,7 @@ OPERATION_RENDER_PROC(UpdateDragAnimationClip)
{ {
drag_animation_clip_state* OpState = (drag_animation_clip_state*)Operation.OpStateMemory; 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); Assert(AnimationPanel.Panel);
s32 ClipInitialStartTimeXPosition = GetXPositionFromTimeInAnimationPanel(OpState->SelectedClip_InitialStartTime, AnimationPanel.Bounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame, State->AnimationSystem.SecondsPerFrame); 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) 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 MouseDownPositionPercent = (Mouse.Pos.x - ActivePanel.Bounds.Min.x) / Width(ActivePanel.Bounds);
r32 NewBlockTimeStart = MouseDownPositionPercent * State->AnimationSystem.AnimationEnd; r32 NewBlockTimeStart = MouseDownPositionPercent * State->AnimationSystem.AnimationEnd;
#define NEW_BLOCK_DURATION 1 #define NEW_BLOCK_DURATION 1