842 lines
30 KiB
C++
842 lines
30 KiB
C++
#include "vn_workspace_commands.cpp"
|
|
#include "vn_workspace_view.cpp"
|
|
#include "vn_workspace_file_lister.cpp"
|
|
#include "vn_workspace_text_editor.cpp"
|
|
#include "vn_workspace_nav_editor.cpp"
|
|
|
|
//- sixten: State management
|
|
per_thread workspace *ThreadLocal_Workspace;
|
|
|
|
static workspace_keybind Workspace_Keybinds[] =
|
|
{
|
|
{Key_P, PlatformModifier_Ctrl, W_Command_SplitPanelHorizontal},
|
|
{Key_L, PlatformModifier_Ctrl, W_Command_SplitPanelVertical},
|
|
|
|
{Key_O, PlatformModifier_Ctrl, W_Command_OpenView, W_ViewKind_FileLister},
|
|
{Key_P, PlatformModifier_Ctrl|PlatformModifier_Shift, W_Command_OpenView, W_ViewKind_Settings},
|
|
|
|
#if VN_INTERNAL
|
|
{Key_U, PlatformModifier_Ctrl|PlatformModifier_Shift, W_Command_ToggleRenderUIDebugRects},
|
|
#endif
|
|
};
|
|
|
|
static void W_SetState(workspace *Workspace)
|
|
{
|
|
ThreadLocal_Workspace = Workspace;
|
|
}
|
|
|
|
static workspace *W_GetState(void)
|
|
{
|
|
return(ThreadLocal_Workspace);
|
|
}
|
|
|
|
//- sixten: Commands
|
|
static void W_IssueCommand(workspace_command_sig *Sig, u64 Argument)
|
|
{
|
|
workspace_command *Result = 0;
|
|
|
|
workspace *Workspace = W_GetState();
|
|
|
|
if(Workspace->FirstFreeCommand)
|
|
{
|
|
Result = Workspace->FirstFreeCommand;
|
|
DLLRemove(Workspace->FirstFreeCommand, Workspace->LastFreeCommand, Result);
|
|
}
|
|
|
|
if(!Result)
|
|
{
|
|
Result = PushStruct(Workspace->CommandArena, workspace_command);
|
|
}
|
|
|
|
Result->Command = Sig;
|
|
Result->Argument = Argument;
|
|
DLLInsertLast(Workspace->FirstCommand, Workspace->LastCommand, Result);
|
|
}
|
|
|
|
static void W_ProcessCommands(void)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
|
|
workspace_command *Command = Workspace->FirstCommand;
|
|
while(Command != 0)
|
|
{
|
|
Command->Command(Command->Argument);
|
|
|
|
workspace_command *ToRemove = Command;
|
|
Command = Command->Next;
|
|
|
|
DLLRemove(Workspace->FirstCommand, Workspace->LastCommand, ToRemove);
|
|
Fill(ToRemove, 0, sizeof(workspace_command));
|
|
DLLInsertLast(Workspace->FirstFreeCommand, Workspace->LastFreeCommand, ToRemove);
|
|
}
|
|
|
|
ArenaClear(Workspace->CommandDataArena);
|
|
}
|
|
|
|
static void W_ProcessKeyBinds()
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
|
|
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 < ArrayCount(Workspace_Keybinds);
|
|
++KeybindIndex)
|
|
{
|
|
workspace_keybind *Keybind = Workspace_Keybinds + KeybindIndex;
|
|
if((Event->Key == Keybind->Key) && (Event->Modifiers == Keybind->Modifiers))
|
|
{
|
|
W_IssueCommand(Keybind->Command, Keybind->Argument);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//- sixten: Builder code
|
|
static ui_signal W_BuildToolbarButton(char *Text, workspace_toolbar_menu Menu)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
|
|
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 == W_ToolbarMenu_None)
|
|
{
|
|
if(Signal.Clicked)
|
|
{
|
|
Workspace->Menu = Menu;
|
|
Workspace->MenuT = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(Signal.Hovering)
|
|
{
|
|
if(Workspace->Menu != Menu)
|
|
{
|
|
Workspace->MenuT = 0;
|
|
}
|
|
|
|
Workspace->Menu = Menu;
|
|
Workspace->MenuP = V2(Box->Rect.Min.x, Box->Rect.Max.y);
|
|
}
|
|
}
|
|
|
|
return(Signal);
|
|
}
|
|
|
|
static ui_signal W_BuildMenuItem(u32 Icon, char *Text, char *Shortcut)
|
|
{
|
|
temporary_memory Scratch = GetScratch(0, 0);
|
|
|
|
UI_SetNextLayoutAxis(Axis2_X);
|
|
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
|
|
|
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);
|
|
}
|
|
|
|
static void W_BuildToolbar(void)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
|
|
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)
|
|
{
|
|
W_BuildToolbarButton("Panel", W_ToolbarMenu_Panel);
|
|
W_BuildToolbarButton("View", W_ToolbarMenu_View);
|
|
W_BuildToolbarButton("Window", W_ToolbarMenu_Window);
|
|
}
|
|
|
|
if(Workspace->Menu != W_ToolbarMenu_None)
|
|
{
|
|
r32 MenuT = Workspace->MenuT;
|
|
|
|
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(MenuT, 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 == W_ToolbarMenu_Panel)
|
|
{
|
|
if(W_BuildMenuItem(FontIcon_ResizeHorizontal, "Split Horizontal", "Ctrl + P").Clicked)
|
|
{
|
|
W_IssueCommand(W_Command_SplitPanelHorizontal);
|
|
Workspace->Menu = W_ToolbarMenu_None;
|
|
}
|
|
if(W_BuildMenuItem(FontIcon_ResizeVertical, "Split Vertical", "Ctrl + L").Clicked)
|
|
{
|
|
W_IssueCommand(W_Command_SplitPanelVertical);
|
|
Workspace->Menu = W_ToolbarMenu_None;
|
|
}
|
|
}
|
|
else if(Workspace->Menu == W_ToolbarMenu_View)
|
|
{
|
|
workspace_view_kind ViewKind = W_ViewKind_None;
|
|
if(W_BuildMenuItem(FontIcon_None, "Welcome", "").Clicked) {ViewKind = W_ViewKind_Startup;}
|
|
if(W_BuildMenuItem(FontIcon_Pencil, "File Lister", "Ctrl + O").Clicked) {ViewKind = W_ViewKind_FileLister;}
|
|
if(W_BuildMenuItem(FontIcon_Users, "Navigation Editor", "").Clicked) {ViewKind = W_ViewKind_NavEditor;}
|
|
if(W_BuildMenuItem(FontIcon_Terminal, "Scene View", "").Clicked) {ViewKind = W_ViewKind_SceneView;}
|
|
if(W_BuildMenuItem(FontIcon_Wrench, "Settings", "Ctrl + Shift + P").Clicked) {ViewKind = W_ViewKind_Settings;}
|
|
|
|
if(ViewKind != W_ViewKind_None)
|
|
{
|
|
W_IssueCommand(W_Command_OpenView, ViewKind);
|
|
Workspace->Menu = W_ToolbarMenu_None;
|
|
}
|
|
}
|
|
else if(Workspace->Menu == W_ToolbarMenu_Window)
|
|
|
|
if(W_BuildMenuItem(FontIcon_WindowMaximize, "ToggleFullscreen", "Alt + Enter").Clicked)
|
|
{
|
|
Platform.ToggleFullscreen();
|
|
Workspace->Menu = W_ToolbarMenu_None;
|
|
}
|
|
}
|
|
|
|
AC_AnimateValueDirect(1, 0.1, &Workspace->MenuT);
|
|
|
|
// sixten: Unless the mouse press was captured, we close the menu.
|
|
if(Platform_KeyPress(Workspace->EventList, Key_MouseLeft))
|
|
{
|
|
Workspace->Menu = W_ToolbarMenu_None;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//- sixten: Panels
|
|
static workspace_panel *W_CreateNewPanel(workspace_panel *Parent)
|
|
{
|
|
workspace_panel *Result = 0;
|
|
|
|
workspace *Workspace = W_GetState();
|
|
|
|
if(DLLIsEmpty(Workspace->FirstFreePanel))
|
|
{
|
|
Result = PushStruct(Workspace->PanelArena, workspace_panel);
|
|
}
|
|
else
|
|
{
|
|
Result = Workspace->FirstFreePanel;
|
|
DLLRemove(Workspace->FirstFreePanel, Workspace->LastFreePanel, Result);
|
|
|
|
*Result = {};
|
|
}
|
|
|
|
Result->Parent = Parent;
|
|
|
|
return(Result);
|
|
}
|
|
|
|
static void W_DeletePanel(workspace_panel *Panel)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
|
|
if(Workspace->CurrentPanel == Panel)
|
|
{
|
|
Workspace->CurrentPanel = 0;
|
|
}
|
|
|
|
*Panel = {};
|
|
DLLInsertLast(Workspace->FirstFreePanel, Workspace->LastFreePanel, Panel);
|
|
}
|
|
|
|
static void W_PanelViewPush(workspace_panel_view_list *List, workspace_panel_view *PanelView)
|
|
{
|
|
DLLInsertLast(List->First, List->Last, PanelView);
|
|
List->Count += 1;
|
|
}
|
|
|
|
static void W_PanelViewRemove(workspace_panel_view_list *List, workspace_panel_view *PanelView)
|
|
{
|
|
DLLRemove(List->First, List->Last, PanelView);
|
|
List->Count -= 1;
|
|
}
|
|
|
|
static workspace_panel_view *W_CreatePanelView(void)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
workspace_panel_view *PanelView = Workspace->PanelViewFreeList.First;
|
|
if(PanelView)
|
|
{
|
|
W_PanelViewRemove(&Workspace->PanelViewFreeList, PanelView);
|
|
}
|
|
else
|
|
{
|
|
PanelView = PushStruct(Workspace->PanelViewArena, workspace_panel_view);
|
|
}
|
|
return(PanelView);
|
|
}
|
|
|
|
static void W_DeletePanelView(workspace_panel_view *PanelView)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
ZeroStruct(PanelView);
|
|
W_PanelViewPush(&Workspace->PanelViewFreeList, PanelView);
|
|
}
|
|
|
|
static void W_SplitPanel(workspace_panel *Panel, axis2 Axis)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
|
|
if(Panel)
|
|
{
|
|
workspace_panel *Parent = Panel->Parent;
|
|
|
|
if(Parent && (Parent->SplitAxis == Axis))
|
|
{
|
|
workspace_panel *NewPanel = W_CreateNewPanel(Parent);
|
|
NewPanel->PercentOfParent = Panel->PercentOfParent = Panel->PercentOfParent * 0.5;
|
|
|
|
DLLInsert_NP(Parent->First, Parent->Last, Panel, NewPanel, Next, Prev);
|
|
}
|
|
else
|
|
{
|
|
workspace_panel *NewPanel = W_CreateNewPanel(Panel);
|
|
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);
|
|
|
|
NewPanel = W_CreateNewPanel(Panel);
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static b32 W_ViewIsDragged(workspace_view *View)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
b32 Result = (Workspace->DragPayloadState != W_DragPayload_Inactive && Workspace->DragPayload.View == View) &&
|
|
UI_GetState()->DragStartP != UI_MouseP();
|
|
return(Result);
|
|
}
|
|
|
|
inline void W_BeginDrag(workspace_drag_payload *Payload)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
|
|
// sixten(no longer a 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 == W_DragPayload_Inactive);
|
|
// sixten(from the future): I have concluded that this should never be an issue.
|
|
|
|
Workspace->DragPayload = *Payload;
|
|
Workspace->DragPayloadState = W_DragPayload_Active;
|
|
}
|
|
|
|
inline b32 W_GetDragPayload(workspace_drag_payload *Dest)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
|
|
b32 Result = (Workspace->DragPayloadState != W_DragPayload_Inactive);
|
|
*Dest = Workspace->DragPayload;
|
|
return(Result);
|
|
}
|
|
|
|
static void W_BuildTabItem(workspace_panel *Panel, workspace_view *View)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
|
|
b32 ViewIsCurrent = (Panel->CurrentView == View);
|
|
b32 PanelIsCurrent = (Workspace->CurrentPanel == Panel);
|
|
|
|
string Name = W_GetViewName(UI_FrameArena(), View);
|
|
|
|
b32 Open = !(W_ViewIsDragged(View) && Workspace->DragPayloadState != W_DragPayload_Released);
|
|
r32 OpenT = AC_AnimateValueF(Open, 0.0f, 0.3f, "Workspace Tab Item %p", View);
|
|
r32 SpaceT = AC_AnimateValueF(Open, 1.0f, 0.3f, "Workspace Tab Item Space %p", View);
|
|
|
|
UI_Size(UI_ChildrenSum(SpaceT, 1), UI_Percent(1, 1)) UI_Column()
|
|
{
|
|
UI_Spacer(UI_Percent(1-OpenT, 1));
|
|
|
|
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_Clip |
|
|
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_SetNextHoverCursor(PlatformCursor_Hand);
|
|
|
|
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)
|
|
{
|
|
W_IssueCommand(W_Command_CloseView, PointerToU64(View));
|
|
}
|
|
}
|
|
}
|
|
|
|
ui_signal Signal = UI_SignalFromBox(TabBox);
|
|
if(Signal.Clicked)
|
|
{
|
|
Workspace->CurrentPanel = Panel;
|
|
Panel->CurrentView = View;
|
|
}
|
|
|
|
// sixten: Handle dragging the view.
|
|
if(Signal.Dragging)
|
|
{
|
|
if(Signal.Pressed)
|
|
{
|
|
workspace_drag_payload Payload = {};
|
|
Payload.View = View;
|
|
Payload.Key = TabBox->Key;
|
|
|
|
W_BeginDrag(&Payload);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void W_BuildPanelHeader(workspace_panel *Panel)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
|
|
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)
|
|
{
|
|
W_BuildTabItem(Panel, View);
|
|
}
|
|
|
|
// sixten: Panel Close Button
|
|
if(Panel != Workspace->RootPanel)
|
|
{
|
|
UI_Spacer(UI_Percent(1, 0));
|
|
|
|
UI_SetNextSize(UI_Pixels(30, 1), UI_Pixels(30, 1));
|
|
UI_SetNextFont(Font_Icons);
|
|
UI_SetNextCornerRadius(4);
|
|
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
|
|
|
ui_box *CloseBox = UI_MakeBoxF(UI_BoxFlag_HotAnimation |
|
|
UI_BoxFlag_ActiveAnimation |
|
|
UI_BoxFlag_DrawText |
|
|
UI_BoxFlag_Clickable,
|
|
"%U", FontIcon_Cancel);
|
|
|
|
ui_signal Signal = UI_SignalFromBox(CloseBox);
|
|
if(Signal.Clicked)
|
|
{
|
|
W_IssueCommand(W_Command_ClosePanel, PointerToU64(Panel));
|
|
}
|
|
}
|
|
|
|
UI_Spacer(UI_Pixels(2, 1));
|
|
}
|
|
}
|
|
|
|
static void W_BuildPanel(workspace_panel *Panel)
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
|
|
// 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))
|
|
{
|
|
W_BuildPanelHeader(Panel);
|
|
|
|
// sixten: Main body
|
|
{
|
|
b32 PanelIsCurrent = (Workspace->CurrentPanel == Panel);
|
|
|
|
UI_PushSize(UI_Percent(1, 0), UI_Percent(1, 0));
|
|
|
|
r32 HighlightTransition = AC_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
|
|
{
|
|
UI_Column() UI_Padding(UI_Percent(1, 0))
|
|
UI_Height(UI_ChildrenSum(1, 1)) UI_Row() UI_Padding(UI_Percent(1, 0))
|
|
{
|
|
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
|
|
{
|
|
UI_LabelF("- empty -");
|
|
}
|
|
}
|
|
}
|
|
|
|
if(Panel->CurrentView)
|
|
{
|
|
ui_key CurrentActive = UI_ActiveKey();
|
|
|
|
W_BuildView(Panel->CurrentView);
|
|
|
|
if(!AreEqual(CurrentActive, UI_ActiveKey()))
|
|
{
|
|
Workspace->CurrentPanel = Panel;
|
|
}
|
|
}
|
|
|
|
// sixten: Draw dragged view overlay.
|
|
{
|
|
workspace_drag_payload Payload;
|
|
b32 DragActive = W_GetDragPayload(&Payload);
|
|
|
|
b32 OverlayActive = (DragActive && (Payload.View->Parent != Panel) &&
|
|
InRange(BodyBox->Rect, UI_GetState()->MouseP));
|
|
|
|
if(OverlayActive && Workspace->DragPayloadState == W_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 = W_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 = AC_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));
|
|
W_BuildPanel(Child);
|
|
|
|
// sixten: Create drag area
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void W_BuildDragPayload()
|
|
{
|
|
workspace *Workspace = W_GetState();
|
|
|
|
workspace_drag_payload Payload;
|
|
if(W_GetDragPayload(&Payload) && W_ViewIsDragged(Payload.View))
|
|
{
|
|
if(Workspace->DragPayloadState == W_DragPayload_Released)
|
|
{
|
|
Workspace->DragPayloadState = W_DragPayload_Inactive;
|
|
}
|
|
|
|
if(AreEqual(Payload.Key, UI_ActiveKey()))
|
|
{
|
|
workspace_view *DraggedView = Payload.View;
|
|
UI_SetNextCornerRadius(4);
|
|
UI_TooltipLabel(W_GetViewName(UI_FrameArena(), DraggedView), UI_MouseP());
|
|
}
|
|
else
|
|
{
|
|
if(Workspace->DragPayloadState == W_DragPayload_Active)
|
|
{
|
|
Workspace->DragPayloadState = W_DragPayload_Released;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//- sixten: Workspace
|
|
static void W_Init(workspace *Workspace)
|
|
{
|
|
W_SetState(Workspace);
|
|
|
|
Workspace->CommandArena = ArenaAlloc(Kilobytes(4), true);
|
|
Workspace->CommandDataArena = ArenaAlloc(Kilobytes(4), true);
|
|
Workspace->PanelArena = ArenaAlloc(Kilobytes(4), true);
|
|
|
|
Workspace->RootPanel = Workspace->CurrentPanel = W_CreateNewPanel(0);
|
|
|
|
if(DEBUG_DebugSettings->ShowWelcomeMessage)
|
|
{
|
|
W_CreateNewView(W_ViewKind_Startup, Workspace->RootPanel);
|
|
}
|
|
|
|
// sixten: build text editor / scene view layout
|
|
if(0)
|
|
{
|
|
W_CreateNewView(W_ViewKind_TextEditor, Workspace->RootPanel);
|
|
W_SplitPanel(Workspace->RootPanel, Axis2_X);
|
|
W_CreateNewView(W_ViewKind_SceneView, Workspace->RootPanel->Last);
|
|
}
|
|
|
|
W_CreateNewView(W_ViewKind_NavEditor, Workspace->RootPanel);
|
|
}
|
|
|
|
static void W_Update(workspace *Workspace, vn_render_commands *RenderCommands, vn_input *Input, glyph_atlas *GlyphAtlas)
|
|
{
|
|
Workspace->Input = Input;
|
|
Workspace->EventList = Input->EventList;
|
|
|
|
W_SetState(Workspace);
|
|
|
|
// sixten: Process the keybinds and commands.
|
|
W_ProcessKeyBinds();
|
|
W_ProcessCommands();
|
|
|
|
// sixten: Make sure that a view/panel is always selected.
|
|
if(!Workspace->CurrentPanel)
|
|
{
|
|
Workspace->CurrentPanel = Workspace->RootPanel;
|
|
while(Workspace->CurrentPanel->First != 0)
|
|
{
|
|
Workspace->CurrentPanel = Workspace->CurrentPanel->First;
|
|
}
|
|
}
|
|
|
|
// sixten: Build the UI.
|
|
{
|
|
W_BuildDragPayload();
|
|
|
|
W_BuildToolbar();
|
|
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 0));
|
|
W_BuildPanel(Workspace->RootPanel);
|
|
}
|
|
} |