// Copyright Epic Games, Inc. All Rights Reserved. #include "ViewportSnappingModule.h" #include "PlanarConstraintSnapPolicy.h" #include "Framework/MultiBox/MultiBoxBuilder.h" #include "LevelEditor.h" #define LOCTEXT_NAMESPACE "SmartSnapping" ////////////////////////////////////////////////////////////////////////// // FSmartSnappingModule class FSmartSnappingModule : public FDefaultModuleImpl { public: TSharedPtr PlanarPolicy; FLevelEditorModule::FLevelEditorMenuExtender ViewMenuExtender; FDelegateHandle ViewMenuExtenderHandle; virtual void StartupModule() override { if (!IsRunningCommandlet()) { // Create and register the snapping policy PlanarPolicy = MakeShareable(new FPlanarConstraintSnapPolicy); IViewportSnappingModule& SnappingModule = FModuleManager::LoadModuleChecked("ViewportSnapping"); SnappingModule.RegisterSnappingPolicy(PlanarPolicy); // Register the extension with the level editor { // TODO: This should extend the viewport toolbar menu "LevelEditor.ViewportToolbar.Show" using the // ToolMenus system instead of using legacy menu extenders. ViewMenuExtender = FLevelEditorModule::FLevelEditorMenuExtender::CreateRaw(this, &FSmartSnappingModule::OnExtendLevelEditorViewMenu); FLevelEditorModule& LevelEditor = FModuleManager::LoadModuleChecked(TEXT("LevelEditor")); auto& MenuExtenders = LevelEditor.GetAllLevelEditorToolbarViewMenuExtenders(); MenuExtenders.Add(ViewMenuExtender); ViewMenuExtenderHandle = MenuExtenders.Last().GetHandle(); } } } virtual void ShutdownModule() override { if (UObjectInitialized() && !IsRunningCommandlet()) { // Unregister the level editor extensions { FLevelEditorModule& LevelEditor = FModuleManager::GetModuleChecked( TEXT("LevelEditor") ); LevelEditor.GetAllLevelEditorToolbarViewMenuExtenders().RemoveAll([this](const FLevelEditorModule::FLevelEditorMenuExtender& Extender) { return Extender.GetHandle() == ViewMenuExtenderHandle; }); } // // Unregister the snapping policy IViewportSnappingModule& SnappingModule = FModuleManager::LoadModuleChecked("ViewportSnapping"); SnappingModule.UnregisterSnappingPolicy(PlanarPolicy); PlanarPolicy.Reset(); } } void CreateSnappingOptionsMenu(FMenuBuilder& Builder) { FUIAction Action_TogglePlanarSnap( FExecuteAction::CreateRaw(PlanarPolicy.Get(), &FPlanarConstraintSnapPolicy::ToggleEnabled), FCanExecuteAction(), FIsActionChecked::CreateRaw(PlanarPolicy.Get(), &FPlanarConstraintSnapPolicy::IsEnabled)); Builder.AddMenuEntry( LOCTEXT("View_Extension_PlanarSnap_Enable", "Planar"), LOCTEXT( "View_Extension_PlanarSnap_Tooltip", "If Enabled, actors will snap to the nearest location on the constraint plane (NOTE: Only works correctly in perspective views right now!)" ), FSlateIcon(FAppStyle::GetAppStyleSetName(), "ViewportToolbar.SnapPlanar"), Action_TogglePlanarSnap, NAME_None, EUserInterfaceActionType::ToggleButton ); // Builder.AddWidget(SNew(STextBlock).Text(TEXT("Depth value goes here")), // LOCTEXT("View_Extension_PlanarSnap_Depth", "Distance from plane")); // FUIAction Action_TogglePlanarSnap( // FExecuteAction::CreateSP(PlanarPolicy, &FPlanarConstraintSnapPolicy::ToggleEnabled), // FCanExecuteAction(), // FIsActionChecked::CreateSP(PlanarPolicy, &FPlanarConstraintSnapPolicy::IsEnabled)); } TSharedRef OnExtendLevelEditorViewMenu(const TSharedRef CommandList) { TSharedRef Extender(new FExtender()); Extender->AddMenuExtension( "Snapping", EExtensionHook::After, nullptr, FMenuExtensionDelegate::CreateRaw(this, &FSmartSnappingModule::CreateSnappingOptionsMenu)); return Extender; } }; ////////////////////////////////////////////////////////////////////////// IMPLEMENT_MODULE(FSmartSnappingModule, SmartSnapping); ////////////////////////////////////////////////////////////////////////// #undef LOCTEXT_NAMESPACE