// Project Lab - NHTV IGAD ////////////////////////////////////////// // Author: Yoshi van Belkom - 130118 ////////////////////////////////////////// #include "SkillTreeEditorPrivatePCH.h" #include "SkillTreeEditorViewport.h" #include "SceneViewport.h" #include "GraphEditor.h" #include "SDockTab.h" #include "SEditorViewport.h" #include "SCommonEditorViewportToolbarBase.h" #include "ISkillTree.h" #include "SkillTreeEditorViewportClient.h" #include "SSkillTreeEditorViewportToolbar.h" #include "SkillTreeObject.h" #include "SkillObject.h" #include "WorkspaceMenuStructureModule.h" #include "SkillTreeEditorCommands.h" #include "SSingleObjectDetailsPanel.h" #include "SkillTreeDetailsCustomization.h" #define LOCTEXT_NAMESPACE "SkillTreeEditor" const FName skillTreeEditorAppName = FName( TEXT( "SkillTreeEditorApp" ) ); // Tab identifiers. struct FSkillTreeEditorTabs { static const FName skillTreeViewportID; static const FName skillTreeDetailViewportID; static const FName skillViewportID; static const FName skillDetailViewportID; }; const FName FSkillTreeEditorTabs::skillTreeViewportID( TEXT( "STViewport" ) ); const FName FSkillTreeEditorTabs::skillViewportID( TEXT( "SViewport" ) ); const FName FSkillTreeEditorTabs::skillTreeDetailViewportID( TEXT( "STDViewport" ) ); const FName FSkillTreeEditorTabs::skillDetailViewportID( TEXT( "SDViewport" ) ); //TODO: Make separate headers for these classes. ///////////////////////////////////////////////////// // SSkillTreePropertiesTabBody class SSkillTreePropertiesTabBody : public SSingleObjectDetailsPanel { public: SLATE_BEGIN_ARGS( SSkillTreePropertiesTabBody ) {} SLATE_END_ARGS() private: // Pointer back to owning skill tree editor instance. TWeakPtr m_skillTreeEditorPtr; public: void Construct( const FArguments& a_args, TSharedPtr a_skillTreeEditor ) { m_skillTreeEditorPtr = a_skillTreeEditor; SSingleObjectDetailsPanel::Construct( SSingleObjectDetailsPanel::FArguments().HostCommandList( a_skillTreeEditor->GetToolkitCommands() ), true, true ); FOnGetDetailCustomizationInstance customizeSkillTreeForEditor = FOnGetDetailCustomizationInstance::CreateStatic( &FSkillTreeDetailsCustomization::MakeInstanceForSkillTreeEditor ); PropertyView->RegisterInstancedCustomPropertyLayout( USkillTreeObject::StaticClass(), customizeSkillTreeForEditor ); } // SSingleObjectDetailsPanel interface virtual UObject* GetObjectToObserve() const override { return m_skillTreeEditorPtr.Pin()->GetSkillTreeBeingEdited(); } virtual TSharedRef PopulateSlot( TSharedRef a_propertyEditorWidget ) override { return SNew( SVerticalBox ) + SVerticalBox::Slot() .FillHeight( 1 ) [ a_propertyEditorWidget ]; } // End of SSingleObjectDetailsPanel interface }; ///////////////////////////////////////////////////// // SSkillPropertiesTabBody class SSkillPropertiesTabBody : public SSingleObjectDetailsPanel { public: SLATE_BEGIN_ARGS( SSkillPropertiesTabBody ) {} SLATE_END_ARGS() private: // Pointer back to owning sprite editor instance (the keeper of state) TWeakPtr m_skillTreeEditorPtr; public: void Construct( const FArguments& InArgs, TSharedPtr a_skillTreeEditor ) { m_skillTreeEditorPtr = a_skillTreeEditor; SSingleObjectDetailsPanel::Construct( SSingleObjectDetailsPanel::FArguments().HostCommandList( a_skillTreeEditor->GetToolkitCommands() ), true, true ); FOnGetDetailCustomizationInstance customizeSkillTreeForEditor = FOnGetDetailCustomizationInstance::CreateStatic( &FSkillDetailsCustomization::MakeInstanceForSkillTreeEditor ); PropertyView->RegisterInstancedCustomPropertyLayout( USkillObject::StaticClass(), customizeSkillTreeForEditor ); } // SSingleObjectDetailsPanel interface virtual UObject* GetObjectToObserve() const override { return m_skillTreeEditorPtr.Pin()->GetSkillBeingEdited(); } virtual TSharedRef PopulateSlot( TSharedRef a_propertyEditorWidget ) override { return SNew( SVerticalBox ) + SVerticalBox::Slot() .FillHeight( 1 ) [ a_propertyEditorWidget ]; } // End of SSingleObjectDetailsPanel interface }; ///////////////////////////////////////////////////// // SSkillTreeEditorViewport class SSkillTreeEditorViewport : public SEditorViewport, public ICommonEditorViewportToolbarInfoProvider { public: SLATE_BEGIN_ARGS( SSkillTreeEditorViewport ) {} SLATE_END_ARGS() void Construct( const FArguments& a_args, TSharedPtr a_spriteEditor ); // SEditorViewport interface virtual void BindCommands() override; virtual TSharedRef MakeEditorViewportClient() override; virtual TSharedPtr MakeViewportToolbar() override; virtual EVisibility GetTransformToolbarVisibility() const override; virtual void OnFloatingButtonClicked() override; // End of SEditorViewport interface // ICommonEditorViewportToolbarInfoProvider interface virtual TSharedRef GetViewportWidget() override; virtual TSharedPtr GetExtenders() const override; // End of ICommonEditorViewportToolbarInfoProvider interface void ActivateEditMode() { m_editorViewportClient->ActivateEditMode(); } void IsSkill( bool a_state ) { m_editorViewportClient->IsSkill( a_state ); } private: // Pointer back to owning Skill Tree editor instance (the keeper of state). TWeakPtr m_skillTreeEditorPtr; // Viewport client TSharedPtr m_editorViewportClient; }; void SSkillTreeEditorViewport::Construct( const FArguments& a_args, TSharedPtr a_skillTreeEditor ) { m_skillTreeEditorPtr = a_skillTreeEditor; SEditorViewport::Construct( SEditorViewport::FArguments() ); } void SSkillTreeEditorViewport::BindCommands() { SEditorViewport::BindCommands(); const FSkillTreeEditorCommands& commands = FSkillTreeEditorCommands::Get(); TSharedRef editorViewportClientRef = m_editorViewportClient.ToSharedRef(); // Show toggles //TODO: Remove. CommandList->MapAction( commands.setShowGrid, FExecuteAction::CreateSP( editorViewportClientRef, &FEditorViewportClient::SetShowGrid ), FCanExecuteAction(), FIsActionChecked::CreateSP( editorViewportClientRef, &FEditorViewportClient::IsSetShowGridChecked ) ); // Editing modes //TODO: Remove. CommandList->MapAction( commands.enterViewMode, FExecuteAction::CreateSP( editorViewportClientRef, &FSkillTreeEditorViewportClient::EnterViewMode ), FCanExecuteAction(), FIsActionChecked::CreateSP( editorViewportClientRef, &FSkillTreeEditorViewportClient::IsInViewMode ) ); } // Make a new client for the viewport. TSharedRef SSkillTreeEditorViewport::MakeEditorViewportClient() { m_editorViewportClient = MakeShareable( new FSkillTreeEditorViewportClient( m_skillTreeEditorPtr, SharedThis( this ) ) ); return m_editorViewportClient.ToSharedRef(); } TSharedPtr SSkillTreeEditorViewport::MakeViewportToolbar() { return SNew( SSkillTreeEditorViewportToolbar, SharedThis( this ) ); } EVisibility SSkillTreeEditorViewport::GetTransformToolbarVisibility() const { return EVisibility::Visible; } TSharedRef SSkillTreeEditorViewport::GetViewportWidget() { return SharedThis( this ); } TSharedPtr SSkillTreeEditorViewport::GetExtenders() const { TSharedPtr Result( MakeShareable( new FExtender ) ); return Result; } //Needed to be implemented but not used. void SSkillTreeEditorViewport::OnFloatingButtonClicked() { } ///////////////////////////////////////////////////// // FSkillTreeEditorViewport TSharedRef FSkillTreeEditorViewport::SpawnTab_SKViewport( const FSpawnTabArgs& a_args ) { return SNew( SDockTab ) .Label( LOCTEXT( "SKViewportTab_Title", "Skill Tree" ) ) [ SNew( SOverlay ) // The Skill Tree editor viewport + SOverlay::Slot() [ m_skillTreeViewport.ToSharedRef() ] // Bottom-right corner text indicating the preview nature of the viewport. + SOverlay::Slot() .Padding( 10 ) .VAlign( VAlign_Bottom ) .HAlign( HAlign_Right ) [ SNew( STextBlock ) .Visibility( EVisibility::HitTestInvisible ) .TextStyle( FEditorStyle::Get(), "Graph.CornerText" ) .Text( LOCTEXT( "SKViewportTab_CornerText", "Edit Skill Tree" ) ) ] ]; } TSharedRef FSkillTreeEditorViewport::SpawnTab_SViewport( const FSpawnTabArgs& a_args ) { return SNew( SDockTab ) .Label( LOCTEXT( "SViewportTab_Title", "Skill" ) ) [ SNew( SOverlay ) // The sprite editor viewport + SOverlay::Slot() [ m_skillViewport.ToSharedRef() ] // Bottom-right corner text indicating the preview nature of the viewport. + SOverlay::Slot() .Padding( 10 ) .VAlign( VAlign_Bottom ) .HAlign( HAlign_Right ) [ SNew( STextBlock ) .Visibility( EVisibility::HitTestInvisible ) .TextStyle( FEditorStyle::Get(), "Graph.CornerText" ) .Text( LOCTEXT("SViewportTab_CornerText", "Edit Skill") ) ] ]; } TSharedRef FSkillTreeEditorViewport::SpawnTab_SKDViewport( const FSpawnTabArgs& a_args ) { TSharedPtr editorPtr = SharedThis( this ); // Spawn the tab return SNew( SDockTab ) .Label( LOCTEXT( "SKDViewportTab_Title", "Skill Tree Details" ) ) [ SNew( SSkillTreePropertiesTabBody, editorPtr ) ]; } TSharedRef FSkillTreeEditorViewport::SpawnTab_SDViewport( const FSpawnTabArgs& a_args ) { TSharedPtr editorPtr = SharedThis( this ); // Spawn the tab return SNew( SDockTab ) .Label( LOCTEXT( "SDViewportTab_Title", "Skill Details" ) ) [ SNew( SSkillPropertiesTabBody, editorPtr ) ]; } void FSkillTreeEditorViewport::RegisterTabSpawners( const TSharedRef& a_tabManager ) { WorkspaceMenuCategory = a_tabManager->AddLocalWorkspaceMenuCategory( LOCTEXT( "WorkspaceMenu_SpriteEditor", "Skill Tree Editor" ) ); auto workspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef(); FAssetEditorToolkit::RegisterTabSpawners( a_tabManager ); a_tabManager->RegisterTabSpawner( FSkillTreeEditorTabs::skillTreeViewportID, FOnSpawnTab::CreateSP( this, &FSkillTreeEditorViewport::SpawnTab_SKViewport ) ) .SetDisplayName( LOCTEXT( "SKViewportTab", "Skill Tree" ) ) .SetGroup( workspaceMenuCategoryRef ) .SetIcon( FSlateIcon( FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Viewports" ) ); a_tabManager->RegisterTabSpawner( FSkillTreeEditorTabs::skillTreeDetailViewportID, FOnSpawnTab::CreateSP( this, &FSkillTreeEditorViewport::SpawnTab_SKDViewport ) ) .SetDisplayName( LOCTEXT( "SKDViewportTab", "Skill Tree Details" ) ) .SetGroup( workspaceMenuCategoryRef ) .SetIcon( FSlateIcon( FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Viewports" ) ); a_tabManager->RegisterTabSpawner( FSkillTreeEditorTabs::skillViewportID, FOnSpawnTab::CreateSP( this, &FSkillTreeEditorViewport::SpawnTab_SViewport ) ) .SetDisplayName( LOCTEXT( "SViewportTab", "Skill" ) ) .SetGroup( workspaceMenuCategoryRef ) .SetIcon( FSlateIcon( FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Viewports" ) ); a_tabManager->RegisterTabSpawner( FSkillTreeEditorTabs::skillDetailViewportID, FOnSpawnTab::CreateSP( this, &FSkillTreeEditorViewport::SpawnTab_SDViewport ) ) .SetDisplayName( LOCTEXT( "SDViewportTab", "Skill Details" ) ) .SetGroup( workspaceMenuCategoryRef ) .SetIcon( FSlateIcon( FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Viewports" ) ); } void FSkillTreeEditorViewport::UnregisterTabSpawners( const TSharedRef& a_tabManager ) { FAssetEditorToolkit::UnregisterTabSpawners( a_tabManager ); a_tabManager->UnregisterTabSpawner( FSkillTreeEditorTabs::skillTreeViewportID ); a_tabManager->UnregisterTabSpawner( FSkillTreeEditorTabs::skillTreeDetailViewportID ); a_tabManager->UnregisterTabSpawner( FSkillTreeEditorTabs::skillViewportID ); a_tabManager->UnregisterTabSpawner( FSkillTreeEditorTabs::skillDetailViewportID ); } FName FSkillTreeEditorViewport::GetToolkitFName() const { return FName( "SkillTreeEditor" ); } void FSkillTreeEditorViewport::SetSkillBeingEdited( USkillObject* a_skill ) { if ( (a_skill != m_skillBeingEdited) && (a_skill != nullptr) ) { USkillObject* oldSkill = m_skillBeingEdited; m_skillBeingEdited = a_skill; //No longer needed. /* RemoveEditingObject( oldSkill ); AddEditingObject( a_skill ); */ } } FText FSkillTreeEditorViewport::GetBaseToolkitName() const { return LOCTEXT( "SkillTreeEditorAppLabel", "Skill Tree" ); } FText FSkillTreeEditorViewport::GetToolkitName() const { bool dirtyState = (m_skillTreeBeingEdited->GetOutermost()->IsDirty() || m_skillBeingEdited->GetOutermost()->IsDirty()); FFormatNamedArguments args; args.Add( TEXT( "SkillTreeName" ), FText::FromString( m_skillTreeBeingEdited->GetName() ) ); args.Add( TEXT( "DirtyState" ), dirtyState ? FText::FromString( TEXT( "*" ) ) : FText::GetEmpty() ); return FText::Format( LOCTEXT( "SkillTreeEditorAppLabel", "{SkillTreeName}{DirtyState}" ), args ); } FText FSkillTreeEditorViewport::GetToolkitToolTipText() const { return LOCTEXT( "SkillTreeToolTip", "Test tooltip text" ); } FString FSkillTreeEditorViewport::GetWorldCentricTabPrefix() const { return TEXT( "SkillTreeEditor" ); } FString FSkillTreeEditorViewport::GetDocumentationLink() const { return TEXT( "http://iamfromtheinternet.nl/wiki/index.php/Skill_Tree" ); } FLinearColor FSkillTreeEditorViewport::GetWorldCentricTabColorScale() const { return FLinearColor::White; } void FSkillTreeEditorViewport::CreateModeToolbarWidgets( FToolBarBuilder& a_ignoredBuilder ) { FToolBarBuilder toolbarBuilder( m_skillTreeViewport->GetCommandList(), FMultiBoxCustomization::None ); toolbarBuilder.AddToolBarButton( FSkillTreeEditorCommands::Get().enterViewMode ); AddToolbarWidget( toolbarBuilder.MakeWidget() ); } void FSkillTreeEditorViewport::InitSkillTreeEditor( const EToolkitMode::Type a_mode, const TSharedPtr< class IToolkitHost >& a_toolkitHost, class USkillTreeObject* a_skillTree, class USkillObject* a_skill ) { m_skillTreeBeingEdited = a_skillTree; m_tmpSkills = m_skillTreeBeingEdited->skills; if ( !a_skill ) { m_skillBeingEdited = NewObject(); m_skillBeingEdited->hexMap.width = 0; m_skillBeingEdited->hexMap.height = 0; } else { m_skillBeingEdited = a_skill; selectedY = m_tmpSkills.Find( TSubclassOf((UClass*)m_skillBeingEdited) ); } FSkillTreeEditorCommands::Register(); TSharedPtr skillTreeEditorPtr = SharedThis( this ); m_skillTreeViewport = SNew( SSkillTreeEditorViewport, skillTreeEditorPtr ); m_skillViewport = SNew( SSkillTreeEditorViewport, skillTreeEditorPtr ); m_skillViewport->IsSkill( true ); const TSharedRef defaultLayout = FTabManager::NewLayout( "SkillTreeEditor_Layout_v2" ) ->AddArea ( FTabManager::NewPrimaryArea() ->SetOrientation( Orient_Vertical ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient( 0.1f ) ->SetHideTabWell( true ) ->AddTab( GetToolbarTabId(), ETabState::OpenedTab ) ) ->Split ( FTabManager::NewSplitter() ->SetOrientation( Orient_Horizontal ) ->SetSizeCoefficient( 0.9f ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient( 0.35f ) ->SetHideTabWell( true ) ->AddTab( FSkillTreeEditorTabs::skillTreeViewportID, ETabState::OpenedTab ) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient( 0.15f ) ->SetHideTabWell( true ) ->AddTab( FSkillTreeEditorTabs::skillTreeDetailViewportID, ETabState::OpenedTab ) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient( 0.35f ) ->SetHideTabWell( true ) ->AddTab( FSkillTreeEditorTabs::skillViewportID, ETabState::OpenedTab ) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient( 0.15f ) ->SetHideTabWell( true ) ->AddTab( FSkillTreeEditorTabs::skillDetailViewportID, ETabState::OpenedTab ) ) ) ); // Initialize the asset editor InitAssetEditor( a_mode, a_toolkitHost, skillTreeEditorAppName, defaultLayout, true, true, a_skillTree ); m_skillTreeViewport->ActivateEditMode(); m_skillViewport->ActivateEditMode(); // Extend things RegenerateMenusAndToolbars(); } void FSkillTreeEditorViewport::UpdateSkills() { if ( m_skillTreeBeingEdited->skills != m_tmpSkills ) { for ( int i = 0; i < m_tmpSkills.Num(); i++ ) { if ( m_tmpSkills[i] != NULL && !m_skillTreeBeingEdited->skills.Contains( m_tmpSkills[i] ) ) { USkillObject* tmpSkill = (USkillObject*)*m_tmpSkills[i];//m_tmpSkills[i]->GetDefaultObject(); if ( tmpSkill != NULL ) tmpSkill->skillTree = NULL; } } for ( int i = 0; i < m_skillTreeBeingEdited->skills.Num(); i++ ) { if ( m_skillTreeBeingEdited->skills[i] != NULL && !m_tmpSkills.Contains( m_skillTreeBeingEdited->skills[i] ) ) { USkillObject* tmpSkill = (USkillObject*)*m_skillTreeBeingEdited->skills[i]; //m_skillTreeBeingEdited->skills[i]->GetDefaultObject(); if ( tmpSkill != NULL ) tmpSkill->skillTree = m_skillTreeBeingEdited; } } m_tmpSkills = m_skillTreeBeingEdited->skills; } } void FSkillTreeEditorViewport::SaveAsset_Execute() { TArray< UPackage* > PackagesToSave; PackagesToSave.Add( m_skillTreeBeingEdited->GetOutermost() ); PackagesToSave.Add( m_skillBeingEdited->GetOutermost() ); FEditorFileUtils::PromptForCheckoutAndSave( PackagesToSave, bCheckDirtyOnAssetSave, /*bPromptToSave=*/ false ); } #undef LOCTEXT_NAMESPACE