refactored panel sytstem

This commit is contained in:
PS 2020-10-24 18:54:47 -07:00
parent a88d675327
commit 57f144ea64
8 changed files with 327 additions and 306 deletions

View File

@ -0,0 +1,107 @@
//
// File: foldhaus_editor.cpp
// Author: Peter Slattery
// Creation Date: 2020-10-24
//
#ifndef FOLDHAUS_EDITOR_CPP
internal void
Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue, mouse_state Mouse, context Context)
{
DEBUG_TRACK_FUNCTION;
b32 PanelSystemHandledInput = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State);
if (!PanelSystemHandledInput)
{
input_command_registry ActiveCommands = {};
if (State->Modes.ActiveModesCount > 0)
{
ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands;
}
else
{
panel* PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, State->PanelSystem.Panels + 0);
if (!PanelWithMouseOverIt) { return; }
State->HotPanel = PanelWithMouseOverIt;
s32 PanelTypeIndex = PanelWithMouseOverIt->TypeIndex;
panel_definition PanelDefinition = GlobalPanelDefs[PanelTypeIndex];
if (!PanelDefinition.InputCommands) { return; }
ActiveCommands.Commands = PanelDefinition.InputCommands;
ActiveCommands.Size = sizeof(*PanelDefinition.InputCommands) / sizeof(PanelDefinition.InputCommands[0]);
ActiveCommands.Used = ActiveCommands.Size;
}
for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++)
{
input_entry Event = InputQueue.Entries[EventIdx];
// NOTE(Peter): These are in the order Down, Up, Held because we want to privalege
// Down and Up over Held. In other words, we don't want to call a Held command on the
// frame when the button was released, even if the command is registered to both events
if (KeyTransitionedDown(Event))
{
FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue);
}
else if (KeyTransitionedUp(Event))
{
FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue);
}
else if (KeyHeldDown(Event))
{
FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue);
}
}
}
// Execute all commands in CommandQueue
for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--)
{
command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx];
Entry->Command.Proc(State, Entry->Event, Mouse, Context);
}
ClearCommandQueue(&State->CommandQueue);
}
internal void
Editor_Update(app_state* State, context* Context, input_queue InputQueue)
{
Context->Mouse.CursorType = CursorType_Arrow;
State->WindowBounds = Context->WindowBounds;
State->Interface.Mouse = Context->Mouse;
State->Camera.AspectRatio = RectAspectRatio(Context->WindowBounds);
PanelSystem_UpdateLayout(&State->PanelSystem, State->WindowBounds);
Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context);
}
internal void
Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer)
{
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
PushRenderClearScreen(RenderBuffer);
State->Interface.RenderBuffer = RenderBuffer;
DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context);
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
{
operation_mode OperationMode = State->Modes.ActiveModes[m];
if (OperationMode.Render != 0)
{
OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context);
}
}
Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext);
Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue);
}
#define FOLDHAUS_EDITOR_CPP
#endif // FOLDHAUS_EDITOR_CPP

View File

