更新 Source/FLESHEditor/Private/DismembermentEditor.cpp
This commit is contained in:
@@ -1,362 +1,61 @@
|
|||||||
#include "DismembermentEditor.h"
|
#pragma once
|
||||||
#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
|
#include "CoreMinimal.h"
|
||||||
const FName FDismembermentEditor::ViewportTabId(TEXT("DismembermentEditor_Viewport"));
|
#include "Toolkits/AssetEditorToolkit.h"
|
||||||
const FName FDismembermentEditor::DetailsTabId(TEXT("DismembermentEditor_Details"));
|
#include "EditorUndoClient.h"
|
||||||
const FName FDismembermentEditor::LayerSystemTabId(TEXT("DismembermentEditor_LayerSystem"));
|
|
||||||
const FName FDismembermentEditor::PhysicsSettingsTabId(TEXT("DismembermentEditor_PhysicsSettings"));
|
|
||||||
|
|
||||||
// Constructor
|
class USkeletalMesh;
|
||||||
FDismembermentEditor::FDismembermentEditor()
|
class SDockTab;
|
||||||
: SkeletalMesh(nullptr)
|
class IDetailsView;
|
||||||
|
class SBorder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dismemberment System Editor
|
||||||
|
* Provides real-time boolean cutting and multi-layer system editing functionality
|
||||||
|
*/
|
||||||
|
class FDismembermentEditor : public FAssetEditorToolkit, public FEditorUndoClient
|
||||||
{
|
{
|
||||||
}
|
public:
|
||||||
|
FDismembermentEditor();
|
||||||
|
virtual ~FDismembermentEditor();
|
||||||
|
|
||||||
// Destructor
|
void InitDismembermentEditor(const EToolkitMode::Type Mode, const TSharedPtr<IToolkitHost>& InitToolkitHost, USkeletalMesh* InSkeletalMesh);
|
||||||
FDismembermentEditor::~FDismembermentEditor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the editor
|
virtual FName GetToolkitFName() const override;
|
||||||
void FDismembermentEditor::InitDismembermentEditor(const EToolkitMode::Type Mode, const TSharedPtr<IToolkitHost>& InitToolkitHost, USkeletalMesh* InSkeletalMesh)
|
virtual FText GetBaseToolkitName() const override;
|
||||||
{
|
virtual FString GetWorldCentricTabPrefix() const override;
|
||||||
// Set the skeletal mesh being edited
|
virtual FLinearColor GetWorldCentricTabColorScale() const override;
|
||||||
SkeletalMesh = InSkeletalMesh;
|
|
||||||
|
|
||||||
// Create the layout
|
virtual void PostUndo(bool bSuccess) override;
|
||||||
CreateEditorLayout();
|
virtual void PostRedo(bool bSuccess) override;
|
||||||
|
|
||||||
// Create the toolbar
|
private:
|
||||||
CreateEditorToolbar();
|
void CreateEditorLayout();
|
||||||
|
void CreateEditorToolbar();
|
||||||
|
|
||||||
// Initialize the asset editor
|
void RegisterTabSpawners(const TSharedRef<FTabManager>& InTabManager);
|
||||||
InitAssetEditor(Mode, InitToolkitHost, FName("DismembermentEditorApp"),
|
void UnregisterTabSpawners(const TSharedRef<FTabManager>& InTabManager);
|
||||||
FTabManager::FLayout::NullLayout,
|
|
||||||
/*bCreateDefaultStandaloneMenu=*/ true,
|
|
||||||
/*bCreateDefaultToolbar=*/ true,
|
|
||||||
InSkeletalMesh);
|
|
||||||
|
|
||||||
// Register for undo/redo
|
TSharedRef<SDockTab> SpawnTab_Viewport(const FSpawnTabArgs& Args);
|
||||||
GEditor->RegisterForUndo(this);
|
TSharedRef<SDockTab> SpawnTab_Details(const FSpawnTabArgs& Args);
|
||||||
}
|
TSharedRef<SDockTab> SpawnTab_LayerSystem(const FSpawnTabArgs& Args);
|
||||||
|
TSharedRef<SDockTab> SpawnTab_PhysicsSettings(const FSpawnTabArgs& Args);
|
||||||
|
|
||||||
// Get the toolkit name
|
void PerformBooleanCut();
|
||||||
FName FDismembermentEditor::GetToolkitFName() const
|
void AddNewLayer();
|
||||||
{
|
void SaveEdits();
|
||||||
return FName("DismembermentEditor");
|
void PreviewEffects();
|
||||||
}
|
|
||||||
|
|
||||||
// Get the base toolkit name
|
private:
|
||||||
FText FDismembermentEditor::GetBaseToolkitName() const
|
USkeletalMesh* SkeletalMesh;
|
||||||
{
|
|
||||||
return FText::FromString("Dismemberment Editor");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the world centric tab prefix
|
TSharedPtr<SBorder> ViewportWidget;
|
||||||
FString FDismembermentEditor::GetWorldCentricTabPrefix() const
|
TSharedPtr<IDetailsView> DetailsWidget;
|
||||||
{
|
TSharedPtr<SBorder> LayerSystemWidget;
|
||||||
return "DismembermentEditor";
|
TSharedPtr<SBorder> PhysicsSettingsWidget;
|
||||||
}
|
|
||||||
|
|
||||||
// Get the world centric tab color scale
|
static const FName ViewportTabId;
|
||||||
FLinearColor FDismembermentEditor::GetWorldCentricTabColorScale() const
|
static const FName DetailsTabId;
|
||||||
{
|
static const FName LayerSystemTabId;
|
||||||
return FLinearColor(0.3f, 0.2f, 0.5f, 0.5f);
|
static const FName PhysicsSettingsTabId;
|
||||||
}
|
};
|
||||||
|
|
||||||
// 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()
|
|
||||||
{
|
|
||||||
// Create the layout
|
|
||||||
TSharedRef<FTabManager::FLayout> StandaloneDefaultLayout = FTabManager::NewLayout("Standalone_DismembermentEditor_Layout_v1")
|
|
||||||
->AddArea
|
|
||||||
(
|
|
||||||
FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical)
|
|
||||||
// In UE5.5.4, toolbar is no longer a separate tab
|
|
||||||
// Skip the toolbar tab section and directly create the main content area
|
|
||||||
->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<IToolkitHost>(),
|
|
||||||
FName("DismembermentEditorApp"),
|
|
||||||
StandaloneDefaultLayout,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
SkeletalMesh
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the editor toolbar
|
|
||||||
void FDismembermentEditor::CreateEditorToolbar()
|
|
||||||
{
|
|
||||||
// Create command list
|
|
||||||
TSharedPtr<FUICommandList> CommandList = MakeShareable(new FUICommandList);
|
|
||||||
|
|
||||||
// Get the toolbar builder
|
|
||||||
TSharedPtr<FExtender> 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<FTabManager>& 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<FTabManager>& 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<SDockTab> 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<SDockTab> FDismembermentEditor::SpawnTab_Details(const FSpawnTabArgs& Args)
|
|
||||||
{
|
|
||||||
// Create the details view
|
|
||||||
FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>("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<SDockTab> 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<SDockTab> 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
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user