233 lines
7.2 KiB
C++
233 lines
7.2 KiB
C++
|
//- sixten: Managing nodes
|
||
|
static workspace_editor_node *Workspace_GetNewEditorNode(workspace_view *View)
|
||
|
{
|
||
|
Assert(View->Type == Workspace_View_Editor);
|
||
|
|
||
|
workspace_view_editor *Editor = (workspace_view_editor *)View->Data;
|
||
|
|
||
|
workspace_editor_node *Result = 0;
|
||
|
|
||
|
if(DLLIsEmpty(Editor->FirstFreeNode))
|
||
|
{
|
||
|
Result = PushStruct(&View->Arena, workspace_editor_node);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Result = Editor->FirstFreeNode;
|
||
|
DLLRemove(Editor->FirstFreeNode, Editor->LastFreeNode, Result);
|
||
|
}
|
||
|
|
||
|
if(Result)
|
||
|
{
|
||
|
*Result = {};
|
||
|
DLLInsertLast(Editor->FirstNode, Editor->LastNode, Result);
|
||
|
}
|
||
|
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
//- sixten: Transformations
|
||
|
inline r32 Workspace_ViewToWorld(r32 Offset, r32 Scale, r32 Dim, r32 P)
|
||
|
{
|
||
|
r32 Result = (P - Dim*0.5)*(1.0/Scale) - Offset;
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline r32 Workspace_WorldToView(r32 Offset, r32 Scale, r32 Dim, r32 P)
|
||
|
{
|
||
|
r32 Result = (P + Offset)*Scale + Dim*0.5;
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline v2 Workspace_ViewToWorld(v2 Offset, r32 Scale, v2 Dim, v2 P)
|
||
|
{
|
||
|
v2 Result = (P - Dim*0.5)*(1.0/Scale) - Offset;
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline v2 Workspace_WorldToView(v2 Offset, r32 Scale, v2 Dim, v2 P)
|
||
|
{
|
||
|
v2 Result = (P + Offset)*Scale + Dim*0.5;
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline r32 Workspace_CalculateScaleFromZoomLevel(r32 ZoomLevel)
|
||
|
{
|
||
|
r32 PixelsPerUnit = 100.0;
|
||
|
|
||
|
r32 Scale = PixelsPerUnit*Pow(1.25, ZoomLevel);
|
||
|
return(Scale);
|
||
|
}
|
||
|
|
||
|
//- sixten: Commands
|
||
|
|
||
|
|
||
|
//- sixten: Builder code
|
||
|
static void Workspace_EditorDrawCallback(render_group *Group, glyph_atlas *Atlas, ui_box *Box, void *Data)
|
||
|
{
|
||
|
workspace_view_editor *Editor = (workspace_view_editor *)Data;
|
||
|
|
||
|
r32 Scale = Editor->Scale;
|
||
|
|
||
|
v4 LineColor = Theme_BorderColor;
|
||
|
|
||
|
v2 Dim = DimOfRange(Box->Rect);
|
||
|
|
||
|
s32 VerticalLineCount = Dim.x / Scale + 4;
|
||
|
for(s32 LineIndex = -VerticalLineCount/2;
|
||
|
LineIndex < VerticalLineCount/2;
|
||
|
++LineIndex)
|
||
|
{
|
||
|
r32 OffsetX = Workspace_WorldToView(Editor->Offset.x, Scale, Dim.x, LineIndex - (s32)Editor->Offset.x);
|
||
|
PushQuad(Group, Box->Rect.Min + V2(OffsetX, 0), V2(1.5, Dim.y), LineColor, 0, 1.2, 0);
|
||
|
}
|
||
|
|
||
|
s32 HorizontalLineCount = Dim.y / Scale + 4;
|
||
|
for(s32 LineIndex = -HorizontalLineCount/2;
|
||
|
LineIndex < HorizontalLineCount/2;
|
||
|
++LineIndex)
|
||
|
{
|
||
|
r32 OffsetY = Workspace_WorldToView(Editor->Offset.y, Scale, Dim.y, LineIndex - (s32)Editor->Offset.y);
|
||
|
|
||
|
PushQuad(Group, Box->Rect.Min + V2(0, OffsetY), V2(Dim.x, 1.5), LineColor, 0, 1.2, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void Workspace_BuildEditor(workspace *Workspace, workspace_view *View)
|
||
|
{
|
||
|
workspace_view_editor *Editor = (workspace_view_editor *)View->Data;
|
||
|
|
||
|
// sixten(TODO): These should be able to have a strictness of 1, but they can't. Fix that.
|
||
|
UI_SetNextWidth(UI_Percent(1, 0));
|
||
|
UI_SetNextHeight(UI_Percent(1, 0));
|
||
|
|
||
|
ui_box *EditorBox = UI_MakeBoxF(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "Workspace Editor %p", View);
|
||
|
EditorBox->DrawCallback = Workspace_EditorDrawCallback;
|
||
|
EditorBox->DrawCallbackData = Editor;
|
||
|
|
||
|
r32 AnimatedZoomLevel = AnimationCurve_AnimateValueF(Editor->ZoomLevel, 0, 0.25, "Workspace Editor Zoom");
|
||
|
Editor->Scale = Workspace_CalculateScaleFromZoomLevel(AnimatedZoomLevel);
|
||
|
|
||
|
v2 EditorDim = DimOfRange(EditorBox->Rect);
|
||
|
|
||
|
// sixten: Build the node boxes.
|
||
|
for(workspace_editor_node *Node = Editor->FirstNode;
|
||
|
Node != 0;
|
||
|
Node = Node->Next)
|
||
|
{
|
||
|
v2 ViewDim = V2(2, 1.5)*Editor->Scale;
|
||
|
v2 ViewP = Workspace_WorldToView(Editor->Offset, Editor->Scale, EditorDim, Node->P) - ViewDim*0.5;
|
||
|
|
||
|
UI_SetNextSize(UI_Pixels(ViewDim.x, 1), UI_Pixels(ViewDim.y, 1));
|
||
|
UI_SetNextFixedP(ViewP);
|
||
|
UI_SetNextLayoutAxis(Axis2_Y);
|
||
|
|
||
|
Node->Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
||
|
UI_BoxFlag_DrawBorder |
|
||
|
UI_BoxFlag_FloatingX |
|
||
|
UI_BoxFlag_FloatingY |
|
||
|
UI_BoxFlag_DrawDropShadow,
|
||
|
"Workspace Editor Node %p", Node);
|
||
|
|
||
|
UI_Parent(Node->Box)
|
||
|
{
|
||
|
UI_SetNextBackgroundColor(LinearBlend(Theme_BackgroundColor, Color_Black, 0.3));
|
||
|
|
||
|
UI_SetNextSize(UI_Percent(1, 1), UI_Pixels(20, 1));
|
||
|
Node->TitleBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
||
|
UI_BoxFlag_DrawBorder |
|
||
|
UI_BoxFlag_Clickable,
|
||
|
"Workspace Editor Node Title");
|
||
|
|
||
|
UI_Parent(Node->TitleBox)
|
||
|
{
|
||
|
UI_Width(UI_TextContent(7, 0)) UI_Font(Font_Bold) UI_LabelF("Node");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// sixten: Get input from boxes.
|
||
|
{
|
||
|
workspace_editor_node *Next = 0;
|
||
|
for(workspace_editor_node *Node = Editor->FirstNode;
|
||
|
Node != 0;
|
||
|
Node = Next)
|
||
|
{
|
||
|
Next = Node->Next;
|
||
|
|
||
|
ui_signal Signal = UI_SignalFromBox(Node->TitleBox);
|
||
|
if(Signal.Dragging)
|
||
|
{
|
||
|
if(Signal.Pressed)
|
||
|
{
|
||
|
UI_StoreDragV2(Node->P);
|
||
|
}
|
||
|
|
||
|
v2 StartP = UI_GetDragV2();
|
||
|
v2 EndP = StartP + Signal.DragDelta*(1.0 / Editor->Scale);
|
||
|
|
||
|
Node->P = EndP;
|
||
|
}
|
||
|
|
||
|
if(Signal.Dragging || Signal.Hovering)
|
||
|
{
|
||
|
Platform.SetCursor(PlatformCursor_ArrowAll);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// sixten: Process the movement of the node.
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// sixten: Process panning and zooming of the editor.
|
||
|
ui_signal Signal = UI_SignalFromBox(EditorBox);
|
||
|
{
|
||
|
if(Signal.Dragging)
|
||
|
{
|
||
|
if(Signal.Pressed)
|
||
|
{
|
||
|
UI_StoreDragV2(Editor->Offset);
|
||
|
}
|
||
|
|
||
|
v2 StartOffset = UI_GetDragV2();
|
||
|
v2 EndOffset = StartOffset + Signal.DragDelta*(1.0 / Editor->Scale);
|
||
|
|
||
|
Editor->Offset = EndOffset;
|
||
|
|
||
|
// sixten: Update node positions, as to not get a one frame delay.
|
||
|
for(workspace_editor_node *Node = 0;
|
||
|
Node != 0;
|
||
|
Node = Node->Next)
|
||
|
{
|
||
|
v2 ViewDim = V2(2, 1.5)*Editor->Scale;
|
||
|
v2 ViewP = Workspace_WorldToView(Editor->Offset, Editor->Scale, EditorDim, Node->P) - ViewDim*0.5;
|
||
|
|
||
|
Node->Box->FixedP = ViewP;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for(platform_event *Event = Workspace->EventList->First;
|
||
|
Event != 0;
|
||
|
Event = Event->Next)
|
||
|
{
|
||
|
if(Event->Type == PlatformEvent_MouseScroll)
|
||
|
{
|
||
|
if(Signal.Dragging)
|
||
|
{
|
||
|
UI_StoreDragV2(Editor->Offset);
|
||
|
UI_UpdateDragStartP();
|
||
|
}
|
||
|
|
||
|
Editor->ZoomLevel = Clamp(Editor->ZoomLevel + Event->Scroll.y, -4, 5);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// sixten: Process shortcuts.
|
||
|
if(Platform_KeyPress(Workspace->EventList, Key_Space, PlatformModifier_Ctrl))
|
||
|
{
|
||
|
Workspace_GetNewEditorNode(View);
|
||
|
}
|
||
|
}
|