vn/code/vn_workspace.cpp

817 lines
29 KiB
C++
Raw Normal View History

2023-06-17 17:00:55 +00:00
#include "vn_workspace_view.cpp"
#include "vn_workspace_editor.cpp"
2023-07-19 15:09:41 +00:00
#include "vn_workspace_text_editor.cpp"
2023-06-17 17:00:55 +00:00
#include "vn_workspace_commands.cpp"
2023-07-19 15:09:41 +00:00
//- sixten: State management
per_thread workspace *ThreadLocal_Workspace;
static void Workspace_SetState(workspace *Workspace)
{
ThreadLocal_Workspace = Workspace;
}
static workspace *Workspace_GetState(void)
{
return(ThreadLocal_Workspace);
}
static memory_arena *Workspace_FrameArena(void)
{
return(ThreadLocal_Workspace->FrameArena);
}
2023-06-17 17:00:55 +00:00
//- sixten: Commands
2023-07-19 15:09:41 +00:00
static void Workspace_IssueCommand(workspace_command_sig *Sig, u64 Argument = 0)
2023-06-17 17:00:55 +00:00
{
workspace_command *Result = 0;
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
if(Workspace->FirstFreeCommand)
{
Result = Workspace->FirstFreeCommand;
DLLRemove(Workspace->FirstFreeCommand, Workspace->LastFreeCommand, Result);
}
if(!Result)
{
2023-07-19 15:09:41 +00:00
Result = PushStruct(Workspace->CommandArena, workspace_command);
2023-06-17 17:00:55 +00:00
}
Result->Command = Sig;
Result->Argument = Argument;
DLLInsertLast(Workspace->FirstCommand, Workspace->LastCommand, Result);
}
2023-07-19 15:09:41 +00:00
static void Workspace_ProcessCommands(void)
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
workspace_command *Command = Workspace->FirstCommand;
while(Command != 0)
{
2023-07-19 15:09:41 +00:00
Command->Command(Command->Argument);
2023-06-17 17:00:55 +00:00
workspace_command *ToRemove = Command;
Command = Command->Next;
DLLRemove(Workspace->FirstCommand, Workspace->LastCommand, ToRemove);
2023-06-21 16:59:36 +00:00
Fill(ToRemove, 0, sizeof(workspace_command));
2023-06-17 17:00:55 +00:00
DLLInsertLast(Workspace->FirstFreeCommand, Workspace->LastFreeCommand, ToRemove);
}
}
2023-07-19 15:09:41 +00:00
static void Workspace_ProcessKeyBinds()
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
platform_event_list *EventList = Workspace->EventList;
for(platform_event *Event = EventList->First;
Event != 0;
Event = Event->Next)
{
if(Event->Type == PlatformEvent_Press)
{
for(s32 KeybindIndex = 0;
KeybindIndex < Workspace->KeybindCount;
++KeybindIndex)
{
workspace_keybind *Keybind = Workspace->Keybinds + KeybindIndex;
if((Event->Key == Keybind->Key) && (Event->Modifiers == Keybind->Modifiers))
{
2023-07-19 15:09:41 +00:00
Workspace_IssueCommand(Keybind->Command, Keybind->Argument);
2023-06-17 17:00:55 +00:00
}
}
}
}
}
//- sixten: Builder code
2023-07-19 15:09:41 +00:00
static ui_signal Workspace_BuildToolbarButton(char *Text, toolbar_menu Menu)
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
UI_SetNextWidth(UI_TextContent(20, 1));
UI_SetNextHeight(UI_Pixels(30, 1));
UI_SetNextCornerRadius(4);
UI_SetNextBackgroundColor(ColorFromHex(0x252728FF));
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
UI_BoxFlag_DrawBorder |
UI_BoxFlag_DrawText |
UI_BoxFlag_HotAnimation |
UI_BoxFlag_ActiveAnimation |
UI_BoxFlag_Clickable,
Text);
ui_signal Signal = UI_SignalFromBox(Box);
if(Workspace->Menu == ToolbarMenu_None)
{
if(Signal.Clicked)
{
Workspace->Menu = Menu;
Workspace->MenuTransition = 0;
}
}
else
{
if(Signal.Hovering)
{
if(Workspace->Menu != Menu)
{
Workspace->MenuTransition = 0;
}
Workspace->Menu = Menu;
Workspace->MenuP = V2(Box->Rect.Min.x, Box->Rect.Max.y);
}
}
return(Signal);
}
static ui_signal Workspace_BuildMenuItem(u32 Icon, char *Text, char *Shortcut)
{
temporary_memory Scratch = GetScratch(0, 0);
UI_SetNextLayoutAxis(Axis2_X);
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
UI_BoxFlag_DrawBorder |
UI_BoxFlag_HotAnimation |
UI_BoxFlag_ActiveAnimation |
UI_BoxFlag_Clickable,
"Menu Item %s", Text);
UI_Parent(Box)
{
UI_Width(UI_Pixels(25, 1)) UI_Font(Font_Icons) UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Icon);
UI_Width(UI_TextContent(5, 1)) UI_MakeBoxF(UI_BoxFlag_DrawText, Text);
UI_Spacer(UI_Percent(1, 0));
UI_TextColor(V4(0.5, 0.5, 0.5, 1.0)) UI_Width(UI_TextContent(15, 1))
UI_MakeBoxF(UI_BoxFlag_DrawText, Shortcut);
}
ReleaseScratch(Scratch);
ui_signal Signal = UI_SignalFromBox(Box);
return(Signal);
}
2023-07-19 15:09:41 +00:00
static void Workspace_BuildToolbar()
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
UI_SetNextLayoutAxis(Axis2_X);
UI_SetNextHeight(UI_Pixels(30, 1));
UI_SetNextBackgroundColor(Theme_BackgroundColor);
ui_box *ToolbarBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder,
"Workspace Toolbar");
UI_Parent(ToolbarBox)
{
2023-07-19 15:09:41 +00:00
Workspace_BuildToolbarButton("Panel", ToolbarMenu_Panel);
Workspace_BuildToolbarButton("View", ToolbarMenu_View);
Workspace_BuildToolbarButton("Window", ToolbarMenu_Window);
2023-06-17 17:00:55 +00:00
}
if(Workspace->Menu != ToolbarMenu_None)
{
r32 MenuTransition = Workspace->MenuTransition;
UI_SetNextTooltip();
UI_SetNextFixedX(Workspace->MenuP.x);
UI_SetNextFixedY(Workspace->MenuP.y);
UI_SetNextLayoutAxis(Axis2_Y);
UI_SetNextWidth(UI_Pixels(250, 1));
UI_SetNextHeight(UI_ChildrenSum(MenuTransition, 1));
ui_box *Dropdown = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
UI_BoxFlag_DrawDropShadow |
UI_BoxFlag_Clip |
UI_BoxFlag_FloatingX |
UI_BoxFlag_FloatingY,
"Workspace Dropdown");
UI_Parent(Dropdown)
UI_BackgroundColor(V4(0.25, 0.25, 0.25, 1))
UI_BorderColor(V4(0.45, 0.45, 0.45, 1))
UI_CornerRadius(2)
UI_Size(UI_Percent(1, 1), UI_Pixels(25, 1))
{
if(Workspace->Menu == ToolbarMenu_Panel)
{
if(Workspace_BuildMenuItem(FontIcon_ResizeHorizontal, "Split Horizontal", "Ctrl + P").Clicked)
{
2023-07-19 15:09:41 +00:00
Workspace_IssueCommand(Workspace_Command_SplitPanelHorizontal);
2023-06-17 17:00:55 +00:00
Workspace->Menu = ToolbarMenu_None;
}
if(Workspace_BuildMenuItem(FontIcon_ResizeVertical, "Split Vertical", "Ctrl + L").Clicked)
{
2023-07-19 15:09:41 +00:00
Workspace_IssueCommand(Workspace_Command_SplitPanelVertical);
2023-06-17 17:00:55 +00:00
Workspace->Menu = ToolbarMenu_None;
}
}
else if(Workspace->Menu == ToolbarMenu_View)
{
workspace_panel *CurrentPanel = Workspace->CurrentPanel;
2023-07-19 15:09:41 +00:00
// sixten(TODO): The views should be created at the end of the frame i.e. this should be done via
// commmands instead. (since we want all things that deals with major state changes to occur at a fixed
// point in our programs execution)
2023-06-17 17:00:55 +00:00
if(Workspace_BuildMenuItem(FontIcon_None, "Welcome", "").Clicked)
{
2023-06-17 21:06:25 +00:00
Workspace_CreateNewView(Workspace_View_Startup, CurrentPanel);
2023-06-17 17:00:55 +00:00
Workspace->Menu = ToolbarMenu_None;
}
if(Workspace_BuildMenuItem(FontIcon_Pencil, "Script Editor", "Ctrl + O").Clicked)
2023-06-17 17:00:55 +00:00
{
Workspace_CreateNewView(Workspace_View_TextEditor, CurrentPanel);
2023-06-27 14:14:28 +00:00
Workspace->Menu = ToolbarMenu_None;
}
2023-06-17 17:00:55 +00:00
if(Workspace_BuildMenuItem(FontIcon_Wrench, "Settings", "").Clicked)
{
2023-06-17 21:06:25 +00:00
Workspace_CreateNewView(Workspace_View_Settings, CurrentPanel);
2023-06-17 17:00:55 +00:00
Workspace->Menu = ToolbarMenu_None;
}
}
else if(Workspace->Menu == ToolbarMenu_Window)
{
if(Workspace_BuildMenuItem(FontIcon_WindowMaximize, "ToggleFullscreen", "Alt + Enter").Clicked)
{
Platform.ToggleFullscreen();
Workspace->Menu = ToolbarMenu_None;
}
}
AnimationCurve_AnimateValueDirect(1, 0.1, &Workspace->MenuTransition);
}
// sixten: Unless the mouse press was captured, we close the menu.
if(Platform_KeyPress(Workspace->EventList, Key_MouseLeft))
{
Workspace->Menu = ToolbarMenu_None;
}
}
}
//- sixten: Panels
2023-07-19 15:09:41 +00:00
static workspace_panel *Workspace_CreateNewPanel(workspace_panel *Parent)
2023-06-17 17:00:55 +00:00
{
workspace_panel *Result = 0;
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
if(DLLIsEmpty(Workspace->FirstFreePanel))
{
2023-07-19 15:09:41 +00:00
Result = PushStruct(Workspace->PanelArena, workspace_panel);
2023-06-17 17:00:55 +00:00
}
else
{
Result = Workspace->FirstFreePanel;
DLLRemove(Workspace->FirstFreePanel, Workspace->LastFreePanel, Result);
*Result = {};
}
Result->Parent = Parent;
return(Result);
}
2023-07-19 15:09:41 +00:00
static void Workspace_DeletePanel(workspace_panel *Panel)
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
if(Workspace->CurrentPanel == Panel)
{
Workspace->CurrentPanel = 0;
}
*Panel = {};
DLLInsertLast(Workspace->FirstFreePanel, Workspace->LastFreePanel, Panel);
}
2023-07-19 15:09:41 +00:00
static void Workspace_SplitPanel(workspace_panel *Panel, axis2 Axis)
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
if(Panel)
{
workspace_panel *Parent = Panel->Parent;
if(Parent && (Parent->SplitAxis == Axis))
{
2023-07-19 15:09:41 +00:00
workspace_panel *NewPanel = Workspace_CreateNewPanel(Parent);
2023-06-17 17:00:55 +00:00
NewPanel->PercentOfParent = Panel->PercentOfParent = Panel->PercentOfParent * 0.5;
DLLInsert_NP(Parent->First, Parent->Last, Panel, NewPanel, Next, Prev);
}
else
{
2023-07-19 15:09:41 +00:00
workspace_panel *NewPanel = Workspace_CreateNewPanel(Panel);
2023-06-17 17:00:55 +00:00
NewPanel->FirstView = Panel->FirstView;
NewPanel->LastView = Panel->LastView;
// sixten: Update the parents of the children.
for(workspace_view *Child = NewPanel->FirstView;
Child != 0;
Child = Child->Next)
{
Child->Parent = NewPanel;
}
NewPanel->CurrentView = Panel->CurrentView;
NewPanel->PercentOfParent = 0.5;
DLLInsertLast(Panel->First, Panel->Last, NewPanel);
2023-07-19 15:09:41 +00:00
NewPanel = Workspace_CreateNewPanel(Panel);
2023-06-17 17:00:55 +00:00
NewPanel->PercentOfParent = 0.5;
DLLInsertLast(Panel->First, Panel->Last, NewPanel);
Panel->FirstView = 0;
Panel->LastView = 0;
Panel->CurrentView = 0;
Panel->SplitAxis = Axis;
if(Workspace->CurrentPanel == Panel)
{
Workspace->CurrentPanel = Panel->First;
}
}
}
}
2023-07-19 15:09:41 +00:00
inline void Workspace_BeginDrag(workspace_drag_payload *Payload)
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
// sixten(TODO): Right now, if you spam-click a draggable item, you can trigger this
// assertion. I don't know what I want to do about this at the moment, but I'm sure
// future me will have a soulution at hand. ^.^
Assert(Workspace->DragPayloadState == Workspace_DragPayload_Inactive);
Workspace->DragPayload = *Payload;
Workspace->DragPayloadState = Workspace_DragPayload_Active;
}
2023-07-19 15:09:41 +00:00
inline b32 Workspace_GetDragPayload(workspace_drag_payload *Dest)
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
b32 Result = (Workspace->DragPayloadState != Workspace_DragPayload_Inactive);
*Dest = Workspace->DragPayload;
return(Result);
}
2023-07-19 15:09:41 +00:00
static void Workspace_BuildTabItem(workspace_panel *Panel, workspace_view *View)
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
b32 ViewIsCurrent = (Panel->CurrentView == View);
b32 PanelIsCurrent = (Workspace->CurrentPanel == Panel);
string Name = Workspace_GetViewName(View);
v4 BackgroundColor = ViewIsCurrent ? (PanelIsCurrent ? Theme_HighlightBorderColor : Theme_BorderColor) : ColorFromHex(0x353738FF);
UI_SetNextWidth(UI_ChildrenSum(1, 1));
UI_SetNextHeight(UI_Percent(1, 1));
UI_SetNextBackgroundColor(BackgroundColor);
UI_SetNextBorderColor(LinearBlend(UI_TopBackgroundColor(), Color_Grey, 0.5));
UI_SetNextLayoutAxis(Axis2_X);
UI_SetNextCornerRadius(0.0);
ui_box *TabBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
UI_BoxFlag_DrawDropShadow |
UI_BoxFlag_HotAnimation |
UI_BoxFlag_ActiveAnimation |
UI_BoxFlag_Clickable,
"Workspace Panel Tab Item %S#%p", Name, View);
UI_Parent(TabBox)
UI_Padding(UI_Pixels(5, 1))
{
UI_Size(UI_TextContent(1, 1), UI_Percent(1, 1)) UI_Label(Name);
UI_Spacer(UI_Pixels(5, 1));
// sixten: Build close button
{
UI_SetNextFont(Font_Icons);
UI_SetNextSize(UI_TextContent(1, 1), UI_Percent(1, 1));
ui_box *CloseBox = UI_MakeBoxF(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, "%U", FontIcon_Cancel);
CloseBox->TextColor = LinearBlend(TabBox->BackgroundColor, Color_Black,
0.3 - CloseBox->HotTransition*0.8);
ui_signal Signal = UI_SignalFromBox(CloseBox);
if(Signal.Clicked)
{
DLLRemove(Panel->FirstView, Panel->LastView, View);
if(ViewIsCurrent)
{
Panel->CurrentView = Panel->FirstView;
}
// sixten(TODO): Issue a "DeleteView" command.
}
}
}
ui_signal Signal = UI_SignalFromBox(TabBox);
if(Signal.Clicked)
{
Workspace->CurrentPanel = Panel;
Panel->CurrentView = View;
}
2023-07-19 15:09:41 +00:00
// sixten: Handle dragging the view.
2023-06-17 17:00:55 +00:00
if(Signal.Dragging)
{
if(Signal.Pressed)
{
workspace_drag_payload Payload = {};
Payload.View = View;
Payload.Key = TabBox->Key;
2023-07-19 15:09:41 +00:00
Workspace_BeginDrag(&Payload);
2023-06-17 17:00:55 +00:00
}
}
}
2023-07-19 15:09:41 +00:00
static void Workspace_BuildPanelHeader(workspace_panel *Panel)
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
UI_SetNextLayoutAxis(Axis2_X);
UI_SetNextBackgroundColor(ColorFromHex(0x252728FF));
UI_SetNextCornerRadius(0);
UI_SetNextSize(UI_Percent(1, 1), UI_Pixels(30, 1));
UI_Parent(UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_Clip, "Workspace Panel Header"))
{
for(workspace_view *View = Panel->FirstView;
View != 0;
View = View->Next)
{
2023-07-19 15:09:41 +00:00
Workspace_BuildTabItem(Panel, View);
2023-06-17 17:00:55 +00:00
}
// sixten: Panel Close Button
if(Panel != Workspace->RootPanel)
{
2023-07-19 15:09:41 +00:00
UI_Spacer(UI_Percent(1, 0));
2023-06-17 17:00:55 +00:00
UI_SetNextSize(UI_Pixels(30, 1), UI_Pixels(30, 1));
UI_SetNextFont(Font_Icons);
UI_SetNextBorderColor(ColorFromHex(0xA6514288));
UI_SetNextBackgroundColor(ColorFromHex(0xC24630BB));
UI_SetNextCornerRadius(4);
ui_box *CloseBox = UI_MakeBoxF(UI_BoxFlag_HotAnimation |
UI_BoxFlag_ActiveAnimation |
//UI_BoxFlag_DrawBackground |
//UI_BoxFlag_DrawBorder |
UI_BoxFlag_DrawText |
UI_BoxFlag_Clickable,
"%U", FontIcon_Cancel);
ui_signal Signal = UI_SignalFromBox(CloseBox);
if(Signal.Clicked)
{
2023-07-19 15:09:41 +00:00
Workspace_IssueCommand(Workspace_Command_ClosePanel, PointerToU64(Panel));
2023-06-17 17:00:55 +00:00
}
}
UI_Spacer(UI_Pixels(2, 1));
}
}
2023-07-19 15:09:41 +00:00
static void Workspace_BuildPanel(workspace_panel *Panel)
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
2023-06-17 17:00:55 +00:00
// sixten: Fill remaining percent of parent.
workspace_panel *Parent = Panel->Parent;
if(Parent && Panel != Parent->First)
{
r32 TotalOfParent = 0;
for(workspace_panel *Child = Parent->First;
Child != 0;
Child = Child->Next)
{
if(Child != Panel)
{
TotalOfParent += Child->PercentOfParent;
}
}
Panel->PercentOfParent = 1.0 - TotalOfParent;
}
ui_box *PanelBox = UI_MakeBoxF(0, "Workspace Panel %p", Panel);
UI_Parent(PanelBox)
{
if(DLLIsEmpty(Panel->First))
{
2023-07-19 15:09:41 +00:00
Workspace_BuildPanelHeader(Panel);
2023-06-17 17:00:55 +00:00
// sixten: Main body
{
b32 PanelIsCurrent = (Workspace->CurrentPanel == Panel);
UI_PushSize(UI_Percent(1, 0), UI_Percent(1, 0));
r32 HighlightTransition = AnimationCurve_AnimateValueF(PanelIsCurrent, 0, 0.25, "Workspace Panel Highlight %p", Panel);
UI_SetNextBorderColor(LinearBlend(Theme_BorderColor, Theme_HighlightBorderColor, HighlightTransition));
UI_SetNextBackgroundColor(Theme_BackgroundColor);
ui_box *BodyBox = UI_MakeBoxF(UI_BoxFlag_DrawBorder |
UI_BoxFlag_DrawBackground |
UI_BoxFlag_Clip |
UI_BoxFlag_Clickable,
"Workspace Panel Body");
UI_Parent(BodyBox)
{
if(Panel->FirstView)
{
if(!Panel->CurrentView)
{
Panel->CurrentView = Panel->FirstView;
}
}
else
{
2023-06-27 14:14:28 +00:00
UI_Column() UI_Padding(UI_Percent(1, 0))
UI_Height(UI_ChildrenSum(1, 1)) UI_Row() UI_Padding(UI_Percent(1, 0))
2023-06-17 17:00:55 +00:00
{
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
{
UI_LabelF("- empty -");
}
}
}
if(Panel->CurrentView)
{
ui_key CurrentActive = UI_GetActive();
2023-07-19 15:09:41 +00:00
Workspace_BuildView(Panel->CurrentView);
2023-06-17 17:00:55 +00:00
if(!AreEqual(CurrentActive, UI_GetActive()))
{
Workspace->CurrentPanel = Panel;
}
}
// sixten: Draw dragged view overlay.
{
workspace_drag_payload Payload;
2023-07-19 15:09:41 +00:00
b32 DragActive = Workspace_GetDragPayload(&Payload);
2023-06-17 17:00:55 +00:00
b32 OverlayActive = (DragActive && (Payload.View->Parent != Panel) &&
InRange(BodyBox->Rect, UI_GetState()->MouseP));
if(OverlayActive && Workspace->DragPayloadState == Workspace_DragPayload_Released)
{
// sixten(NOTE): I need to be careful here. If something else sees that a payload has
// been released and tries to act upon on it may lead to unwanted behaviour. Just
// keep that in mind.
// sixten(NOTE): On that previous note, I could just:
Workspace->DragPayloadState = Workspace_DragPayload_Inactive;
// sixten(TODO): Pull out the code below into separate functions.
// sixten: Move view
workspace_view *View = Payload.View;
{
workspace_panel *OldParent = View->Parent;
b32 ViewWasCurrent = ((OldParent->CurrentView == View) &&
(Workspace->CurrentPanel == OldParent));
// sixten: Detatch view
{
Assert(OldParent);
if(OldParent->CurrentView == View)
{
OldParent->CurrentView = 0;
}
DLLRemove(OldParent->FirstView, OldParent->LastView, View);
}
View->Parent = Panel;
DLLInsertLast(Panel->FirstView, Panel->LastView, View);
if(ViewWasCurrent)
{
Workspace->CurrentPanel = Panel;
Panel->CurrentView = View;
}
}
}
r32 OverlayTransition = AnimationCurve_AnimateValueF(OverlayActive, 0, 0.25, "Panel Drag Overlay %p", Panel);
v4 OverlayColor = LinearBlend(Color_Grey, Theme_HighlightBorderColor, 0.75);
OverlayColor.a = 0.5*OverlayTransition;
UI_SetNextBackgroundColor(OverlayColor);
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 1));
UI_MakeBoxF(UI_BoxFlag_DrawBackground |
UI_BoxFlag_FloatingX |
UI_BoxFlag_FloatingY,
"Workspace Panel Drag Hover");
}
}
ui_signal Signal = UI_SignalFromBox(BodyBox);
if(Signal.Pressed)
{
Workspace->CurrentPanel = Panel;
}
UI_PopSize();
}
}
else
{
UI_SetNextSize(UI_Percent(1, 0), UI_Percent(1, 0));
UI_SetNextLayoutAxis(Panel->SplitAxis);
UI_Parent(UI_MakeBoxF(0, ""))
{
s32 ChildCount = 0;
for(workspace_panel *Child = Panel->First;
Child != 0;
Child = Child->Next)
{
++ChildCount;
}
v2 PanelDim = DimOfRange(PanelBox->Rect);
r32 PaddingSize = 5;
r32 PaddedSpace = (ChildCount - 1)*PaddingSize;
r32 PercentPaddedSpace = PaddedSpace / PanelDim.E[Panel->SplitAxis];
r32 SizeScalar = 1.0 - PercentPaddedSpace;
for(workspace_panel *Child = Panel->First;
Child != 0;
Child = Child->Next)
{
UI_SetNextAxisSize(Panel->SplitAxis, UI_Percent(Child->PercentOfParent*SizeScalar, 0));
UI_SetNextAxisSize(Opposite(Panel->SplitAxis), UI_Percent(1, 0));
2023-07-19 15:09:41 +00:00
Workspace_BuildPanel(Child);
2023-06-17 17:00:55 +00:00
2023-07-19 15:09:41 +00:00
// sixten: Create drag area
2023-06-17 17:00:55 +00:00
if(Child->Next)
{
UI_SetNextAxisSize(Panel->SplitAxis, UI_Pixels(PaddingSize, 1));
UI_SetNextAxisSize(Opposite(Panel->SplitAxis), UI_Percent(1, 0));
ui_box *DragBox = UI_MakeBoxF(UI_BoxFlag_Clickable, "Workspace Panel Drag %p", Child);
ui_signal Signal = UI_SignalFromBox(DragBox);
if(Signal.Hovering || Signal.Dragging)
{
Platform.SetCursor((Panel->SplitAxis == Axis2_X) ?
PlatformCursor_ArrowHorizontal :
PlatformCursor_ArrowVertical);
}
if(Signal.Dragging)
{
if(Signal.Pressed)
{
UI_StoreDragR32(Child->PercentOfParent);
}
r32 Delta = Signal.DragDelta.E[Panel->SplitAxis]/PanelDim.E[Panel->SplitAxis];
r32 StartOffset = UI_GetDragR32();
r32 EndOffset = StartOffset + Delta;
Child->PercentOfParent = Clamp(EndOffset, 0.05, 0.95);
}
}
}
}
}
}
}
2023-07-19 15:09:41 +00:00
static void Workspace_BuildDragPayload()
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
workspace *Workspace = Workspace_GetState();
vn_input *Input = Workspace->Input;
2023-06-17 17:00:55 +00:00
workspace_drag_payload Payload;
2023-07-19 15:09:41 +00:00
if(Workspace_GetDragPayload(&Payload))
2023-06-17 17:00:55 +00:00
{
if(Workspace->DragPayloadState == Workspace_DragPayload_Released)
{
Workspace->DragPayloadState = Workspace_DragPayload_Inactive;
}
if(AreEqual(Payload.Key, UI_GetActive()))
{
workspace_view *DraggedView = Payload.View;
UI_Tooltip
{
UI_SetNextWidth(UI_TextContent(5, 1));
UI_SetNextHeight(UI_TextContent(5, 1));
UI_SetNextFixedX(Input->MouseP.x + 10);
UI_SetNextFixedY(Input->MouseP.y);
UI_MakeBox(UI_BoxFlag_DrawBorder |
UI_BoxFlag_DrawBackground |
UI_BoxFlag_DrawText |
UI_BoxFlag_FloatingX |
UI_BoxFlag_FloatingY,
Workspace_GetViewName(DraggedView));
}
}
else
{
if(Workspace->DragPayloadState == Workspace_DragPayload_Active)
{
Workspace->DragPayloadState = Workspace_DragPayload_Released;
}
}
}
}
//- sixten: Workspace
static void Workspace_Init(workspace *Workspace)
{
2023-07-19 15:09:41 +00:00
Workspace_SetState(Workspace);
Workspace->FrameArena = ArenaAllocate(Gigabytes(1));
2023-07-19 15:09:41 +00:00
Workspace->CommandArena = ArenaAllocate(Gigabytes(1));
Workspace->PanelArena = ArenaAllocate(Gigabytes(1));
Workspace->RootPanel = Workspace->CurrentPanel = Workspace_CreateNewPanel(0);
2023-06-17 17:00:55 +00:00
2023-07-19 15:09:41 +00:00
if(DEBUG_DebugSettings->ShowWelcomeMessage)
{
Workspace_CreateNewView(Workspace_View_Startup, Workspace->RootPanel);
}
2023-06-17 17:00:55 +00:00
// sixten: Setup keybinds
{
#define BIND_COMMAND(...) Workspace->Keybinds[Workspace->KeybindCount++] = {__VA_ARGS__}
BIND_COMMAND(Key_P, PlatformModifier_Ctrl, Workspace_Command_SplitPanelHorizontal);
BIND_COMMAND(Key_L, PlatformModifier_Ctrl, Workspace_Command_SplitPanelVertical);
2023-07-19 15:09:41 +00:00
BIND_COMMAND(Key_O, PlatformModifier_Ctrl, Workspace_Command_OpenView, Workspace_View_TextEditor);
2023-07-19 15:09:41 +00:00
#if VN_INTERNAL
BIND_COMMAND(Key_U, PlatformModifier_Ctrl|PlatformModifier_Shift, Workspace_Command_ToggleRenderUIDebugRects);
#endif
2023-06-17 17:00:55 +00:00
#undef BIND_COMMAND
}
}
2023-06-19 17:12:26 +00:00
static void Workspace_Update(workspace *Workspace, vn_render_commands *RenderCommands,
vn_input *Input, glyph_atlas *GlyphAtlas)
2023-06-17 17:00:55 +00:00
{
2023-07-19 15:09:41 +00:00
Workspace_SetState(Workspace);
ArenaClear(Workspace->FrameArena);
2023-07-19 15:09:41 +00:00
2023-06-19 17:12:26 +00:00
Workspace->Input = Input;
2023-06-17 17:00:55 +00:00
Workspace->EventList = Input->EventList;
2023-07-19 15:09:41 +00:00
// sixten: Make sure that a view/panel is always selected.
2023-06-17 17:00:55 +00:00
if(!Workspace->CurrentPanel)
{
Workspace->CurrentPanel = Workspace->RootPanel;
while(Workspace->CurrentPanel->First != 0)
{
Workspace->CurrentPanel = Workspace->CurrentPanel->First;
}
}
// sixten: Build the UI.
{
2023-07-19 15:09:41 +00:00
Workspace_BuildToolbar();
2023-06-17 17:00:55 +00:00
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 0));
2023-07-19 15:09:41 +00:00
Workspace_BuildPanel(Workspace->RootPanel);
2023-06-17 17:00:55 +00:00
2023-07-19 15:09:41 +00:00
Workspace_BuildDragPayload();
2023-06-17 17:00:55 +00:00
}
2023-07-19 15:09:41 +00:00
// sixten: Process the keybinds and commands.
Workspace_ProcessKeyBinds();
Workspace_ProcessCommands();
2023-06-17 17:00:55 +00:00
}