void FExtender::Apply( FName ExtensionHook, EExtensionHook::Position HookPosition, FMenuBuilder& MenuBuilder ) const { for( auto ExtensionIt( Extensions.CreateConstIterator() ); ExtensionIt; ++ExtensionIt ) { const auto& Extension = *ExtensionIt; if( Extension->GetType() == EExtensionType::Menu && Extension->Hook == ExtensionHook && Extension->HookPosition == HookPosition ) { const auto& MenuExtension = StaticCastSharedPtr< const FMenuExtension >( Extension ); if ( Extension->CommandList.IsValid() ) { // Push the command list needed for this extension's menu items MenuBuilder.PushCommandList( Extension->CommandList.ToSharedRef() ); } // Extend the menu! MenuExtension->MenuExtensionDelegate.ExecuteIfBound( MenuBuilder ); if ( Extension->CommandList.IsValid() ) { // Restore the original command list MenuBuilder.PopCommandList(); } } } }
void FToolBarButtonBlock::CreateMenuEntry(FMenuBuilder& MenuBuilder) const { TSharedPtr<const FUICommandInfo> MenuEntryAction = GetAction(); TSharedPtr<const FUICommandList> MenuEntryActionList = GetActionList(); if (MenuEntryAction.IsValid() && MenuEntryActionList.IsValid()) { MenuBuilder.PushCommandList(MenuEntryActionList.ToSharedRef()); MenuBuilder.AddMenuEntry(MenuEntryAction); MenuBuilder.PopCommandList(); } else if ( LabelOverride.IsSet() ) { const FUIAction& DirectAction = GetDirectActions(); MenuBuilder.AddMenuEntry( LabelOverride.Get(), ToolTipOverride.Get(), IconOverride.Get(), DirectAction ); } }
void FLevelEditorContextMenu::FillMenu( FMenuBuilder& MenuBuilder, TWeakPtr<SLevelEditor> LevelEditor, LevelEditorMenuContext ContextType, TSharedPtr<FExtender> Extender ) { // Generate information about our selection TArray<AActor*> SelectedActors; GEditor->GetSelectedActors()->GetSelectedObjects<AActor>( SelectedActors ); FSelectedActorInfo& SelectionInfo = FLevelEditorContextMenuImpl::SelectionInfo; SelectionInfo = AssetSelectionUtils::BuildSelectedActorInfo( SelectedActors ); // Get all menu extenders for this context menu from the level editor module FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>( TEXT("LevelEditor") ); TArray<FLevelEditorModule::FLevelViewportMenuExtender_SelectedActors> MenuExtenderDelegates = LevelEditorModule.GetAllLevelViewportContextMenuExtenders(); TArray<TSharedPtr<FExtender>> Extenders; if(Extender.IsValid()) { Extenders.Add(Extender); } auto LevelEditorActions = LevelEditor.Pin()->GetLevelEditorActions().ToSharedRef(); for (int32 i = 0; i < MenuExtenderDelegates.Num(); ++i) { if (MenuExtenderDelegates[i].IsBound()) { Extenders.Add(MenuExtenderDelegates[i].Execute(LevelEditorActions, SelectedActors)); } } MenuBuilder.PushCommandList(LevelEditorActions); MenuBuilder.PushExtender(FExtender::Combine(Extenders).ToSharedRef()); TArray<TWeakObjectPtr<UObject>> LabelObjects; for ( FSelectionIterator SelItor(*GEditor->GetSelectedActors()) ; SelItor ; ++SelItor ) { LabelObjects.Add(*SelItor); } // Check if current selection has any assets that can be browsed to TArray< UObject* > ReferencedAssets; GEditor->GetReferencedAssetsForEditorSelection( ReferencedAssets ); const bool bCanSyncToContentBrowser = GEditor->CanSyncToContentBrowser(); if( bCanSyncToContentBrowser || ReferencedAssets.Num() > 0 ) { MenuBuilder.BeginSection("ActorAsset", LOCTEXT("AssetHeading", "Asset") ); { if( bCanSyncToContentBrowser ) { MenuBuilder.AddMenuEntry( FGlobalEditorCommonCommands::Get().FindInContentBrowser ); } if( ReferencedAssets.Num() == 1 ) { auto Asset = ReferencedAssets[0]; MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().EditAsset, NAME_None, FText::Format( LOCTEXT("EditAssociatedAsset", "Edit {0}"), FText::FromString( Asset->GetName() ) ), TAttribute<FText>(), FSlateIcon( FEditorStyle::GetStyleSetName(), FClassIconFinder::FindIconNameForClass( Asset->GetClass() ) ) ); } else if ( ReferencedAssets.Num() > 1 ) { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().EditAssetNoConfirmMultiple, NAME_None, LOCTEXT("EditAssociatedAssetsMultiple", "Edit Multiple Assets"), TAttribute<FText>(), FSlateIcon( FEditorStyle::GetStyleSetName(), "ClassIcon.Default" ) ); } MenuBuilder.AddMenuEntry( FGlobalEditorCommonCommands::Get().ViewReferences ); } MenuBuilder.EndSection(); } MenuBuilder.BeginSection( "ActorControl", LOCTEXT("ActorHeading", "Actor") ); { MenuBuilder.AddMenuEntry( FEditorViewportCommands::Get().FocusViewportToSelection ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().SnapCameraToActor ); } MenuBuilder.EndSection(); // Go to C++ Code if( SelectionInfo.SelectionClass != NULL ) { if ( FSourceCodeNavigation::IsCompilerAvailable()) { FString ClassHeaderPath; if( FSourceCodeNavigation::FindClassHeaderPath( SelectionInfo.SelectionClass, ClassHeaderPath ) && IFileManager::Get().FileSize( *ClassHeaderPath ) != INDEX_NONE ) { const FString CodeFileName = FPaths::GetCleanFilename( *ClassHeaderPath ); MenuBuilder.BeginSection( "ActorCode", LOCTEXT("ActorCodeHeading", "C++") ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().GoToCodeForActor, NAME_None, FText::Format( LOCTEXT("GoToCodeForActor", "Open {0}"), FText::FromString( CodeFileName ) ), FText::Format( LOCTEXT("GoToCodeForActor_ToolTip", "Opens the header file for this actor ({0}) in a code editing program"), FText::FromString( CodeFileName ) ) ); } MenuBuilder.EndSection(); } } const FString DocumentationLink = FEditorClassUtils::GetDocumentationLink(SelectionInfo.SelectionClass); if (!DocumentationLink.IsEmpty()) { MenuBuilder.BeginSection( "ActorDocumentation", LOCTEXT("ActorDocsHeading", "Documentation") ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().GoToDocsForActor, NAME_None, LOCTEXT("GoToDocsForActor", "View Documentation"), LOCTEXT("GoToDocsForActor_ToolTip", "Click to open documentation for this actor"), FSlateIcon(FEditorStyle::GetStyleSetName(), "HelpIcon.Hovered" )); } MenuBuilder.EndSection(); } } MenuBuilder.BeginSection("ActorSelectVisibilityLevels"); { // Add a sub-menu for "Select" MenuBuilder.AddSubMenu( LOCTEXT("SelectSubMenu", "Select"), LOCTEXT("SelectSubMenu_ToolTip", "Opens the actor selection menu"), FNewMenuDelegate::CreateStatic( &FLevelEditorContextMenuImpl::FillSelectActorMenu ) ); MenuBuilder.AddSubMenu( LOCTEXT("EditSubMenu", "Edit"), FText::GetEmpty(), FNewMenuDelegate::CreateStatic( &FLevelEditorContextMenuImpl::FillEditMenu, ContextType ) ); MenuBuilder.AddSubMenu( LOCTEXT("VisibilitySubMenu", "Visibility"), LOCTEXT("VisibilitySubMenu_ToolTip", "Selected actor visibility options"), FNewMenuDelegate::CreateStatic( &FLevelEditorContextMenuImpl::FillActorVisibilityMenu ) ); // Build the menu for grouping actors BuildGroupMenu( MenuBuilder, SelectionInfo ); MenuBuilder.AddSubMenu( LOCTEXT("LevelSubMenu", "Level"), LOCTEXT("LevelSubMenu_ToolTip", "Options for interacting with this actor's level"), FNewMenuDelegate::CreateStatic( &FLevelEditorContextMenuImpl::FillActorLevelMenu ) ); } MenuBuilder.EndSection(); if (ContextType == LevelEditorMenuContext::Viewport) { LevelEditorCreateActorMenu::FillAddReplaceViewportContextMenuSections( MenuBuilder ); } if( GEditor->PlayWorld != NULL ) { if( SelectionInfo.NumSelected > 0 ) { MenuBuilder.BeginSection( "Simulation", NSLOCTEXT( "LevelViewportContextMenu", "SimulationHeading", "Simulation" ) ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().KeepSimulationChanges ); } MenuBuilder.EndSection(); } } MenuBuilder.BeginSection("LevelViewportAttach"); { // Only display the attach menu if we have actors selected if ( GEditor->GetSelectedActorCount() ) { if(SelectionInfo.bHaveAttachedActor) { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().DetachFromParent ); } MenuBuilder.AddSubMenu( LOCTEXT( "ActorAttachToSubMenu", "Attach To" ), LOCTEXT( "ActorAttachToSubMenu_ToolTip", "Attach Actor as child" ), FNewMenuDelegate::CreateStatic( &FLevelEditorContextMenuImpl::FillActorMenu ) ); } // Add a heading for "Movement" if an actor is selected if ( GEditor->GetSelectedActorIterator() ) { // Add a sub-menu for "Transform" MenuBuilder.AddSubMenu( LOCTEXT("TransformSubMenu", "Transform"), LOCTEXT("TransformSubMenu_ToolTip", "Actor transform utils"), FNewMenuDelegate::CreateStatic( &FLevelEditorContextMenuImpl::FillTransformMenu ) ); } // @todo UE4: The current pivot options only work for brushes if( SelectionInfo.bHaveBrush ) { // You can only move the pivot in ortho viewports, but you can reset it in any viewport if( GCurrentLevelEditingViewportClient->ViewportType != LVT_Perspective ) { // Add a sub-menu for "Pivot" MenuBuilder.AddSubMenu( LOCTEXT("PivotSubMenu", "Pivot"), LOCTEXT("PivotSubMenu_ToolTip", "Actor pivoting utils"), FNewMenuDelegate::CreateStatic( &FLevelEditorContextMenuImpl::FillPivotMenu ) ); } else { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().ResetPivot ); } } if (GetDefault<UEditorExperimentalSettings>()->bActorMerging && (SelectionInfo.bHaveStaticMeshComponent || SelectionInfo.bHaveLandscape)) { MenuBuilder.AddSubMenu( LOCTEXT("MergeActorsSubMenu", "Merge"), LOCTEXT("MergeActorsSubMenu_ToolTip", "Actor merging utils"), FNewMenuDelegate::CreateStatic( &FLevelEditorContextMenuImpl::FillMergeActorsMenu ) ); } } MenuBuilder.EndSection(); FLevelScriptEventMenuHelper::FillLevelBlueprintEventsMenu(MenuBuilder, SelectedActors); MenuBuilder.PopCommandList(); MenuBuilder.PopExtender(); }