Files
UnrealEngineUWP/Engine/Source/Editor/EnvironmentQueryEditor/Private/EnvironmentQueryEditor.cpp

733 lines
22 KiB
C++
Raw Normal View History

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "EnvironmentQueryEditorPrivatePCH.h"
#include "GraphEditorActions.h"
#include "ScopedTransaction.h"
#include "EdGraphUtilities.h"
#include "EnvironmentQuery/EnvQuery.h"
#include "EnvironmentQuery/EnvQueryOption.h"
#include "EnvironmentQuery/EnvQueryGenerator.h"
#include "Toolkits/IToolkitHost.h"
#include "Editor/WorkspaceMenuStructure/Public/WorkspaceMenuStructureModule.h"
#include "Editor/PropertyEditor/Public/PropertyEditorModule.h"
#include "Editor/PropertyEditor/Public/IDetailsView.h"
#include "SDockTab.h"
#include "GenericCommands.h"
Window menu refactor & polish - Window menu is now sectioned and labeled based on the current editor. There's now a local workspace root member in FTabManager and a workspace category in FAssetEditorToolkit (both are FWorkspaceItem objects). Individual editors attach their local category to the tab manager's local root. Workflow app modes have their own category members that are swapped out when the mode changes. - Finally, the AssetEditorCategory of FWorkspaceMenuStructure has been removed entirely. - Replaced the AddMenuSeparator() call in FTabManager::PopulateSpawnerMenu_Helper() with a section of the same title as the workspace category. - Tab spawner menu entries for the local editor now properly show the icon of the associated tab. To accomplish this it was necessary to change FWorkflowTabFactory::TabIcon to be an FSlateIcon instead of an FSlateBrush*. All factory instances have been updated accordingly. - Added & updated lots of icons! (those missing will be TTP'd) - The nomad tab spawner section (named "General" in the menu) has been largely compressed into the Developer Tools submenu, which has also been organized into sections for readability. - Unreal frontend options were also moved into a context menu within the General section - Moved all experimental tools to their own section of the Window menu. When they're no longer experimental they should register as nomads in the appropriate category - Undo history now under Edit menu [CL 2324285 by Dan Hertzka in Main branch]
2014-10-09 12:34:55 -04:00
#define LOCTEXT_NAMESPACE "EnvironmentQueryEditor"
const FName FEnvironmentQueryEditor::EQSUpdateGraphTabId( TEXT( "EnvironmentQueryEditor_UpdateGraph" ) );
const FName FEnvironmentQueryEditor::EQSPropertiesTabId( TEXT( "EnvironmentQueryEditor_Properties" ) );
void FEnvironmentQueryEditor::RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager)
{
WorkspaceMenuCategory = TabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_EnvironmentQueryEditor", "Environment Query Editor"));
Window menu refactor & polish - Window menu is now sectioned and labeled based on the current editor. There's now a local workspace root member in FTabManager and a workspace category in FAssetEditorToolkit (both are FWorkspaceItem objects). Individual editors attach their local category to the tab manager's local root. Workflow app modes have their own category members that are swapped out when the mode changes. - Finally, the AssetEditorCategory of FWorkspaceMenuStructure has been removed entirely. - Replaced the AddMenuSeparator() call in FTabManager::PopulateSpawnerMenu_Helper() with a section of the same title as the workspace category. - Tab spawner menu entries for the local editor now properly show the icon of the associated tab. To accomplish this it was necessary to change FWorkflowTabFactory::TabIcon to be an FSlateIcon instead of an FSlateBrush*. All factory instances have been updated accordingly. - Added & updated lots of icons! (those missing will be TTP'd) - The nomad tab spawner section (named "General" in the menu) has been largely compressed into the Developer Tools submenu, which has also been organized into sections for readability. - Unreal frontend options were also moved into a context menu within the General section - Moved all experimental tools to their own section of the Window menu. When they're no longer experimental they should register as nomads in the appropriate category - Undo history now under Edit menu [CL 2324285 by Dan Hertzka in Main branch]
2014-10-09 12:34:55 -04:00
auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef();
Window menu refactor & polish - Window menu is now sectioned and labeled based on the current editor. There's now a local workspace root member in FTabManager and a workspace category in FAssetEditorToolkit (both are FWorkspaceItem objects). Individual editors attach their local category to the tab manager's local root. Workflow app modes have their own category members that are swapped out when the mode changes. - Finally, the AssetEditorCategory of FWorkspaceMenuStructure has been removed entirely. - Replaced the AddMenuSeparator() call in FTabManager::PopulateSpawnerMenu_Helper() with a section of the same title as the workspace category. - Tab spawner menu entries for the local editor now properly show the icon of the associated tab. To accomplish this it was necessary to change FWorkflowTabFactory::TabIcon to be an FSlateIcon instead of an FSlateBrush*. All factory instances have been updated accordingly. - Added & updated lots of icons! (those missing will be TTP'd) - The nomad tab spawner section (named "General" in the menu) has been largely compressed into the Developer Tools submenu, which has also been organized into sections for readability. - Unreal frontend options were also moved into a context menu within the General section - Moved all experimental tools to their own section of the Window menu. When they're no longer experimental they should register as nomads in the appropriate category - Undo history now under Edit menu [CL 2324285 by Dan Hertzka in Main branch]
2014-10-09 12:34:55 -04:00
FAssetEditorToolkit::RegisterTabSpawners(TabManager);
TabManager->RegisterTabSpawner( EQSUpdateGraphTabId, FOnSpawnTab::CreateSP(this, &FEnvironmentQueryEditor::SpawnTab_UpdateGraph) )
.SetDisplayName( NSLOCTEXT("EnvironmentQueryEditor", "Graph", "Graph") )
Window menu refactor & polish - Window menu is now sectioned and labeled based on the current editor. There's now a local workspace root member in FTabManager and a workspace category in FAssetEditorToolkit (both are FWorkspaceItem objects). Individual editors attach their local category to the tab manager's local root. Workflow app modes have their own category members that are swapped out when the mode changes. - Finally, the AssetEditorCategory of FWorkspaceMenuStructure has been removed entirely. - Replaced the AddMenuSeparator() call in FTabManager::PopulateSpawnerMenu_Helper() with a section of the same title as the workspace category. - Tab spawner menu entries for the local editor now properly show the icon of the associated tab. To accomplish this it was necessary to change FWorkflowTabFactory::TabIcon to be an FSlateIcon instead of an FSlateBrush*. All factory instances have been updated accordingly. - Added & updated lots of icons! (those missing will be TTP'd) - The nomad tab spawner section (named "General" in the menu) has been largely compressed into the Developer Tools submenu, which has also been organized into sections for readability. - Unreal frontend options were also moved into a context menu within the General section - Moved all experimental tools to their own section of the Window menu. When they're no longer experimental they should register as nomads in the appropriate category - Undo history now under Edit menu [CL 2324285 by Dan Hertzka in Main branch]
2014-10-09 12:34:55 -04:00
.SetGroup(WorkspaceMenuCategoryRef)
.SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "GraphEditor.EventGraph_16x"));
TabManager->RegisterTabSpawner( EQSPropertiesTabId, FOnSpawnTab::CreateSP(this, &FEnvironmentQueryEditor::SpawnTab_Properties) )
.SetDisplayName( NSLOCTEXT("EnvironmentQueryEditor", "PropertiesTab", "Details" ) )
Window menu refactor & polish - Window menu is now sectioned and labeled based on the current editor. There's now a local workspace root member in FTabManager and a workspace category in FAssetEditorToolkit (both are FWorkspaceItem objects). Individual editors attach their local category to the tab manager's local root. Workflow app modes have their own category members that are swapped out when the mode changes. - Finally, the AssetEditorCategory of FWorkspaceMenuStructure has been removed entirely. - Replaced the AddMenuSeparator() call in FTabManager::PopulateSpawnerMenu_Helper() with a section of the same title as the workspace category. - Tab spawner menu entries for the local editor now properly show the icon of the associated tab. To accomplish this it was necessary to change FWorkflowTabFactory::TabIcon to be an FSlateIcon instead of an FSlateBrush*. All factory instances have been updated accordingly. - Added & updated lots of icons! (those missing will be TTP'd) - The nomad tab spawner section (named "General" in the menu) has been largely compressed into the Developer Tools submenu, which has also been organized into sections for readability. - Unreal frontend options were also moved into a context menu within the General section - Moved all experimental tools to their own section of the Window menu. When they're no longer experimental they should register as nomads in the appropriate category - Undo history now under Edit menu [CL 2324285 by Dan Hertzka in Main branch]
2014-10-09 12:34:55 -04:00
.SetGroup(WorkspaceMenuCategoryRef)
.SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Details"));
}
void FEnvironmentQueryEditor::UnregisterTabSpawners(const TSharedRef<class FTabManager>& TabManager)
{
FAssetEditorToolkit::UnregisterTabSpawners(TabManager);
TabManager->UnregisterTabSpawner( EQSPropertiesTabId );
TabManager->UnregisterTabSpawner( EQSUpdateGraphTabId );
}
FEnvironmentQueryEditor::FEnvironmentQueryEditor() : IEnvironmentQueryEditor()
{
UEditorEngine* Editor = (UEditorEngine*)GEngine;
if (Editor != NULL)
{
Editor->RegisterForUndo(this);
}
}
FEnvironmentQueryEditor::~FEnvironmentQueryEditor()
{
UEditorEngine* Editor = (UEditorEngine*)GEngine;
if (Editor)
{
Editor->UnregisterForUndo( this );
}
}
void FEnvironmentQueryEditor::InitEnvironmentQueryEditor( const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UEnvQuery* InScript )
{
Query = InScript;
check(Query != NULL);
TSharedRef<FTabManager::FLayout> StandaloneDefaultLayout = FTabManager::NewLayout( "Standalone_EnvironmentQuery_Layout" )
->AddArea
(
FTabManager::NewPrimaryArea() ->SetOrientation(Orient_Vertical)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(0.1f)
->AddTab(GetToolbarTabId(), ETabState::OpenedTab)
->SetHideTabWell( true )
)
->Split
(
FTabManager::NewSplitter() ->SetOrientation(Orient_Horizontal)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(0.7f)
->AddTab( EQSUpdateGraphTabId, ETabState::OpenedTab )
)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(0.3f)
->AddTab( EQSPropertiesTabId, ETabState::OpenedTab )
)
)
);
const bool bCreateDefaultStandaloneMenu = true;
const bool bCreateDefaultToolbar = true;
FAssetEditorToolkit::InitAssetEditor( Mode, InitToolkitHost, FEnvironmentQueryEditorModule::EnvironmentQueryEditorAppIdentifier, StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, Query );
FEnvironmentQueryEditorModule& EnvironmentQueryEditorModule = FModuleManager::LoadModuleChecked<FEnvironmentQueryEditorModule>( "EnvironmentQueryEditor" );
AddMenuExtender(EnvironmentQueryEditorModule.GetMenuExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects()));
RegenerateMenusAndToolbars();
// Update BT asset data based on saved graph to have correct data in editor
TSharedPtr<SGraphEditor> UpdateGraphEditor = UpdateGraphEdPtr.Pin();
if (UpdateGraphEditor.IsValid() && UpdateGraphEditor->GetCurrentGraph() != NULL)
{
//let's find root node
UEnvironmentQueryGraph* EQSGraph = Cast<UEnvironmentQueryGraph>(UpdateGraphEditor->GetCurrentGraph());
EQSGraph->UpdateAsset();
}
}
FName FEnvironmentQueryEditor::GetToolkitFName() const
{
return FName("Environment Query");
}
FText FEnvironmentQueryEditor::GetBaseToolkitName() const
{
return NSLOCTEXT("EnvironmentQueryEditor", "AppLabel", "EnvironmentQuery");
}
FString FEnvironmentQueryEditor::GetWorldCentricTabPrefix() const
{
return NSLOCTEXT("EnvironmentQueryEditor", "WorldCentricTabPrefix", "EnvironmentQuery ").ToString();
}
FLinearColor FEnvironmentQueryEditor::GetWorldCentricTabColorScale() const
{
return FLinearColor( 0.0f, 0.0f, 0.2f, 0.5f );
}
/** Create new tab for the supplied graph - don't call this directly, call SExplorer->FindTabForGraph.*/
TSharedRef<SGraphEditor> FEnvironmentQueryEditor::CreateGraphEditorWidget(UEdGraph* InGraph)
{
check(InGraph != NULL);
GraphEditorCommands = MakeShareable( new FUICommandList );
{
// Editing commands
GraphEditorCommands->MapAction( FGenericCommands::Get().SelectAll,
FExecuteAction::CreateSP( this, &FEnvironmentQueryEditor::SelectAllNodes ),
FCanExecuteAction::CreateSP( this, &FEnvironmentQueryEditor::CanSelectAllNodes )
);
GraphEditorCommands->MapAction( FGenericCommands::Get().Delete,
FExecuteAction::CreateSP( this, &FEnvironmentQueryEditor::DeleteSelectedNodes ),
FCanExecuteAction::CreateSP( this, &FEnvironmentQueryEditor::CanDeleteNodes )
);
GraphEditorCommands->MapAction( FGenericCommands::Get().Copy,
FExecuteAction::CreateSP( this, &FEnvironmentQueryEditor::CopySelectedNodes ),
FCanExecuteAction::CreateSP( this, &FEnvironmentQueryEditor::CanCopyNodes )
);
GraphEditorCommands->MapAction( FGenericCommands::Get().Cut,
FExecuteAction::CreateSP( this, &FEnvironmentQueryEditor::CutSelectedNodes ),
FCanExecuteAction::CreateSP( this, &FEnvironmentQueryEditor::CanCutNodes )
);
GraphEditorCommands->MapAction( FGenericCommands::Get().Paste,
FExecuteAction::CreateSP( this, &FEnvironmentQueryEditor::PasteNodes ),
FCanExecuteAction::CreateSP( this, &FEnvironmentQueryEditor::CanPasteNodes )
);
GraphEditorCommands->MapAction( FGenericCommands::Get().Duplicate,
FExecuteAction::CreateSP( this, &FEnvironmentQueryEditor::DuplicateNodes ),
FCanExecuteAction::CreateSP( this, &FEnvironmentQueryEditor::CanDuplicateNodes )
);
}
// Create the appearance info
FGraphAppearanceInfo AppearanceInfo;
AppearanceInfo.CornerText = NSLOCTEXT("EnvironmentQueryEditor", "AppearanceCornerText", "ENVIRONMENT QUERY");
SGraphEditor::FGraphEditorEvents InEvents;
InEvents.OnSelectionChanged = SGraphEditor::FOnSelectionChanged::CreateSP(this, &FEnvironmentQueryEditor::OnSelectedNodesChanged);
// Make title bar
TSharedRef<SWidget> TitleBarWidget =
SNew(SBorder)
.BorderImage( FEditorStyle::GetBrush( TEXT("Graph.TitleBackground") ) )
.HAlign(HAlign_Fill)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.HAlign(HAlign_Center)
.FillWidth(1.f)
[
SNew(STextBlock)
.Text(NSLOCTEXT("EnvironmentQueryEditor", "TheQueryGraphLabel", "Query Graph"))
.TextStyle( FEditorStyle::Get(), TEXT("GraphBreadcrumbButtonText") )
]
];
// Make full graph editor
return SNew(SGraphEditor)
.AdditionalCommands(GraphEditorCommands)
.Appearance(AppearanceInfo)
.TitleBar(TitleBarWidget)
.GraphToEdit(InGraph)
.GraphEvents(InEvents);
}
TSharedRef<SDockTab> FEnvironmentQueryEditor::SpawnTab_UpdateGraph( const FSpawnTabArgs& Args )
{
check( Args.GetTabId().TabType == EQSUpdateGraphTabId );
if (Query->EdGraph == NULL)
{
UEnvironmentQueryGraph* MyGraph = NewObject<UEnvironmentQueryGraph>(Query, NAME_None, RF_Transactional);
MyGraph->MarkVersion();
Query->EdGraph = MyGraph;
// let's read data from BT script and generate nodes
const UEdGraphSchema* Schema = Query->EdGraph->GetSchema();
Schema->CreateDefaultNodesForGraph(*Query->EdGraph);
}
// Conversion should be removed are a while
UEnvironmentQueryGraph* QueryGraph = Cast<UEnvironmentQueryGraph>(Query->EdGraph);
QueryGraph->UpdateVersion();
QueryGraph->CalculateAllWeights();
TSharedRef<SGraphEditor> UpdateGraphEditor = CreateGraphEditorWidget(Query->EdGraph);
UpdateGraphEdPtr = UpdateGraphEditor; // Keep pointer to editor
return SNew(SDockTab)
.Label( NSLOCTEXT("EnvironmentQueryEditor", "UpdateGraph", "Update Graph") )
.TabColorScale( GetTabColorScale() )
[
UpdateGraphEditor
];
}
TSharedRef<SDockTab> FEnvironmentQueryEditor::SpawnTab_Properties(const FSpawnTabArgs& Args)
{
check( Args.GetTabId() == EQSPropertiesTabId );
CreateInternalWidgets();
TSharedRef<SDockTab> SpawnedTab = SNew(SDockTab)
.Icon( FEditorStyle::GetBrush("SoundClassEditor.Tabs.Properties") )
.Label( NSLOCTEXT("EnvironmentQueryEditor", "SoundClassPropertiesTitle", "Details" ) )
[
DetailsView.ToSharedRef()
];
return SpawnedTab;
}
void FEnvironmentQueryEditor::OnSelectedNodesChanged(const TSet<class UObject*>& NewSelection)
{
TArray<UObject*> Selection;
if(NewSelection.Num())
{
for(TSet<class UObject*>::TConstIterator SetIt(NewSelection);SetIt;++SetIt)
{
UEnvironmentQueryGraphNode* GraphNode = CastChecked<UEnvironmentQueryGraphNode>(*SetIt);
if (GraphNode)
{
if (GraphNode->IsA(UEnvironmentQueryGraphNode_Root::StaticClass()))
{
Selection.Add(GraphNode);
}
else if (GraphNode->IsA(UEnvironmentQueryGraphNode_Option::StaticClass()))
{
UEnvQueryOption* QueryOption = Cast<UEnvQueryOption>(GraphNode->NodeInstance);
if (QueryOption)
{
Selection.Add(QueryOption->Generator);
}
}
else
{
Selection.Add(GraphNode->NodeInstance);
}
}
}
}
if (Selection.Num() == 1)
{
DetailsView->SetObjects(Selection);
}
else
{
DetailsView->SetObject(NULL);
}
}
void FEnvironmentQueryEditor::CreateInternalWidgets()
{
FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>( "PropertyEditor" );
const FDetailsViewArgs DetailsViewArgs( false, false, true, FDetailsViewArgs::ObjectsUseNameArea, false );
DetailsView = PropertyEditorModule.CreateDetailView( DetailsViewArgs );
DetailsView->SetObject( NULL );
DetailsView->OnFinishedChangingProperties().AddSP(this, &FEnvironmentQueryEditor::OnFinishedChangingProperties);
}
void FEnvironmentQueryEditor::SaveAsset_Execute()
{
// modify BT asset
TSharedPtr<SGraphEditor> UpdateGraphEditor = UpdateGraphEdPtr.Pin();
if (UpdateGraphEditor.IsValid() && UpdateGraphEditor->GetCurrentGraph() != NULL)
{
//let's find root node
UEnvironmentQueryGraph* EdGraph = Cast<UEnvironmentQueryGraph>(UpdateGraphEditor->GetCurrentGraph());
EdGraph->UpdateAsset();
}
// save it
IEnvironmentQueryEditor::SaveAsset_Execute();
}
void FEnvironmentQueryEditor::OnFinishedChangingProperties(const FPropertyChangedEvent& PropertyChangedEvent)
{
if (PropertyChangedEvent.Property)
{
FGraphPanelSelectionSet CurrentSelection = GetSelectedNodes();
if (CurrentSelection.Num() == 1)
{
for (FGraphPanelSelectionSet::TConstIterator It(CurrentSelection); It; ++It)
{
UEnvironmentQueryGraphNode_Test* TestNode = Cast<UEnvironmentQueryGraphNode_Test>(*It);
if (TestNode && TestNode->ParentNode)
{
TestNode->ParentNode->CalculateWeights();
break;
}
}
}
}
}
void FEnvironmentQueryEditor::PostUndo(bool bSuccess)
{
if (bSuccess)
{
// Clear selection, to avoid holding refs to nodes that go away
TSharedPtr<SGraphEditor> CurrentGraphEditor = UpdateGraphEdPtr.Pin();
if (CurrentGraphEditor.IsValid())
{
CurrentGraphEditor->ClearSelectionSet();
CurrentGraphEditor->NotifyGraphChanged();
}
FSlateApplication::Get().DismissAllMenus();
}
}
void FEnvironmentQueryEditor::PostRedo(bool bSuccess)
{
if (bSuccess)
{
// Clear selection, to avoid holding refs to nodes that go away
TSharedPtr<SGraphEditor> CurrentGraphEditor = UpdateGraphEdPtr.Pin();
if (CurrentGraphEditor.IsValid())
{
CurrentGraphEditor->ClearSelectionSet();
CurrentGraphEditor->NotifyGraphChanged();
}
FSlateApplication::Get().DismissAllMenus();
}
}
FGraphPanelSelectionSet FEnvironmentQueryEditor::GetSelectedNodes() const
{
FGraphPanelSelectionSet CurrentSelection;
TSharedPtr<SGraphEditor> FocusedGraphEd = UpdateGraphEdPtr.Pin();
if (FocusedGraphEd.IsValid())
{
CurrentSelection = FocusedGraphEd->GetSelectedNodes();
}
return CurrentSelection;
}
void FEnvironmentQueryEditor::SelectAllNodes()
{
TSharedPtr<SGraphEditor> CurrentGraphEditor = UpdateGraphEdPtr.Pin();
if (CurrentGraphEditor.IsValid())
{
CurrentGraphEditor->SelectAllNodes();
}
}
bool FEnvironmentQueryEditor::CanSelectAllNodes() const
{
return true;
}
void FEnvironmentQueryEditor::DeleteSelectedNodes()
{
TSharedPtr<SGraphEditor> CurrentGraphEditor = UpdateGraphEdPtr.Pin();
if (!CurrentGraphEditor.IsValid())
{
return;
}
const FScopedTransaction Transaction( FGenericCommands::Get().Delete->GetDescription() );
CurrentGraphEditor->GetCurrentGraph()->Modify();
const FGraphPanelSelectionSet SelectedNodes = CurrentGraphEditor->GetSelectedNodes();
CurrentGraphEditor->ClearSelectionSet();
for (FGraphPanelSelectionSet::TConstIterator NodeIt( SelectedNodes ); NodeIt; ++NodeIt)
{
if (UEdGraphNode* Node = Cast<UEdGraphNode>(*NodeIt))
{
if (Node->CanUserDeleteNode())
{
Node->Modify();
Node->DestroyNode();
}
}
}
}
bool FEnvironmentQueryEditor::CanDeleteNodes() const
{
// If any of the nodes can be deleted then we should allow deleting
const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes();
for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
{
UEdGraphNode* Node = Cast<UEdGraphNode>(*SelectedIter);
if (Node && Node->CanUserDeleteNode())
{
return true;
}
}
return false;
}
void FEnvironmentQueryEditor::DeleteSelectedDuplicatableNodes()
{
TSharedPtr<SGraphEditor> CurrentGraphEditor = UpdateGraphEdPtr.Pin();
if (!CurrentGraphEditor.IsValid())
{
return;
}
const FGraphPanelSelectionSet OldSelectedNodes = CurrentGraphEditor->GetSelectedNodes();
CurrentGraphEditor->ClearSelectionSet();
for (FGraphPanelSelectionSet::TConstIterator SelectedIter(OldSelectedNodes); SelectedIter; ++SelectedIter)
{
UEdGraphNode* Node = Cast<UEdGraphNode>(*SelectedIter);
if (Node && Node->CanDuplicateNode())
{
CurrentGraphEditor->SetNodeSelection(Node, true);
}
}
// Delete the duplicatable nodes
DeleteSelectedNodes();
CurrentGraphEditor->ClearSelectionSet();
for (FGraphPanelSelectionSet::TConstIterator SelectedIter(OldSelectedNodes); SelectedIter; ++SelectedIter)
{
if (UEdGraphNode* Node = Cast<UEdGraphNode>(*SelectedIter))
{
CurrentGraphEditor->SetNodeSelection(Node, true);
}
}
}
void FEnvironmentQueryEditor::CutSelectedNodes()
{
CopySelectedNodes();
DeleteSelectedDuplicatableNodes();
}
bool FEnvironmentQueryEditor::CanCutNodes() const
{
return CanCopyNodes() && CanDeleteNodes();
}
void FEnvironmentQueryEditor::CopySelectedNodes()
{
// Export the selected nodes and place the text on the clipboard
FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes();
TArray<UEnvironmentQueryGraphNode*> SubNodes;
FString ExportedText;
int32 CopySubNodeIndex = 0;
for (FGraphPanelSelectionSet::TIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
{
UEnvironmentQueryGraphNode_Option* OptionNode = Cast<UEnvironmentQueryGraphNode_Option>(*SelectedIter);
UEnvironmentQueryGraphNode_Test* TestNode = Cast<UEnvironmentQueryGraphNode_Test>(*SelectedIter);
UEnvironmentQueryGraphNode* Node = OptionNode ? (UEnvironmentQueryGraphNode*)OptionNode : (UEnvironmentQueryGraphNode*)TestNode;
if (OptionNode == NULL && TestNode == NULL)
{
SelectedIter.RemoveCurrent();
continue;
}
Node->PrepareForCopying();
Node->CopySubNodeIndex = CopySubNodeIndex;
// append all subnodes for selection
if (OptionNode)
{
for (int32 i = 0; i < OptionNode->Tests.Num(); i++)
{
OptionNode->Tests[i]->CopySubNodeIndex = CopySubNodeIndex;
SubNodes.Add(OptionNode->Tests[i]);
}
}
CopySubNodeIndex++;
}
for (int32 i = 0; i < SubNodes.Num(); i++)
{
SelectedNodes.Add(SubNodes[i]);
SubNodes[i]->PrepareForCopying();
}
FEdGraphUtilities::ExportNodesToText(SelectedNodes, ExportedText);
FPlatformMisc::ClipboardCopy(*ExportedText);
for (FGraphPanelSelectionSet::TIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
{
UEnvironmentQueryGraphNode* Node = Cast<UEnvironmentQueryGraphNode>(*SelectedIter);
Node->PostCopyNode();
}
}
bool FEnvironmentQueryEditor::CanCopyNodes() const
{
// If any of the nodes can be duplicated then we should allow copying
const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes();
for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
{
UEdGraphNode* Node = Cast<UEdGraphNode>(*SelectedIter);
if (Node && Node->CanDuplicateNode())
{
return true;
}
}
return false;
}
void FEnvironmentQueryEditor::PasteNodes()
{
TSharedPtr<SGraphEditor> CurrentGraphEditor = UpdateGraphEdPtr.Pin();
if (CurrentGraphEditor.IsValid())
{
PasteNodesHere(CurrentGraphEditor->GetPasteLocation());
}
}
void FEnvironmentQueryEditor::PasteNodesHere(const FVector2D& Location)
{
TSharedPtr<SGraphEditor> CurrentGraphEditor = UpdateGraphEdPtr.Pin();
if (!CurrentGraphEditor.IsValid())
{
return;
}
// Undo/Redo support
const FScopedTransaction Transaction( FGenericCommands::Get().Paste->GetDescription() );
UEnvironmentQueryGraph* EdGraph = Cast<UEnvironmentQueryGraph>(CurrentGraphEditor->GetCurrentGraph());
EdGraph->Modify();
EdGraph->LockUpdates();
// Find currently selected option to paste all new tests into
UEnvironmentQueryGraphNode_Option* SelectedOption = NULL;
bool bHasMultipleOptionsSelected = false;
const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes();
for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
{
UEnvironmentQueryGraphNode_Option* Node = Cast<UEnvironmentQueryGraphNode_Option>(*SelectedIter);
UEnvironmentQueryGraphNode_Test* TestNode = Cast<UEnvironmentQueryGraphNode_Test>(*SelectedIter);
if (TestNode)
{
Node = TestNode->ParentNode;
}
if (Node)
{
if (SelectedOption == NULL)
{
SelectedOption = Node;
}
else
{
bHasMultipleOptionsSelected = true;
break;
}
}
}
// Clear the selection set (newly pasted stuff will be selected)
CurrentGraphEditor->ClearSelectionSet();
// Grab the text to paste from the clipboard.
FString TextToImport;
FPlatformMisc::ClipboardPaste(TextToImport);
// Import the nodes
TSet<UEdGraphNode*> PastedNodes;
FEdGraphUtilities::ImportNodesFromText(EdGraph, TextToImport, /*out*/ PastedNodes);
//Average position of nodes so we can move them while still maintaining relative distances to each other
FVector2D AvgNodePosition(0.0f,0.0f);
for (TSet<UEdGraphNode*>::TIterator It(PastedNodes); It; ++It)
{
UEnvironmentQueryGraphNode* BTNode = Cast<UEnvironmentQueryGraphNode>(*It);
if (BTNode && !BTNode->IsSubNode())
{
AvgNodePosition.X += BTNode->NodePosX;
AvgNodePosition.Y += BTNode->NodePosY;
}
}
if (PastedNodes.Num() > 0)
{
float InvNumNodes = 1.0f/float(PastedNodes.Num());
AvgNodePosition.X *= InvNumNodes;
AvgNodePosition.Y *= InvNumNodes;
}
bool bPastedOptionNode = false;
TMap<int32, UEnvironmentQueryGraphNode_Option*> ParentMap;
for (TSet<UEdGraphNode*>::TIterator It(PastedNodes); It; ++It)
{
UEnvironmentQueryGraphNode* PasteNode = Cast<UEnvironmentQueryGraphNode>(*It);
if (PasteNode && !PasteNode->IsSubNode())
{
bPastedOptionNode = true;
// Select the newly pasted stuff
CurrentGraphEditor->SetNodeSelection(PasteNode, true);
PasteNode->NodePosX = (PasteNode->NodePosX - AvgNodePosition.X) + Location.X ;
PasteNode->NodePosY = (PasteNode->NodePosY - AvgNodePosition.Y) + Location.Y ;
PasteNode->SnapToGrid(16);
// Give new node a different Guid from the old one
PasteNode->CreateNewGuid();
UEnvironmentQueryGraphNode_Option* PasteOption = Cast<UEnvironmentQueryGraphNode_Option>(PasteNode);
if (PasteOption)
{
PasteOption->Tests.Reset();
ParentMap.Add(PasteOption->CopySubNodeIndex, PasteOption);
}
}
}
for (TSet<UEdGraphNode*>::TIterator It(PastedNodes); It; ++It)
{
UEnvironmentQueryGraphNode_Test* PasteTest = Cast<UEnvironmentQueryGraphNode_Test>(*It);
if (PasteTest)
{
PasteTest->NodePosX = 0;
PasteTest->NodePosY = 0;
// Give new node a different Guid from the old one
PasteTest->CreateNewGuid();
// remove subnode from graph, it will be referenced from parent node
PasteTest->DestroyNode();
PasteTest->ParentNode = ParentMap.FindRef(PasteTest->CopySubNodeIndex);
if (PasteTest->ParentNode)
{
PasteTest->ParentNode->Tests.Add(PasteTest);
}
else if (!bHasMultipleOptionsSelected && !bPastedOptionNode && SelectedOption)
{
PasteTest->ParentNode = SelectedOption;
SelectedOption->Tests.Add(PasteTest);
SelectedOption->Modify();
}
}
}
// Update UI
EdGraph->UnlockUpdates();
CurrentGraphEditor->NotifyGraphChanged();
Query->PostEditChange();
Query->MarkPackageDirty();
}
bool FEnvironmentQueryEditor::CanPasteNodes() const
{
TSharedPtr<SGraphEditor> CurrentGraphEditor = UpdateGraphEdPtr.Pin();
if (!CurrentGraphEditor.IsValid())
{
return false;
}
FString ClipboardContent;
FPlatformMisc::ClipboardPaste(ClipboardContent);
return FEdGraphUtilities::CanImportNodesFromText(CurrentGraphEditor->GetCurrentGraph(), ClipboardContent);
}
void FEnvironmentQueryEditor::DuplicateNodes()
{
CopySelectedNodes();
PasteNodes();
}
bool FEnvironmentQueryEditor::CanDuplicateNodes() const
{
return CanCopyNodes();
}
Window menu refactor & polish - Window menu is now sectioned and labeled based on the current editor. There's now a local workspace root member in FTabManager and a workspace category in FAssetEditorToolkit (both are FWorkspaceItem objects). Individual editors attach their local category to the tab manager's local root. Workflow app modes have their own category members that are swapped out when the mode changes. - Finally, the AssetEditorCategory of FWorkspaceMenuStructure has been removed entirely. - Replaced the AddMenuSeparator() call in FTabManager::PopulateSpawnerMenu_Helper() with a section of the same title as the workspace category. - Tab spawner menu entries for the local editor now properly show the icon of the associated tab. To accomplish this it was necessary to change FWorkflowTabFactory::TabIcon to be an FSlateIcon instead of an FSlateBrush*. All factory instances have been updated accordingly. - Added & updated lots of icons! (those missing will be TTP'd) - The nomad tab spawner section (named "General" in the menu) has been largely compressed into the Developer Tools submenu, which has also been organized into sections for readability. - Unreal frontend options were also moved into a context menu within the General section - Moved all experimental tools to their own section of the Window menu. When they're no longer experimental they should register as nomads in the appropriate category - Undo history now under Edit menu [CL 2324285 by Dan Hertzka in Main branch]
2014-10-09 12:34:55 -04:00
#undef LOCTEXT_NAMESPACE