void SBehaviorTreeBlackboardEditor::FillToolbar(FToolBarBuilder& ToolbarBuilder) const { ToolbarBuilder.AddComboButton( FUIAction( FExecuteAction(), FCanExecuteAction::CreateSP(this, &SBehaviorTreeBlackboardEditor::CanCreateNewEntry) ), FOnGetContent::CreateSP(this, &SBehaviorTreeBlackboardEditor::HandleCreateNewEntryMenu), LOCTEXT( "New_Label", "New Key" ), LOCTEXT( "New_ToolTip", "Create a new blackboard entry" ), FSlateIcon(FEditorStyle::GetStyleSetName(), "BTEditor.Blackboard.NewEntry") ); }
void FGameplayDebugger::CreateSettingSubMenu(FMenuBuilder& Builder) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) Builder.AddMenuEntry( LOCTEXT("Test_GameplayDebugger_Menu", "Test Gameplay Debugger Option"), LOCTEXT("Test_GameplayDebugger_Menu_Tooltip", "If Enabled, actors will snap to the nearest location on the constraint plane (NOTE: Only works correctly in perspective views right now!)"), FSlateIcon(), FUIAction( FExecuteAction()/*FExecuteAction::CreateRaw(PlanarPolicy.Get(), &FPlanarConstraintSnapPolicy::ToggleEnabled)*/, FCanExecuteAction(), FIsActionChecked()/*FIsActionChecked::CreateRaw(PlanarPolicy.Get(), &FPlanarConstraintSnapPolicy::IsEnabled)*/ ), NAME_None, EUserInterfaceActionType::Button, NAME_None); #endif }
/** * Takes the provided menu builder and adds elements representing various * profiles that the user can choose from (default, tutorial, etc.). * * @param MenuBuilder The builder to modify and add entries to. */ static void BuildProfilesSubMenu(FMenuBuilder& MenuBuilder) { TArray<FString> AvailableProfiles; const UEditorPerProjectUserSettings* EditorPerProjectUserSettings = GetDefault<UEditorPerProjectUserSettings>(); if (EditorPerProjectUserSettings->BlueprintFavorites != NULL) { static FString const ProfilesConfigKey("Profiles"); GConfig->GetArray(*SBlueprintFavoritesPaletteUtils::ConfigSection, *ProfilesConfigKey, AvailableProfiles, GEditorIni); } struct LocalUtils { static bool CanExecute() { return true; } static bool CannotExecute() { return false; } static void NavigateToURL(FString URL) { FPlatformProcess::LaunchURL(*URL, NULL, NULL); } }; if (AvailableProfiles.Num() > 0) { for (FString const& Profile : AvailableProfiles) { FString ProfileName; FParse::Value(*Profile, TEXT("Name="), ProfileName); FString FriendlyProfileName; FParse::Value(*Profile, TEXT("FriendlyName="), FriendlyProfileName); FString ProfileToolTip; FParse::Value(*Profile, TEXT("ToolTip="), ProfileToolTip); FString ProfileURL; FParse::Value(*Profile, TEXT("URL="), ProfileURL); FString ProfileURLName; FParse::Value(*Profile, TEXT("URLText="), ProfileURLName); // @TODO how to best localize this? FText ToolTipText = FText::FromString(ProfileToolTip); if (ProfileURLName.IsEmpty()) { ProfileURLName = ProfileURL; } if (FriendlyProfileName.IsEmpty()) { FriendlyProfileName = ProfileName; } FUIAction ProfileAction; if (SBlueprintFavoritesPaletteUtils::CanLoadFavoritesProfile(ProfileName)) { if (ToolTipText.IsEmpty()) { ToolTipText = FText::Format(LOCTEXT("ProfileAvailableFmt", "Loads {0} node favorites"), FText::FromString(FriendlyProfileName)); } ProfileAction = FUIAction( FExecuteAction::CreateStatic(&SBlueprintFavoritesPaletteUtils::LoadFavoritesProfile, ProfileName), FCanExecuteAction::CreateStatic(&LocalUtils::CanExecute) ); } else { if (ToolTipText.IsEmpty()) { ToolTipText = LOCTEXT("ProfileLoaded", "Current profile"); } ProfileAction = FUIAction( FExecuteAction(), FCanExecuteAction::CreateStatic(&LocalUtils::CannotExecute) ); } // build the text that goes in the sub-menu TSharedRef<STextBlock> MenuTextEntry = SNew(STextBlock) .TextStyle(MenuBuilder.GetStyleSet(), FEditorStyle::Join("Menu", ".Label")) // @TODO how do we best localize this .Text(FText::FromString(FriendlyProfileName)); FSlateFontInfo ToolTipFont(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 8); TSharedPtr<SVerticalBox> ToolTipBox; // build the specialized tooltip TSharedRef<SToolTip> ToolTipWidget = SNew(SToolTip) [ SAssignNew(ToolTipBox, SVerticalBox) +SVerticalBox::Slot() [ SNew(STextBlock) .WrapTextAt(400) .Font(ToolTipFont) .Text(ToolTipText) ] ]; // add the url if one was specified if (!ProfileURL.IsEmpty()) { ToolTipBox->AddSlot() .AutoHeight() .HAlign(HAlign_Right) [ SNew(SHyperlink) // @TODO how to best localize this? .Text(FText::FromString(ProfileURLName)) .OnNavigate_Static(&LocalUtils::NavigateToURL, ProfileURL) ]; } // now build the actual menu widget TSharedRef<SWidget> MenuEntryWidget = SNew(SHorizontalBox) .ToolTip(ToolTipWidget) // so the tool tip shows up for the whole entry: .Visibility(EVisibility::Visible) +SHorizontalBox::Slot() // match the padding with normal sub-men entries .Padding(FMargin(18.f, 0.f, 6.f, 0.f)) .FillWidth(1.0f) [ MenuTextEntry ]; MenuBuilder.AddMenuEntry(ProfileAction, MenuEntryWidget); } } else { FUIAction NullProfileAction(FExecuteAction(), FCanExecuteAction::CreateStatic(&LocalUtils::CannotExecute)); MenuBuilder.AddMenuEntry(LOCTEXT("NoProfiles", "No profiles available"), FText::GetEmpty(), FSlateIcon(), NullProfileAction); } }
void FPathContextMenu::MakePathViewContextMenu(FMenuBuilder& MenuBuilder) { int32 NumAssetPaths, NumClassPaths; ContentBrowserUtils::CountPathTypes(SelectedPaths, NumAssetPaths, NumClassPaths); // Only add something if at least one folder is selected if ( SelectedPaths.Num() > 0 ) { const bool bHasAssetPaths = NumAssetPaths > 0; const bool bHasClassPaths = NumClassPaths > 0; // Common operations section // MenuBuilder.BeginSection("PathViewFolderOptions", LOCTEXT("PathViewOptionsMenuHeading", "Folder Options") ); { if(bHasAssetPaths) { FText NewAssetToolTip; if(SelectedPaths.Num() == 1) { if(CanCreateAsset()) { NewAssetToolTip = FText::Format(LOCTEXT("NewAssetTooltip_CreateIn", "Create a new asset in {0}."), FText::FromString(SelectedPaths[0])); } else { NewAssetToolTip = FText::Format(LOCTEXT("NewAssetTooltip_InvalidPath", "Cannot create new assets in {0}."), FText::FromString(SelectedPaths[0])); } } else { NewAssetToolTip = LOCTEXT("NewAssetTooltip_InvalidNumberOfPaths", "Can only create assets when there is a single path selected."); } // New Asset (submenu) MenuBuilder.AddSubMenu( LOCTEXT( "NewAssetLabel", "New Asset" ), NewAssetToolTip, FNewMenuDelegate::CreateRaw( this, &FPathContextMenu::MakeNewAssetSubMenu ), FUIAction( FExecuteAction(), FCanExecuteAction::CreateRaw( this, &FPathContextMenu::CanCreateAsset ) ), NAME_None, EUserInterfaceActionType::Button, false, FSlateIcon() ); } if(bHasClassPaths) { FText NewClassToolTip; if(SelectedPaths.Num() == 1) { if(CanCreateClass()) { NewClassToolTip = FText::Format(LOCTEXT("NewClassTooltip_CreateIn", "Create a new class in {0}."), FText::FromString(SelectedPaths[0])); } else { NewClassToolTip = FText::Format(LOCTEXT("NewClassTooltip_InvalidPath", "Cannot create new classes in {0}."), FText::FromString(SelectedPaths[0])); } } else { NewClassToolTip = LOCTEXT("NewClassTooltip_InvalidNumberOfPaths", "Can only create classes when there is a single path selected."); } // New Class MenuBuilder.AddMenuEntry( LOCTEXT("NewClassLabel", "New C++ Class..."), NewClassToolTip, FSlateIcon(FEditorStyle::GetStyleSetName(), "MainFrame.AddCodeToProject"), FUIAction( FExecuteAction::CreateRaw( this, &FPathContextMenu::ExecuteCreateClass ), FCanExecuteAction::CreateRaw( this, &FPathContextMenu::CanCreateClass ) ) ); } // Explore MenuBuilder.AddMenuEntry( ContentBrowserUtils::GetExploreFolderText(), LOCTEXT("ExploreTooltip", "Finds this folder on disk."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FPathContextMenu::ExecuteExplore ) ) ); MenuBuilder.AddMenuEntry(FGenericCommands::Get().Rename, NAME_None, LOCTEXT("RenameFolder", "Rename"), LOCTEXT("RenameFolderTooltip", "Rename the selected folder.") ); // If any colors have already been set, display color options as a sub menu if ( ContentBrowserUtils::HasCustomColors() ) { // Set Color (submenu) MenuBuilder.AddSubMenu( LOCTEXT("SetColor", "Set Color"), LOCTEXT("SetColorTooltip", "Sets the color this folder should appear as."), FNewMenuDelegate::CreateRaw( this, &FPathContextMenu::MakeSetColorSubMenu ), false, FSlateIcon() ); } else { // Set Color MenuBuilder.AddMenuEntry( LOCTEXT("SetColor", "Set Color"), LOCTEXT("SetColorTooltip", "Sets the color this folder should appear as."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FPathContextMenu::ExecutePickColor ) ) ); } } MenuBuilder.EndSection(); if(bHasAssetPaths) { // Bulk operations section // MenuBuilder.BeginSection("PathContextBulkOperations", LOCTEXT("AssetTreeBulkMenuHeading", "Bulk Operations") ); { // Save MenuBuilder.AddMenuEntry( LOCTEXT("SaveFolder", "Save All"), LOCTEXT("SaveFolderTooltip", "Saves all modified assets in this folder."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FPathContextMenu::ExecuteSaveFolder ) ) ); // Delete MenuBuilder.AddMenuEntry(FGenericCommands::Get().Delete, NAME_None, LOCTEXT("DeleteFolder", "Delete"), LOCTEXT("DeleteFolderTooltip", "Removes this folder and all assets it contains."), FSlateIcon() ); // Reference Viewer MenuBuilder.AddMenuEntry( LOCTEXT("ReferenceViewer", "Reference Viewer..."), LOCTEXT("ReferenceViewerOnFolderTooltip", "Shows a graph of references for this folder."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FPathContextMenu::ExecuteReferenceViewer ) ) ); // Size Map MenuBuilder.AddMenuEntry( LOCTEXT("SizeMap", "Size Map..."), LOCTEXT("SizeMapOnFolderTooltip", "Shows an interactive map of the approximate memory used by the assets in this folder and everything they reference."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FPathContextMenu::ExecuteSizeMap ) ) ); // Fix Up Redirectors in Folder MenuBuilder.AddMenuEntry( LOCTEXT("FixUpRedirectorsInFolder", "Fix Up Redirectors in Folder"), LOCTEXT("FixUpRedirectorsInFolderTooltip", "Finds referencers to all redirectors in the selected folders and resaves them if possible, then deletes any redirectors that had all their referencers fixed."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FPathContextMenu::ExecuteFixUpRedirectorsInFolder ) ) ); if ( NumAssetPaths == 1 && NumClassPaths == 0 ) { // Migrate Folder MenuBuilder.AddMenuEntry( LOCTEXT("MigrateFolder", "Migrate..."), LOCTEXT("MigrateFolderTooltip", "Copies assets found in this folder and their dependencies to another game content folder."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FPathContextMenu::ExecuteMigrateFolder ) ) ); } } MenuBuilder.EndSection(); // Source control section // MenuBuilder.BeginSection("PathContextSourceControl", LOCTEXT("AssetTreeSCCMenuHeading", "Source Control") ); ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); if ( SourceControlProvider.IsEnabled() ) { // Check out MenuBuilder.AddMenuEntry( LOCTEXT("FolderSCCCheckOut", "Check Out"), LOCTEXT("FolderSCCCheckOutTooltip", "Checks out all assets from source control which are in this folder."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FPathContextMenu::ExecuteSCCCheckOut ), FCanExecuteAction::CreateSP( this, &FPathContextMenu::CanExecuteSCCCheckOut ) ) ); // Open for Add MenuBuilder.AddMenuEntry( LOCTEXT("FolderSCCOpenForAdd", "Mark For Add"), LOCTEXT("FolderSCCOpenForAddTooltip", "Adds all assets to source control that are in this folder and not already added."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FPathContextMenu::ExecuteSCCOpenForAdd ), FCanExecuteAction::CreateSP( this, &FPathContextMenu::CanExecuteSCCOpenForAdd ) ) ); // Check in MenuBuilder.AddMenuEntry( LOCTEXT("FolderSCCCheckIn", "Check In"), LOCTEXT("FolderSCCCheckInTooltip", "Checks in all assets to source control which are in this folder."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FPathContextMenu::ExecuteSCCCheckIn ), FCanExecuteAction::CreateSP( this, &FPathContextMenu::CanExecuteSCCCheckIn ) ) ); // Sync MenuBuilder.AddMenuEntry( LOCTEXT("FolderSCCSync", "Sync"), LOCTEXT("FolderSCCSyncTooltip", "Syncs all the assets in this folder to the latest version."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FPathContextMenu::ExecuteSCCSync ), FCanExecuteAction::CreateSP( this, &FPathContextMenu::CanExecuteSCCSync ) ) ); } else { MenuBuilder.AddMenuEntry( LOCTEXT("FolderSCCConnect", "Connect To Source Control"), LOCTEXT("FolderSCCConnectTooltip", "Connect to source control to allow source control operations to be performed on content and levels."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FPathContextMenu::ExecuteSCCConnect ), FCanExecuteAction::CreateSP( this, &FPathContextMenu::CanExecuteSCCConnect ) ) ); } MenuBuilder.EndSection(); } } }
TSharedPtr<SWidget> FCollectionContextMenu::MakeCollectionTreeContextMenu(TSharedPtr< FUICommandList > InCommandList) { // Get all menu extenders for this context menu from the content browser module FContentBrowserModule& ContentBrowserModule = FModuleManager::GetModuleChecked<FContentBrowserModule>( TEXT("ContentBrowser") ); TArray<FContentBrowserMenuExtender> MenuExtenderDelegates = ContentBrowserModule.GetAllCollectionListContextMenuExtenders(); TArray<TSharedPtr<FExtender>> Extenders; for (int32 i = 0; i < MenuExtenderDelegates.Num(); ++i) { if (MenuExtenderDelegates[i].IsBound()) { Extenders.Add(MenuExtenderDelegates[i].Execute()); } } TSharedPtr<FExtender> MenuExtender = FExtender::Combine(Extenders); FMenuBuilder MenuBuilder(/*bInShouldCloseWindowAfterMenuSelection=*/true, InCommandList, MenuExtender); UpdateProjectSourceControl(); TArray<TSharedPtr<FCollectionItem>> SelectedCollections = CollectionView.Pin()->CollectionTreePtr->GetSelectedItems(); bool bAnyManagedBySCC = false; bool bAnyNeedSCCUpdate = false; bool bAnyNeedSave = false; for (int32 CollectionIdx = 0; CollectionIdx < SelectedCollections.Num(); ++CollectionIdx) { bAnyManagedBySCC |= SelectedCollections[CollectionIdx]->CollectionType != ECollectionShareType::CST_Local; bAnyNeedSCCUpdate |= SelectedCollections[CollectionIdx]->CurrentStatus == ECollectionItemStatus::IsOutOfDate; bAnyNeedSave |= SelectedCollections[CollectionIdx]->CurrentStatus == ECollectionItemStatus::HasLocalChanges; if (bAnyManagedBySCC && bAnyNeedSCCUpdate && bAnyNeedSave) { // Found collections to turn all options on, break now break; } } MenuBuilder.BeginSection("CollectionOptions", LOCTEXT("CollectionListOptionsMenuHeading", "Collection Options")); { const bool bHasSingleSelectedCollection = SelectedCollections.Num() == 1; const bool bIsFirstSelectedCollectionStatic = SelectedCollections.Num() > 0 && SelectedCollections[0]->StorageMode == ECollectionStorageMode::Static; // New... (submenu) MenuBuilder.AddSubMenu( LOCTEXT("NewChildCollection", "New..."), LOCTEXT("NewChildCollectionTooltip", "Create child a collection."), FNewMenuDelegate::CreateRaw( this, &FCollectionContextMenu::MakeNewCollectionSubMenu, ECollectionStorageMode::Static, SCollectionView::FCreateCollectionPayload( FCollectionNameType( SelectedCollections[0]->CollectionName, SelectedCollections[0]->CollectionType ) ) ), FUIAction( FExecuteAction(), FCanExecuteAction::CreateLambda( [=]{ return bHasSingleSelectedCollection && bIsFirstSelectedCollectionStatic; } ) ), NAME_None, EUserInterfaceActionType::Button ); // Rename MenuBuilder.AddMenuEntry( FGenericCommands::Get().Rename, NAME_None, LOCTEXT("RenameCollection", "Rename"), LOCTEXT("RenameCollectionTooltip", "Rename this collection.")); // Set Share Type MenuBuilder.AddSubMenu( LOCTEXT("SetCollectionShareType", "Set Share Type"), LOCTEXT("SetCollectionShareTypeTooltip", "Change the share type of this collection."), FNewMenuDelegate::CreateRaw( this, &FCollectionContextMenu::MakeCollectionShareTypeSubMenu ), FUIAction( FExecuteAction(), FCanExecuteAction::CreateLambda( [=]{ return bHasSingleSelectedCollection; } ) ), NAME_None, EUserInterfaceActionType::Button ); // If any colors have already been set, display color options as a sub menu if ( CollectionViewUtils::HasCustomColors() ) { // Set Color (submenu) MenuBuilder.AddSubMenu( LOCTEXT("SetColor", "Set Color"), LOCTEXT("SetCollectionColorTooltip", "Sets the color this collection should appear as."), FNewMenuDelegate::CreateRaw( this, &FCollectionContextMenu::MakeSetColorSubMenu ) ); } else { // Set Color MenuBuilder.AddMenuEntry( LOCTEXT("SetColor", "Set Color"), LOCTEXT("SetCollectionColorTooltip", "Sets the color this collection should appear as."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecutePickColor ) ) ); } } MenuBuilder.EndSection(); if ( SelectedCollections.Num() > 0 ) { MenuBuilder.BeginSection("CollectionBulkOperations", LOCTEXT("CollectionListBulkOperationsMenuHeading", "Bulk Operations")); { // Save MenuBuilder.AddMenuEntry( LOCTEXT("SaveCollection", "Save"), LOCTEXT("SaveCollectionTooltip", "Save this collection."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteSaveCollection ), FCanExecuteAction::CreateLambda( [=]{ return bAnyNeedSave; } ) ) ); // Delete MenuBuilder.AddMenuEntry( LOCTEXT("DestroyCollection", "Delete"), LOCTEXT("DestroyCollectionTooltip", "Delete this collection."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteDestroyCollection ), FCanExecuteAction::CreateSP( this, &FCollectionContextMenu::CanExecuteDestroyCollection, bAnyManagedBySCC ) ) ); // Update MenuBuilder.AddMenuEntry( LOCTEXT("UpdateCollection", "Update"), LOCTEXT("UpdateCollectionTooltip", "Update this collection to make sure it's using the latest version from source control."), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteUpdateCollection ), FCanExecuteAction::CreateLambda( [=]{ return bAnyNeedSCCUpdate; } ) ) ); } MenuBuilder.EndSection(); } return MenuBuilder.MakeWidget(); }