#include "FLESHEditor.h" #include "FLESHEditorCommands.h" #include "FLESHEditorStyle.h" #include "MatrixInputWidget.h" #include "DismembermentGraph/DismembermentGraphEditor.h" #include "Framework/Docking/TabManager.h" #include "Widgets/Docking/SDockTab.h" #include "Widgets/Layout/SBox.h" #include "Widgets/Layout/SBorder.h" #include "Widgets/Input/SButton.h" #include "PropertyEditorModule.h" #include "EditorStyleSet.h" #include "LevelEditor.h" #include "ToolMenus.h" #define LOCTEXT_NAMESPACE "FLESHEditor" const FName FFLESHEditor::ViewportTabId(TEXT("FLESHEditor_Viewport")); const FName FFLESHEditor::DetailsTabId(TEXT("FLESHEditor_Details")); const FName FFLESHEditor::AssetBrowserTabId(TEXT("FLESHEditor_AssetBrowser")); const FName FFLESHEditor::MatrixEditorTabId(TEXT("FLESHEditor_MatrixEditor")); const FName FFLESHEditor::GraphEditorTabId(TEXT("FLESHEditor_GraphEditor")); const FName FFLESHEditor::ToolbarTabId(TEXT("FLESHEditor_Toolbar")); FFLESHEditor::FFLESHEditor() { } FFLESHEditor::~FFLESHEditor() { } void FFLESHEditor::InitFLESHEditor(const EToolkitMode::Type Mode, const TSharedPtr& InitToolkitHost) { // Create command list CreateCommandList(); // Create tab layout const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("FLESHEditorLayout_v1.0") ->AddArea ( FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.1f) ->AddTab(ToolbarTabId, ETabState::OpenedTab) ) ->Split ( FTabManager::NewSplitter()->SetOrientation(Orient_Horizontal) ->Split ( FTabManager::NewSplitter()->SetOrientation(Orient_Vertical) ->SetSizeCoefficient(0.7f) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.7f) ->AddTab(ViewportTabId, ETabState::OpenedTab) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.3f) ->AddTab(MatrixEditorTabId, ETabState::OpenedTab) ) ) ->Split ( FTabManager::NewSplitter()->SetOrientation(Orient_Vertical) ->SetSizeCoefficient(0.3f) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.6f) ->AddTab(DetailsTabId, ETabState::OpenedTab) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.4f) ->AddTab(AssetBrowserTabId, ETabState::OpenedTab) ) ) ) ); // Initialize toolkit const bool bCreateDefaultStandaloneMenu = true; const bool bCreateDefaultToolbar = true; FAssetEditorToolkit::InitAssetEditor(Mode, InitToolkitHost, FName("FLESHEditorApp"), StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar); } void FFLESHEditor::RegisterTabSpawners(const TSharedRef& InTabManager) { FAssetEditorToolkit::RegisterTabSpawners(InTabManager); // Register tab spawners InTabManager->RegisterTabSpawner(ViewportTabId, FOnSpawnTab::CreateSP(this, &FFLESHEditor::SpawnTab_Viewport)) .SetDisplayName(LOCTEXT("ViewportTab", "Viewport")) .SetGroup(WorkspaceMenuCategory.ToSharedRef()) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Viewports")); InTabManager->RegisterTabSpawner(DetailsTabId, FOnSpawnTab::CreateSP(this, &FFLESHEditor::SpawnTab_Details)) .SetDisplayName(LOCTEXT("DetailsTab", "Details")) .SetGroup(WorkspaceMenuCategory.ToSharedRef()) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Details")); InTabManager->RegisterTabSpawner(AssetBrowserTabId, FOnSpawnTab::CreateSP(this, &FFLESHEditor::SpawnTab_AssetBrowser)) .SetDisplayName(LOCTEXT("AssetBrowserTab", "Asset Browser")) .SetGroup(WorkspaceMenuCategory.ToSharedRef()) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "ContentBrowser.TabIcon")); InTabManager->RegisterTabSpawner(MatrixEditorTabId, FOnSpawnTab::CreateSP(this, &FFLESHEditor::SpawnTab_MatrixEditor)) .SetDisplayName(LOCTEXT("MatrixEditorTab", "Matrix Editor")) .SetGroup(WorkspaceMenuCategory.ToSharedRef()) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "PropertyEditor.Grid.TabIcon")); InTabManager->RegisterTabSpawner(GraphEditorTabId, FOnSpawnTab::CreateSP(this, &FFLESHEditor::SpawnTab_GraphEditor)) .SetDisplayName(LOCTEXT("GraphEditorTab", "Graph Editor")) .SetGroup(WorkspaceMenuCategory.ToSharedRef()) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "GraphEditor.EventGraph_16x")); InTabManager->RegisterTabSpawner(ToolbarTabId, FOnSpawnTab::CreateSP(this, &FFLESHEditor::SpawnTab_Toolbar)) .SetDisplayName(LOCTEXT("ToolbarTab", "Toolbar")) .SetGroup(WorkspaceMenuCategory.ToSharedRef()) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Toolbar")); } void FFLESHEditor::UnregisterTabSpawners(const TSharedRef& InTabManager) { FAssetEditorToolkit::UnregisterTabSpawners(InTabManager); // Unregister tab spawners InTabManager->UnregisterTabSpawner(ViewportTabId); InTabManager->UnregisterTabSpawner(DetailsTabId); InTabManager->UnregisterTabSpawner(AssetBrowserTabId); InTabManager->UnregisterTabSpawner(MatrixEditorTabId); InTabManager->UnregisterTabSpawner(GraphEditorTabId); InTabManager->UnregisterTabSpawner(ToolbarTabId); } FName FFLESHEditor::GetToolkitFName() const { return FName("FLESHEditor"); } FText FFLESHEditor::GetBaseToolkitName() const { return LOCTEXT("FLESHEditorAppLabel", "FLESH Editor"); } FString FFLESHEditor::GetWorldCentricTabPrefix() const { return TEXT("FLESH "); } FLinearColor FFLESHEditor::GetWorldCentricTabColorScale() const { return FLinearColor(0.7f, 0.0f, 0.0f, 0.5f); } void FFLESHEditor::OpenEditor() { // Create new editor instance TSharedRef NewEditor = MakeShareable(new FFLESHEditor()); NewEditor->InitFLESHEditor(EToolkitMode::Standalone, nullptr); } TSharedRef FFLESHEditor::SpawnTab_Viewport(const FSpawnTabArgs& Args) { return SNew(SDockTab) .Label(LOCTEXT("ViewportTitle", "Viewport")) [ CreateViewportWidget() ]; } TSharedRef FFLESHEditor::SpawnTab_Details(const FSpawnTabArgs& Args) { return SNew(SDockTab) .Label(LOCTEXT("DetailsTitle", "Details")) [ CreateDetailsWidget() ]; } TSharedRef FFLESHEditor::SpawnTab_AssetBrowser(const FSpawnTabArgs& Args) { return SNew(SDockTab) .Label(LOCTEXT("AssetBrowserTitle", "Asset Browser")) [ CreateAssetBrowserWidget() ]; } TSharedRef FFLESHEditor::SpawnTab_MatrixEditor(const FSpawnTabArgs& Args) { return SNew(SDockTab) .Label(LOCTEXT("MatrixEditorTitle", "Matrix Editor")) [ CreateMatrixEditorWidget() ]; } TSharedRef FFLESHEditor::SpawnTab_GraphEditor(const FSpawnTabArgs& Args) { return SNew(SDockTab) .Label(LOCTEXT("GraphEditorTitle", "Graph Editor")) [ CreateGraphEditorWidget() ]; } TSharedRef FFLESHEditor::SpawnTab_Toolbar(const FSpawnTabArgs& Args) { return SNew(SDockTab) .Label(LOCTEXT("ToolbarTitle", "Toolbar")) [ CreateToolbarWidget() ]; } TSharedRef FFLESHEditor::CreateViewportWidget() { // Create viewport widget return SNew(SBorder) .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) .Padding(4.0f) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(STextBlock) .Text(LOCTEXT("ViewportHeader", "FLESH Viewport")) .Font(FEditorStyle::GetFontStyle("HeadingFont")) ] + SVerticalBox::Slot() .FillHeight(1.0f) [ SNew(SBorder) .BorderImage(FEditorStyle::GetBrush("ToolPanel.DarkGroupBorder")) .Padding(4.0f) [ SNew(STextBlock) .Text(LOCTEXT("ViewportPlaceholder", "Character model and dismemberment effects will be displayed here")) ] ] ]; } TSharedRef FFLESHEditor::CreateDetailsWidget() { // Create details panel FPropertyEditorModule& PropertyEditorModule = FModuleManager::LoadModuleChecked("PropertyEditor"); FDetailsViewArgs DetailsViewArgs; DetailsViewArgs.bUpdatesFromSelection = true; DetailsViewArgs.bLockable = false; DetailsViewArgs.bAllowSearch = true; DetailsViewArgs.NameAreaSettings = FDetailsViewArgs::HideNameArea; DetailsViewArgs.bHideSelectionTip = true; DetailsViewArgs.NotifyHook = nullptr; DetailsViewArgs.bSearchInitialKeyFocus = false; DetailsViewArgs.ViewIdentifier = NAME_None; DetailsViewArgs.DefaultsOnlyVisibility = EEditDefaultsOnlyNodeVisibility::Automatic; DetailsViewArgs.bShowOptions = true; DetailsViewArgs.bAllowMultipleTopLevelObjects = true; DetailsWidget = PropertyEditorModule.CreateDetailView(DetailsViewArgs); return SNew(SBorder) .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) .Padding(4.0f) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(STextBlock) .Text(LOCTEXT("DetailsHeader", "Property Editor")) .Font(FEditorStyle::GetFontStyle("HeadingFont")) ] + SVerticalBox::Slot() .FillHeight(1.0f) [ DetailsWidget.ToSharedRef() ] ]; } TSharedRef FFLESHEditor::CreateAssetBrowserWidget() { // Create asset browser return SNew(SBorder) .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) .Padding(4.0f) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(STextBlock) .Text(LOCTEXT("AssetBrowserHeader", "Asset Browser")) .Font(FEditorStyle::GetFontStyle("HeadingFont")) ] + SVerticalBox::Slot() .FillHeight(1.0f) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .Padding(2.0f) [ SNew(SButton) .Text(LOCTEXT("ImportCharacterModel", "Import Character Model")) .OnClicked_Lambda([this]() { OnImportCharacterModel(); return FReply::Handled(); }) .ButtonStyle(FFLESHEditorStyle::Get(), "FLESHEditor.RoundedButton") ] + SVerticalBox::Slot() .AutoHeight() .Padding(2.0f) [ SNew(SButton) .Text(LOCTEXT("ImportOrganModel", "Import Organ Model")) .OnClicked_Lambda([this]() { OnImportOrganModel(); return FReply::Handled(); }) .ButtonStyle(FFLESHEditorStyle::Get(), "FLESHEditor.RoundedButton") ] + SVerticalBox::Slot() .AutoHeight() .Padding(2.0f) [ SNew(SButton) .Text(LOCTEXT("ImportSkeletonModel", "Import Skeleton Model")) .OnClicked_Lambda([this]() { OnImportSkeletonModel(); return FReply::Handled(); }) .ButtonStyle(FFLESHEditorStyle::Get(), "FLESHEditor.RoundedButton") ] + SVerticalBox::Slot() .AutoHeight() .Padding(2.0f) [ SNew(SButton) .Text(LOCTEXT("ImportPhysicsAsset", "Import Physics Asset")) .OnClicked_Lambda([this]() { OnImportPhysicsAsset(); return FReply::Handled(); }) .ButtonStyle(FFLESHEditorStyle::Get(), "FLESHEditor.RoundedButton") ] ] ]; } TSharedRef FFLESHEditor::CreateMatrixEditorWidget() { // Create matrix editor MatrixEditorWidget = SNew(SMatrixInputWidget) .Matrix(FMatrix::Identity) .OnMatrixChanged_Lambda([this](const FMatrix& NewMatrix) { // Handle matrix change }); return SNew(SBorder) .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) .Padding(4.0f) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(STextBlock) .Text(LOCTEXT("MatrixEditorHeader", "Matrix Editor")) .Font(FEditorStyle::GetFontStyle("HeadingFont")) ] + SVerticalBox::Slot() .FillHeight(1.0f) [ MatrixEditorWidget.ToSharedRef() ] + SVerticalBox::Slot() .AutoHeight() .Padding(2.0f) [ SNew(SButton) .Text(LOCTEXT("TestMatrix", "Test Matrix")) .OnClicked_Lambda([this]() { OnTestMatrix(); return FReply::Handled(); }) .ButtonStyle(FFLESHEditorStyle::Get(), "FLESHEditor.RoundedButton") ] ]; } TSharedRef FFLESHEditor::CreateGraphEditorWidget() { // Create graph editor return SNew(SBorder) .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) .Padding(4.0f) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(STextBlock) .Text(LOCTEXT("GraphEditorHeader", "Graph Editor")) .Font(FEditorStyle::GetFontStyle("HeadingFont")) ] + SVerticalBox::Slot() .FillHeight(1.0f) [ SNew(SBorder) .BorderImage(FEditorStyle::GetBrush("ToolPanel.DarkGroupBorder")) .Padding(4.0f) [ SNew(STextBlock) .Text(LOCTEXT("GraphEditorPlaceholder", "Dismemberment system logic graph will be displayed here")) ] ] ]; } TSharedRef FFLESHEditor::CreateToolbarWidget() { // Create toolbar return SNew(SBorder) .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) .Padding(4.0f) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .Padding(2.0f) [ SNew(SButton) .Text(LOCTEXT("DismembermentGraphEditor", "Dismemberment Graph Editor")) .OnClicked_Lambda([this]() { OnOpenDismembermentGraphEditor(); return FReply::Handled(); }) .ButtonStyle(FFLESHEditorStyle::Get(), "FLESHEditor.RoundedButton") ] + SHorizontalBox::Slot() .AutoWidth() .Padding(2.0f) [ SNew(SButton) .Text(LOCTEXT("AnatomicalLayerEditor", "Anatomical Layer Editor")) .OnClicked_Lambda([this]() { OnOpenAnatomicalLayerEditor(); return FReply::Handled(); }) .ButtonStyle(FFLESHEditorStyle::Get(), "FLESHEditor.RoundedButton") ] + SHorizontalBox::Slot() .AutoWidth() .Padding(2.0f) [ SNew(SButton) .Text(LOCTEXT("BooleanCutTool", "Boolean Cut Tool")) .OnClicked_Lambda([this]() { OnOpenBooleanCutTool(); return FReply::Handled(); }) .ButtonStyle(FFLESHEditorStyle::Get(), "FLESHEditor.RoundedButton") ] + SHorizontalBox::Slot() .AutoWidth() .Padding(2.0f) [ SNew(SButton) .Text(LOCTEXT("BloodSystemEditor", "Blood System Editor")) .OnClicked_Lambda([this]() { OnOpenBloodSystemEditor(); return FReply::Handled(); }) .ButtonStyle(FFLESHEditorStyle::Get(), "FLESHEditor.RoundedButton") ] ]; } void FFLESHEditor::CreateCommandList() { // Create command list CommandList = MakeShareable(new FUICommandList); // Bind commands CommandList->MapAction( FFLESHEditorCommands::Get().OpenDismembermentGraphEditor, FExecuteAction::CreateSP(this, &FFLESHEditor::OnOpenDismembermentGraphEditor), FCanExecuteAction()); CommandList->MapAction( FFLESHEditorCommands::Get().OpenAnatomicalLayerEditor, FExecuteAction::CreateSP(this, &FFLESHEditor::OnOpenAnatomicalLayerEditor), FCanExecuteAction()); CommandList->MapAction( FFLESHEditorCommands::Get().OpenBooleanCutTool, FExecuteAction::CreateSP(this, &FFLESHEditor::OnOpenBooleanCutTool), FCanExecuteAction()); CommandList->MapAction( FFLESHEditorCommands::Get().OpenBloodSystemEditor, FExecuteAction::CreateSP(this, &FFLESHEditor::OnOpenBloodSystemEditor), FCanExecuteAction()); } void FFLESHEditor::OnOpenDismembermentGraphEditor() { // Open dismemberment graph editor FGlobalTabmanager::Get()->TryInvokeTab(GraphEditorTabId); } void FFLESHEditor::OnOpenAnatomicalLayerEditor() { // Open anatomical layer editor FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("AnatomicalLayerEditorNotImplemented", "Anatomical Layer Editor is not implemented yet")); } void FFLESHEditor::OnOpenBooleanCutTool() { // Open boolean cut tool FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("BooleanCutToolNotImplemented", "Boolean Cut Tool is not implemented yet")); } void FFLESHEditor::OnOpenBloodSystemEditor() { // Open blood system editor FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("BloodSystemEditorNotImplemented", "Blood System Editor is not implemented yet")); } void FFLESHEditor::OnImportCharacterModel() { // Import character model FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("ImportCharacterModelNotImplemented", "Import Character Model feature is not implemented yet")); } void FFLESHEditor::OnImportOrganModel() { // Import organ model FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("ImportOrganModelNotImplemented", "Import Organ Model feature is not implemented yet")); } void FFLESHEditor::OnImportSkeletonModel() { // Import skeleton model FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("ImportSkeletonModelNotImplemented", "Import Skeleton Model feature is not implemented yet")); } void FFLESHEditor::OnImportPhysicsAsset() { // Import physics asset FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("ImportPhysicsAssetNotImplemented", "Import Physics Asset feature is not implemented yet")); } void FFLESHEditor::OnTestMatrix() { // Test matrix FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("TestMatrixNotImplemented", "Test Matrix feature is not implemented yet")); } #undef LOCTEXT_NAMESPACE