Consolidated all panel code in one file, and removed all external dependencies. ITS A LIBRARY NOW (still needs refinement)
This commit is contained in:
parent
9b9fe2f5e1
commit
b83d718d37
|
@ -1,11 +1,3 @@
|
||||||
// TODO
|
|
||||||
// [] - Moving animation blocks
|
|
||||||
// [] - dragging beginning and end of time blocks
|
|
||||||
// [] - creating a timeblock with a specific animation
|
|
||||||
// [x] - play, pause, stop,
|
|
||||||
// [] - setting the start and end of the animation system
|
|
||||||
// [] - displaying multiple layers
|
|
||||||
// [] -
|
|
||||||
|
|
||||||
FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlock)
|
FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlock)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,85 @@
|
||||||
#include "foldhaus_platform.h"
|
#include "foldhaus_platform.h"
|
||||||
#include "foldhaus_app.h"
|
#include "foldhaus_app.h"
|
||||||
|
|
||||||
|
internal void
|
||||||
|
SetPanelDefinitionExternal(panel* Panel, s32 OldPanelDefinitionIndex, s32 NewPanelDefinitionIndex)
|
||||||
|
{
|
||||||
|
if(OldPanelDefinitionIndex >= 0)
|
||||||
|
{
|
||||||
|
GlobalPanelDefs[OldPanelDefinitionIndex].Cleanup(Panel);
|
||||||
|
}
|
||||||
|
GlobalPanelDefs[NewPanelDefinitionIndex].Init(Panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal void
|
||||||
|
DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, v2 FooterMin, v2 FooterMax, interface_config Interface, mouse_state Mouse)
|
||||||
|
{
|
||||||
|
PushRenderQuad2D(RenderBuffer, FooterMin, v2{FooterMax.x, FooterMin.y + 25}, v4{.5f, .5f, .5f, 1.f});
|
||||||
|
PushRenderQuad2D(RenderBuffer, FooterMin, FooterMin + v2{25, 25}, WhiteV4);
|
||||||
|
|
||||||
|
v2 PanelSelectButtonMin = FooterMin + v2{30, 1};
|
||||||
|
v2 PanelSelectButtonMax = PanelSelectButtonMin + v2{100, 23};
|
||||||
|
|
||||||
|
if (Panel->PanelSelectionMenuOpen)
|
||||||
|
{
|
||||||
|
v2 ButtonDimension = v2{100, 25};
|
||||||
|
v2 ButtonMin = v2{PanelSelectButtonMin.x, FooterMax.y};
|
||||||
|
|
||||||
|
v2 MenuMin = ButtonMin;
|
||||||
|
v2 MenuMax = v2{ButtonMin.x + ButtonDimension.x, ButtonMin.y + (ButtonDimension.y * GlobalPanelDefsCount)};
|
||||||
|
if (MouseButtonTransitionedDown(Mouse.LeftButtonState)
|
||||||
|
&& !PointIsInRange(Mouse.DownPos, MenuMin, MenuMax))
|
||||||
|
{
|
||||||
|
Panel->PanelSelectionMenuOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (s32 i = 0; i < GlobalPanelDefsCount; i++)
|
||||||
|
{
|
||||||
|
panel_definition Def = GlobalPanelDefs[i];
|
||||||
|
string DefName = MakeString(Def.PanelName, Def.PanelNameLength);
|
||||||
|
button_result DefinitionButton = EvaluateButton(RenderBuffer,
|
||||||
|
ButtonMin, ButtonMin + ButtonDimension,
|
||||||
|
DefName, Interface, Mouse);
|
||||||
|
if (DefinitionButton.Pressed)
|
||||||
|
{
|
||||||
|
SetPanelDefinition(Panel, i);
|
||||||
|
Panel->PanelSelectionMenuOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonMin.y += ButtonDimension.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button_result ButtonResult = EvaluateButton(RenderBuffer,
|
||||||
|
PanelSelectButtonMin,
|
||||||
|
PanelSelectButtonMax,
|
||||||
|
MakeStringLiteral("Select"), Interface, Mouse);
|
||||||
|
if (ButtonResult.Pressed)
|
||||||
|
{
|
||||||
|
Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Assert(Panel->PanelDefinitionIndex >= 0);
|
||||||
|
|
||||||
|
v2 FooterMin = PanelMin;
|
||||||
|
v2 FooterMax = v2{PanelMax.x, PanelMin.y + 25};
|
||||||
|
v2 PanelViewMin = v2{PanelMin.x, FooterMax.y};
|
||||||
|
v2 PanelViewMax = PanelMax;
|
||||||
|
|
||||||
|
panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex];
|
||||||
|
Definition.Render(*Panel, PanelMin, PanelMax, RenderBuffer, State, Context, Mouse);
|
||||||
|
|
||||||
|
PushRenderOrthographic(RenderBuffer, WindowMin.x, WindowMin.y, WindowMax.x, WindowMax.y);
|
||||||
|
DrawPanelFooter(Panel, RenderBuffer, FooterMin, FooterMax, State->Interface, Mouse);
|
||||||
|
}
|
||||||
|
|
||||||
internal v4
|
internal v4
|
||||||
MouseToWorldRay(r32 MouseX, r32 MouseY, camera* Camera, r32 WindowWidth, r32 WindowHeight)
|
MouseToWorldRay(r32 MouseX, r32 MouseY, camera* Camera, r32 WindowWidth, r32 WindowHeight)
|
||||||
{
|
{
|
||||||
|
@ -271,9 +350,9 @@ INITIALIZE_APPLICATION(InitializeApplication)
|
||||||
{ // Panels Playground
|
{ // Panels Playground
|
||||||
InitializePanelLayout(&State->PanelLayout);
|
InitializePanelLayout(&State->PanelLayout);
|
||||||
panel* Panel = TakeNewPanel(&State->PanelLayout);
|
panel* Panel = TakeNewPanel(&State->PanelLayout);
|
||||||
SetPanelDefinition(Panel, GlobalPanelDefs[0]);
|
SetPanelDefinition(Panel, 0);
|
||||||
SplitPanelVertically(Panel, .5f, v2{0, 0}, v2{Context.WindowWidth, Context.WindowHeight}, &State->PanelLayout);
|
SplitPanelVertically(Panel, .5f, v2{0, 0}, v2{Context.WindowWidth, Context.WindowHeight}, &State->PanelLayout);
|
||||||
SetPanelDefinition(&Panel->Right->Panel, GlobalPanelDefs[1]);
|
SetPanelDefinition(&Panel->Right->Panel, 1);
|
||||||
} // End Panels Playground
|
} // End Panels Playground
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,14 +636,13 @@ PushRenderOrthographic(RenderBuffer, 0, 0, Context.WindowWidth, Context.WindowHe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v2 TimelineMin = v2{0, 0};
|
DrawDebugInterface(RenderBuffer, 25,
|
||||||
v2 TimelineMax = v2{Context.WindowWidth, 125};
|
State->Interface, Context.WindowWidth, Context.WindowHeight - TopBarHeight,
|
||||||
animation_block_handle NewSelection = DrawAnimationPanel(&State->AnimationSystem,
|
Context.DeltaTime, State, State->Camera, Mouse, &State->Transient);
|
||||||
TimelineMin, TimelineMax,
|
#endif
|
||||||
State->SelectedAnimationBlockHandle,
|
}
|
||||||
RenderBuffer, State->Interface, Mouse);
|
|
||||||
State->SelectedAnimationBlockHandle = NewSelection;
|
|
||||||
|
|
||||||
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
|
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
|
||||||
{
|
{
|
||||||
operation_mode OperationMode = State->Modes.ActiveModes[m];
|
operation_mode OperationMode = State->Modes.ActiveModes[m];
|
||||||
|
@ -574,11 +652,6 @@ PushRenderOrthographic(RenderBuffer, 0, 0, Context.WindowWidth, Context.WindowHe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawDebugInterface(RenderBuffer, 25,
|
|
||||||
State->Interface, Context.WindowWidth, Context.WindowHeight - TopBarHeight,
|
|
||||||
Context.DeltaTime, State, State->Camera, Mouse, &State->Transient);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checking for overflows
|
// Checking for overflows
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
typedef struct app_state app_state;
|
typedef struct app_state app_state;
|
||||||
|
|
||||||
|
|
||||||
#include "foldhaus_panel.h"
|
#include "foldhaus_panel.h"
|
||||||
|
|
||||||
#include "foldhaus_command_dispatch.h"
|
#include "foldhaus_command_dispatch.h"
|
||||||
|
@ -171,10 +172,27 @@ r32 GreenSize = 20.0f;
|
||||||
#include "foldhaus_interface.cpp"
|
#include "foldhaus_interface.cpp"
|
||||||
#include "animation/foldhaus_animation_interface.h"
|
#include "animation/foldhaus_animation_interface.h"
|
||||||
|
|
||||||
|
#define PANEL_INIT_PROC(name) void name(panel* Panel)
|
||||||
|
typedef PANEL_INIT_PROC(panel_init_proc);
|
||||||
|
|
||||||
|
#define PANEL_CLEANUP_PROC(name) void name(panel* Panel)
|
||||||
|
typedef PANEL_CLEANUP_PROC(panel_cleanup_proc);
|
||||||
|
|
||||||
|
#define PANEL_RENDER_PROC(name) void name(panel Panel, v2 PanelMin, v2 PanelMax, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
|
||||||
|
typedef PANEL_RENDER_PROC(panel_render_proc);
|
||||||
|
|
||||||
|
struct panel_definition
|
||||||
|
{
|
||||||
|
char* PanelName;
|
||||||
|
s32 PanelNameLength;
|
||||||
|
panel_init_proc* Init;
|
||||||
|
panel_cleanup_proc* Cleanup;
|
||||||
|
panel_render_proc* Render;
|
||||||
|
};
|
||||||
|
|
||||||
#include "panels/foldhaus_panel_sculpture_view.h"
|
#include "panels/foldhaus_panel_sculpture_view.h"
|
||||||
#include "panels/foldhaus_panel_profiler.h"
|
#include "panels/foldhaus_panel_profiler.h"
|
||||||
#include "panels/foldhaus_panel_dmx_view.h"
|
#include "panels/foldhaus_panel_dmx_view.h"
|
||||||
#include "panels/foldhaus_panel_animation_timeline.h"
|
#include "panels/foldhaus_panel_animation_timeline.h"
|
||||||
|
|
||||||
#include "generated/foldhaus_panels_generated.h"
|
#include "generated/foldhaus_panels_generated.h"
|
||||||
#include "foldhaus_panel.cpp"
|
|
||||||
|
|
|
@ -1,313 +0,0 @@
|
||||||
|
|
||||||
/////////////////////////////////
|
|
||||||
//
|
|
||||||
// Book-Keeping
|
|
||||||
//
|
|
||||||
/////////////////////////////////
|
|
||||||
|
|
||||||
internal void
|
|
||||||
InitializePanelLayout(panel_layout* Layout)
|
|
||||||
{
|
|
||||||
Layout->FreeList.Free.Next = &Layout->FreeList;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal panel_entry*
|
|
||||||
TakeNewPanelEntry(panel_layout* Layout)
|
|
||||||
{
|
|
||||||
panel_entry* FreeEntry = 0;
|
|
||||||
if (Layout->FreeList.Free.Next != &Layout->FreeList)
|
|
||||||
{
|
|
||||||
FreeEntry = Layout->FreeList.Free.Next;
|
|
||||||
Layout->FreeList.Free.Next = FreeEntry->Free.Next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert(Layout->PanelsUsed < PANELS_MAX);
|
|
||||||
FreeEntry = Layout->Panels + Layout->PanelsUsed++;
|
|
||||||
}
|
|
||||||
return FreeEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal panel*
|
|
||||||
TakeNewPanel(panel_layout* Layout)
|
|
||||||
{
|
|
||||||
panel* Result = 0;
|
|
||||||
panel_entry* FreeEntry = TakeNewPanelEntry(Layout);
|
|
||||||
Result = &FreeEntry->Panel;
|
|
||||||
*Result = {0};
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
FreePanelEntry(panel_entry* Entry, panel_layout* Layout)
|
|
||||||
{
|
|
||||||
Assert(Entry >= Layout->Panels && Entry <= Layout->Panels + PANELS_MAX);
|
|
||||||
Entry->Panel = {0};
|
|
||||||
Entry->Free.Next = Layout->FreeList.Free.Next;
|
|
||||||
Layout->FreeList.Free.Next = Entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
FreePanelAtIndex(s32 Index, panel_layout* Layout)
|
|
||||||
{
|
|
||||||
Assert(Index > 0 && Index < (s32)Layout->PanelsUsed);
|
|
||||||
panel_entry* EntryToFree = Layout->Panels + Index;
|
|
||||||
EntryToFree->Free.Next = Layout->FreeList.Free.Next;
|
|
||||||
Layout->FreeList.Free.Next = EntryToFree;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
SplitPanelVertically(panel* Parent, r32 Percent, v2 ParentMin, v2 ParentMax, panel_layout* Layout)
|
|
||||||
{
|
|
||||||
r32 SplitX = GSLerp(ParentMin.x, ParentMax.x, Percent);
|
|
||||||
if (SplitX > ParentMin.x && SplitX < ParentMax.x)
|
|
||||||
{
|
|
||||||
Parent->SplitDirection = PanelSplit_Vertical;
|
|
||||||
Parent->SplitPercent = Percent;
|
|
||||||
|
|
||||||
Parent->Left = TakeNewPanelEntry(Layout);
|
|
||||||
Parent->Left->Panel.Render = Parent->Render;
|
|
||||||
|
|
||||||
Parent->Right = TakeNewPanelEntry(Layout);
|
|
||||||
Parent->Right->Panel.Render = Parent->Render;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
SplitPanelHorizontally(panel* Parent, r32 Percent, v2 ParentMin, v2 ParentMax, panel_layout* Layout)
|
|
||||||
{
|
|
||||||
r32 SplitY = GSLerp(ParentMin.y, ParentMax.y, Percent);
|
|
||||||
if (SplitY > ParentMin.y && SplitY < ParentMax.y)
|
|
||||||
{
|
|
||||||
Parent->SplitDirection = PanelSplit_Horizontal;
|
|
||||||
Parent->SplitPercent = Percent;
|
|
||||||
|
|
||||||
Parent->Bottom = TakeNewPanelEntry(Layout);
|
|
||||||
Parent->Bottom->Panel.Render = Parent->Render;
|
|
||||||
|
|
||||||
Parent->Top = TakeNewPanelEntry(Layout);
|
|
||||||
Parent->Top->Panel.Render = Parent->Render;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_layout* Layout)
|
|
||||||
{
|
|
||||||
panel_entry* LeftChild = Parent->Left;
|
|
||||||
panel_entry* RightChild = Parent->Right;
|
|
||||||
|
|
||||||
*Parent = PanelEntryToKeep->Panel;
|
|
||||||
Parent->SplitDirection = PanelSplit_NoSplit;
|
|
||||||
|
|
||||||
FreePanelEntry(LeftChild, Layout);
|
|
||||||
FreePanelEntry(RightChild, Layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
SetPanelDefinition(panel* Panel, panel_definition Def)
|
|
||||||
{
|
|
||||||
if(Panel->Cleanup)
|
|
||||||
{
|
|
||||||
Panel->Cleanup(Panel);
|
|
||||||
}
|
|
||||||
|
|
||||||
Panel->Cleanup = Def.Cleanup;
|
|
||||||
Panel->Render = Def.Render;
|
|
||||||
Def.Init(Panel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////
|
|
||||||
//
|
|
||||||
// Rendering And Interaction
|
|
||||||
//
|
|
||||||
/////////////////////////////////
|
|
||||||
|
|
||||||
internal void
|
|
||||||
HandleMousePanelInteractionOrRecurse(panel* Panel, v2 PanelMin, v2 PanelMax, 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, PanelMin, PanelMin + 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 - PanelMin.x) / (PanelMax.x - PanelMin.x);
|
|
||||||
SplitPanelVertically(Panel, XPercent, PanelMin, PanelMax, PanelLayout);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r32 YPercent = (Mouse.Pos.y - PanelMin.y) / (PanelMax.y - PanelMin.y);
|
|
||||||
SplitPanelHorizontally(Panel, YPercent, PanelMin, PanelMax, PanelLayout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Panel->SplitDirection == PanelSplit_Horizontal)
|
|
||||||
{
|
|
||||||
r32 SplitY = GSLerp(PanelMin.y, PanelMax.y, Panel->SplitPercent);
|
|
||||||
r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.y - SplitY);
|
|
||||||
if (ClickDistanceFromSplit < PanelEdgeClickMaxDistance)
|
|
||||||
{
|
|
||||||
r32 NewSplitY = Mouse.Pos.y;
|
|
||||||
if (NewSplitY <= PanelMin.y)
|
|
||||||
{
|
|
||||||
ConsolidatePanelsKeepOne(Panel, Panel->Top, PanelLayout);
|
|
||||||
}
|
|
||||||
else if (NewSplitY >= PanelMax.y)
|
|
||||||
{
|
|
||||||
ConsolidatePanelsKeepOne(Panel, Panel->Bottom, PanelLayout);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Panel->SplitPercent = (NewSplitY - PanelMin.y) / (PanelMax.y - PanelMin.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HandleMousePanelInteractionOrRecurse(&Panel->Bottom->Panel, PanelMin, v2{PanelMax.x, SplitY}, PanelLayout, Mouse);
|
|
||||||
HandleMousePanelInteractionOrRecurse(&Panel->Top->Panel, v2{PanelMin.x, SplitY}, PanelMax, PanelLayout, Mouse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Panel->SplitDirection == PanelSplit_Vertical)
|
|
||||||
{
|
|
||||||
r32 SplitX = GSLerp(PanelMin.x, PanelMax.x, Panel->SplitPercent);
|
|
||||||
r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.x - SplitX);
|
|
||||||
if (ClickDistanceFromSplit < PanelEdgeClickMaxDistance)
|
|
||||||
{
|
|
||||||
r32 NewSplitX = Mouse.Pos.x;
|
|
||||||
if (NewSplitX <= PanelMin.x)
|
|
||||||
{
|
|
||||||
ConsolidatePanelsKeepOne(Panel, Panel->Right, PanelLayout);
|
|
||||||
}
|
|
||||||
else if (NewSplitX >= PanelMax.x)
|
|
||||||
{
|
|
||||||
ConsolidatePanelsKeepOne(Panel, Panel->Left, PanelLayout);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Panel->SplitPercent = (NewSplitX - PanelMin.x) / (PanelMax.x - PanelMin.x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HandleMousePanelInteractionOrRecurse(&Panel->Left->Panel, PanelMin, v2{SplitX, PanelMax.y}, PanelLayout, Mouse);
|
|
||||||
HandleMousePanelInteractionOrRecurse(&Panel->Right->Panel, v2{SplitX, PanelMin.y}, PanelMax, PanelLayout, Mouse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
HandleMousePanelInteraction(panel_layout* PanelLayout, v2 WindowMin, v2 WindowMax, mouse_state Mouse)
|
|
||||||
{
|
|
||||||
r32 PanelEdgeClickMaxDistance = 4;
|
|
||||||
|
|
||||||
if (MouseButtonTransitionedUp(Mouse.LeftButtonState))
|
|
||||||
{
|
|
||||||
Assert(PanelLayout->PanelsUsed > 0);
|
|
||||||
panel* FirstPanel = &PanelLayout->Panels[0].Panel;
|
|
||||||
HandleMousePanelInteractionOrRecurse(FirstPanel, WindowMin, WindowMax, PanelLayout, Mouse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, v2 FooterMin, v2 FooterMax, interface_config Interface, mouse_state Mouse)
|
|
||||||
{
|
|
||||||
PushRenderQuad2D(RenderBuffer, FooterMin, v2{FooterMax.x, FooterMin.y + 25}, v4{.5f, .5f, .5f, 1.f});
|
|
||||||
PushRenderQuad2D(RenderBuffer, FooterMin, FooterMin + v2{25, 25}, WhiteV4);
|
|
||||||
|
|
||||||
v2 PanelSelectButtonMin = FooterMin + v2{30, 1};
|
|
||||||
v2 PanelSelectButtonMax = PanelSelectButtonMin + v2{100, 23};
|
|
||||||
|
|
||||||
if (Panel->PanelSelectionMenuOpen)
|
|
||||||
{
|
|
||||||
v2 ButtonDimension = v2{100, 25};
|
|
||||||
v2 ButtonMin = v2{PanelSelectButtonMin.x, FooterMax.y};
|
|
||||||
|
|
||||||
v2 MenuMin = ButtonMin;
|
|
||||||
v2 MenuMax = v2{ButtonMin.x + ButtonDimension.x, ButtonMin.y + (ButtonDimension.y * GlobalPanelDefsCount)};
|
|
||||||
if (MouseButtonTransitionedDown(Mouse.LeftButtonState)
|
|
||||||
&& !PointIsInRange(Mouse.DownPos, MenuMin, MenuMax))
|
|
||||||
{
|
|
||||||
Panel->PanelSelectionMenuOpen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (s32 i = 0; i < GlobalPanelDefsCount; i++)
|
|
||||||
{
|
|
||||||
panel_definition Def = GlobalPanelDefs[i];
|
|
||||||
string DefName = MakeString(Def.PanelName, Def.PanelNameLength);
|
|
||||||
button_result DefinitionButton = EvaluateButton(RenderBuffer,
|
|
||||||
ButtonMin, ButtonMin + ButtonDimension,
|
|
||||||
DefName, Interface, Mouse);
|
|
||||||
if (DefinitionButton.Pressed)
|
|
||||||
{
|
|
||||||
SetPanelDefinition(Panel, Def);
|
|
||||||
Panel->PanelSelectionMenuOpen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ButtonMin.y += ButtonDimension.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button_result ButtonResult = EvaluateButton(RenderBuffer,
|
|
||||||
PanelSelectButtonMin,
|
|
||||||
PanelSelectButtonMax,
|
|
||||||
MakeStringLiteral("Select"), Interface, Mouse);
|
|
||||||
if (ButtonResult.Pressed)
|
|
||||||
{
|
|
||||||
Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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, v2 PanelMin, v2 PanelMax, v2 WindowMin, v2 WindowMax, render_command_buffer* RenderBuffer, interface_config Interface, mouse_state Mouse, app_state* State, context Context)
|
|
||||||
{
|
|
||||||
if (Panel->SplitDirection == PanelSplit_NoSplit)
|
|
||||||
{
|
|
||||||
v2 FooterMin = PanelMin;
|
|
||||||
v2 FooterMax = v2{PanelMax.x, PanelMin.y + 25};
|
|
||||||
v2 PanelViewMin = v2{PanelMin.x, FooterMax.y};
|
|
||||||
v2 PanelViewMax = PanelMax;
|
|
||||||
|
|
||||||
Panel->Render(*Panel, PanelViewMin, PanelViewMax, RenderBuffer, State, Context, Mouse);
|
|
||||||
v4 BorderColor = v4{0, 1, 1, 1};
|
|
||||||
if (PointIsInRange(Mouse.Pos, PanelMin, PanelMax))
|
|
||||||
{
|
|
||||||
BorderColor = v4{1, 0, 1, 1};
|
|
||||||
}
|
|
||||||
|
|
||||||
PushRenderOrthographic(RenderBuffer, WindowMin.x, WindowMin.y, WindowMax.x, WindowMax.y);
|
|
||||||
DrawPanelBorder(*Panel, PanelMin, PanelMax, BorderColor, RenderBuffer);
|
|
||||||
DrawPanelFooter(Panel, RenderBuffer, FooterMin, FooterMax, Interface, Mouse);
|
|
||||||
}
|
|
||||||
else if (Panel->SplitDirection == PanelSplit_Horizontal)
|
|
||||||
{
|
|
||||||
r32 SplitY = GSLerp(PanelMin.y, PanelMax.y, Panel->SplitPercent);
|
|
||||||
DrawPanelOrRecurse(&Panel->Bottom->Panel, PanelMin, v2{PanelMax.x, SplitY}, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
|
|
||||||
DrawPanelOrRecurse(&Panel->Top->Panel, v2{PanelMin.x, SplitY}, PanelMax, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
|
|
||||||
}
|
|
||||||
else if (Panel->SplitDirection == PanelSplit_Vertical)
|
|
||||||
{
|
|
||||||
r32 SplitX = GSLerp(PanelMin.x, PanelMax.x, Panel->SplitPercent);
|
|
||||||
DrawPanelOrRecurse(&Panel->Left->Panel, PanelMin, v2{SplitX, PanelMax.y}, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
|
|
||||||
DrawPanelOrRecurse(&Panel->Right->Panel, v2{SplitX, PanelMin.y}, PanelMax, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
DrawAllPanels(panel_layout PanelLayout, v2 WindowMin, v2 WindowMax, 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, WindowMin, WindowMax, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
|
|
||||||
}
|
|
|
@ -1,15 +1,17 @@
|
||||||
|
/*
|
||||||
|
File: foldhaus_panel.cpp
|
||||||
|
Description: a system for laying out panels on a screen
|
||||||
|
Author: Peter Slattery
|
||||||
|
Creation Date: 2019-12-26
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
Include this file in ONE file in your project.
|
||||||
|
Define both RenderPanel and SetPanelDefinitionExternal
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
typedef struct panel panel;
|
typedef struct panel panel;
|
||||||
|
|
||||||
#define PANEL_INIT_PROC(name) void name(panel* Panel)
|
|
||||||
typedef PANEL_INIT_PROC(panel_init_proc);
|
|
||||||
|
|
||||||
#define PANEL_CLEANUP_PROC(name) void name(panel* Panel)
|
|
||||||
typedef PANEL_CLEANUP_PROC(panel_cleanup_proc);
|
|
||||||
|
|
||||||
#define PANEL_RENDER_PROC(name) void name(panel Panel, v2 PanelMin, v2 PanelMax, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
|
|
||||||
typedef PANEL_RENDER_PROC(panel_render_proc);
|
|
||||||
|
|
||||||
enum panel_split_direction
|
enum panel_split_direction
|
||||||
{
|
{
|
||||||
PanelSplit_NoSplit,
|
PanelSplit_NoSplit,
|
||||||
|
@ -23,9 +25,8 @@ typedef struct panel_entry panel_entry;
|
||||||
|
|
||||||
struct panel
|
struct panel
|
||||||
{
|
{
|
||||||
panel_render_proc* Render;
|
s32 PanelDefinitionIndex;
|
||||||
panel_cleanup_proc* Cleanup;
|
|
||||||
|
|
||||||
panel_split_direction SplitDirection;
|
panel_split_direction SplitDirection;
|
||||||
r32 SplitPercent;
|
r32 SplitPercent;
|
||||||
|
|
||||||
|
@ -63,11 +64,259 @@ panel_entry Panels[PANELS_MAX];
|
||||||
panel_entry FreeList;
|
panel_entry FreeList;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct panel_definition
|
internal void SetPanelDefinitionExternal(panel* Panel, s32 OldPanelDefinitionIndex, s32 NewPanelDefinitionIndex);
|
||||||
|
internal void RenderPanel(panel* Panel, v2 PanelMin, v2 PanelMax, v2 WindowMin, v2 WindowMax, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse);
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////
|
||||||
|
//
|
||||||
|
// Book-Keeping
|
||||||
|
//
|
||||||
|
/////////////////////////////////
|
||||||
|
|
||||||
|
internal void
|
||||||
|
InitializePanelLayout(panel_layout* Layout)
|
||||||
{
|
{
|
||||||
char* PanelName;
|
Layout->FreeList.Free.Next = &Layout->FreeList;
|
||||||
s32 PanelNameLength;
|
}
|
||||||
panel_init_proc* Init;
|
|
||||||
panel_cleanup_proc* Cleanup;
|
internal panel_entry*
|
||||||
panel_render_proc* Render;
|
TakeNewPanelEntry(panel_layout* Layout)
|
||||||
};
|
{
|
||||||
|
panel_entry* FreeEntry = 0;
|
||||||
|
if (Layout->FreeList.Free.Next != &Layout->FreeList)
|
||||||
|
{
|
||||||
|
FreeEntry = Layout->FreeList.Free.Next;
|
||||||
|
Layout->FreeList.Free.Next = FreeEntry->Free.Next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert(Layout->PanelsUsed < PANELS_MAX);
|
||||||
|
FreeEntry = Layout->Panels + Layout->PanelsUsed++;
|
||||||
|
}
|
||||||
|
return FreeEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal panel*
|
||||||
|
TakeNewPanel(panel_layout* Layout)
|
||||||
|
{
|
||||||
|
panel* Result = 0;
|
||||||
|
panel_entry* FreeEntry = TakeNewPanelEntry(Layout);
|
||||||
|
Result = &FreeEntry->Panel;
|
||||||
|
|
||||||
|
*Result = {0};
|
||||||
|
Result->PanelDefinitionIndex = -1;
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
FreePanelEntry(panel_entry* Entry, panel_layout* Layout)
|
||||||
|
{
|
||||||
|
Assert(Entry >= Layout->Panels && Entry <= Layout->Panels + PANELS_MAX);
|
||||||
|
Entry->Panel = {0};
|
||||||
|
Entry->Free.Next = Layout->FreeList.Free.Next;
|
||||||
|
Layout->FreeList.Free.Next = Entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
FreePanelAtIndex(s32 Index, panel_layout* Layout)
|
||||||
|
{
|
||||||
|
Assert(Index > 0 && Index < (s32)Layout->PanelsUsed);
|
||||||
|
panel_entry* EntryToFree = Layout->Panels + Index;
|
||||||
|
EntryToFree->Free.Next = Layout->FreeList.Free.Next;
|
||||||
|
Layout->FreeList.Free.Next = EntryToFree;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
SplitPanelVertically(panel* Parent, r32 Percent, v2 ParentMin, v2 ParentMax, panel_layout* Layout)
|
||||||
|
{
|
||||||
|
r32 SplitX = GSLerp(ParentMin.x, ParentMax.x, Percent);
|
||||||
|
if (SplitX > ParentMin.x && SplitX < ParentMax.x)
|
||||||
|
{
|
||||||
|
Parent->SplitDirection = PanelSplit_Vertical;
|
||||||
|
Parent->SplitPercent = Percent;
|
||||||
|
|
||||||
|
Parent->Left = TakeNewPanelEntry(Layout);
|
||||||
|
Parent->Left->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex;
|
||||||
|
|
||||||
|
Parent->Right = TakeNewPanelEntry(Layout);
|
||||||
|
Parent->Right->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
SplitPanelHorizontally(panel* Parent, r32 Percent, v2 ParentMin, v2 ParentMax, panel_layout* Layout)
|
||||||
|
{
|
||||||
|
r32 SplitY = GSLerp(ParentMin.y, ParentMax.y, Percent);
|
||||||
|
if (SplitY > ParentMin.y && SplitY < ParentMax.y)
|
||||||
|
{
|
||||||
|
Parent->SplitDirection = PanelSplit_Horizontal;
|
||||||
|
Parent->SplitPercent = Percent;
|
||||||
|
|
||||||
|
Parent->Bottom = TakeNewPanelEntry(Layout);
|
||||||
|
Parent->Bottom->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex;
|
||||||
|
|
||||||
|
Parent->Top = TakeNewPanelEntry(Layout);
|
||||||
|
Parent->Top->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_layout* Layout)
|
||||||
|
{
|
||||||
|
panel_entry* LeftChild = Parent->Left;
|
||||||
|
panel_entry* RightChild = Parent->Right;
|
||||||
|
|
||||||
|
*Parent = PanelEntryToKeep->Panel;
|
||||||
|
Parent->SplitDirection = PanelSplit_NoSplit;
|
||||||
|
|
||||||
|
FreePanelEntry(LeftChild, Layout);
|
||||||
|
FreePanelEntry(RightChild, Layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
SetPanelDefinition(panel* Panel, s32 NewDefinitionIndex)
|
||||||
|
{
|
||||||
|
s32 OldDefinitionIndex = Panel->PanelDefinitionIndex;
|
||||||
|
Panel->PanelDefinitionIndex = NewDefinitionIndex;
|
||||||
|
SetPanelDefinitionExternal(Panel, OldDefinitionIndex, NewDefinitionIndex);
|
||||||
|
}
|
||||||
|
/////////////////////////////////
|
||||||
|
//
|
||||||
|
// Rendering And Interaction
|
||||||
|
//
|
||||||
|
/////////////////////////////////
|
||||||
|
|
||||||
|
internal void
|
||||||
|
HandleMousePanelInteractionOrRecurse(panel* Panel, v2 PanelMin, v2 PanelMax, 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, PanelMin, PanelMin + 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 - PanelMin.x) / (PanelMax.x - PanelMin.x);
|
||||||
|
SplitPanelVertically(Panel, XPercent, PanelMin, PanelMax, PanelLayout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r32 YPercent = (Mouse.Pos.y - PanelMin.y) / (PanelMax.y - PanelMin.y);
|
||||||
|
SplitPanelHorizontally(Panel, YPercent, PanelMin, PanelMax, PanelLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Panel->SplitDirection == PanelSplit_Horizontal)
|
||||||
|
{
|
||||||
|
r32 SplitY = GSLerp(PanelMin.y, PanelMax.y, Panel->SplitPercent);
|
||||||
|
r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.y - SplitY);
|
||||||
|
if (ClickDistanceFromSplit < PanelEdgeClickMaxDistance)
|
||||||
|
{
|
||||||
|
r32 NewSplitY = Mouse.Pos.y;
|
||||||
|
if (NewSplitY <= PanelMin.y)
|
||||||
|
{
|
||||||
|
ConsolidatePanelsKeepOne(Panel, Panel->Top, PanelLayout);
|
||||||
|
}
|
||||||
|
else if (NewSplitY >= PanelMax.y)
|
||||||
|
{
|
||||||
|
ConsolidatePanelsKeepOne(Panel, Panel->Bottom, PanelLayout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Panel->SplitPercent = (NewSplitY - PanelMin.y) / (PanelMax.y - PanelMin.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HandleMousePanelInteractionOrRecurse(&Panel->Bottom->Panel, PanelMin, v2{PanelMax.x, SplitY}, PanelLayout, Mouse);
|
||||||
|
HandleMousePanelInteractionOrRecurse(&Panel->Top->Panel, v2{PanelMin.x, SplitY}, PanelMax, PanelLayout, Mouse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Panel->SplitDirection == PanelSplit_Vertical)
|
||||||
|
{
|
||||||
|
r32 SplitX = GSLerp(PanelMin.x, PanelMax.x, Panel->SplitPercent);
|
||||||
|
r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.x - SplitX);
|
||||||
|
if (ClickDistanceFromSplit < PanelEdgeClickMaxDistance)
|
||||||
|
{
|
||||||
|
r32 NewSplitX = Mouse.Pos.x;
|
||||||
|
if (NewSplitX <= PanelMin.x)
|
||||||
|
{
|
||||||
|
ConsolidatePanelsKeepOne(Panel, Panel->Right, PanelLayout);
|
||||||
|
}
|
||||||
|
else if (NewSplitX >= PanelMax.x)
|
||||||
|
{
|
||||||
|
ConsolidatePanelsKeepOne(Panel, Panel->Left, PanelLayout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Panel->SplitPercent = (NewSplitX - PanelMin.x) / (PanelMax.x - PanelMin.x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HandleMousePanelInteractionOrRecurse(&Panel->Left->Panel, PanelMin, v2{SplitX, PanelMax.y}, PanelLayout, Mouse);
|
||||||
|
HandleMousePanelInteractionOrRecurse(&Panel->Right->Panel, v2{SplitX, PanelMin.y}, PanelMax, PanelLayout, Mouse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
HandleMousePanelInteraction(panel_layout* PanelLayout, v2 WindowMin, v2 WindowMax, mouse_state Mouse)
|
||||||
|
{
|
||||||
|
r32 PanelEdgeClickMaxDistance = 4;
|
||||||
|
|
||||||
|
if (MouseButtonTransitionedUp(Mouse.LeftButtonState))
|
||||||
|
{
|
||||||
|
Assert(PanelLayout->PanelsUsed > 0);
|
||||||
|
panel* FirstPanel = &PanelLayout->Panels[0].Panel;
|
||||||
|
HandleMousePanelInteractionOrRecurse(FirstPanel, WindowMin, WindowMax, 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, v2 PanelMin, v2 PanelMax, v2 WindowMin, v2 WindowMax, render_command_buffer* RenderBuffer, interface_config Interface, mouse_state Mouse, app_state* State, context Context)
|
||||||
|
{
|
||||||
|
if (Panel->SplitDirection == PanelSplit_NoSplit)
|
||||||
|
{
|
||||||
|
RenderPanel(Panel, PanelMin, PanelMax, WindowMin, WindowMax, RenderBuffer, State, Context, Mouse);
|
||||||
|
v4 BorderColor = v4{0, 1, 1, 1};
|
||||||
|
if (PointIsInRange(Mouse.Pos, PanelMin, PanelMax))
|
||||||
|
{
|
||||||
|
BorderColor = v4{1, 0, 1, 1};
|
||||||
|
}
|
||||||
|
|
||||||
|
PushRenderOrthographic(RenderBuffer, WindowMin.x, WindowMin.y, WindowMax.x, WindowMax.y);
|
||||||
|
DrawPanelBorder(*Panel, PanelMin, PanelMax, BorderColor, RenderBuffer);
|
||||||
|
}
|
||||||
|
else if (Panel->SplitDirection == PanelSplit_Horizontal)
|
||||||
|
{
|
||||||
|
r32 SplitY = GSLerp(PanelMin.y, PanelMax.y, Panel->SplitPercent);
|
||||||
|
DrawPanelOrRecurse(&Panel->Bottom->Panel, PanelMin, v2{PanelMax.x, SplitY}, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
|
||||||
|
DrawPanelOrRecurse(&Panel->Top->Panel, v2{PanelMin.x, SplitY}, PanelMax, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
|
||||||
|
}
|
||||||
|
else if (Panel->SplitDirection == PanelSplit_Vertical)
|
||||||
|
{
|
||||||
|
r32 SplitX = GSLerp(PanelMin.x, PanelMax.x, Panel->SplitPercent);
|
||||||
|
DrawPanelOrRecurse(&Panel->Left->Panel, PanelMin, v2{SplitX, PanelMax.y}, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
|
||||||
|
DrawPanelOrRecurse(&Panel->Right->Panel, v2{SplitX, PanelMin.y}, PanelMax, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
DrawAllPanels(panel_layout PanelLayout, v2 WindowMin, v2 WindowMax, 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, WindowMin, WindowMax, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
// TODO
|
||||||
|
// [] - Moving animation blocks
|
||||||
|
// [] - dragging beginning and end of time blocks
|
||||||
|
// [] - creating a timeblock with a specific animation
|
||||||
|
// [x] - play, pause, stop,
|
||||||
|
// [] - setting the start and end of the animation system
|
||||||
|
// [] - displaying multiple layers
|
||||||
|
// [] -
|
||||||
|
|
||||||
PANEL_INIT_PROC(AnimationTimeline_Init)
|
PANEL_INIT_PROC(AnimationTimeline_Init)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue