// Copyright Epic Games, Inc. All Rights Reserved. #include "Framework/MultiBox/MultiBoxBuilder.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Widgets/Text/STextBlock.h" #include "Framework/MultiBox/MultiBox.h" #include "Widgets/Layout/SBox.h" #include "Widgets/SBoxPanel.h" #include "Framework/MultiBox/SHeadingBlock.h" #include "Framework/MultiBox/SMenuEntryBlock.h" #include "Framework/MultiBox/SMenuSeparatorBlock.h" #include "Framework/MultiBox/SToolBarSeparatorBlock.h" #include "Framework/MultiBox/SToolBarButtonBlock.h" #include "Framework/MultiBox/SToolBarComboButtonBlock.h" #include "Framework/MultiBox/SToolBarStackButtonBlock.h" #include "Framework/MultiBox/SEditableTextBlock.h" #include "Framework/MultiBox/SButtonRowBlock.h" #include "Framework/MultiBox/SWidgetBlock.h" #include "Framework/MultiBox/SGroupMarkerBlock.h" #include "Framework/MultiBox/ToolMenuBase.h" #include "Widgets/Layout/SScrollBox.h" #include "Styling/ToolBarStyle.h" FMultiBoxBuilder::FMultiBoxBuilder( const EMultiBoxType InType, FMultiBoxCustomization InCustomization, const bool bInShouldCloseWindowAfterMenuSelection, const TSharedPtr< const FUICommandList >& InCommandList, TSharedPtr InExtender, FName InTutorialHighlightName, FName InMenuName ) : MultiBox( FMultiBox::Create( InType, (InMenuName != NAME_None) ? FMultiBoxCustomization::AllowCustomization(InMenuName) : InCustomization, bInShouldCloseWindowAfterMenuSelection ) ) , CommandListStack() , TutorialHighlightName(InTutorialHighlightName) , MenuName(InMenuName) , bExtendersEnabled(true) { CommandListStack.Push( InCommandList ); ExtenderStack.Push(InExtender); } void FMultiBoxBuilder::AddEditableText( const FText& InLabel, const FText& InToolTip, const FSlateIcon& InIcon, const TAttribute< FText >& InTextAttribute, const FOnTextCommitted& InOnTextCommitted, const FOnTextChanged& InOnTextChanged, bool bInReadOnly ) { MultiBox->AddMultiBlock( MakeShareable( new FEditableTextBlock( InLabel, InToolTip, InIcon, InTextAttribute, bInReadOnly, InOnTextCommitted, InOnTextChanged ) ) ); } void FMultiBoxBuilder::AddVerifiedEditableText(const FText& InLabel, const FText& InToolTip, const FSlateIcon& InIcon, const TAttribute< FText >& InTextAttribute, const FOnVerifyTextChanged& InOnVerifyTextChanged, const FOnTextCommitted& InOnTextCommitted /*= FOnTextCommitted()*/, const FOnTextChanged& InOnTextChanged /*= FOnTextChanged()*/, bool bInReadOnly /*= false*/) { MultiBox->AddMultiBlock(MakeShareable(new FEditableTextBlock(InLabel, InToolTip, InIcon, InTextAttribute, bInReadOnly, InOnTextCommitted, InOnTextChanged, InOnVerifyTextChanged))); } void FMultiBoxBuilder::PushCommandList( const TSharedRef< const FUICommandList > CommandList ) { CommandListStack.Push( CommandList ); } void FMultiBoxBuilder::PopCommandList() { // Never allowed to pop the last command-list! This command-list was set when the multibox was first created and is canonical. if( ensure( CommandListStack.Num() > 1 ) ) { CommandListStack.Pop(); } } TSharedPtr FMultiBoxBuilder::GetTopCommandList() { return (CommandListStack.Num() > 0) ? CommandListStack.Top() : TSharedPtr(NULL); } void FMultiBoxBuilder::PushExtender( TSharedRef< FExtender > InExtender ) { ExtenderStack.Push( InExtender ); } void FMultiBoxBuilder::PopExtender() { // Never allowed to pop the last extender! This extender was set when the multibox was first created and is canonical. if( ensure( ExtenderStack.Num() > 1 ) ) { ExtenderStack.Pop(); } } const ISlateStyle* FMultiBoxBuilder::GetStyleSet() const { return MultiBox->GetStyleSet(); } const FName& FMultiBoxBuilder::GetStyleName() const { return MultiBox->GetStyleName(); } void FMultiBoxBuilder::SetStyle( const ISlateStyle* InStyleSet, const FName& InStyleName ) { MultiBox->SetStyle( InStyleSet, InStyleName ); } FMultiBoxCustomization FMultiBoxBuilder::GetCustomization() const { return FMultiBoxCustomization( MultiBox->GetCustomizationName() ); } TSharedRef< class SWidget > FMultiBoxBuilder::MakeWidget( FMultiBox::FOnMakeMultiBoxBuilderOverride* InMakeMultiBoxBuilderOverride, uint32 MaxHeight /* = nullptr */ ) { return MultiBox->MakeWidget( false, InMakeMultiBoxBuilderOverride ); } TSharedRef< class FMultiBox > FMultiBoxBuilder::GetMultiBox() { return MultiBox; } /** Helper function to generate unique widget-identifying names given various bits of information */ static FName GenerateTutorialIdentfierName(FName InContainerName, FName InElementName, const TSharedPtr< const FUICommandInfo > InCommand, int32 InIndex) { FString BaseName; if(InContainerName != NAME_None) { BaseName = InContainerName.ToString() + TEXT("."); } if(InElementName != NAME_None) { return FName(*(BaseName + InElementName.ToString())); } else if(InCommand.IsValid() && InCommand->GetCommandName() != NAME_None) { return FName(*(BaseName + InCommand->GetCommandName().ToString())); } else { // default to index if no other info is available const FString IndexedName = FString::Printf(TEXT("MultiboxWidget%d"), InIndex); return FName(*(BaseName + IndexedName)); } } FBaseMenuBuilder::FBaseMenuBuilder( const EMultiBoxType InType, const bool bInShouldCloseWindowAfterMenuSelection, TSharedPtr< const FUICommandList > InCommandList, bool bInCloseSelfOnly, TSharedPtr InExtender, const ISlateStyle* InStyleSet, FName InTutorialHighlightName, FName InMenuName ) : FMultiBoxBuilder( InType, FMultiBoxCustomization::None, bInShouldCloseWindowAfterMenuSelection, InCommandList, InExtender, InTutorialHighlightName, InMenuName ) , bCloseSelfOnly( bInCloseSelfOnly ) { MultiBox->SetStyle(InStyleSet, "Menu"); } void FBaseMenuBuilder::AddMenuEntry( const TSharedPtr< const FUICommandInfo > InCommand, FName InExtensionHook, const TAttribute& InLabelOverride, const TAttribute& InToolTipOverride, const FSlateIcon& InIconOverride, FName InTutorialHighlightName ) { ApplySectionBeginning(); ApplyHook(InExtensionHook, EExtensionHook::Before); // The command must be valid check( InCommand.IsValid() ); TSharedRef< FMenuEntryBlock > NewMenuEntryBlock = MakeShared( InExtensionHook, InCommand, CommandListStack.Last(), InLabelOverride, InToolTipOverride, InIconOverride, bCloseSelfOnly ); NewMenuEntryBlock->SetTutorialHighlightName(GenerateTutorialIdentfierName(TutorialHighlightName, InTutorialHighlightName, InCommand, MultiBox->GetBlocks().Num())); MultiBox->AddMultiBlock( NewMenuEntryBlock ); ApplyHook(InExtensionHook, EExtensionHook::After); } void FBaseMenuBuilder::AddMenuEntry( const TAttribute& InLabel, const TAttribute& InToolTip, const FSlateIcon& InIcon, const FUIAction& InAction, FName InExtensionHook, const EUserInterfaceActionType UserInterfaceActionType, FName InTutorialHighlightName ) { ApplySectionBeginning(); ApplyHook(InExtensionHook, EExtensionHook::Before); TSharedRef< FMenuEntryBlock > NewMenuEntryBlock = MakeShared( InExtensionHook, InLabel, InToolTip, InIcon, InAction, UserInterfaceActionType, bCloseSelfOnly ); NewMenuEntryBlock->SetTutorialHighlightName(GenerateTutorialIdentfierName(TutorialHighlightName, InTutorialHighlightName, nullptr, MultiBox->GetBlocks().Num())); MultiBox->AddMultiBlock( NewMenuEntryBlock ); ApplyHook(InExtensionHook, EExtensionHook::After); } void FBaseMenuBuilder::AddMenuEntry( const FUIAction& UIAction, const TSharedRef< SWidget > Contents, const FName& InExtensionHook, const TAttribute& InToolTip, const EUserInterfaceActionType UserInterfaceActionType, FName InTutorialHighlightName ) { ApplySectionBeginning(); ApplyHook(InExtensionHook, EExtensionHook::Before); TSharedRef< FMenuEntryBlock > NewMenuEntryBlock = MakeShared( InExtensionHook, UIAction, Contents, InToolTip, UserInterfaceActionType, bCloseSelfOnly ); NewMenuEntryBlock->SetTutorialHighlightName(GenerateTutorialIdentfierName(TutorialHighlightName, InTutorialHighlightName, nullptr, MultiBox->GetBlocks().Num())); MultiBox->AddMultiBlock( NewMenuEntryBlock ); ApplyHook(InExtensionHook, EExtensionHook::After); } void FBaseMenuBuilder::AddMenuEntry(const FMenuEntryParams& InMenuEntryParams) { ApplySectionBeginning(); ApplyHook(InMenuEntryParams.ExtensionHook, EExtensionHook::Before); TSharedPtr< FMenuEntryBlock > NewMenuEntryBlock = MakeShared(InMenuEntryParams); NewMenuEntryBlock->SetTutorialHighlightName(GenerateTutorialIdentfierName(TutorialHighlightName, InMenuEntryParams.TutorialHighlightName, nullptr, MultiBox->GetBlocks().Num())); MultiBox->AddMultiBlock(NewMenuEntryBlock.ToSharedRef()); ApplyHook(InMenuEntryParams.ExtensionHook, EExtensionHook::After); } TSharedRef< class SWidget > FMenuBuilder::MakeWidget( FMultiBox::FOnMakeMultiBoxBuilderOverride* InMakeMultiBoxBuilderOverride /* = nullptr */, uint32 MaxHeight) { // Make menu builders searchable (by default) TAttribute MaxHeightAttribute; if (MaxHeight < INT_MAX) { MaxHeightAttribute.Set((float)MaxHeight); } return MultiBox->MakeWidget(bSearchable, InMakeMultiBoxBuilderOverride, MaxHeightAttribute); } void FMenuBuilder::BeginSection( FName InExtensionHook, const TAttribute< FText >& InHeadingText ) { check(CurrentSectionExtensionHook == NAME_None && !bSectionNeedsToBeApplied); ApplyHook(InExtensionHook, EExtensionHook::Before); // Do not actually apply the section header, because if this section is ended immediately // then nothing ever gets created, preventing empty sections from ever appearing bSectionNeedsToBeApplied = true; CurrentSectionExtensionHook = InExtensionHook; CurrentSectionHeadingText = InHeadingText.Get(); // Do apply the section beginning if we are in developer "show me all the hooks" mode if (FMultiBoxSettings::DisplayMultiboxHooks.Get()) { ApplySectionBeginning(); } ApplyHook(InExtensionHook, EExtensionHook::First); } void FMenuBuilder::EndSection() { FName SectionExtensionHook = CurrentSectionExtensionHook; CurrentSectionExtensionHook = NAME_None; bSectionNeedsToBeApplied = false; CurrentSectionHeadingText = FText::GetEmpty(); ApplyHook(SectionExtensionHook, EExtensionHook::After); } void FMenuBuilder::AddMenuSeparator(FName InExtensionHook) { AddSeparator(InExtensionHook); } void FMenuBuilder::AddSeparator(FName InExtensionHook /*= NAME_None*/) { ApplySectionBeginning(); ApplyHook(InExtensionHook, EExtensionHook::Before); // Never add a menu separate as the first item, even if we were asked to if (MultiBox->GetBlocks().Num() > 0 || FMultiBoxSettings::DisplayMultiboxHooks.Get()) { TSharedRef< FMenuSeparatorBlock > NewMenuSeparatorBlock(new FMenuSeparatorBlock(InExtensionHook, /* bInIsPartOfHeading=*/ false)); MultiBox->AddMultiBlock(NewMenuSeparatorBlock); } ApplyHook(InExtensionHook, EExtensionHook::After); } void FMenuBuilder::AddSubMenu( const TAttribute& InMenuLabel, const TAttribute& InToolTip, const FNewMenuDelegate& InSubMenu, const FUIAction& InUIAction, FName InExtensionHook, const EUserInterfaceActionType InUserInterfaceActionType, const bool bInOpenSubMenuOnClick, const FSlateIcon& InIcon, const bool bInShouldCloseWindowAfterMenuSelection /*= true*/ ) { ApplySectionBeginning(); const bool bIsSubMenu = true; TSharedRef< FMenuEntryBlock > NewMenuEntryBlock = MakeShared( InExtensionHook, InMenuLabel, InToolTip, InSubMenu, ExtenderStack.Top(), bIsSubMenu, bInOpenSubMenuOnClick, InIcon, InUIAction, InUserInterfaceActionType, bCloseSelfOnly, bInShouldCloseWindowAfterMenuSelection, CommandListStack.Last() ); NewMenuEntryBlock->SetRecursivelySearchable(bRecursivelySearchable); MultiBox->AddMultiBlock( NewMenuEntryBlock ); } void FMenuBuilder::AddSubMenu( const TAttribute& InMenuLabel, const TAttribute& InToolTip, const FNewMenuDelegate& InSubMenu, const bool bInOpenSubMenuOnClick /*= false*/, const FSlateIcon& InIcon /*= FSlateIcon()*/, const bool bInShouldCloseWindowAfterMenuSelection /*= true*/, FName InExtensionHook /*=NAME_None*/) { ApplySectionBeginning(); const bool bIsSubMenu = true; TSharedRef< FMenuEntryBlock > NewMenuEntryBlock = MakeShared( InExtensionHook, InMenuLabel, InToolTip, InSubMenu, ExtenderStack.Top(), bIsSubMenu, bInOpenSubMenuOnClick, CommandListStack.Last(), bCloseSelfOnly, InIcon, bInShouldCloseWindowAfterMenuSelection ); NewMenuEntryBlock->SetRecursivelySearchable(bRecursivelySearchable); MultiBox->AddMultiBlock( NewMenuEntryBlock ); } void FMenuBuilder::AddSubMenu( const TSharedRef< SWidget > Contents, const FNewMenuDelegate& InSubMenu, const bool bInOpenSubMenuOnClick /*= false*/, const bool bInShouldCloseWindowAfterMenuSelection /*= true*/ ) { ApplySectionBeginning(); const bool bIsSubMenu = true; TSharedRef< FMenuEntryBlock > NewMenuEntryBlock = MakeShared( NAME_None, Contents, InSubMenu, ExtenderStack.Top(), bIsSubMenu, bInOpenSubMenuOnClick, CommandListStack.Last(), bCloseSelfOnly, bInShouldCloseWindowAfterMenuSelection ); NewMenuEntryBlock->SetRecursivelySearchable(bRecursivelySearchable); MultiBox->AddMultiBlock( NewMenuEntryBlock ); } void FMenuBuilder::AddSubMenu( const FUIAction& UIAction, const TSharedRef< SWidget > Contents, const FNewMenuDelegate& InSubMenu, const bool bInShouldCloseWindowAfterMenuSelection /*= true*/ ) { ApplySectionBeginning(); const bool bIsSubMenu = true; TSharedRef< FMenuEntryBlock > NewMenuEntryBlock = MakeShared( NAME_None, UIAction, Contents, InSubMenu, ExtenderStack.Top(), bIsSubMenu, CommandListStack.Last(), bCloseSelfOnly, bInShouldCloseWindowAfterMenuSelection ); NewMenuEntryBlock->SetRecursivelySearchable(bRecursivelySearchable); MultiBox->AddMultiBlock( NewMenuEntryBlock ); } void FMenuBuilder::AddWrapperSubMenu( const FText& InMenuLabel, const FText& InToolTip, const FOnGetContent& InSubMenu, const FSlateIcon& InIcon ) { ApplySectionBeginning(); const bool bIsSubMenu = true; TSharedRef< FMenuEntryBlock > NewMenuEntryBlock = MakeShared( NAME_None, InMenuLabel, InToolTip, InSubMenu, ExtenderStack.Top(), bIsSubMenu, false, CommandListStack.Last(), bCloseSelfOnly, InIcon ); NewMenuEntryBlock->SetRecursivelySearchable(bRecursivelySearchable); MultiBox->AddMultiBlock( NewMenuEntryBlock ); } void FMenuBuilder::AddWrapperSubMenu( const FText& InMenuLabel, const FText& InToolTip, const FOnGetContent& InSubMenu, const FSlateIcon& InIcon, const FUIAction& UIAction ) { ApplySectionBeginning(); const bool bIsSubMenu = true; TSharedRef< FMenuEntryBlock > NewMenuEntryBlock = MakeShared( NAME_None, UIAction, InMenuLabel, InToolTip, InSubMenu, ExtenderStack.Top(), bIsSubMenu, false, bCloseSelfOnly, InIcon ); NewMenuEntryBlock->SetRecursivelySearchable(bRecursivelySearchable); MultiBox->AddMultiBlock( NewMenuEntryBlock ); } void FMenuBuilder::AddWrapperSubMenu( const FText& InMenuLabel, const FText& InToolTip, const TSharedPtr& InSubMenu, const FSlateIcon& InIcon ) { ApplySectionBeginning(); const bool bIsSubMenu = true; TSharedRef< FMenuEntryBlock > NewMenuEntryBlock = MakeShared( NAME_None, InMenuLabel, InToolTip, InSubMenu, ExtenderStack.Top(), bIsSubMenu, false, CommandListStack.Last(), bCloseSelfOnly, InIcon ); NewMenuEntryBlock->SetRecursivelySearchable(bRecursivelySearchable); MultiBox->AddMultiBlock( NewMenuEntryBlock ); } void FMenuBuilder::AddWidget( TSharedRef InWidget, const FText& Label, bool bNoIndent, bool bInSearchable ) { ApplySectionBeginning(); TSharedRef< FWidgetBlock > NewWidgetBlock(new FWidgetBlock( InWidget, Label, bNoIndent )); NewWidgetBlock->SetSearchable( bInSearchable ); MultiBox->AddMultiBlock( NewWidgetBlock ); } void FMenuBuilder::AddSearchWidget() { MultiBox->bHasSearchWidget = true; } void FMenuBuilder::ApplyHook(FName InExtensionHook, EExtensionHook::Position HookPosition) { if (ExtendersEnabled()) { // this is a virtual function to get a properly typed "this" pointer auto& Extender = ExtenderStack.Top(); if (InExtensionHook != NAME_None && Extender.IsValid()) { if (!MultiBox->IsInEditMode()) { Extender->Apply(InExtensionHook, HookPosition, *this); } } } } void FMenuBuilder::ApplySectionBeginning() { if (bSectionNeedsToBeApplied) { if (!CurrentSectionHeadingText.IsEmpty()) { MultiBox->AddMultiBlock( MakeShareable( new FHeadingBlock(CurrentSectionExtensionHook, CurrentSectionHeadingText) ) ); } bSectionNeedsToBeApplied = false; CurrentSectionHeadingText = FText::GetEmpty(); } } void FMenuBarBuilder::AddPullDownMenu(const TAttribute& InMenuLabel, const TAttribute& InToolTip, const FNewMenuDelegate& InPullDownMenu, FName InExtensionHook, FName InTutorialHighlightName) { ApplySectionBeginning(); ApplyHook(InExtensionHook, EExtensionHook::Before); const bool bIsSubMenu = false; const bool bOpenSubMenuOnClick = false; // Pulldown menus always close all menus not just themselves const bool bShouldCloseSelfOnly = false; TSharedRef< FMenuEntryBlock > NewMenuEntryBlock(new FMenuEntryBlock(InExtensionHook, InMenuLabel, InToolTip, InPullDownMenu, ExtenderStack.Top(), bIsSubMenu, bOpenSubMenuOnClick, CommandListStack.Last(), bShouldCloseSelfOnly)); NewMenuEntryBlock->SetTutorialHighlightName(GenerateTutorialIdentfierName(TutorialHighlightName, InTutorialHighlightName, nullptr, MultiBox->GetBlocks().Num())); MultiBox->AddMultiBlock(NewMenuEntryBlock); ApplyHook(InExtensionHook, EExtensionHook::After); } void FMenuBarBuilder::AddPullDownMenu(const TAttribute& InMenuLabel, const TAttribute& InToolTip, const FOnGetContent& InMenuContentGenerator, FName InExtensionHook, FName InTutorialHighlightName) { ApplySectionBeginning(); ApplyHook(InExtensionHook, EExtensionHook::Before); const bool bIsSubMenu = false; const bool bOpenSubMenuOnClick = false; // Pulldown menus always close all menus not just themselves const bool bShouldCloseSelfOnly = false; TSharedRef< FMenuEntryBlock > NewMenuEntryBlock(new FMenuEntryBlock(InExtensionHook, InMenuLabel, InToolTip, InMenuContentGenerator, ExtenderStack.Top(), bIsSubMenu, bOpenSubMenuOnClick, CommandListStack.Last(), bShouldCloseSelfOnly)); NewMenuEntryBlock->SetTutorialHighlightName(GenerateTutorialIdentfierName(TutorialHighlightName, InTutorialHighlightName, nullptr, MultiBox->GetBlocks().Num())); MultiBox->AddMultiBlock(NewMenuEntryBlock); ApplyHook(InExtensionHook, EExtensionHook::After); } void FMenuBarBuilder::ApplyHook(FName InExtensionHook, EExtensionHook::Position HookPosition) { if (ExtendersEnabled()) { // this is a virtual function to get a properly typed "this" pointer auto& Extender = ExtenderStack.Top(); if (InExtensionHook != NAME_None && Extender.IsValid()) { Extender->Apply(InExtensionHook, HookPosition, *this); } } } void FToolBarBuilder::SetIsFocusable(bool bInIsFocusable) { bIsFocusable = bInIsFocusable; MultiBox->bIsFocusable = bIsFocusable; } void FToolBarBuilder::AddToolBarButton(const TSharedPtr< const FUICommandInfo > InCommand, FName InExtensionHook, const TAttribute& InLabelOverride, const TAttribute& InToolTipOverride, const TAttribute& InIconOverride, FName InTutorialHighlightName, FNewMenuDelegate InCustomMenuDelegate ) { ApplySectionBeginning(); ApplyHook(InExtensionHook, EExtensionHook::Before); TSharedRef< FToolBarButtonBlock > NewToolBarButtonBlock( new FToolBarButtonBlock( InCommand.ToSharedRef(), CommandListStack.Last(), InLabelOverride, InToolTipOverride, InIconOverride ) ); if ( LabelVisibility.IsSet() ) { NewToolBarButtonBlock->SetLabelVisibility( LabelVisibility.GetValue() ); } NewToolBarButtonBlock->SetIsFocusable(bIsFocusable); NewToolBarButtonBlock->SetForceSmallIcons(bForceSmallIcons); NewToolBarButtonBlock->SetTutorialHighlightName(GenerateTutorialIdentfierName(TutorialHighlightName, InTutorialHighlightName, InCommand, MultiBox->GetBlocks().Num())); NewToolBarButtonBlock->SetStyleNameOverride(CurrentStyleOverride); NewToolBarButtonBlock->SetCustomMenuDelegate(InCustomMenuDelegate); MultiBox->AddMultiBlock( NewToolBarButtonBlock ); ApplyHook(InExtensionHook, EExtensionHook::After); } void FToolBarBuilder::AddToolBarButton(const FUIAction& InAction, FName InExtensionHook, const TAttribute& InLabelOverride, const TAttribute& InToolTipOverride, const TAttribute& InIconOverride, const EUserInterfaceActionType UserInterfaceActionType, FName InTutorialHighlightName ) { ApplySectionBeginning(); ApplyHook(InExtensionHook, EExtensionHook::Before); TSharedRef< FToolBarButtonBlock > NewToolBarButtonBlock( new FToolBarButtonBlock( InLabelOverride, InToolTipOverride, InIconOverride, InAction, UserInterfaceActionType ) ); if ( LabelVisibility.IsSet() ) { NewToolBarButtonBlock->SetLabelVisibility( LabelVisibility.GetValue() ); } NewToolBarButtonBlock->SetIsFocusable(bIsFocusable); NewToolBarButtonBlock->SetForceSmallIcons(bForceSmallIcons); NewToolBarButtonBlock->SetTutorialHighlightName(GenerateTutorialIdentfierName(TutorialHighlightName, InTutorialHighlightName, nullptr, MultiBox->GetBlocks().Num())); NewToolBarButtonBlock->SetStyleNameOverride(CurrentStyleOverride); MultiBox->AddMultiBlock( NewToolBarButtonBlock ); ApplyHook(InExtensionHook, EExtensionHook::After); } void FToolBarBuilder::AddComboButton( const FUIAction& InAction, const FOnGetContent& InMenuContentGenerator, const TAttribute& InLabelOverride, const TAttribute& InToolTipOverride, const TAttribute& InIconOverride, bool bInSimpleComboBox, FName InTutorialHighlightName ) { ApplySectionBeginning(); TSharedRef NewToolBarComboButtonBlock( new FToolBarComboButtonBlock( InAction, InMenuContentGenerator, InLabelOverride, InToolTipOverride, InIconOverride, bInSimpleComboBox ) ); if ( LabelVisibility.IsSet() ) { NewToolBarComboButtonBlock->SetLabelVisibility( LabelVisibility.GetValue() ); } NewToolBarComboButtonBlock->SetForceSmallIcons(bForceSmallIcons); NewToolBarComboButtonBlock->SetTutorialHighlightName(GenerateTutorialIdentfierName(TutorialHighlightName, InTutorialHighlightName, nullptr, MultiBox->GetBlocks().Num())); NewToolBarComboButtonBlock->SetStyleNameOverride(CurrentStyleOverride); MultiBox->AddMultiBlock( NewToolBarComboButtonBlock ); } void FToolBarBuilder::AddToolbarStackButton(const TSharedPtr< const FUICommandInfo > InCommand, FName InTutorialHighlightName) { ApplySectionBeginning(); TSharedRef< FToolBarStackButtonBlock > NewToolBarStackButtonBlock(new FToolBarStackButtonBlock(InCommand.ToSharedRef(), CommandListStack.Last())); if (LabelVisibility.IsSet()) { NewToolBarStackButtonBlock->SetLabelVisibility(LabelVisibility.GetValue()); } NewToolBarStackButtonBlock->SetForceSmallIcons(bForceSmallIcons); NewToolBarStackButtonBlock->SetTutorialHighlightName(GenerateTutorialIdentfierName(TutorialHighlightName, InTutorialHighlightName, InCommand, MultiBox->GetBlocks().Num())); NewToolBarStackButtonBlock->SetStyleNameOverride(CurrentStyleOverride); MultiBox->AddMultiBlock(NewToolBarStackButtonBlock); } void FToolBarBuilder::AddToolBarWidget( TSharedRef InWidget, const TAttribute& InLabel, FName InTutorialHighlightName, bool bSearchable ) { ApplySectionBeginning(); // If tutorial name specified, wrap in tutorial wrapper const FName WrapperName = GenerateTutorialIdentfierName(InTutorialHighlightName, NAME_None, nullptr, MultiBox->GetBlocks().Num()); const FToolBarStyle& ToolBarStyle = GetStyleSet()->GetWidgetStyle(GetStyleName()); TSharedRef ChildWidget = InWidget; InWidget = SNew( SVerticalBox ) .AddMetaData(FTagMetaData(InTutorialHighlightName)) +SVerticalBox::Slot() .AutoHeight() .HAlign( HAlign_Center ) [ ChildWidget ] +SVerticalBox::Slot() .AutoHeight() .Padding(ToolBarStyle.LabelPadding) .HAlign( HAlign_Center ) [ SNew( STextBlock ) .Visibility_Lambda( [ChildWidget] () -> EVisibility { if (FMultiBoxSettings::UseSmallToolBarIcons.Get()) return EVisibility::Collapsed; return ChildWidget->GetVisibility(); }) .IsEnabled_Lambda( [ChildWidget] () -> bool { return ChildWidget->IsEnabled(); } ) .Text( InLabel ) .TextStyle(&ToolBarStyle.LabelStyle) // Smaller font for tool tip labels ] ; TSharedRef< FWidgetBlock > NewWidgetBlock( new FWidgetBlock( InWidget, FText::GetEmpty(), true ) ); MultiBox->AddMultiBlock( NewWidgetBlock ); NewWidgetBlock->SetSearchable(bSearchable); } void FToolBarBuilder::AddWidget( TSharedRef InWidget, FName InTutorialHighlightName, bool bSearchable, EHorizontalAlignment Alignment, FNewMenuDelegate InCustomMenuDelegate ) { ApplySectionBeginning(); // If tutorial name specified, wrap in tutorial wrapper const FName WrapperName = GenerateTutorialIdentfierName(InTutorialHighlightName, NAME_None, nullptr, MultiBox->GetBlocks().Num()); TSharedRef ChildWidget = InWidget; InWidget = SNew( SBox ) .AddMetaData(FTagMetaData(InTutorialHighlightName)) [ ChildWidget ]; TSharedRef< FWidgetBlock > NewWidgetBlock( new FWidgetBlock( InWidget, FText::GetEmpty(), true, Alignment) ); MultiBox->AddMultiBlock( NewWidgetBlock ); NewWidgetBlock->SetSearchable(bSearchable); NewWidgetBlock->SetCustomMenuDelegate(InCustomMenuDelegate); } void FToolBarBuilder::AddSeparator(FName InExtensionHook) { ApplySectionBeginning(); ApplyHook(InExtensionHook, EExtensionHook::Before); TSharedRef NewSeparatorBlock = MakeShared(InExtensionHook); NewSeparatorBlock->SetStyleNameOverride(CurrentStyleOverride); MultiBox->AddMultiBlock(NewSeparatorBlock); ApplyHook(InExtensionHook, EExtensionHook::After); } void FToolBarBuilder::BeginSection( FName InExtensionHook ) { checkf(CurrentSectionExtensionHook == NAME_None && !bSectionNeedsToBeApplied, TEXT("Did you forget to call EndSection()?")); ApplyHook(InExtensionHook, EExtensionHook::Before); // Do not actually apply the section header, because if this section is ended immediately // then nothing ever gets created, preventing empty sections from ever appearing bSectionNeedsToBeApplied = true; CurrentSectionExtensionHook = InExtensionHook; // Do apply the section beginning if we are in developer "show me all the hooks" mode if (FMultiBoxSettings::DisplayMultiboxHooks.Get()) { ApplySectionBeginning(); } ApplyHook(InExtensionHook, EExtensionHook::First); } void FToolBarBuilder::EndSection() { FName SectionExtensionHook = CurrentSectionExtensionHook; CurrentSectionExtensionHook = NAME_None; bSectionNeedsToBeApplied = false; ApplyHook(SectionExtensionHook, EExtensionHook::After); } void FToolBarBuilder::ApplyHook(FName InExtensionHook, EExtensionHook::Position HookPosition) { if (ExtendersEnabled()) { // this is a virtual function to get a properly typed "this" pointer auto& Extender = ExtenderStack.Top(); if (InExtensionHook != NAME_None && Extender.IsValid()) { Extender->Apply(InExtensionHook, HookPosition, *this); } } } void FToolBarBuilder::ApplySectionBeginning() { if (bSectionNeedsToBeApplied) { if( MultiBox->GetBlocks().Num() > 0 || FMultiBoxSettings::DisplayMultiboxHooks.Get() ) { TSharedRef NewSeparatorBlock = MakeShared(CurrentSectionExtensionHook); NewSeparatorBlock->SetStyleNameOverride(CurrentStyleOverride); MultiBox->AddMultiBlock(NewSeparatorBlock); } bSectionNeedsToBeApplied = false; } } void FToolBarBuilder::EndBlockGroup() { ApplySectionBeginning(); TSharedRef NewGroupEndBlock( new FGroupEndBlock() ); NewGroupEndBlock->SetStyleNameOverride(CurrentStyleOverride); MultiBox->AddMultiBlock( NewGroupEndBlock ); } void FToolBarBuilder::BeginStyleOverride(FName StyleOverrideName) { CurrentStyleOverride = StyleOverrideName; } void FToolBarBuilder::EndStyleOverride() { CurrentStyleOverride = NAME_None; } void FToolBarBuilder::BeginBlockGroup() { ApplySectionBeginning(); TSharedRef< FGroupStartBlock > NewGroupStartBlock( new FGroupStartBlock() ); NewGroupStartBlock->SetStyleNameOverride(CurrentStyleOverride); MultiBox->AddMultiBlock( NewGroupStartBlock ); } void FButtonRowBuilder::AddButton( const TSharedPtr< const FUICommandInfo > InCommand, const TAttribute& InLabelOverride, const TAttribute& InToolTipOverride, const FSlateIcon& InIconOverride ) { ApplySectionBeginning(); TSharedRef< FButtonRowBlock > NewButtonRowBlock( new FButtonRowBlock( InCommand.ToSharedRef(), CommandListStack.Last(), InLabelOverride, InToolTipOverride, InIconOverride ) ); MultiBox->AddMultiBlock( NewButtonRowBlock ); } void FButtonRowBuilder::AddButton( const FText& InLabel, const FText& InToolTip, const FUIAction& UIAction, const FSlateIcon& InIcon, const EUserInterfaceActionType UserInterfaceActionType ) { ApplySectionBeginning(); TSharedRef< FButtonRowBlock > NewButtonRowBlock( new FButtonRowBlock( InLabel, InToolTip, InIcon, UIAction, UserInterfaceActionType ) ); MultiBox->AddMultiBlock( NewButtonRowBlock ); }