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
{
PanelEdit_Invalid,
PanelEdit_Modify,
PanelEdit_Destroy,
@ -111,6 +113,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
else
{
Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Rect2Height(PanelBounds);
Panel_UpdateLayout(Panel, PanelBounds);
}
}
else if (Panel->SplitDirection == PanelSplit_Vertical)
@ -127,6 +130,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
else
{
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;
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);
}
@ -251,12 +255,12 @@ input_command SplitPanelCommands[] = {
};
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);
split_panel_operation_state* OpState = CreateOperationState(SplitPanel, &State->Modes, split_panel_operation_state);
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
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;
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
&& PointIsInRect(PanelSplitButtonBounds, Mouse.DownPos))
{
BeginSplitPanelOperation(Panel, PanelBounds, Mouse, State);
BeginSplitPanelOperation(Panel, Mouse, State);
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);
r32 ClickDistanceFromSplit = Abs(Mouse.DownPos.y - SplitY);
u32 ElementIndex = 0;
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)
{
BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Horizontal, Mouse, State);
HandledMouseInput = true;
BeginDragPanelBorder(Panel, PanelEditMode, Panel->Bounds, Panel->SplitDirection, Mouse, State);
}
else
{
rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds);
rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds);
if (PointIsInRect(BottomPanelBounds, Mouse.DownPos))
if (PointIsInRect(Panel->Bottom->Bounds, 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);
}
}
}
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);
HandleMouseDownPanelInteractionOrRecurse(Panel->Top, PanelEditMode, Mouse, State);
}
}
}
@ -332,14 +319,21 @@ HandleMousePanelInteraction(panel_system* PanelSystem, rect2 WindowBounds, mouse
{
b32 HandledMouseInput = false;
panel* FirstPanel = &PanelSystem->Panels[0].Panel;
panel* FirstPanel = PanelSystem->Panels + 0;
panel_edit_mode EditMode = PanelEdit_Invalid;
if (MouseButtonTransitionedDown(Mouse.LeftButtonState))
{
HandledMouseInput = HandleMouseDownPanelInteractionOrRecurse(FirstPanel, PanelEdit_Modify, WindowBounds, Mouse, State);
EditMode = PanelEdit_Modify;
}
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;
@ -456,21 +450,36 @@ RenderPanel(panel* Panel, rect2 PanelBounds, rect2 WindowBounds, render_command_
}
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];
panel* Panel = PanelWithLayout.Panel;
rect2 PanelBounds = PanelWithLayout.Bounds;
case PanelSplit_Horizontal:
case PanelSplit_Vertical:
{
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:
{
RenderPanel(Panel, Panel->Bounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse);
v4 BorderColor = v4{0, 0, 0, 1};
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
DrawPanelBorder(*Panel, PanelBounds.Min, PanelBounds.Max, BorderColor, Mouse, RenderBuffer);
DrawPanelBorder(*Panel, Panel->Bounds.Min, Panel->Bounds.Max, BorderColor, Mouse, RenderBuffer);
}break;
InvalidDefaultCase;
}
}
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
#endif // FOLDHAUS_INTERFACE_CPP

View File

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

View File

@ -264,9 +264,9 @@ FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand)
{
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;
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);
SelectAnimationBlock(NewBlockHandle, State);
@ -641,7 +641,7 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer*
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);
}
}

View File

@ -75,7 +75,7 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren
PrintF(&TempString, "+ Add Assembly");
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);
}
}

View File

@ -162,66 +162,6 @@ INITIALIZE_APPLICATION(InitializeApplication)
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)
{
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
// incorrect to clear the arena, and then access the memory later.
ClearArena(State->Transient);
Context->Mouse.CursorType = CursorType_Arrow;
PushRenderClearScreen(RenderBuffer);
State->Camera.AspectRatio = RectAspectRatio(Context->WindowBounds);
HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context);
Editor_Update(State, Context, InputQueue);
{
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
@ -348,27 +284,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem);
}
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
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);
Editor_Render(State, Context, RenderBuffer);
// Checking for overflows
#if 0

View File

@ -233,5 +233,7 @@ animation_clip GlobalAnimationClips[] = {
#include "../meta/gs_meta_include.cpp"
#include "editor/foldhaus_editor.cpp"
#define 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 StaticAssert(c) \
enum { \
Glue(gs_AssertFail_, __LINE__) = 1 / (int)(!!(c)), \
Glue(gs_AssertFail_, __LINE__) = 1 / (int)(!!(c)), \
}
#else
# define Assert(c)