#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) { temp 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_FolderOpen, "File Lister", "Ctrl + O").Clicked) {ViewKind = W_ViewKind_FileLister;} 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_NameFromView(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_NameFromView(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); } } 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); } }