// Copyright Epic Games, Inc. All Rights Reserved. #include "SEditToolMenuDialog.h" #include "IToolMenusEditorModule.h" #include "Misc/MessageDialog.h" #include "HAL/FileManager.h" #include "IDetailsView.h" #include "Misc/App.h" #include "SlateOptMacros.h" #include "Widgets/Layout/SSeparator.h" #include "Widgets/Images/SImage.h" #include "Widgets/Layout/SGridPanel.h" #include "Widgets/Layout/SUniformGridPanel.h" #include "Widgets/Input/SEditableTextBox.h" #include "Widgets/Input/SButton.h" #include "Widgets/Input/SCheckBox.h" #include "Widgets/Layout/SScrollBox.h" #include "Framework/Docking/TabManager.h" #include "Styling/AppStyle.h" #include "ToolMenus.h" #include "Editor.h" #include "AssetRegistry/IAssetRegistry.h" #include "AssetRegistry/AssetRegistryModule.h" #include "Serialization/StaticMemoryReader.h" #include "Widgets/Colors/SColorBlock.h" #include "Framework/Commands/UICommandDragDropOp.h" #include "PropertyEditorModule.h" #define LOCTEXT_NAMESPACE "EditToolMenuDialog" class SVisibilityEditWidget : public SImage { public: SLATE_BEGIN_ARGS(SVisibilityEditWidget) {} SLATE_END_ARGS() /** Construct this widget */ void Construct(const FArguments& InArgs, TSharedRef InBaseWidget, TSharedRef InBlock, TSharedRef InDialogWidget) { BaseWidget = InBaseWidget; Block = InBlock; DialogWidget = InDialogWidget; SImage::Construct( SImage::FArguments() .Image(this, &SVisibilityEditWidget::GetBrush) ); } private: FReply HandleClick() { ToggleVisible(); return FReply::Handled(); } virtual FReply OnMouseButtonDoubleClick(const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent) override { return HandleClick(); } virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override { if (MouseEvent.GetEffectingButton() != EKeys::LeftMouseButton) { return FReply::Unhandled(); } return HandleClick(); } virtual FReply OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override { if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton) { return FReply::Handled(); } return FReply::Unhandled(); } const FSlateBrush* GetBrush() const { if (IsVisible()) { static const FName NAME_VisibleHoveredBrush("Level.VisibleHighlightIcon16x"); static const FName NAME_VisibleNotHoveredBrush("Level.VisibleIcon16x"); return IsHovered() ? FAppStyle::GetBrush(NAME_VisibleHoveredBrush) : FAppStyle::GetBrush(NAME_VisibleNotHoveredBrush); } else { static const FName NAME_NotVisibleHoveredBrush("Level.NotVisibleHighlightIcon16x"); static const FName NAME_NotVisibleNotHoveredBrush("Level.NotVisibleIcon16x"); return IsHovered() ? FAppStyle::GetBrush(NAME_NotVisibleHoveredBrush) : FAppStyle::GetBrush(NAME_NotVisibleNotHoveredBrush); } } bool IsVisible() const { const FName ItemName = Block->GetExtensionHook(); if (ItemName == NAME_None) { return true; } UToolMenuBase* ToolMenu = BaseWidget.IsValid() ? BaseWidget.Pin()->GetMultiBox()->GetToolMenu() : nullptr; if (!ToolMenu) { return true; } FCustomizedToolMenuHierarchy MenuCustomizationHierarchy = ToolMenu->GetMenuCustomizationHierarchy(); if (MenuCustomizationHierarchy.Hierarchy.Num() > 0) { if (Block->GetType() == EMultiBlockType::Heading) { return !MenuCustomizationHierarchy.IsSectionHidden(ItemName); } else { return !MenuCustomizationHierarchy.IsEntryHidden(ItemName); } } return true; } void ToggleVisible() { if (DialogWidget.IsValid()) { DialogWidget.Pin()->OnToggleVisibleClicked(Block.ToSharedRef(), BaseWidget); } } TSharedPtr Block; TWeakPtr BaseWidget; TWeakPtr DialogWidget; }; class SMultiBlockDragHandle : public SCompoundWidget { SLATE_BEGIN_ARGS( SMultiBlockDragHandle ) {} SLATE_END_ARGS() void Construct( const FArguments& InArgs, TSharedRef InBaseWidget, TSharedRef InBlock, bool bInIsBlockNamedAndToolMenu ); FReply OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; FReply OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; virtual void OnDragEnter( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) override; virtual FReply OnDragOver( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) override; virtual FReply OnDrop( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) override; virtual FReply OnDragDetected( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override { LayerId = SCompoundWidget::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); bool bIsDropDestination = false; bool bInsertAfter = false; if (BaseWidget.IsValid() && Block.IsValid()) { const EVisibility Status = BaseWidget.Pin()->GetCustomizationBorderDragVisibility(Block->GetExtensionHook(), Block->GetType(), bInsertAfter); if (Status == EVisibility::Visible) { bIsDropDestination = true; } } if (bIsDropDestination) { const FSlateBrush* DropIndicatorBrush = FAppStyle::GetBrush(bInsertAfter ? "MultiBox.DragBelow" : "MultiBox.DragAbove"); FSlateDrawElement::MakeBox ( OutDrawElements, LayerId++, AllottedGeometry.ToPaintGeometry(), DropIndicatorBrush, ESlateDrawEffect::None, DropIndicatorBrush->GetTint(InWidgetStyle) * InWidgetStyle.GetColorAndOpacityTint() ); } return LayerId; } private: TSharedPtr Block; TWeakPtr BaseWidget; bool bIsBlockNamedAndToolMenu; }; void SMultiBlockDragHandle::Construct( const FArguments& InArgs, TSharedRef InBaseWidget, TSharedRef InBlock, bool bInIsBlockNamedAndToolMenu ) { BaseWidget = InBaseWidget; Block = InBlock; bIsBlockNamedAndToolMenu = bInIsBlockNamedAndToolMenu; } FReply SMultiBlockDragHandle::OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton) { if (Block->GetExtensionHook() != NAME_None && bIsBlockNamedAndToolMenu) { return FReply::Handled().DetectDrag(SharedThis(this), MouseEvent.GetEffectingButton()); } } return FReply::Unhandled(); } FReply SMultiBlockDragHandle::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton) { BaseWidget.Pin()->GetMultiBox()->OnEditSelectionChanged().ExecuteIfBound(Block.ToSharedRef()); } return FReply::Unhandled(); } void SMultiBlockDragHandle::OnDragEnter( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) { if ( DragDropEvent.GetOperationAs().IsValid() ) { BaseWidget.Pin()->OnCustomCommandDragEnter( Block.ToSharedRef(), MyGeometry, DragDropEvent ); } } FReply SMultiBlockDragHandle::OnDragOver( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) { if ( DragDropEvent.GetOperationAs().IsValid() ) { BaseWidget.Pin()->OnCustomCommandDragged( Block.ToSharedRef(), MyGeometry, DragDropEvent ); return FReply::Handled(); } return FReply::Unhandled(); } FReply SMultiBlockDragHandle::OnDrop( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) { if ( DragDropEvent.GetOperationAs().IsValid() ) { BaseWidget.Pin()->OnCustomCommandDropped(); return FReply::Handled(); } return FReply::Unhandled(); } FReply SMultiBlockDragHandle::OnDragDetected( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { TSharedPtr CustomDecorator; TSharedRef BlockWidget = Block->MakeWidget(BaseWidget.Pin().ToSharedRef(), EMultiBlockLocation::None, false, nullptr)->AsWidget(); if (Block->IsSeparator()) { CustomDecorator = SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() [ SNew(SHorizontalBox) +SHorizontalBox::Slot() [ SNew(SSeparator) ] ] +SVerticalBox::Slot() .AutoHeight() [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .Padding( 20, 0, 40, 0 ) .AutoWidth() [ SNew(STextBlock) .Text(FText::FromName(Block->GetExtensionHook())) ] ]; } else if (Block->GetType() == EMultiBlockType::Heading) { CustomDecorator = SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() [ SNew(SHorizontalBox) +SHorizontalBox::Slot() [ SNew(SSeparator) ] ] +SVerticalBox::Slot() .AutoHeight() [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .Padding( 20, 0, 40, 0 ) .AutoWidth() [ BlockWidget ] ]; } else { CustomDecorator = BlockWidget; } TSharedRef NewOp = FUICommandDragDropOp::New( Block->GetExtensionHook(), Block->GetType(), Block->IsPartOfHeading(), NAME_None, CustomDecorator, FVector2D(MyGeometry.AbsolutePosition)-MouseEvent.GetScreenSpacePosition() ); NewOp->SetOnDropNotification( FSimpleDelegate::CreateSP( BaseWidget.Pin().ToSharedRef(), &SMultiBoxWidget::OnDropExternal ) ); TSharedRef DragDropOp = NewOp; return FReply::Handled().BeginDragDrop( DragDropOp ); } void SEditToolMenuDialog::InitMenu(UToolMenu* InMenu) { MenuDialogOpenedWith = InMenu; OriginalSettings.Reset(); if (UToolMenu* GeneratedMenu = UToolMenus::Get()->GenerateMenuOrSubMenuForEdit(InMenu)) { for (const FCustomizedToolMenu* CustomizedToolMenu : GeneratedMenu->GetMenuCustomizationHierarchy().Hierarchy) { if (CustomizedToolMenu) { OriginalSettings.Add(*CustomizedToolMenu); } } CurrentGeneratedMenu = GeneratedMenu; MenuNames = GeneratedMenu->GetMenuHierarchyNames(true); } else { CurrentGeneratedMenu = nullptr; MenuNames.Reset(); } } void SEditToolMenuDialog::Construct( const FArguments& InArgs ) { InitMenu(InArgs._SourceMenu); SetSelectedItem(NAME_None, ESelectedEditMenuEntryType::Menu); BuildWidget(); } void SEditToolMenuDialog::HandleOnLiveCodingPatchComplete() { Refresh(); } void SEditToolMenuDialog::OnSelectedEntryChanged(TSharedRef InBlock) { UToolMenu* ToolMenu = CurrentGeneratedMenu.Get(); const FName BlockName = InBlock->GetExtensionHook(); ESelectedEditMenuEntryType SelectedType = ESelectedEditMenuEntryType::None; if (InBlock->IsPartOfHeading()) { SelectedType = ESelectedEditMenuEntryType::Section; if (!ToolMenu->ContainsSection(BlockName)) { return; } } else { SelectedType = ESelectedEditMenuEntryType::Entry; if (!ToolMenu->ContainsEntry(BlockName)) { return; } } SetSelectedItem(BlockName, SelectedType); if (PropertiesWidget.IsValid()) { PropertiesWidget->SetObject(SelectedObject.Get()); } } void SEditToolMenuDialog::SetSelectedItem(const FName InName, ESelectedEditMenuEntryType InType) { UToolMenu* ToolMenu = CurrentGeneratedMenu.Get(); if (!ToolMenu) { SelectedObject.Reset(); return; } if (ESelectedEditMenuEntryType::Entry == InType) { UToolMenuEditorDialogEntry* NewSelectedObject = NewObject(); NewSelectedObject->Init(ToolMenu, InName); SelectedObject = TStrongObjectPtr(NewSelectedObject); } else if (ESelectedEditMenuEntryType::Section == InType) { UToolMenuEditorDialogSection* NewSelectedObject = NewObject(); NewSelectedObject->Init(ToolMenu, InName); SelectedObject = TStrongObjectPtr(NewSelectedObject); } else if (ESelectedEditMenuEntryType::Menu == InType) { UToolMenuEditorDialogMenu* NewSelectedObject = NewObject(); NewSelectedObject->Init(ToolMenu, ToolMenu->GetMenuName()); SelectedObject = TStrongObjectPtr(NewSelectedObject); } else { SelectedObject.Reset(); } } TSharedRef SEditToolMenuDialog::ModifyBlockWidgetAfterMake(const TSharedRef& InMultiBoxWidget, const FMultiBlock& InBlock, const TSharedRef& InBlockWidget) { TSharedRef MultiBox = InMultiBoxWidget->GetMultiBox(); const bool bIsEditing = MultiBox->IsInEditMode(); static const FName SelectionColor("SelectionColor"); UToolMenuBase* ToolMenuBase = MultiBox->GetToolMenu(); const FName BlockName = InBlock.GetExtensionHook(); const EMultiBlockType BlockType = InBlock.GetType(); bool bIsBlockNamedAndToolMenu = false; if (BlockName != NAME_None && ToolMenuBase) { if (InBlock.IsPartOfHeading()) { bIsBlockNamedAndToolMenu = ToolMenuBase->ContainsSection(BlockName); } else { bIsBlockNamedAndToolMenu = ToolMenuBase->ContainsEntry(BlockName); } } if (!bIsBlockNamedAndToolMenu) { return SNew(SOverlay) +SOverlay::Slot() [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .Padding(36, 0, 0, 0) [ InBlockWidget ] ] +SOverlay::Slot() [ SNew( SMultiBlockDragHandle, InMultiBoxWidget, InBlock.AsShared(), bIsBlockNamedAndToolMenu ) ]; } else if (InBlock.IsSeparator() && InBlock.IsPartOfHeading()) { return SNew(SOverlay) +SOverlay::Slot() [ InBlockWidget ] +SOverlay::Slot() [ SNew( SMultiBlockDragHandle, InMultiBoxWidget, InBlock.AsShared(), bIsBlockNamedAndToolMenu ) ]; } else { return SNew(SOverlay) +SOverlay::Slot() [ SNew(SHorizontalBox) // Drag handle +SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) [ SNew(SOverlay) +SOverlay::Slot() [ SNew(SVerticalBox) +SVerticalBox::Slot() .Padding(4, 0, 32, 0) .AutoHeight() [ SNew(SImage) .Image(FCoreStyle::Get().GetBrush("VerticalBoxDragIndicatorShort")) ] ] ] // Widget content +SHorizontalBox::Slot() [ SNew(SOverlay) +SOverlay::Slot() [ InBlockWidget ] ] ] // Prevent input from reaching BlockWidget and allow drag/drop +SOverlay::Slot() [ SNew( SMultiBlockDragHandle, InMultiBoxWidget, InBlock.AsShared(), bIsBlockNamedAndToolMenu ) ] // Toggle Hidden +SOverlay::Slot() [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) [ SNew(SVerticalBox) +SVerticalBox::Slot() .Padding(20, 0, 0, 0) .AutoHeight() [ // TODO: need to be able to update the proxy object being displayed in details panel // or better, perhaps have the proxy object displayed in the details panel directly lookup the config from UToolMenus singleton? SNew(SVisibilityEditWidget, InMultiBoxWidget, InBlock.AsShared(), SharedThis(this)) ] ] ]; } } void SEditToolMenuDialog::BuildWidget() { UToolMenu* ToolMenu = CurrentGeneratedMenu.Get(); if (!ToolMenu) { ChildSlot [ SNew(STextBlock) .TextStyle(FAppStyle::Get(), "LargeText") .Text(LOCTEXT("Unavailable", "Unavailable")) ]; return; } ToolMenu->ModifyBlockWidgetAfterMake.BindSP(this, &SEditToolMenuDialog::ModifyBlockWidgetAfterMake); TSharedRef MenuWidget = UToolMenus::Get()->GenerateWidget(ToolMenu); TSharedRef MultiBoxWidget = StaticCastSharedRef(MenuWidget); TSharedRef MultiBox = ConstCastSharedRef(MultiBoxWidget->GetMultiBox()); MultiBox->OnEditSelectionChanged().BindSP(this, &SEditToolMenuDialog::OnSelectedEntryChanged); TSharedRef DialogCenter = SNew(SHorizontalBox) +SHorizontalBox::Slot() .AutoWidth() [ // Preview SNew(SScrollBox) +SScrollBox::Slot() [ SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() .Padding(0, 8, 0, 8) [ MenuWidget ] ] ] +SHorizontalBox::Slot() .Padding(32, 0, 0, 0) [ SNew(SVerticalBox) // Dialog buttons Save/Cancel +SVerticalBox::Slot() .AutoHeight() .Padding(0) .HAlign(HAlign_Right) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .AutoWidth() [ SNew(SButton) .Text(LOCTEXT("UndoAllChangesButtonText", "Undo all changes")) .ToolTipText(LOCTEXT("UndoAllChangesButtonTooltip", "Undos all changes made to these menus")) .OnClicked(this, &SEditToolMenuDialog::UndoAllChanges) ] +SHorizontalBox::Slot() .Padding(8, 0, 0, 0) .AutoWidth() [ SNew(SButton) .Text(LOCTEXT("ResetAllDefaultsButtonText", "Reset all to Defaults")) .ToolTipText(LOCTEXT("ResetAllDefaultsButtonTooltip", "Reset all settings for all menus to default values")) .OnClicked(this, &SEditToolMenuDialog::HandleResetAllClicked) ] +SHorizontalBox::Slot() .Padding(8, 0, 0, 0) .AutoWidth() [ SNew(SButton) .Text(LOCTEXT("ResetDefaultsButtonText", "Reset to Defaults")) .ToolTipText(LOCTEXT("ResetDefaultsButtonTooltip", "Reset settings for current menu to default values")) .OnClicked(this, &SEditToolMenuDialog::HandleResetClicked) ] ] +SVerticalBox::Slot() .AutoHeight() [ BuildMenuPropertiesWidget() ] ]; { MenuNameComboData.Reset(); for (FName It : MenuNames) { MenuNameComboData.Add(MakeShareable(new FName(It))); } } ChildSlot [ SNew(SBorder) .Padding(20) .BorderImage( FAppStyle::GetBrush("Docking.Tab.ContentAreaBrush") ) [ SNew(SVerticalBox) // Title +SVerticalBox::Slot() .AutoHeight() .Padding(0) [ SNew(STextBlock) .TextStyle(FAppStyle::Get(), "LargeText") .Text(FText::FromName(ToolMenu->MenuName)) ] // Menu names +SVerticalBox::Slot() .AutoHeight() .Padding(0) [ SNew(SComboBox< TSharedPtr >) .OptionsSource(&MenuNameComboData) .OnGenerateWidget(this, &SEditToolMenuDialog::MakeMenuNameComboEntryWidget) .OnSelectionChanged(this, &SEditToolMenuDialog::OnMenuNamesSelectionChanged) [ SNew(STextBlock) .Text(FText::FromName(ToolMenu->MenuName)) ] ] // Title spacer +SVerticalBox::Slot() .AutoHeight() .Padding(0, 16, 0, 8) [ SNew(SSeparator) ] // Middle of dialog +SVerticalBox::Slot() [ DialogCenter ] ] ]; } TSharedRef SEditToolMenuDialog::BuildMenuPropertiesWidget() { FDetailsViewArgs Args; Args.bHideSelectionTip = true; FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); PropertiesWidget = PropertyModule.CreateDetailView(Args); PropertiesWidget->SetObject(SelectedObject.Get()); return PropertiesWidget.ToSharedRef(); } TSharedRef SEditToolMenuDialog::MakeMenuNameComboEntryWidget(TSharedPtr InEntry) { return SNew(STextBlock) .Text(FText::FromName(*InEntry)); } void SEditToolMenuDialog::OnMenuNamesSelectionChanged(TSharedPtr InEntry, ESelectInfo::Type SelectInfo) { UToolMenu* SourceMenu = MenuDialogOpenedWith.Get(); if (!SourceMenu) { BuildWidget(); return; } if (!InEntry.IsValid()) { BuildWidget(); return; } const FName* NewMenuNamePtr = InEntry.Get(); const FName NewMenuName = NewMenuNamePtr ? *NewMenuNamePtr : NAME_None; FName OldMenuName; if (UToolMenu* ToolMenu = CurrentGeneratedMenu.Get()) { if (ToolMenu->GetMenuName() == NewMenuName) { return; } OldMenuName = ToolMenu->GetMenuName(); } FToolMenuContext NewMenuContext = SourceMenu->Context; NewMenuContext.SetIsEditing(true); TArray SubMenuChain = SourceMenu->GetSubMenuChain(); if (!SourceMenu->SubMenuParent) { CurrentGeneratedMenu = UToolMenus::Get()->GenerateMenu(NewMenuName, NewMenuContext); } else if (SubMenuChain.Num() > 0) { FString SubMenuNamePath = SourceMenu->GetSubMenuNamePath(); FString NewMenuNameString = NewMenuName.ToString(); int32 NumCharactersToKeep = NewMenuNameString.Len() - SubMenuNamePath.Len() - 1; if (NumCharactersToKeep > 0) { // "Menu" and "SubMenuA" FString BaseMenuPath = NewMenuNameString.Left(NumCharactersToKeep); // Create the base menu, then walk the down the SubMenus if (UToolMenu* NewMenu = UToolMenus::Get()->GenerateMenu(*BaseMenuPath, NewMenuContext)) { for (int32 i=1; i < SubMenuChain.Num(); ++i) { if (UToolMenu* SubMenu = UToolMenus::Get()->GenerateSubMenu(NewMenu, SubMenuChain[i]->SubMenuSourceEntryName)) { NewMenu = SubMenu; } else { NewMenu = nullptr; break; } } if (NewMenu) { CurrentGeneratedMenu = NewMenu; } } } } BuildWidget(); } void SEditToolMenuDialog::OnToggleVisibleClicked(TSharedRef InBlock, TWeakPtr BaseWidget) { const FName ItemName = InBlock->GetExtensionHook(); if (ItemName == NAME_None) { return; } UToolMenuBase* ToolMenu = BaseWidget.IsValid() ? BaseWidget.Pin()->GetMultiBox()->GetToolMenu() : nullptr; if (!ToolMenu) { return; } // Commit change FCustomizedToolMenu* MenuCustomization = ToolMenu->AddMenuCustomization(); FCustomizedToolMenuHierarchy MenuCustomizationHierarchy = ToolMenu->GetMenuCustomizationHierarchy(); if (InBlock->GetType() == EMultiBlockType::Heading) { bool bHidden = MenuCustomizationHierarchy.IsSectionHidden(ItemName); MenuCustomization->AddSection(ItemName)->Visibility = bHidden ? ECustomizedToolMenuVisibility::Visible : ECustomizedToolMenuVisibility::Hidden; } else { bool bHidden = MenuCustomizationHierarchy.IsEntryHidden(ItemName); MenuCustomization->AddEntry(ItemName)->Visibility = bHidden ? ECustomizedToolMenuVisibility::Visible : ECustomizedToolMenuVisibility::Hidden; } LoadSelectedObjectState(); } void SEditToolMenuDialog::LoadSelectedObjectState() { if (SelectedObject.IsValid()) { SelectedObject->LoadState(); SelectedObject->PostEditChange(); if (PropertiesWidget.IsValid()) { PropertiesWidget->ForceRefresh(); } } } void SEditToolMenuDialog::CloseContainingWindow() { TSharedPtr ContainingWindow = FSlateApplication::Get().FindWidgetWindow(AsShared()); if (ContainingWindow.IsValid()) { ContainingWindow->RequestDestroyWindow(); } } FReply SEditToolMenuDialog::Refresh() { if (UToolMenu* ToolMenu = CurrentGeneratedMenu.Get()) { CurrentGeneratedMenu = UToolMenus::Get()->GenerateMenuOrSubMenuForEdit(ToolMenu); UToolMenus::Get()->RefreshMenuWidget(ToolMenu->GetMenuName()); } BuildWidget(); LoadSelectedObjectState(); return FReply::Handled(); } FReply SEditToolMenuDialog::HandleResetClicked() { if (UToolMenu* ToolMenu = CurrentGeneratedMenu.Get()) { UToolMenus::Get()->RemoveCustomization(ToolMenu->GetMenuName()); Refresh(); } return FReply::Handled(); } FReply SEditToolMenuDialog::HandleResetAllClicked() { if (FMessageDialog::Open(EAppMsgType::YesNo, EAppReturnType::No, LOCTEXT("ResetAllQuestion", "Remove all menu customizations for all menus?"), LOCTEXT("ResetAllQuestion_Question", "Question")) == EAppReturnType::Yes) { UToolMenus::Get()->RemoveAllCustomizations(); OriginalSettings.Reset(); Refresh(); } return FReply::Handled(); } void SEditToolMenuDialog::SaveSettingsToDisk() { UToolMenus::Get()->SaveCustomizations(); } FReply SEditToolMenuDialog::UndoAllChanges() { UToolMenus* ToolMenus = UToolMenus::Get(); for (const FName& HierarchyMenuName : MenuNames) { ToolMenus->RemoveCustomization(HierarchyMenuName); } for (const FCustomizedToolMenu& Original : OriginalSettings) { FCustomizedToolMenu* Destination = ToolMenus->AddMenuCustomization(Original.Name); *Destination = Original; } Refresh(); return FReply::Handled(); } void SEditToolMenuDialog::OnWindowClosed(const TSharedRef& Window) { SaveSettingsToDisk(); UToolMenus::Get()->RefreshAllWidgets(); } #undef LOCTEXT_NAMESPACE