void FMyObjectAssetAction::OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<class IToolkitHost> EditWithinLevelEditor) { const EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone; for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ++ObjIt) { UMyObject* PropData = Cast<UMyObject>(*ObjIt); if (PropData) { TSharedRef<FCustAssetEditor> NewCustEditor(new FCustAssetEditor()); NewCustEditor->InitCustAssetEditor(Mode, EditWithinLevelEditor, PropData); } } }
class FCustAssetEditor : public FAssetEditorToolkit, public FNotifyHook { public: ~FCustAssetEditor(); // IToolkit interface virtual void RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override; virtual void UnregisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override; // FAssetEditorToolkit virtual FName GetToolkitFName() const override; virtual FText GetBaseToolkitName() const override; virtual FLinearColor GetWorldCentricTabColorScale() const override; virtual FString GetWorldCentricTabPrefix() const override; void InitCustAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UMyObject* PropData); int N; protected: void OnGraphChanged(const FEdGraphEditAction& Action); void SelectAllNodes(); bool CanSelectAllNodes() const; void DeleteSelectedNodes(); bool CanDeleteNode(class UEdGraphNode* Node); bool CanDeleteNodes() const; void DeleteNodes(const TArray<class UEdGraphNode*>& NodesToDelete); void CopySelectedNodes(); bool CanCopyNodes() const; void PasteNodes(); void PasteNodesHere(const FVector2D& Location); bool CanPasteNodes() const; void CutSelectedNodes(); bool CanCutNodes() const; void DuplicateNodes(); bool CanDuplicateNodes() const; void DeleteSelectedDuplicatableNodes(); /** Called when the selection changes in the GraphEditor */ void OnSelectedNodesChanged(const TSet<class UObject*>& NewSelection); /** Called when a node is double clicked */ void OnNodeDoubleClicked(class UEdGraphNode* Node); void ShowMessage(); TSharedRef<class SGraphEditor> CreateGraphEditorWidget(UEdGraph* InGraph); TSharedPtr<SGraphEditor> GraphEditor; TSharedPtr<FUICommandList> GraphEditorCommands; TSharedPtr<IDetailsView> PropertyEditor; UMyObject* PropBeingEdited; TSharedRef<SDockTab> SpawnTab_Viewport(const FSpawnTabArgs& Args); TSharedRef<SDockTab> SpawnTab_Details(const FSpawnTabArgs& Args); FDelegateHandle OnGraphChangedDelegateHandle; TSharedPtr<FExtender> ToolbarExtender; TSharedPtr<FUICommandList> MyToolBarCommands; bool bGraphStateChanged; void AddToolbarExtension(FToolBarBuilder &builder); };
const TSharedRef<FTabManager::FLayout> StandaloneDefaultLayout = FTabManager::NewLayout("CustomEditor_Layout") ->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.2f) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.8f) ->SetHideTabWell(true) ->AddTab(FCustomEditorTabs::ViewportID, ETabState::OpenedTab) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.2f) ->SetHideTabWell(true) ->AddTab(FCustomEditorTabs::DetailsID, ETabState::OpenedTab) ) ) );
void FCustAssetEditor::RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) { WorkspaceMenuCategory = TabManager->AddLocalWorkspaceMenuCategory(FText::FromString("Custom Editor")); auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef(); FAssetEditorToolkit::RegisterTabSpawners(TabManager); TabManager->RegisterTabSpawner(FCustomEditorTabs::ViewportID, FOnSpawnTab::CreateSP(this, &FCustAssetEditor::SpawnTab_Viewport)) .SetDisplayName(FText::FromString("Viewport")) .SetGroup(WorkspaceMenuCategoryRef) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Viewports")); TabManager->RegisterTabSpawner(FCustomEditorTabs::DetailsID, FOnSpawnTab::CreateSP(this, &FCustAssetEditor::SpawnTab_Details)) .SetDisplayName(FText::FromString("Details")) .SetGroup(WorkspaceMenuCategoryRef) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Details")); } TSharedRef<SDockTab> FCustAssetEditor::SpawnTab_Viewport(const FSpawnTabArgs& Args) { return SNew(SDockTab) .Label(FText::FromString("Mesh Graph")) .TabColorScale(GetTabColorScale()) [ GraphEditor.ToSharedRef() ]; } TSharedRef<SDockTab> FCustAssetEditor::SpawnTab_Details(const FSpawnTabArgs& Args) { FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor"); const FDetailsViewArgs DetailsViewArgs(false, false, true, FDetailsViewArgs::HideNameArea, true, this); TSharedRef<IDetailsView> PropertyEditorRef = PropertyEditorModule.CreateDetailView(DetailsViewArgs); PropertyEditor = PropertyEditorRef; // Spawn the tab return SNew(SDockTab) .Label(FText::FromString("Details")) [ PropertyEditorRef ]; }
TSharedRef<SGraphEditor> FCustAssetEditor::CreateGraphEditorWidget(UEdGraph* InGraph) { // Create the appearance info FGraphAppearanceInfo AppearanceInfo; AppearanceInfo.CornerText = FText::FromString("Mesh tree Editor"); GraphEditorCommands = MakeShareable(new FUICommandList); { GraphEditorCommands->MapAction(FGenericCommands::Get().SelectAll, FExecuteAction::CreateSP(this, &FCustAssetEditor::SelectAllNodes), FCanExecuteAction::CreateSP(this, &FCustAssetEditor::CanSelectAllNodes) ); GraphEditorCommands->MapAction(FGenericCommands::Get().Delete, FExecuteAction::CreateSP(this, &FCustAssetEditor::DeleteSelectedNodes), FCanExecuteAction::CreateSP(this, &FCustAssetEditor::CanDeleteNodes) ); GraphEditorCommands->MapAction(FGenericCommands::Get().Copy, FExecuteAction::CreateSP(this, &FCustAssetEditor::CopySelectedNodes), FCanExecuteAction::CreateSP(this, &FCustAssetEditor::CanCopyNodes) ); GraphEditorCommands->MapAction(FGenericCommands::Get().Paste, FExecuteAction::CreateSP(this, &FCustAssetEditor::PasteNodes), FCanExecuteAction::CreateSP(this, &FCustAssetEditor::CanPasteNodes) ); GraphEditorCommands->MapAction(FGenericCommands::Get().Cut, FExecuteAction::CreateSP(this, &FCustAssetEditor::CutSelectedNodes), FCanExecuteAction::CreateSP(this, &FCustAssetEditor::CanCutNodes) ); GraphEditorCommands->MapAction(FGenericCommands::Get().Duplicate, FExecuteAction::CreateSP(this, &FCustAssetEditor::DuplicateNodes), FCanExecuteAction::CreateSP(this, &FCustAssetEditor::CanDuplicateNodes) ); } SGraphEditor::FGraphEditorEvents InEvents; InEvents.OnSelectionChanged = SGraphEditor::FOnSelectionChanged::CreateSP(this, &FCustAssetEditor::OnSelectedNodesChanged); InEvents.OnNodeDoubleClicked = FSingleNodeEvent::CreateSP(this, &FCustAssetEditor::OnNodeDoubleClicked); TSharedRef<SGraphEditor> _GraphEditor = SNew(SGraphEditor) .AdditionalCommands(GraphEditorCommands) .Appearance(AppearanceInfo) .GraphToEdit(InGraph) .GraphEvents(InEvents) ; return _GraphEditor; }
UCLASS() class UEdGraphSchema_CustomEditor : public UEdGraphSchema { GENERATED_UCLASS_BODY() // Begin EdGraphSchema interface virtual void GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const override; virtual void GetContextMenuActions(const UEdGraph* CurrentGraph, const UEdGraphNode* InGraphNode, const UEdGraphPin* InGraphPin, FMenuBuilder* MenuBuilder, bool bIsDebugging) const override; virtual const FPinConnectionResponse CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const override; virtual class FConnectionDrawingPolicy* CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const override; virtual FLinearColor GetPinTypeColor(const FEdGraphPinType& PinType) const override; virtual bool ShouldHidePinDefaultValue(UEdGraphPin* Pin) const override; // End EdGraphSchema interface };
void UEdGraphSchema_CustomEditor::GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const { FFormatNamedArguments Args; const FName AttrName("Attributes"); Args.Add(TEXT("Attribute"), FText::FromName(AttrName)); const UEdGraphPin* FromPin = ContextMenuBuilder.FromPin; const UEdGraph* Graph = ContextMenuBuilder.CurrentGraph; TArray<TSharedPtr<FEdGraphSchemaAction> > Actions; CustomSchemaUtils::AddAction<URootNode>(TEXT("Add Root Node"), TEXT("Add root node to the prop graph"), Actions, ContextMenuBuilder.OwnerOfTemporaries); CustomSchemaUtils::AddAction<UBranchNode>(TEXT("Add Brunch Node"), TEXT("Add brunch node to the prop graph"), Actions, ContextMenuBuilder.OwnerOfTemporaries); CustomSchemaUtils::AddAction<URuleNode>(TEXT("Add Rule Node"), TEXT("Add ruleh node to the prop graph"), Actions, ContextMenuBuilder.OwnerOfTemporaries); CustomSchemaUtils::AddAction<USwitcherNode>(TEXT("Add Switch Node"), TEXT("Add switch node to the prop graph"), Actions, ContextMenuBuilder.OwnerOfTemporaries); for (TSharedPtr<FEdGraphSchemaAction> Action : Actions) { ContextMenuBuilder.AddAction(Action); } }
UCLASS() class UICUSTOM_API UCustomNodeBase : public UEdGraphNode { GENERATED_BODY() public: virtual TArray<UCustomNodeBase*> GetChildNodes(FRandomStream& RandomStream); virtual void CreateNodesMesh(UWorld* World, FName ActorTag, FRandomStream& RandomStream, FVector AbsLocation, FRotator AbsRotation); virtual void PostEditChangeProperty(struct FPropertyChangedEvent& e) override; TSharedPtr<FNodePropertyObserver> PropertyObserver; FVector Location; FRotator Rotation; };
class SGraphNode_CustomNodeBase : public SGraphNode, public FNodePropertyObserver { public: SLATE_BEGIN_ARGS(SGraphNode_CustomNodeBase) { } SLATE_END_ARGS() /** Constructs this widget with InArgs */ void Construct(const FArguments& InArgs, UCustomNodeBase* InNode); // SGraphNode interface virtual void UpdateGraphNode() override; virtual void CreatePinWidgets() override; virtual void AddPin(const TSharedRef<SGraphPin>& PinToAdd) override; virtual void CreateNodeWidget(); // End of SGraphNode interface // FPropertyObserver interface virtual void OnPropertyChanged(UEdGraphNode* Sender, const FName& PropertyName) override; // End of FPropertyObserver interface protected: UCustomNodeBase* NodeBace; virtual FSlateColor GetBorderBackgroundColor() const; virtual const FSlateBrush* GetNameIcon() const; TSharedPtr<SHorizontalBox> OutputPinBox; FLinearColor BackgroundColor; TSharedPtr<SOverlay> NodeWiget; };
void FUICustomEditorModule::StartupModule() { //Registrate asset actions for MyObject FMyObjectAssetAction::RegistrateCustomPartAssetType(); //Registrate detail pannel costamization for TestActor FMyClassDetails::RegestrateCostumization(); // Register custom graph nodes TSharedPtr<FGraphPanelNodeFactory> GraphPanelNodeFactory = MakeShareable(new FGraphPanelNodeFactory_Custom); FEdGraphUtilities::RegisterVisualNodeFactory(GraphPanelNodeFactory); //Registrate ToolBarCommand for costom graph FToolBarCommandsCommands::Register(); //Create pool for icon wich show on costom nodes FCustomEditorThumbnailPool::Create(); }
TSharedPtr<class SGraphNode> FGraphPanelNodeFactory_Custom::CreateNode(UEdGraphNode* Node) const { if (URootNode* RootNode = Cast<URootNode>(Node)) { TSharedPtr<SGraphNode_Root> SNode = SNew(SGraphNode_Root, RootNode); RootNode->PropertyObserver = SNode; return SNode; } else if (UBranchNode* BranchNode = Cast<UBranchNode>(Node)) { TSharedPtr<SGraphNode_Brunch> SNode = SNew(SGraphNode_Brunch, BranchNode); BranchNode->PropertyObserver = SNode; return SNode; } else if (URuleNode* RuleNode = Cast<URuleNode>(Node)) { TSharedPtr<SGraphNode_Rule> SNode = SNew(SGraphNode_Rule, RuleNode); RuleNode->PropertyObserver = SNode; return SNode; } else if (USwitcherNode* SwitcherNode = Cast<USwitcherNode>(Node)) { TSharedPtr<SGraphNode_Switcher> SNode = SNew(SGraphNode_Switcher, SwitcherNode); SwitcherNode->PropertyObserver = SNode; return SNode; } return NULL; }
bool ATestAct::GenerateMeshes() { FRandomStream RandomStream = FRandomStream(10); if (!MyObject) { return false; } for (int i = 0; i < Roots.Num(); i++) { URootNode* RootBuf; RootBuf = MyObject->FindRootFromType(Roots[i].RootType); if (RootBuf) { RootBuf->CreateNodesMesh(GetWorld(), ActorTag, RandomStream, Roots[i].Location, FRotator(0, 0, 0)); } } return true; }
class UICUSTOM_API UCustomNodeBase : public UEdGraphNode { GENERATED_BODY() public: virtual TArray<UCustomNodeBase*> GetChildNodes(FRandomStream& RandomStream); virtual void CreateNodesMesh(UWorld* World, FName ActorTag, FRandomStream& RandomStream, FVector AbsLocation, FRotator AbsRotation); #if WITH_EDITORONLY_DATA virtual void PostEditChangeProperty(struct FPropertyChangedEvent& e) override; #endif //WITH_EDITORONLY_DATA TSharedPtr<FNodePropertyObserver> PropertyObserver; };
TArray<UCustomNodeBase*> UCustomNodeBase::GetChildNodes(FRandomStream& RandomStream) { TArray<UCustomNodeBase*> ChildNodes; return ChildNodes; } void UCustomNodeBase::CreateNodesMesh(UWorld* World, FName ActorTag, FRandomStream& RandomStream, FVector AbsLocation, FRotator AbsRotation) { TArray<UCustomNodeBase*>ChailNodes = GetChildNodes(RandomStream); for (int i = 0; i < ChailNodes.Num(); i++) { ChailNodes[i]->CreateNodesMesh(World, ActorTag, RandomStream, AbsLocation, AbsRotation); } } #if WITH_EDITORONLY_DATA void UCustomNodeBase::PostEditChangeProperty(struct FPropertyChangedEvent& e) { if (PropertyObserver.IsValid()) { FName PropertyName = (e.Property != NULL) ? e.Property->GetFName() : NAME_None; PropertyObserver->OnPropertyChanged(this, PropertyName); } Super::PostEditChangeProperty(e); } #endif //WITH_EDITORONLY_DATA
Source: https://habr.com/ru/post/277515/
All Articles