@ -13,6 +13,8 @@
enum panel_edit_mode enum panel_edit_mode
{ {
PanelEdit_Invalid,
PanelEdit_Modify, PanelEdit_Modify,
PanelEdit_Destroy, PanelEdit_Destroy,
@ -111,6 +113,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
else else
{ {
Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Rect2Height(PanelBounds); Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Rect2Height(PanelBounds);
Panel_UpdateLayout(Panel, PanelBounds);
} }
} }
else if (Panel->SplitDirection == PanelSplit_Vertical) else if (Panel->SplitDirection == PanelSplit_Vertical)
@ -127,6 +130,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
else else
{ {
Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Rect2Width(PanelBounds); Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Rect2Width(PanelBounds);
Panel_UpdateLayout(Panel, PanelBounds);
} }
} }
} }
@ -239,9 +243,9 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndSplitPanelOperation)
s32 PanelTypeIndex = Panel->TypeIndex; s32 PanelTypeIndex = Panel->TypeIndex;
gs_data PanelStateMemory = Panel->StateMemory; gs_data PanelStateMemory = Panel->StateMemory;
Panel_SetCurrentType(&Panel->Left->Panel, &State->PanelSystem, PanelTypeIndex, PanelStateMemory, State, Context); Panel_SetCurrentType(Panel->Left, &State->PanelSystem, PanelTypeIndex, PanelStateMemory, State, Context);
SetAndInitPanelType(&Panel->Right->Panel, &State->PanelSystem, PanelTypeIndex, State, Context); SetAndInitPanelType(Panel->Right, &State->PanelSystem, PanelTypeIndex, State, Context);
DeactivateCurrentOperationMode(&State->Modes); DeactivateCurrentOperationMode(&State->Modes);
} }
@ -251,12 +255,12 @@ input_command SplitPanelCommands[] = {
}; };
internal void internal void
BeginSplitPanelOperation(panel* Panel, rect2 PanelBounds, mouse_state Mouse, app_state* State) BeginSplitPanelOperation(panel* Panel, mouse_state Mouse, app_state* State)
{ {
operation_mode* SplitPanel = ActivateOperationModeWithCommands(&State->Modes, SplitPanelCommands, UpdateAndRenderSplitPanel); operation_mode* SplitPanel = ActivateOperationModeWithCommands(&State->Modes, SplitPanelCommands, UpdateAndRenderSplitPanel);
split_panel_operation_state* OpState = CreateOperationState(SplitPanel, &State->Modes, split_panel_operation_state); split_panel_operation_state* OpState = CreateOperationState(SplitPanel, &State->Modes, split_panel_operation_state);
OpState->Panel = Panel; OpState->Panel = Panel;
OpState->InitialPanelBounds = PanelBounds; OpState->InitialPanelBounds = Panel->Bounds;
} }
@ -265,61 +269,44 @@ BeginSplitPanelOperation(panel* Panel, rect2 PanelBounds, mouse_state Mouse, app
#define PANEL_EDGE_CLICK_MAX_DISTANCE 6 #define PANEL_EDGE_CLICK_MAX_DISTANCE 6
internal b32 internal b32
HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEditMode, rect2 PanelBounds, mouse_state Mouse, app_state* State) HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEditMode, mouse_state Mouse, app_state* State)
{ {
b32 HandledMouseInput = false; b32 HandledMouseInput = false;
rect2 PanelSplitButtonBounds = rect2{ PanelBounds.Min, PanelBounds.Min + v2{25, 25} }; // TODO(pjs): this can probably live in panel_with_layout
rect2 PanelSplitButtonBounds = rect2{ Panel->Bounds.Min, Panel->Bounds.Min + v2{25, 25} };
if (Panel->SplitDirection == PanelSplit_NoSplit if (Panel->SplitDirection == PanelSplit_NoSplit
&& PointIsInRect(PanelSplitButtonBounds, Mouse.DownPos)) && PointIsInRect(PanelSplitButtonBounds, Mouse.DownPos))
{ {
BeginSplitPanelOperation(Panel, PanelBounds, Mouse, State); BeginSplitPanelOperation(Panel, Mouse, State);
HandledMouseInput = true; HandledMouseInput = true;
} }
else if (Panel->SplitDirection == PanelSplit_Horizontal) else if (Panel->SplitDirection != PanelSplit_NoSplit)
{ {
r32 SplitY = LerpR32(Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y); u32 ElementIndex = 0;
r32 ClickDistanceFromSplit = Abs(Mouse.DownPos.y - SplitY); switch(Panel->SplitDirection)
{
case PanelSplit_Vertical: { ElementIndex = 0; } break;
case PanelSplit_Horizontal: { ElementIndex = 1; } break;
InvalidDefaultCase;
}
r32 SplitPosition = LerpR32(Panel->SplitPercent, Panel->Bounds.Min.E[ElementIndex], Panel->Bounds.Max.E[ElementIndex]);
r32 ClickDistanceFromSplit = Abs(Mouse.DownPos.E[ElementIndex] - SplitPosition);
if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE)
{ {
BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Horizontal, Mouse, State); BeginDragPanelBorder(Panel, PanelEditMode, Panel->Bounds, Panel->SplitDirection, Mouse, State);
HandledMouseInput = true;
} }
else else
{ {
rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); if (PointIsInRect(Panel->Bottom->Bounds, Mouse.DownPos))
rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds);
if (PointIsInRect(BottomPanelBounds, Mouse.DownPos))
{ {
HandleMouseDownPanelInteractionOrRecurse(&Panel->Bottom->Panel, PanelEditMode, BottomPanelBounds, Mouse, State); HandleMouseDownPanelInteractionOrRecurse(Panel->Bottom, PanelEditMode, Mouse, State);
} }
if (PointIsInRect(TopPanelBounds, Mouse.DownPos)) else if (PointIsInRect(Panel->Top->Bounds, Mouse.DownPos))
{ {
HandleMouseDownPanelInteractionOrRecurse(&Panel->Top->Panel, PanelEditMode, TopPanelBounds, Mouse, State); HandleMouseDownPanelInteractionOrRecurse(Panel->Top, PanelEditMode, Mouse, State);
}
}
}
else if (Panel->SplitDirection == PanelSplit_Vertical)
{
r32 SplitX = LerpR32(Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x);
r32 ClickDistanceFromSplit = Abs(Mouse.DownPos.x - SplitX);
if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE)
{
BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Vertical, Mouse, State);
HandledMouseInput = true;
}
else
{
rect2 LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds);
rect2 RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds);
if (PointIsInRect(LeftPanelBounds, Mouse.DownPos))
{
HandleMouseDownPanelInteractionOrRecurse(&Panel->Left->Panel, PanelEditMode, LeftPanelBounds, Mouse, State);
}
if (PointIsInRect(RightPanelBounds, Mouse.DownPos))
{
HandleMouseDownPanelInteractionOrRecurse(&Panel->Right->Panel, PanelEditMode, RightPanelBounds, Mouse, State);
} }
} }
} }
@ -332,14 +319,21 @@ HandleMousePanelInteraction(panel_system* PanelSystem, rect2 WindowBounds, mouse
{ {
b32 HandledMouseInput = false; b32 HandledMouseInput = false;
panel* FirstPanel = &PanelSystem->Panels[0].Panel; panel* FirstPanel = PanelSystem->Panels + 0;
panel_edit_mode EditMode = PanelEdit_Invalid;
if (MouseButtonTransitionedDown(Mouse.LeftButtonState)) if (MouseButtonTransitionedDown(Mouse.LeftButtonState))
{ {
HandledMouseInput = HandleMouseDownPanelInteractionOrRecurse(FirstPanel, PanelEdit_Modify, WindowBounds, Mouse, State); EditMode = PanelEdit_Modify;
} }
else if (MouseButtonTransitionedDown(Mouse.RightButtonState)) else if (MouseButtonTransitionedDown(Mouse.RightButtonState))
{ {
HandledMouseInput = HandleMouseDownPanelInteractionOrRecurse(FirstPanel, PanelEdit_Destroy, WindowBounds, Mouse, State); EditMode = PanelEdit_Destroy;
}
if (EditMode != PanelEdit_Invalid)
{
HandledMouseInput = HandleMouseDownPanelInteractionOrRecurse(FirstPanel, EditMode, Mouse, State);
} }
return HandledMouseInput; return HandledMouseInput;
@ -456,21 +450,36 @@ RenderPanel(panel* Panel, rect2 PanelBounds, rect2 WindowBounds, render_command_
} }
internal void internal void
DrawAllPanels(panel_layout PanelLayout, render_command_buffer* RenderBuffer, mouse_state* Mouse, app_state* State, context Context) DrawPanelRecursive(panel* Panel, render_command_buffer* RenderBuffer, mouse_state* Mouse, app_state* State, context Context)
{ {
for (u32 i = 0; i < PanelLayout.PanelsCount; i++) switch (Panel->SplitDirection)
{ {
panel_with_layout PanelWithLayout = PanelLayout.Panels[i]; case PanelSplit_Horizontal:
panel* Panel = PanelWithLayout.Panel; case PanelSplit_Vertical:
rect2 PanelBounds = PanelWithLayout.Bounds; {
DrawPanelRecursive(Panel->Left, RenderBuffer, Mouse, State, Context);
DrawPanelRecursive(Panel->Right, RenderBuffer, Mouse, State, Context);
}break;
RenderPanel(Panel, PanelBounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse); case PanelSplit_NoSplit:
v4 BorderColor = v4{0, 0, 0, 1}; {
RenderPanel(Panel, Panel->Bounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse);
v4 BorderColor = v4{0, 0, 0, 1};
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
DrawPanelBorder(*Panel, Panel->Bounds.Min, Panel->Bounds.Max, BorderColor, Mouse, RenderBuffer);
}break;
PushRenderOrthographic(RenderBuffer, State->WindowBounds); InvalidDefaultCase;
DrawPanelBorder(*Panel, PanelBounds.Min, PanelBounds.Max, BorderColor, Mouse, RenderBuffer);
} }
} }
internal void
DrawAllPanels(panel_system System, render_command_buffer* RenderBuffer, mouse_state* Mouse, app_state* State, context Context)
{
panel* PanelAt = System.Panels + 0;
DrawPanelRecursive(PanelAt, RenderBuffer, Mouse, State, Context);
}
#define FOLDHAUS_INTERFACE_CPP #define FOLDHAUS_INTERFACE_CPP
#endif // FOLDHAUS_INTERFACE_CPP #endif // FOLDHAUS_INTERFACE_CPP

View File

@ -18,7 +18,6 @@ enum panel_split_direction
PanelSplit_Count, PanelSplit_Count,
}; };
typedef struct panel_entry panel_entry;
typedef struct panel panel; typedef struct panel panel;
#define PANEL_MODAL_OVERRIDE_CALLBACK(name) void name(panel* ReturningFrom, app_state* State, context Context) #define PANEL_MODAL_OVERRIDE_CALLBACK(name) void name(panel* ReturningFrom, app_state* State, context Context)
@ -29,10 +28,11 @@ struct panel
s32 TypeIndex; s32 TypeIndex;
gs_data StateMemory; gs_data StateMemory;
panel_entry* ModalOverride; panel* ModalOverride;
panel* IsModalOverrideFor; // TODO(pjs): I don't like that this is panel* but ModalOverride is panel_entry* panel* IsModalOverrideFor;
panel_modal_override_callback* ModalOverrideCB; panel_modal_override_callback* ModalOverrideCB;
rect2 Bounds;
panel_split_direction SplitDirection; panel_split_direction SplitDirection;
r32 SplitPercent; r32 SplitPercent;
@ -40,25 +40,21 @@ struct panel
// Probably belongs in a more generalized PanelInterfaceState or something // Probably belongs in a more generalized PanelInterfaceState or something
b32 PanelSelectionMenuOpen; b32 PanelSelectionMenuOpen;
panel* Parent;
union{ union{
panel_entry* Left; panel* Left;
panel_entry* Top; panel* Top;
}; };
union{ union{
panel_entry* Right; panel* Right;
panel_entry* Bottom; panel* Bottom;
}; };
}; };
struct free_panel struct free_panel
{ {
panel_entry* Next; free_panel* Next;
};
struct panel_entry
{
panel Panel;
free_panel Free;
}; };
#define PANEL_INIT_PROC(name) void name(panel* Panel, app_state* State, context Context) #define PANEL_INIT_PROC(name) void name(panel* Panel, app_state* State, context Context)
@ -88,26 +84,10 @@ struct panel_system
panel_definition* PanelDefs; panel_definition* PanelDefs;
u32 PanelDefsCount; u32 PanelDefsCount;
panel_entry Panels[PANELS_MAX]; panel Panels[PANELS_MAX];
u32 PanelsUsed; u32 PanelsUsed;
panel_entry FreeList; free_panel* FreeList;
};
// 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;
rect2 Bounds;
};
struct panel_layout
{
panel_with_layout* Panels;
u32 PanelsCount;
u32 PanelsMax;
}; };
///////////////////////////////// /////////////////////////////////
@ -119,19 +99,20 @@ struct panel_layout
internal void internal void
InitializePanelSystem(panel_system* PanelSystem, panel_definition* PanelDefs, u32 PanelDefsCount) InitializePanelSystem(panel_system* PanelSystem, panel_definition* PanelDefs, u32 PanelDefsCount)
{ {
PanelSystem->FreeList.Free.Next = &PanelSystem->FreeList; PanelSystem->FreeList = 0;
PanelSystem->PanelDefs = PanelDefs; PanelSystem->PanelDefs = PanelDefs;
PanelSystem->PanelDefsCount = PanelDefsCount; PanelSystem->PanelDefsCount = PanelDefsCount;
} }
internal panel_entry* internal panel*
TakeNewPanelEntry(panel_system* PanelSystem) TakeNewPanelEntry(panel_system* PanelSystem)
{ {
panel_entry* FreeEntry = 0; panel* FreeEntry = 0;
if (PanelSystem->FreeList.Free.Next != &PanelSystem->FreeList) if (PanelSystem->FreeList != 0)
{ {
FreeEntry = PanelSystem->FreeList.Free.Next; free_panel* FreePanel = PanelSystem->FreeList;
PanelSystem->FreeList.Free.Next = FreeEntry->Free.Next; PanelSystem->FreeList = FreePanel->Next;
FreeEntry = (panel*)PanelSystem->FreeList;
} }
else else
{ {
@ -142,43 +123,24 @@ TakeNewPanelEntry(panel_system* PanelSystem)
} }
internal void internal void
FreePanelEntry(panel_entry* Entry, panel_system* PanelSystem) FreePanelEntry(panel* Panel, panel_system* PanelSystem)
{ {
Assert(Entry >= PanelSystem->Panels && Entry <= PanelSystem->Panels + PANELS_MAX); Assert(Panel >= PanelSystem->Panels && Panel <= PanelSystem->Panels + PANELS_MAX);
Entry->Panel = {0};
Entry->Free.Next = PanelSystem->FreeList.Free.Next; free_panel* FreeEntry = (free_panel*)Panel;
PanelSystem->FreeList.Free.Next = Entry; FreeEntry->Next = PanelSystem->FreeList;
PanelSystem->FreeList = FreeEntry;
} }
internal void internal void
FreePanelEntryRecursive(panel_entry* Entry, panel_system* PanelSystem) FreePanelEntryRecursive(panel* Panel, panel_system* PanelSystem)
{ {
if (Entry->Panel.SplitDirection != PanelSplit_NoSplit) if (Panel->SplitDirection != PanelSplit_NoSplit)
{ {
FreePanelEntryRecursive(Entry->Panel.Left, PanelSystem); FreePanelEntryRecursive(Panel->Left, PanelSystem);
FreePanelEntryRecursive(Entry->Panel.Right, PanelSystem); FreePanelEntryRecursive(Panel->Right, PanelSystem);
} }
FreePanelEntry(Entry, PanelSystem); FreePanelEntry(Panel, PanelSystem);
}
internal void
FreePanelAtIndex(s32 Index, panel_system* PanelSystem)
{
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 panel_entry*
Panel_GetModalOverride(panel_entry* PanelEntry)
{
panel_entry* Result = PanelEntry;
if (PanelEntry->Panel.ModalOverride != 0)
{
Result = Panel_GetModalOverride(PanelEntry->Panel.ModalOverride);
}
return Result;
} }
internal panel* internal panel*
@ -187,17 +149,17 @@ Panel_GetModalOverride(panel* Panel)
panel* Result = Panel; panel* Result = Panel;
if (Panel->ModalOverride != 0) if (Panel->ModalOverride != 0)
{ {
Result = &Panel_GetModalOverride(Panel->ModalOverride)->Panel; Result = Panel_GetModalOverride(Panel->ModalOverride);
} }
return Result; return Result;
} }
internal void internal void
Panel_PushModalOverride(panel* Root, panel_entry* Override, panel_modal_override_callback* Callback) Panel_PushModalOverride(panel* Root, panel* Override, panel_modal_override_callback* Callback)
{ {
Root->ModalOverride = Override; Root->ModalOverride = Override;
Root->ModalOverrideCB = Callback; Root->ModalOverrideCB = Callback;
Override->Panel.IsModalOverrideFor = Root; Override->IsModalOverrideFor = Root;
} }
internal void internal void
@ -239,12 +201,12 @@ Panel_GetStateMemory(panel* Panel, u64 Size)
return Result; return Result;
} }
internal panel_entry* internal panel*
PanelSystem_PushPanel(panel_system* PanelSystem, s32 PanelTypeIndex, app_state* State, context Context) PanelSystem_PushPanel(panel_system* PanelSystem, s32 PanelTypeIndex, app_state* State, context Context)
{ {
panel_entry* PanelEntry = TakeNewPanelEntry(PanelSystem); panel* Panel = TakeNewPanelEntry(PanelSystem);
SetAndInitPanelType(&PanelEntry->Panel, PanelSystem, PanelTypeIndex, State, Context); SetAndInitPanelType(Panel, PanelSystem, PanelTypeIndex, State, Context);
return PanelEntry; return Panel;
} }
internal void internal void
@ -257,11 +219,14 @@ SplitPanel(panel* Parent, r32 Percent, panel_split_direction SplitDirection, pan
s32 ParentTypeIndex = Parent->TypeIndex; s32 ParentTypeIndex = Parent->TypeIndex;
gs_data ParentStateMemory = Parent->StateMemory; gs_data ParentStateMemory = Parent->StateMemory;
Parent->Left = TakeNewPanelEntry(PanelSystem); Parent->Left = TakeNewPanelEntry(PanelSystem);
Panel_SetCurrentType(&Parent->Left->Panel, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context); Panel_SetCurrentType(Parent->Left, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context);
Parent->Left->Parent = Parent;
Parent->Right = TakeNewPanelEntry(PanelSystem); Parent->Right = TakeNewPanelEntry(PanelSystem);
Panel_SetCurrentType(&Parent->Right->Panel, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context); Panel_SetCurrentType(Parent->Right, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context);
Parent->Right->Parent = Parent;
} }
} }
@ -278,17 +243,17 @@ SplitPanelHorizontally(panel* Parent, r32 Percent, panel_system* PanelSystem, ap
} }
internal void internal void
ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_system* PanelSystem) ConsolidatePanelsKeepOne(panel* Parent, panel* PanelToKeep, panel_system* PanelSystem)
{ {
panel_entry* LeftChild = Parent->Left; panel* LeftChild = Parent->Left;
panel_entry* RightChild = Parent->Right; panel* RightChild = Parent->Right;
panel_entry* PanelEntryToDestroy = PanelEntryToKeep == LeftChild ? RightChild : LeftChild; panel* PanelToDestroy = PanelToKeep == LeftChild ? RightChild : LeftChild;
*Parent = PanelEntryToKeep->Panel; *Parent = *PanelToKeep;
FreePanelEntry(PanelEntryToKeep, PanelSystem); FreePanelEntry(PanelToKeep, PanelSystem);
FreePanelEntryRecursive(PanelEntryToDestroy, PanelSystem); FreePanelEntryRecursive(PanelToDestroy, PanelSystem);
} }
///////////////////////////////// /////////////////////////////////
@ -297,6 +262,54 @@ ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_sys
// //
///////////////////////////////// /////////////////////////////////
internal rect2
GetTopPanelBounds(panel* Panel)
{
rect2 Result = {};
Result.Min = v2{
Panel->Bounds.Min.x,
LerpR32(Panel->SplitPercent, Panel->Bounds.Min.y, Panel->Bounds.Max.y)
};
Result.Max = Panel->Bounds.Max;
return Result;
}
internal rect2
GetBottomPanelBounds(panel* Panel)
{
rect2 Result = {};
Result.Min = Panel->Bounds.Min;
Result.Max = v2{
Panel->Bounds.Max.x,
LerpR32(Panel->SplitPercent, Panel->Bounds.Min.y, Panel->Bounds.Max.y)
};
return Result;
}
internal rect2
GetRightPanelBounds(panel* Panel)
{
rect2 Result = {};
Result.Min = v2{
LerpR32(Panel->SplitPercent, Panel->Bounds.Min.x, Panel->Bounds.Max.x),
Panel->Bounds.Min.y
};
Result.Max = Panel->Bounds.Max;
return Result;
}
internal rect2
GetLeftPanelBounds(panel* Panel)
{
rect2 Result = {};
Result.Min = Panel->Bounds.Min;
Result.Max = v2{
LerpR32(Panel->SplitPercent, Panel->Bounds.Min.x, Panel->Bounds.Max.x),
Panel->Bounds.Max.y
};
return Result;
}
internal rect2 internal rect2
GetTopPanelBounds(panel* Panel, rect2 PanelBounds) GetTopPanelBounds(panel* Panel, rect2 PanelBounds)
{ {
@ -346,103 +359,77 @@ GetLeftPanelBounds(panel* Panel, rect2 PanelBounds)
} }
internal void internal void
LayoutPanel(panel* Panel, rect2 PanelBounds, panel_layout* Layout) Panel_UpdateLayout(panel* Panel, rect2 Bounds)
{ {
if (Panel->SplitDirection == PanelSplit_NoSplit) Panel->Bounds = Bounds;
if (Panel->SplitDirection != PanelSplit_NoSplit)
{ {
panel_with_layout* WithLayout = Layout->Panels + Layout->PanelsCount++; rect2 LeftOrTopBounds = {};
WithLayout->Panel = Panel_GetModalOverride(Panel); rect2 RightOrBottomBounds = {};
WithLayout->Bounds = PanelBounds; switch (Panel->SplitDirection)
} {
else if (Panel->SplitDirection == PanelSplit_Horizontal) case PanelSplit_Horizontal:
{ {
rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); LeftOrTopBounds = GetTopPanelBounds(Panel);
rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); RightOrBottomBounds = GetBottomPanelBounds(Panel);
} break;
case PanelSplit_Vertical:
{
LeftOrTopBounds = GetLeftPanelBounds(Panel);
RightOrBottomBounds = GetRightPanelBounds(Panel);
} break;
InvalidDefaultCase;
}
panel* TopPanel = Panel_GetModalOverride(&Panel->Top->Panel); Panel_UpdateLayout(Panel->Left, LeftOrTopBounds);
panel* BottomPanel = Panel_GetModalOverride(&Panel->Bottom->Panel); Panel_UpdateLayout(Panel->Right, RightOrBottomBounds);
LayoutPanel(&Panel->Top->Panel, TopPanelBounds, Layout);
LayoutPanel(&Panel->Bottom->Panel, BottomPanelBounds, Layout);
}
else if (Panel->SplitDirection == PanelSplit_Vertical)
{
rect2 LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds);
rect2 RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds);
panel* LeftPanel = Panel_GetModalOverride(&Panel->Top->Panel);
panel* RightPanel = Panel_GetModalOverride(&Panel->Bottom->Panel);
LayoutPanel(&Panel->Left->Panel, LeftPanelBounds, Layout);
LayoutPanel(&Panel->Right->Panel, RightPanelBounds, Layout);
} }
} }
internal panel_layout internal void
GetPanelLayout(panel_system* System, rect2 WindowBounds, gs_memory_arena* Storage) PanelSystem_UpdateLayout(panel_system* System, rect2 WindowBounds)
{ {
panel_layout Result = {}; panel* Root = System->Panels;
Result.PanelsMax = System->PanelsUsed; Panel_UpdateLayout(Root, WindowBounds);
Result.Panels = PushArray(Storage, panel_with_layout, Result.PanelsMax);
LayoutPanel(&System->Panels[0].Panel, WindowBounds, &Result);
return Result;
} }
internal panel_with_layout internal panel*
GetPanelContainingPoint(v2 Point, panel* Panel, rect2 PanelBounds) GetPanelContainingPoint(v2 Point, panel* Panel)
{ {
panel_with_layout Result = {0}; panel* Result = 0;
if (Panel->SplitDirection == PanelSplit_NoSplit) if (PointIsInRect(Panel->Bounds, Point))
{ {
Result.Panel = Panel; switch (Panel->SplitDirection)
Result.Bounds = PanelBounds;
}
else if (Panel->SplitDirection == PanelSplit_Horizontal)
{
rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds);
rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds);
if (PointIsInRect(TopPanelBounds, Point))
{ {
Result = GetPanelContainingPoint(Point, &Panel->Top->Panel, TopPanelBounds); case PanelSplit_NoSplit:
} {
else if (PointIsInRect(BottomPanelBounds, Point)) Result = Panel;
{ }break;
Result = GetPanelContainingPoint(Point, &Panel->Bottom->Panel, BottomPanelBounds);
} case PanelSplit_Vertical:
} case PanelSplit_Horizontal:
else if (Panel->SplitDirection == PanelSplit_Vertical) {
{ if (PointIsInRect(Panel->Left->Bounds, Point))
rect2 LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); {
rect2 RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); Result = GetPanelContainingPoint(Point, Panel->Left);
}
if (PointIsInRect(LeftPanelBounds, Point)) else if (PointIsInRect(Panel->Right->Bounds, Point))
{ {
Result = GetPanelContainingPoint(Point, &Panel->Left->Panel, LeftPanelBounds); Result = GetPanelContainingPoint(Point, Panel->Right);
} }
else if (PointIsInRect(RightPanelBounds, Point)) }break;
{
Result = GetPanelContainingPoint(Point, &Panel->Right->Panel, RightPanelBounds); InvalidDefaultCase;
} }
} }
return Result; return Result;
} }
internal panel_with_layout
GetPanelContainingPoint(v2 Point, panel_system* PanelSystem, rect2 WindowBounds)
{
panel_with_layout Result = {0};
if (PanelSystem->PanelsUsed > 0)
{
Result = GetPanelContainingPoint(Point, &PanelSystem->Panels[0].Panel, WindowBounds);
}
return Result;
}
#define FOLDHAUS_PANEL_H #define FOLDHAUS_PANEL_H
#endif // FOLDHAUS_PANEL_H #endif // FOLDHAUS_PANEL_H

