442 lines
15 KiB
C++
442 lines
15 KiB
C++
UI_CUSTOM_DRAW_CALLBACK(BuildNavViewDrawCallback)
|
|
{
|
|
scene_view *SceneView = (scene_view *)Data;
|
|
SV_DrawBackground(SceneView, Box, Group);
|
|
}
|
|
|
|
static void W_NavEditorSerializeItems(workspace_view_nav_editor *Editor)
|
|
{
|
|
temp Scratch = GetScratch();
|
|
|
|
//- sixten: find total size
|
|
u64 TotalSize = sizeof(u16); // item count
|
|
for(scene_nav_item_node *Node = Editor->Items.First; Node != 0; Node = Node->Next)
|
|
{
|
|
string AssetName = MakeString(AssetNameLUT[Node->Item.TextureID]);
|
|
|
|
TotalSize += 1; TotalSize += sizeof(u16); TotalSize += AssetName.Count; // texture id
|
|
TotalSize += 1; TotalSize += sizeof(r32); // scale
|
|
TotalSize += 1; TotalSize += sizeof(v2_r32); // origin
|
|
TotalSize += 1; TotalSize += sizeof(v2_r32); // p
|
|
TotalSize += 1; TotalSize += sizeof(u16); TotalSize += Node->Item.HoverText.Count; // hover text
|
|
TotalSize += 1; TotalSize += sizeof(u16); TotalSize += sizeof(u8); TotalSize += Node->Item.Action.Content.Count; // action
|
|
TotalSize += 1; // end of item
|
|
}
|
|
|
|
u8 *FileData = PushArray(Scratch.Arena, u8, TotalSize);
|
|
u8 *Data = FileData;
|
|
|
|
*(u16 *)Data = Editor->Items.Count;
|
|
Data += sizeof(u16);
|
|
|
|
#define WriteByte(Op) do { *Data++ = Op; } while(0)
|
|
#define WriteField(Op, type, Member) do { *Data++ = Op; *(type *)Data = Member; Data += sizeof(type); } while(0)
|
|
#define WriteString(String) do { *(u16 *)Data = (u16)String.Count; Data += sizeof(u16); Copy(Data, String.Data, String.Count); Data += String.Count; } while(0)
|
|
|
|
for(scene_nav_item_node *Node = Editor->Items.First; Node != 0; Node = Node->Next)
|
|
{
|
|
scene_nav_item *Item = &Node->Item;
|
|
string AssetName = MakeString(AssetNameLUT[Node->Item.TextureID]);
|
|
WriteByte(S_NavItemOp_TextureID); WriteString(AssetName);
|
|
WriteField(S_NavItemOp_Scale, r32, Item->Scale);
|
|
WriteField(S_NavItemOp_Origin, v2_r32, Item->Origin);
|
|
WriteField(S_NavItemOp_P, v2_r32, Item->P);
|
|
WriteByte(S_NavItemOp_HoverText); WriteString(Item->HoverText);
|
|
WriteByte(S_NavItemOp_Action); WriteByte(Item->Action.Kind); WriteString(Item->Action.Content);
|
|
WriteByte(S_NavItemOp_None);
|
|
}
|
|
#undef WriteByte
|
|
#undef WriteField
|
|
#undef WriteString
|
|
|
|
platform_file_handle File = Platform.OpenFile(PushFormat(Scratch.Arena, "%S/%S", Editor->FilePath, Editor->FileName), PlatformAccess_Write);
|
|
if(File.IsValid)
|
|
{
|
|
Platform.WriteFile(File, FileData, 0, TotalSize);
|
|
Platform.CloseFile(File);
|
|
}
|
|
ReleaseScratch(Scratch);
|
|
}
|
|
|
|
static workspace_string_chunk *W_StringChunkAlloc(arena *Arena, workspace_string_chunk_list *FreeList)
|
|
{
|
|
workspace_string_chunk *Result = FreeList->First;
|
|
if(Result)
|
|
{
|
|
DLLRemove(FreeList->First, FreeList->Last, Result);
|
|
*Result = {};
|
|
}
|
|
else
|
|
{
|
|
Result = PushStruct(Arena, workspace_string_chunk);
|
|
}
|
|
|
|
return(Result);
|
|
}
|
|
|
|
static void W_StringChunkRelease(workspace_string_chunk_list *FreeList, workspace_string_chunk *Chunk)
|
|
{
|
|
DLLInsertLast(FreeList->First, FreeList->Last, Chunk);
|
|
}
|
|
|
|
static scene_nav_item_node *W_SceneNavItemNodeAlloc(arena *Arena, workspace_view_nav_editor *Editor)
|
|
{
|
|
scene_nav_item_node *Result = Editor->FirstFree;
|
|
if(Result)
|
|
{
|
|
DLLRemove(Editor->FirstFree, Editor->LastFree, Result);
|
|
*Result = {};
|
|
}
|
|
else
|
|
{
|
|
Result = PushStruct(Arena, scene_nav_item_node);
|
|
}
|
|
|
|
Result->HoverTextStringChunk = W_StringChunkAlloc(Arena, &Editor->FreeStrings);
|
|
Result->ActionStringChunk = W_StringChunkAlloc(Arena, &Editor->FreeStrings);
|
|
|
|
Result->Item.HoverText.Data = Result->HoverTextStringChunk->Data;
|
|
Result->Item.Action.Content.Data = Result->ActionStringChunk->Data;
|
|
|
|
DLLInsertLast(Editor->Items.First, Editor->Items.Last, Result);
|
|
Editor->Items.Count += 1;
|
|
return(Result);
|
|
}
|
|
|
|
static void W_SceneNavItemNodeRelease(workspace_view_nav_editor *Editor, scene_nav_item_node *Node)
|
|
{
|
|
W_StringChunkRelease(&Editor->FreeStrings, Node->HoverTextStringChunk);
|
|
W_StringChunkRelease(&Editor->FreeStrings, Node->ActionStringChunk);
|
|
DLLRemove(Editor->Items.First, Editor->Items.Last, Node);
|
|
DLLInsertLast(Editor->FirstFree, Editor->LastFree, Node);
|
|
Editor->Items.Count -= 1;
|
|
}
|
|
|
|
static void W_NavEditorInspectNode(workspace_view_nav_editor *Editor, scene_nav_item_node *Node)
|
|
{
|
|
Editor->SelectedItem = Node;
|
|
Editor->TextureDropdownOpen = false;
|
|
Editor->NavActionDropdownOpen = false;
|
|
}
|
|
|
|
static void W_NavEditorSetup(workspace_view *View, string FilePath, string FileName, string FileContents)
|
|
{
|
|
workspace_view_nav_editor *Editor = (workspace_view_nav_editor *)View->Data;
|
|
|
|
//- sixten: setup file info
|
|
Editor->FileName = PushString(View->Arena, FileName);
|
|
Editor->FilePath = PushString(View->Arena, FilePath);
|
|
|
|
//- sixten: deserialize data
|
|
if(FileContents.Count != 0)
|
|
{
|
|
u8 *DataBegin = FileContents.Data;
|
|
u8 *Byte = DataBegin;
|
|
|
|
u16 ItemCount = *(u16 *)Byte;
|
|
Byte += 2;
|
|
|
|
//- sixten: parse items
|
|
for(u64 ItemIndex = 0; ItemIndex < ItemCount; ItemIndex += 1)
|
|
{
|
|
scene_nav_item_node *Node = W_SceneNavItemNodeAlloc(View->Arena, Editor);
|
|
scene_nav_item *Item = &Node->Item;
|
|
for(;;)
|
|
{
|
|
switch(*Byte++)
|
|
{
|
|
case S_NavItemOp_TextureID:
|
|
{
|
|
string AssetName;
|
|
AssetName.Count = *(u16 *)Byte;
|
|
Byte += sizeof(u16);
|
|
AssetName.Data = Byte;
|
|
Byte += AssetName.Count;
|
|
|
|
Item->TextureID = AssetID_Error;
|
|
for(u64 AssetIndex = 0; AssetIndex < AssetID_COUNT; AssetIndex += 1)
|
|
{
|
|
if(AreEqual(MakeString(AssetNameLUT[AssetIndex]), AssetName))
|
|
{
|
|
Item->TextureID = AssetIndex;
|
|
break;
|
|
}
|
|
}
|
|
} goto Next;
|
|
case S_NavItemOp_Scale:
|
|
{
|
|
Item->Scale = *(r32 *)Byte;
|
|
Byte += sizeof(r32);
|
|
} goto Next;
|
|
case S_NavItemOp_Origin:
|
|
{
|
|
Item->Origin = *(v2_r32 *)Byte;
|
|
Byte += sizeof(v2_r32);
|
|
} goto Next;
|
|
case S_NavItemOp_P:
|
|
{
|
|
Item->P = *(v2_r32 *)Byte;
|
|
Byte += sizeof(v2_r32);
|
|
} goto Next;
|
|
case S_NavItemOp_HoverText:
|
|
{
|
|
Item->HoverText.Count = *(u16 *)Byte;
|
|
Byte += 2;
|
|
Assert(Item->HoverText.Count <= W_STRING_CHUNK_SIZE-2*sizeof(void *));
|
|
|
|
Copy(Item->HoverText.Data, Byte, Item->HoverText.Count);
|
|
Byte += Item->HoverText.Count;
|
|
} goto Next;
|
|
case S_NavItemOp_Action:
|
|
{
|
|
Item->Action.Kind = (scene_nav_action_kind)*Byte;
|
|
Byte += 1;
|
|
|
|
Item->Action.Content.Count = *(u16 *)Byte;
|
|
Byte += 2;
|
|
Assert(Item->Action.Content.Count <= W_STRING_CHUNK_SIZE-2*sizeof(void *));
|
|
|
|
Copy(Item->Action.Content.Data, Byte, Item->Action.Content.Count);
|
|
Byte += Item->Action.Content.Count;
|
|
} goto Next;
|
|
}
|
|
|
|
//- sixten: no op found, assume item done
|
|
break;
|
|
|
|
Next:;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void W_BuildNavEditor(workspace_view *View)
|
|
{
|
|
workspace_view_nav_editor *Editor = (workspace_view_nav_editor *)View->Data;
|
|
scene_view *SceneView = SV_GetState();
|
|
|
|
UI_BackgroundColor(V4(0.25, 0.25, 0.25, 1))
|
|
UI_BorderColor(V4(0.45, 0.45, 0.45, 1))
|
|
UI_WidthFill UI_Height(UI_Em(2.0f, 1.0f))
|
|
UI_LayoutAxis(Axis2_X)
|
|
UI_Parent(UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, "Workspace Nav Editor Toolbar"))
|
|
{
|
|
UI_Width(UI_Em(2.0f, 1.0f)) UI_Font(Font_Icons) UI_CornerRadius(4.0f)
|
|
{
|
|
//- sixten: create nav item button
|
|
if(UI_ButtonF("%U", FontIcon_UserPlus).Clicked)
|
|
{
|
|
scene_nav_item_node *Node = W_SceneNavItemNodeAlloc(View->Arena, Editor);
|
|
|
|
//- sixten: apply default options
|
|
Node->Item.Scale = 0.01f;
|
|
Node->Item.Origin = V2R32(0.5, 1.0f);
|
|
Node->Item.P = V2R32(0.0, 0.0f);
|
|
Node->Item.TextureID = AssetID_ArthurNormal;
|
|
}
|
|
|
|
//- sixten: create save nav items button
|
|
if(UI_ButtonF("%U", FontIcon_Floppy).Clicked)
|
|
{
|
|
W_NavEditorSerializeItems(Editor);
|
|
}
|
|
|
|
//- sixten: create force reload
|
|
if(UI_ButtonF("%U", FontIcon_ArrowsCW).Clicked)
|
|
{
|
|
SV_LoadNavItems();
|
|
}
|
|
}
|
|
}
|
|
|
|
UI_Row()
|
|
{
|
|
//- sixten: build inspector panel
|
|
scene_nav_item_node *SelectedItem = Editor->SelectedItem;
|
|
UI_SetNextLayoutAxis(Axis2_X);
|
|
UI_Width(UI_Em(24.0f*AC_AnimateValueF(SelectedItem != 0, 0, 0.3f, "Workspace Nav Editor Inspector %p", Editor), 1.0f)) UI_HeightFill
|
|
UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBorder, StrLit("Workspace Nav Editor Inspector")))
|
|
UI_Padding(UI_Em(1, 1)) UI_Width(UI_Percent(1.0f, 0.0f)) UI_Column()
|
|
{
|
|
if(SelectedItem)
|
|
{
|
|
UI_CornerRadius(4.0f) UI_Width(UI_Percent(1, 1)) UI_Height(UI_TextContent(15, 1))
|
|
{
|
|
//- sixten: inspect position
|
|
UI_Row() UI_Width(UI_Percent(0.5f, 1.0f)) {UI_LabelF("Position X:"); UI_Font(Font_Monospace) UI_LabelF("%f", SelectedItem->Item.P.x);}
|
|
UI_Row() UI_Width(UI_Percent(0.5f, 1.0f)) {UI_LabelF("Position Y:"); UI_Font(Font_Monospace) UI_LabelF("%f", SelectedItem->Item.P.y);}
|
|
|
|
//- sixten: inspect scale
|
|
UI_Row() UI_Width(UI_Percent(0.5f, 1.0f))
|
|
{
|
|
UI_LabelF("Scale:");
|
|
UI_Font(Font_Monospace)
|
|
{
|
|
UI_SetNextHoverCursor(PlatformCursor_ArrowHorizontal);
|
|
ui_box *ScaleBox = UI_MakeBoxF(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, "%f##Scale", SelectedItem->Item.Scale);
|
|
|
|
ui_signal ScaleSignal = UI_SignalFromBox(ScaleBox);
|
|
if(ScaleSignal.Dragging)
|
|
{
|
|
if(ScaleSignal.Pressed)
|
|
{
|
|
UI_StoreDragR32(SelectedItem->Item.Scale);
|
|
}
|
|
|
|
SelectedItem->Item.Scale = UI_GetDragR32() + ScaleSignal.DragDelta.x*0.001f;
|
|
}
|
|
}
|
|
}
|
|
|
|
//- sixten: inspect texture
|
|
UI_Row(0, StrLit("Texture")) UI_Width(UI_Percent(0.5f, 1.0f))
|
|
{
|
|
UI_LabelF("Texture:");
|
|
UI_DropdownSelection(AssetNameLUT, ArrayCount(AssetNameLUT), &Editor->TextureDropdownOpen, &SelectedItem->Item.TextureID);
|
|
}
|
|
|
|
//- sixten: inspect nav action kind
|
|
UI_Row(0, StrLit("Nav Action")) UI_Width(UI_Percent(0.5f, 1.0f))
|
|
{
|
|
UI_LabelF("Nav Action Type:");
|
|
char *Actions[] = { "None", "Trigger Proc", "Change Scene" };
|
|
UI_DropdownSelection(Actions, ArrayCount(Actions), &Editor->NavActionDropdownOpen, (s32 *)&SelectedItem->Item.Action);
|
|
}
|
|
|
|
//- sixten: inspect nav action contents
|
|
UI_Row(0, StrLit("Nav Action String")) UI_Width(UI_Percent(0.5f, 1.0f))
|
|
{
|
|
UI_LabelF("Nav Action Contents:");
|
|
ui_signal Signal = UI_LineEdit(&Editor->NavActionStringEditState, ArrayCount(SelectedItem->ActionStringChunk->Data), SelectedItem->ActionStringChunk->Data, &SelectedItem->Item.Action.Content.Count, StrLit("Nav Action Text"), Editor->ActiveTextThing == 1);
|
|
if(AreEqual(UI_ActiveKey(), Signal.Box->Key))
|
|
{
|
|
Editor->ActiveTextThing = 1;
|
|
}
|
|
else if(!AreEqual(UI_ActiveKey(), UI_EmptyKey()) && Editor->ActiveTextThing == 1)
|
|
{
|
|
Editor->ActiveTextThing = 0;
|
|
}
|
|
}
|
|
|
|
//- sixten: inspect hover text
|
|
UI_Row(0, StrLit("Hover Text")) UI_Width(UI_Percent(0.5f, 1.0f))
|
|
{
|
|
UI_LabelF("Hover Text:");
|
|
ui_signal Signal = UI_LineEdit(&Editor->HoverTextEditState, ArrayCount(SelectedItem->HoverTextStringChunk->Data), SelectedItem->HoverTextStringChunk->Data, &SelectedItem->Item.HoverText.Count, StrLit("Hover Text Input"), Editor->ActiveTextThing == 2);
|
|
if(AreEqual(UI_ActiveKey(), Signal.Box->Key))
|
|
{
|
|
Editor->ActiveTextThing = 2;
|
|
}
|
|
else if(!AreEqual(UI_ActiveKey(), UI_EmptyKey()) && Editor->ActiveTextThing == 2)
|
|
{
|
|
Editor->ActiveTextThing = 0;
|
|
}
|
|
}
|
|
|
|
UI_Spacer(UI_TextContent(15, 1));
|
|
|
|
UI_Row() UI_FillPadding
|
|
{
|
|
UI_Width(UI_TextContent(15, 1)) if(UI_ButtonF("Remove Item").Pressed)
|
|
{
|
|
W_SceneNavItemNodeRelease(Editor, SelectedItem);
|
|
Editor->SelectedItem = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//- sixten: build nav view
|
|
UI_Width(UI_Percent(1, 0)) UI_Height(UI_Percent(1, 0)) UI_Parent(UI_MakeBoxF(UI_BoxFlag_Clip, "Workspace View Nav Editor Thing"))
|
|
{
|
|
//- sixten: calculate nav view size
|
|
v2_r32 ParentDim = DimOfRange(UI_TopParent()->Rect);
|
|
v2_r32 BoxDim = ParentDim;
|
|
|
|
r32 TargetRatio = 16.0f/9.0f;
|
|
r32 ActualRatio = ParentDim.x/ParentDim.y;
|
|
|
|
if(ActualRatio>TargetRatio)
|
|
{
|
|
BoxDim.x = BoxDim.y*TargetRatio;
|
|
}
|
|
else
|
|
{
|
|
BoxDim.y = BoxDim.x/TargetRatio;
|
|
}
|
|
|
|
UI_SetNextWidth(UI_Pixels(BoxDim.x, 1));
|
|
UI_SetNextHeight(UI_Pixels(BoxDim.y, 1));
|
|
UI_SetNextLayoutAxis(Axis2_Y);
|
|
UI_SetNextFixedP((ParentDim-BoxDim)*0.5f);
|
|
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_Clip|UI_BoxFlag_DrawDropShadow|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY|UI_BoxFlag_Clickable, "Nav View %p", View);
|
|
UI_EquipBoxCustomDrawCallback(Box, BuildNavViewDrawCallback, SceneView);
|
|
|
|
r32 GlobalScale = CalculateGlobalScaleFromDim(BoxDim);
|
|
|
|
//- sixten: build all nav items
|
|
s32 ItemIndex = 0;
|
|
UI_Parent(Box) for(scene_nav_item_node *Node = Editor->Items.First; Node != 0; Node = Node->Next, ItemIndex += 1)
|
|
{
|
|
scene_nav_item *Item = &Node->Item;
|
|
|
|
//- sixten: calculate item position
|
|
r32 AppliedScale = GlobalScale*Item->Scale;
|
|
render_handle Texture = TextureFromAssetID(Item->TextureID);
|
|
v2_r32 TextureDim = ConvertV2ToR32(DimFromTexture(Texture));
|
|
v2_r32 TextureOrigin = Hadamard(TextureDim, Item->Origin);
|
|
v2_r32 Dim = TextureDim*AppliedScale;
|
|
v2_r32 OriginP = TextureOrigin*AppliedScale;
|
|
|
|
//- sixten: build the item
|
|
scene_nav_item_info *Data = PushStruct(UI_FrameArena(), scene_nav_item_info);
|
|
Data->Item = Item;
|
|
|
|
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
|
UI_SetNextSize(UI_Pixels(Dim.x, 1), UI_Pixels(Dim.y, 1));
|
|
ui_box *ItemBox = UI_MakeBoxF(UI_BoxFlag_Clickable|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY|((Node==Editor->SelectedItem)?UI_BoxFlag_DrawBorder:0),
|
|
"View Item Box %i", ItemIndex);
|
|
UI_EquipBoxCustomDrawCallback(ItemBox, BuildNavItemDrawCallback, Data);
|
|
|
|
if(Node == Editor->SelectedItem)
|
|
{
|
|
// sixten(TODO): this:
|
|
//ui_box *OriginBox = UI_MakeBoxF(UI_BoxFlag_Clickable|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, "View Item Origin Box %i", ItemIndex);
|
|
}
|
|
//- sixten: handle signals
|
|
{
|
|
ui_signal Signal = UI_SignalFromBox(ItemBox);
|
|
Data->Signal = Signal;
|
|
|
|
//- sixten: inspect pressed item
|
|
if(Signal.Clicked && Signal.DragDelta == V2R32(0, 0))
|
|
{
|
|
W_NavEditorInspectNode(Editor, Node);
|
|
}
|
|
|
|
//- sixten: handle dragging
|
|
if(Signal.Dragging)
|
|
{
|
|
if(Signal.Pressed)
|
|
{
|
|
UI_StoreDragV2(Item->P);
|
|
}
|
|
|
|
Item->P = UI_GetDragV2() + Signal.DragDelta/BoxDim*2;
|
|
}
|
|
}
|
|
|
|
//- sixten: apply the calculated position
|
|
v2_r32 OffsetP = BoxDim*(V2R32(1, 1) + Item->P)*0.5f;
|
|
ItemBox->FixedP = (OffsetP-OriginP);
|
|
}
|
|
|
|
ui_signal BackgroundSignal = UI_SignalFromBox(Box);
|
|
if(BackgroundSignal.Pressed)
|
|
{
|
|
W_NavEditorInspectNode(Editor, 0);
|
|
}
|
|
}
|
|
}
|
|
} |