介绍
我们添加了一个UStateMachine的自定义资源,现在我们在创建一个FStateMachineEditor的编辑器类来编辑这个资源。UE4中任何的编辑器都是由一个个Tab(页签)组成,由编辑器中的TabManager管理。StateMachineEditor打开后会和蓝图编辑器类似,有默认的菜单栏和工具栏。有图表和细节面板,这里菜单栏、工具栏、图表、细节面板都是页签。
我们先创建只有默认菜单栏、工具栏、和细节面板的编辑器,后面再详细介绍图表页签的创建。
创建编辑器类
首先创建一个FStateMachineEditor编辑器类,用于编辑StateMachine资源类。FStateMachineEditor从FWorkflowCentricApplication继承则可以切换编辑模式,结构会更加清晰,建议都从FWorkflowCentricApplication继承。编辑器类额外添加了一个DocumentManager变量,DocumentManager可以替换TabManager可以用于管理所有的图表页签。
- //StatMachineEditor.h:
class STATEMACHINEEDITOR_API FStateMachineEditor : public FWorkflowCentricApplication, public FNotifyHook, public FEditorUndoClient
{
public:
FStateMachineEditor();
virtual ~FStateMachineEditor();
//初始化编辑器函数
void InitStateMachineEditor(const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UStateMachine* InStateMachine);
public:
//~ Begin FWorkflowCentricApplication Interface
virtual void RegisterTabSpawners(const TSharedRef<class FTabManager>& InTabManager) override;
//~ End FWorkflowCentricApplication Interface
//~ Begin IToolkit Interface
virtual FName GetToolkitFName() const override;
virtual FText GetBaseToolkitName() const override;
virtual FString GetWorldCentricTabPrefix() const override;
virtual FLinearColor GetWorldCentricTabColorScale() const override;
//~ End IToolkit Interface
virtual void RegisterToolbarTab(const TSharedRef<class FTabManager>& InTabManager);
virtual void InvokeStateMachineGraphTab(); //打开图表Tab,预留
UStateMachine* GetStateMachine() { return StateMachine.Get(); }
TSharedPtr<FDocumentTracker> GetDocumentManager() { return DocumentManager; }
private:
TWeakObjectPtr<UStateMachine> StateMachine;
TSharedPtr<FDocumentTracker> DocumentManager;
};
- StatMachineEditor.cpp:
void FStateMachineEditor::InitStateMachineEditor(const EToolkitMode::Type Mode, const TSharedPtr<class IToolkitHost>& InitToolkitHost, UStateMachine* InStateMachine)
{
StateMachine = InStateMachine;
// Initialize the asset editor and spawn nothing (dummy layout)
const TSharedRef<FTabManager::FLayout> DummyLayout = FTabManager::NewLayout("NullLayout")->AddArea(FTabManager::NewPrimaryArea());
InitAssetEditor(Mode, InitToolkitHost, FName("StateMachineEditorApp"), DummyLayout, true, true, InStateMachine);
//Init DocumentManager
DocumentManager = MakeShareable(new FDocumentTracker);
DocumentManager->Initialize(SharedThis(this));
DocumentManager->SetTabManager(TabManager.ToSharedRef());
// Init Mode
AddApplicationMode(FStateMachineEditorApplicationModes::StandardMode, MakeShareable(new FStandardStateMachineEditorApplicationMode(SharedThis(this))));
SetCurrentMode(FStateMachineEditorApplicationModes::StandardMode);
}
void FStateMachineEditor::RegisterTabSpawners(const TSharedRef<class FTabManager>& InTabManager)
{
FWorkflowCentricApplication::RegisterTabSpawners(InTabManager);
}
FName FStateMachineEditor::GetToolkitFName() const
{
return FName("StateMachineEditor");
}
FText FStateMachineEditor::GetBaseToolkitName() const
{
return LOCTEXT("StateMachineEditor", "StateMachine Editor");
}
FString FStateMachineEditor::GetWorldCentricTabPrefix() const
{
return FString();
}
FLinearColor FStateMachineEditor::GetWorldCentricTabColorScale() const
{
return FLinearColor();
}
void FStateMachineEditor::RegisterToolbarTab(const TSharedRef<class FTabManager>& InTabManager)
{
FAssetEditorToolkit::RegisterTabSpawners(InTabManager);
}
void FStateMachineEditor::InvokeStateMachineGraphTab()
{
//预留
}
创建好Editor类后,需要在相关的AssetTypeAction中创建Editor类对象,在打开StateMachine资源类时创建和初始化相应的Editor类。
// AssetTypeAction_StateMachine.cpp:
void FAssetTypeActions_StateMachine::OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<IToolkitHost> EditWithinLevelEditor)
{
EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone;
for (UObject* Object : InObjects)
{
if (UStateMachine* StateMachine = Cast<UStateMachine>(Object))
{
TSharedRef<FStateMachineEditor> NewEditor(new FStateMachineEditor());
NewEditor->InitStateMachineEditor(Mode, EditWithinLevelEditor, StateMachine);
}
}
}
创建编辑模式
FWorkflowCentricApplication继承的类可以使用和切换编辑模式。编辑模式主要是负责创建布局,并注册相应的页签类。菜单栏和工具栏可以使用默认,在编辑器初始化时设置。
为状态机创建一个“StandardMode”的编辑模式。
// StateMachineEditorApplicationModes.h
class STATEMACHINEEDITOR_API FStandardStateMachineEditorApplicationMode : public FApplicationMode
{
public:
FStandardStateMachineEditorApplicationMode(TSharedPtr<class FStateMachineEditor> InStateMachineEditor);
virtual void RegisterTabFactories(TSharedPtr<FTabManager> InTabManager) override;
virtual void AddTabFactory(FCreateWorkflowTabFactory FactoryCreator) override;
virtual void RemoveTabFactory(FName TabFactoryID) override;
virtual void PreDeactivateMode() override {};
virtual void PostActivateMode() override;
protected:
TWeakPtr<FStateMachineEditor> StateMachineEditor;
FWorkflowAllowedTabSet StardardTabFactories;
};
// StateMachineEditorApplicationModes.cpp
FStandardStateMachineEditorApplicationMode::FStandardStateMachineEditorApplicationMode(TSharedPtr<class FStateMachineEditor> InStateMachineEditor)
: FApplicationMode(FName("StandardMode"), FStateMachineEditorApplicationModes::GetLocalizedMode)
{
StateMachineEditor = InStateMachineEditor;
//Save TabFactories
//StardardTabFactories.RegisterFactory(MakeShareable(new FStateMachineGraphTabFactory(InStateMachineEditor)));
StardardTabFactories.RegisterFactory(MakeShareable(new FStateMachineDetailsTabFactory(InStateMachineEditor)));
//创建一个默认的布局,
TabLayout = FTabManager::NewLayout("StardardStateMachineEditorLayout")
->AddArea
(
FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(0.186721f)
->SetHideTabWell(true)
->AddTab(InStateMachineEditor->GetToolbarTabId(), ETabState::OpenedTab)
)
->Split
(
FTabManager::NewSplitter()->SetOrientation(Orient_Horizontal)
->Split
(
FTabManager::NewSplitter()->SetOrientation(Orient_Vertical)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(0.80f)
->AddTab("Document", ETabState::ClosedTab)//提供给DocumentManager使用,图表的位置
)
)
->Split
(
FTabManager::NewSplitter()->SetOrientation(Orient_Vertical)
->Split
(
FTabManager::NewStack()->SetSizeCoefficient(0.2f)
->AddTab("Detailes", ETabState::OpenedTab)
)
)
)
);
}
void FStandardStateMachineEditorApplicationMode::RegisterTabFactories(TSharedPtr<FTabManager> InTabManager)
{
TSharedPtr<FStateMachineEditor> Editor = StateMachineEditor.Pin();
// Tool bar tab
Editor->RegisterToolbarTab(InTabManager.ToSharedRef());
// Other tabs
Editor->PushTabFactories(StardardTabFactories);
// Graph tab
//Editor->GetDocumentManager()->RegisterDocumentFactory(MakeShareable(new FStateMachineGraphTabFactory(Editor)));
FApplicationMode::RegisterTabFactories(InTabManager);
}
void FStandardStateMachineEditorApplicationMode::AddTabFactory(FCreateWorkflowTabFactory FactoryCreator)
{
if (FactoryCreator.IsBound())
{
StardardTabFactories.RegisterFactory(FactoryCreator.Execute(StateMachineEditor.Pin()));
}
}
void FStandardStateMachineEditorApplicationMode::RemoveTabFactory(FName TabFactoryID)
{
StardardTabFactories.UnregisterFactory(TabFactoryID);
}
void FStandardStateMachineEditorApplicationMode::PostActivateMode()
{
StateMachineEditor.Pin()->InvokeStateMachineGraphTab();
}
创建细节面板页签工厂类
细节面板的Slate可使用PropertyEditorModule.CreateDetailView()接口,通过SetObject()设置要显示细节的对象。该工厂类需要在编辑模式类中注册到Editor中。
//StateMachineEditorTabFactories.h:
// 生成类的细节面板
struct FStateMachineDetailsTabFactory : public FWorkflowTabFactory
{
public:
FStateMachineDetailsTabFactory(TSharedPtr<class FStateMachineEditor> InStateMachineEditor);
virtual TSharedRef<SWidget> CreateTabBody(const FWorkflowTabSpawnInfo& Info) const override;
virtual FText GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const override;
protected:
TWeakPtr<FStateMachineEditor> StateMachineEditor;
};
//StateMachineEditorTabFactories.cpp:
FStateMachineDetailsTabFactory::FStateMachineDetailsTabFactory(TSharedPtr<class FStateMachineEditor> InStateMachineEditor)
: FWorkflowTabFactory(FName("Details"), InStateMachineEditor)
, StateMachineEditor(InStateMachineEditor)
{
TabLabel = LOCTEXT("DetailsLabel", "Details");
TabIcon = FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.Components");
bIsSingleton = true;
ViewMenuDescription = LOCTEXT("DetailsView", "Details");
ViewMenuTooltip = LOCTEXT("DetailsView_ToolTip", "Show the details view");
}
TSharedRef<SWidget> FStateMachineDetailsTabFactory::CreateTabBody(const FWorkflowTabSpawnInfo& Info) const
{
// 创建细节面板
FStateMachineEditor* Editor = StateMachineEditor.Pin().Get();
FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
FDetailsViewArgs DetailsViewArgs(false, false, true, FDetailsViewArgs::HideNameArea, false);
DetailsViewArgs.NotifyHook = Editor;
DetailsViewArgs.DefaultsOnlyVisibility = EEditDefaultsOnlyNodeVisibility::Hide;
TSharedRef<IDetailsView> DetailsView = PropertyEditorModule.CreateDetailView(DetailsViewArgs);
DetailsView->SetObject(Editor->GetStateMachine());
//DetailsView->SetIsPropertyEditingEnabledDelegate(FIsPropertyEditingEnabled::CreateSP(Editor, &FStateMachineEditor::IsPropertyEditable));
//DetailsView->OnFinishedChangingProperties().AddSP(Editor, &FStateMachineEditor::OnFinishedChangingProperties);
return
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.FillHeight(1.0f)
.HAlign(HAlign_Fill)
[
DetailsView
];
}
FText FStateMachineDetailsTabFactory::GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const
{
return LOCTEXT("DetailsTabTooltip", "The details tab allows editing of the properties");
}
最后可以打开资源,就会打开对应的编辑器,并创建一个显示StateMachine类的细节面板。
总结:
- 需要创建一个自定义编辑器类,并在自定义资源的AssetTypeActions中打开资源时创建和初始化。
- 创建一个编辑器模式类,用于设定布局,注册Tab工厂。
- 需要什么Tab就创建对应的Tab工厂类,并在编辑器模式类中注册到Editor的TabManager中。