View File

@ -264,9 +264,9 @@ FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand)
{ {
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
panel_with_layout ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, State->WindowBounds); panel* ActivePanel = GetPanelContainingPoint(Mouse.Pos, State->PanelSystem.Panels + 0);
frame_range Range = ActiveAnim->PlayableRange; frame_range Range = ActiveAnim->PlayableRange;
u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel.Bounds, Range); u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel->Bounds, Range);
handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, State->SelectedAnimationLayer); handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, State->SelectedAnimationLayer);
SelectAnimationBlock(NewBlockHandle, State); SelectAnimationBlock(NewBlockHandle, State);
@ -641,7 +641,7 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer*
if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Load"))) if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Load")))
{ {
panel_entry* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context);
Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback); Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback);
} }
} }

View File

@ -75,7 +75,7 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren
PrintF(&TempString, "+ Add Assembly"); PrintF(&TempString, "+ Add Assembly");
if (ui_ListButton(&State->Interface, TempString, LineBounds[AssembliesToDraw], AssembliesToDraw)) if (ui_ListButton(&State->Interface, TempString, LineBounds[AssembliesToDraw], AssembliesToDraw))
{ {
panel_entry* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context);
Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback); Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback);
} }
} }

View File

@ -162,66 +162,6 @@ INITIALIZE_APPLICATION(InitializeApplication)
PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context); PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context);
} }
internal void
HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue, mouse_state Mouse, context Context)
{
DEBUG_TRACK_FUNCTION;
b32 PanelSystemHandledInput = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State);
if (!PanelSystemHandledInput)
{
input_command_registry ActiveCommands = {};
if (State->Modes.ActiveModesCount > 0)
{
ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands;
}
else
{
panel_with_layout PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, WindowBounds);
if (!PanelWithMouseOverIt.Panel) { return; }
State->HotPanel = PanelWithMouseOverIt.Panel;
s32 PanelTypeIndex = PanelWithMouseOverIt.Panel->TypeIndex;
panel_definition PanelDefinition = GlobalPanelDefs[PanelTypeIndex];
if (!PanelDefinition.InputCommands) { return; }
ActiveCommands.Commands = PanelDefinition.InputCommands;
ActiveCommands.Size = sizeof(*PanelDefinition.InputCommands) / sizeof(PanelDefinition.InputCommands[0]);
ActiveCommands.Used = ActiveCommands.Size;
}
for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++)
{
input_entry Event = InputQueue.Entries[EventIdx];
// NOTE(Peter): These are in the order Down, Up, Held because we want to privalege
// Down and Up over Held. In other words, we don't want to call a Held command on the
// frame when the button was released, even if the command is registered to both events
if (KeyTransitionedDown(Event))
{
FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue);
}
else if (KeyTransitionedUp(Event))
{
FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue);
}
else if (KeyHeldDown(Event))
{
FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue);
}
}
}
// Execute all commands in CommandQueue
for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--)
{
command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx];
Entry->Command.Proc(State, Entry->Event, Mouse, Context);
}
ClearCommandQueue(&State->CommandQueue);
}
UPDATE_AND_RENDER(UpdateAndRender) UPDATE_AND_RENDER(UpdateAndRender)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
@ -232,12 +172,8 @@ UPDATE_AND_RENDER(UpdateAndRender)
// zero the Transient arena when we clear it so it wouldn't be a problem, but it is technically // zero the Transient arena when we clear it so it wouldn't be a problem, but it is technically
// incorrect to clear the arena, and then access the memory later. // incorrect to clear the arena, and then access the memory later.
ClearArena(State->Transient); ClearArena(State->Transient);
Context->Mouse.CursorType = CursorType_Arrow;
PushRenderClearScreen(RenderBuffer); Editor_Update(State, Context, InputQueue);
State->Camera.AspectRatio = RectAspectRatio(Context->WindowBounds);
HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context);
{ {
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
@ -348,27 +284,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem); UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem);
} }
PushRenderOrthographic(RenderBuffer, State->WindowBounds); Editor_Render(State, Context, RenderBuffer);
PushRenderClearScreen(RenderBuffer);
State->WindowBounds = Context->WindowBounds;
State->Interface.RenderBuffer = RenderBuffer;
State->Interface.Mouse = Context->Mouse;
panel_layout PanelsToRender = GetPanelLayout(&State->PanelSystem, State->WindowBounds, State->Transient);
DrawAllPanels(PanelsToRender, RenderBuffer, &Context->Mouse, State, *Context);
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
{
operation_mode OperationMode = State->Modes.ActiveModes[m];
if (OperationMode.Render != 0)
{
OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context);
}
}
Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext);
Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue);
// Checking for overflows // Checking for overflows
#if 0 #if 0

View File

@ -233,5 +233,7 @@ animation_clip GlobalAnimationClips[] = {
#include "../meta/gs_meta_include.cpp" #include "../meta/gs_meta_include.cpp"
#include "editor/foldhaus_editor.cpp"
#define FOLDHAUS_APP_H #define FOLDHAUS_APP_H
#endif // FOLDHAUS_APP_H #endif // FOLDHAUS_APP_H

View File

@ -231,7 +231,7 @@ struct u64_array
# define InvalidDefaultCase default: { AssertBreak("invalid default case"); } break; # define InvalidDefaultCase default: { AssertBreak("invalid default case"); } break;
# define StaticAssert(c) \ # define StaticAssert(c) \
enum { \ enum { \
Glue(gs_AssertFail_, __LINE__) = 1 / (int)(!!(c)), \ Glue(gs_AssertFail_, __LINE__) = 1 / (int)(!!(c)), \
} }
#else #else
# define Assert(c) # define Assert(c)