#include "DismembermentEditor.h" #include "Widgets/Docking/SDockTab.h" #include "PropertyEditorModule.h" #include "Modules/ModuleManager.h" #include "IDetailsView.h" #include "Widgets/Layout/SBorder.h" #include "Styling/AppStyle.h" #include "Engine/SkeletalMesh.h" #include "Framework/Commands/UICommandList.h" #include "Framework/MultiBox/MultiBoxBuilder.h" #include "ToolMenus.h" // Define tab names const FName FDismembermentEditor::ViewportTabId(TEXT("DismembermentEditor_Viewport")); const FName FDismembermentEditor::DetailsTabId(TEXT("DismembermentEditor_Details")); const FName FDismembermentEditor::LayerSystemTabId(TEXT("DismembermentEditor_LayerSystem")); const FName FDismembermentEditor::PhysicsSettingsTabId(TEXT("DismembermentEditor_PhysicsSettings")); // Constructor FDismembermentEditor::FDismembermentEditor() : SkeletalMesh(nullptr) { } // Destructor FDismembermentEditor::~FDismembermentEditor() { } // Initialize the editor void FDismembermentEditor::InitDismembermentEditor(const EToolkitMode::Type Mode, const TSharedPtr& InitToolkitHost, USkeletalMesh* InSkeletalMesh) { // Set the skeletal mesh being edited SkeletalMesh = InSkeletalMesh; // Create the layout CreateEditorLayout(); // Create the toolbar CreateEditorToolbar(); // Initialize the asset editor InitAssetEditor(Mode, InitToolkitHost, FName("DismembermentEditorApp"), FTabManager::FLayout::NullLayout, /*bCreateDefaultStandaloneMenu=*/ true, /*bCreateDefaultToolbar=*/ true, InSkeletalMesh); // Register for undo/redo GEditor->RegisterForUndo(this); } // Get the toolkit name FName FDismembermentEditor::GetToolkitFName() const { return FName("DismembermentEditor"); } // Get the base toolkit name FText FDismembermentEditor::GetBaseToolkitName() const { return FText::FromString("Dismemberment Editor"); } // Get the world centric tab prefix FString FDismembermentEditor::GetWorldCentricTabPrefix() const { return "DismembermentEditor"; } // Get the world centric tab color scale FLinearColor FDismembermentEditor::GetWorldCentricTabColorScale() const { return FLinearColor(0.3f, 0.2f, 0.5f, 0.5f); } // Post undo handler void FDismembermentEditor::PostUndo(bool bSuccess) { // Refresh the views if (DetailsWidget.IsValid()) { DetailsWidget->ForceRefresh(); } } // Post redo handler void FDismembermentEditor::PostRedo(bool bSuccess) { // Refresh the views if (DetailsWidget.IsValid()) { DetailsWidget->ForceRefresh(); } } // Create the editor layout void FDismembermentEditor::CreateEditorLayout() { // Register tab spawners TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("Standalone_DismembermentEditor_Layout_v1") ->AddArea ( FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.1f) ->AddTab(GetToolbarTabId(), ETabState::OpenedTab) ->SetHideTabWell(true) ) ->Split ( FTabManager::NewSplitter()->SetOrientation(Orient_Horizontal)->SetSizeCoefficient(0.9f) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.7f) ->AddTab(ViewportTabId, ETabState::OpenedTab) ) ->Split ( FTabManager::NewSplitter()->SetOrientation(Orient_Vertical) ->SetSizeCoefficient(0.3f) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.4f) ->AddTab(DetailsTabId, ETabState::OpenedTab) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.3f) ->AddTab(LayerSystemTabId, ETabState::OpenedTab) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.3f) ->AddTab(PhysicsSettingsTabId, ETabState::OpenedTab) ) ) ) ); // Set the layout FAssetEditorToolkit::InitAssetEditor( EToolkitMode::Standalone, TSharedPtr(), FName("DismembermentEditorApp"), StandaloneDefaultLayout, true, true, SkeletalMesh ); } // Create the editor toolbar void FDismembermentEditor::CreateEditorToolbar() { // Create command list TSharedPtr CommandList = MakeShareable(new FUICommandList); // Get the toolbar builder TSharedPtr ToolbarExtender = MakeShareable(new FExtender); ToolbarExtender->AddToolBarExtension( "Asset", EExtensionHook::After, CommandList, FToolBarExtensionDelegate::CreateLambda([this](FToolBarBuilder& ToolbarBuilder) { ToolbarBuilder.BeginSection("Dismemberment"); { ToolbarBuilder.AddToolBarButton( FUIAction(FExecuteAction::CreateSP(this, &FDismembermentEditor::PerformBooleanCut)), NAME_None, FText::FromString("Boolean Cut"), FText::FromString("Perform a boolean cut operation"), FSlateIcon(FAppStyle::GetAppStyleSetName(), "ClassIcon.CurveBase"), EUserInterfaceActionType::Button ); ToolbarBuilder.AddToolBarButton( FUIAction(FExecuteAction::CreateSP(this, &FDismembermentEditor::AddNewLayer)), NAME_None, FText::FromString("Add Layer"), FText::FromString("Add a new anatomical layer"), FSlateIcon(FAppStyle::GetAppStyleSetName(), "ClassIcon.Layer"), EUserInterfaceActionType::Button ); ToolbarBuilder.AddToolBarButton( FUIAction(FExecuteAction::CreateSP(this, &FDismembermentEditor::PreviewEffects)), NAME_None, FText::FromString("Preview"), FText::FromString("Preview the dismemberment effects"), FSlateIcon(FAppStyle::GetAppStyleSetName(), "ClassIcon.ParticleSystem"), EUserInterfaceActionType::Button ); ToolbarBuilder.AddToolBarButton( FUIAction(FExecuteAction::CreateSP(this, &FDismembermentEditor::SaveEdits)), NAME_None, FText::FromString("Save"), FText::FromString("Save the dismemberment setup"), FSlateIcon(FAppStyle::GetAppStyleSetName(), "AssetEditor.SaveAsset"), EUserInterfaceActionType::Button ); } ToolbarBuilder.EndSection(); }) ); // Add the extender AddToolbarExtender(ToolbarExtender); } // Register tab spawners void FDismembermentEditor::RegisterTabSpawners(const TSharedRef& InTabManager) { // Call the base implementation FAssetEditorToolkit::RegisterTabSpawners(InTabManager); // Register the tab spawners InTabManager->RegisterTabSpawner(ViewportTabId, FOnSpawnTab::CreateSP(this, &FDismembermentEditor::SpawnTab_Viewport)) .SetDisplayName(FText::FromString("Viewport")) .SetGroup(WorkspaceMenuCategory.ToSharedRef()) .SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Viewports")); InTabManager->RegisterTabSpawner(DetailsTabId, FOnSpawnTab::CreateSP(this, &FDismembermentEditor::SpawnTab_Details)) .SetDisplayName(FText::FromString("Details")) .SetGroup(WorkspaceMenuCategory.ToSharedRef()) .SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Details")); InTabManager->RegisterTabSpawner(LayerSystemTabId, FOnSpawnTab::CreateSP(this, &FDismembermentEditor::SpawnTab_LayerSystem)) .SetDisplayName(FText::FromString("Layer System")) .SetGroup(WorkspaceMenuCategory.ToSharedRef()) .SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "ClassIcon.Layer")); InTabManager->RegisterTabSpawner(PhysicsSettingsTabId, FOnSpawnTab::CreateSP(this, &FDismembermentEditor::SpawnTab_PhysicsSettings)) .SetDisplayName(FText::FromString("Physics Settings")) .SetGroup(WorkspaceMenuCategory.ToSharedRef()) .SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "ClassIcon.PhysicsAsset")); } // Unregister tab spawners void FDismembermentEditor::UnregisterTabSpawners(const TSharedRef& InTabManager) { // Call the base implementation FAssetEditorToolkit::UnregisterTabSpawners(InTabManager); // Unregister the tab spawners InTabManager->UnregisterTabSpawner(ViewportTabId); InTabManager->UnregisterTabSpawner(DetailsTabId); InTabManager->UnregisterTabSpawner(LayerSystemTabId); InTabManager->UnregisterTabSpawner(PhysicsSettingsTabId); } // Spawn the viewport tab TSharedRef FDismembermentEditor::SpawnTab_Viewport(const FSpawnTabArgs& Args) { // Create the viewport widget ViewportWidget = SNew(SBorder) .BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) .Padding(FMargin(4.0f)) [ SNew(STextBlock) .Text(FText::FromString("Viewport will be implemented here")) ]; // Create the tab return SNew(SDockTab) .Label(FText::FromString("Viewport")) [ ViewportWidget.ToSharedRef() ]; } // Spawn the details tab TSharedRef FDismembermentEditor::SpawnTab_Details(const FSpawnTabArgs& Args) { // Create the details view FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked("PropertyEditor"); FDetailsViewArgs DetailsViewArgs; DetailsViewArgs.bUpdatesFromSelection = true; DetailsViewArgs.bLockable = false; DetailsViewArgs.bAllowSearch = true; DetailsViewArgs.NameAreaSettings = FDetailsViewArgs::HideNameArea; DetailsViewArgs.bHideSelectionTip = true; DetailsWidget = PropertyEditorModule.CreateDetailView(DetailsViewArgs); DetailsWidget->SetObject(SkeletalMesh); // Create the tab return SNew(SDockTab) .Label(FText::FromString("Details")) [ DetailsWidget.ToSharedRef() ]; } // Spawn the layer system tab TSharedRef FDismembermentEditor::SpawnTab_LayerSystem(const FSpawnTabArgs& Args) { // Create the layer system widget LayerSystemWidget = SNew(SBorder) .BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) .Padding(FMargin(4.0f)) [ SNew(STextBlock) .Text(FText::FromString("Layer System will be implemented here")) ]; // Create the tab return SNew(SDockTab) .Label(FText::FromString("Layer System")) [ LayerSystemWidget.ToSharedRef() ]; } // Spawn the physics settings tab TSharedRef FDismembermentEditor::SpawnTab_PhysicsSettings(const FSpawnTabArgs& Args) { // Create the physics settings widget PhysicsSettingsWidget = SNew(SBorder) .BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) .Padding(FMargin(4.0f)) [ SNew(STextBlock) .Text(FText::FromString("Physics Settings will be implemented here")) ]; // Create the tab return SNew(SDockTab) .Label(FText::FromString("Physics Settings")) [ PhysicsSettingsWidget.ToSharedRef() ]; } // Perform a boolean cut operation void FDismembermentEditor::PerformBooleanCut() { // To be implemented } // Add a new layer void FDismembermentEditor::AddNewLayer() { // To be implemented } // Save the edits void FDismembermentEditor::SaveEdits() { // To be implemented } // Preview the effects void FDismembermentEditor::PreviewEffects() { // To be implemented }