2023-12-07 15:50:57 +00:00
UI_CUSTOM_DRAW_CALLBACK ( BuildNavViewDrawCallback )
{
2023-12-23 07:27:22 +00:00
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 ) ;
2023-12-07 15:50:57 +00:00
}
static scene_nav_item_node * W_SceneNavItemNodeAlloc ( arena * Arena , workspace_view_nav_editor * Editor )
{
2023-12-23 07:27:22 +00:00
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 ) ;
2023-12-07 15:50:57 +00:00
}
static void W_SceneNavItemNodeRelease ( workspace_view_nav_editor * Editor , scene_nav_item_node * Node )
{
2023-12-23 07:27:22 +00:00
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 ;
2023-12-07 15:50:57 +00:00
}
2023-12-23 07:27:22 +00:00
static void W_NavEditorSetup ( workspace_view * View , string FilePath , string FileName , string FileContents )
2023-12-07 15:50:57 +00:00
{
2023-12-23 07:27:22 +00:00
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 : ;
}
}
}
2023-12-07 15:50:57 +00:00
}
static void W_BuildNavEditor ( workspace_view * View )
{
2023-12-23 07:27:22 +00:00
workspace_view_nav_editor * Editor = ( workspace_view_nav_editor * ) View - > Data ;
scene_view * SceneView = SV_GetState ( ) ;
2024-01-20 11:18:57 +00:00
UI_BackgroundColor ( V4R32 ( 0.25 , 0.25 , 0.25 , 1 ) )
UI_BorderColor ( V4R32 ( 0.45 , 0.45 , 0.45 , 1 ) )
2023-12-23 07:27:22 +00:00
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 ;
2024-01-20 11:18:57 +00:00
render_handle Texture = A_TextureFromAssetID ( Item - > TextureID ) ;
2023-12-23 07:27:22 +00:00
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 ) ,
2024-01-20 11:18:57 +00:00
" View Item Box %i " , ItemIndex ) ;
2023-12-23 07:27:22 +00:00
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 ) ;
}
}
}
2023-12-07 15:50:57 +00:00
}