MVVM - SSourceSelector now displays the widget hierarchy view for widgets.

#jira UE-158306
[REVIEW] [at]patrick.boutot
#rnx
#preflight 62d174c93c3df3239042a737

#ROBOMERGE-AUTHOR: sebastian.nordgren
#ROBOMERGE-SOURCE: CL 21110778 via CL 21111461 via CL 21111789
#ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v972-20964824)

[CL 21142326 by sebastian nordgren in ue5-main branch]
This commit is contained in:
sebastian nordgren
2022-07-17 22:38:12 -04:00
parent 721f3dbc72
commit 7b0eb4ae43
2 changed files with 184 additions and 54 deletions

View File

@@ -3,7 +3,10 @@
#include "SMVVMSourceSelector.h"
#include "Algo/Transform.h"
#include "Editor.h"
#include "MVVMEditorSubsystem.h"
#include "SSimpleButton.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/SMVVMFieldIcon.h"
#include "Widgets/SMVVMSourceEntry.h"
@@ -12,74 +15,185 @@
namespace UE::MVVM
{
void SSourceSelector::Construct(const FArguments& Args)
void SSourceSelector::Construct(const FArguments& Args, const UWidgetBlueprint* InWidgetBlueprint)
{
TextStyle = Args._TextStyle;
AvailableSourcesAttribute = Args._AvailableSources;
check(AvailableSourcesAttribute.IsSet());
SelectedSourceAttribute = Args._SelectedSource;
check(SelectedSourceAttribute.IsSet());
WidgetBlueprint = InWidgetBlueprint;
check(InWidgetBlueprint);
bAutoRefresh = Args._AutoRefresh;
bViewModels = Args._ViewModels;
bShowClear = Args._ShowClear;
Refresh();
TSharedRef<SHorizontalBox> HorizontalBox = SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
[
SAssignNew(MenuAnchor, SMenuAnchor)
.OnGetMenuContent(this, &SSourceSelector::OnGetMenuContent)
[
SNew(SButton)
.ButtonStyle(&FAppStyle::Get().GetWidgetStyle<FComboButtonStyle>("ComboButton").ButtonStyle)
.OnClicked_Lambda([this]()
{
MenuAnchor->SetIsOpen(true);
return FReply::Handled();
})
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
[
SAssignNew(SelectedSourceWidget, SSourceEntry)
.Source(SelectedSource)
.TextStyle(TextStyle)
]
+ SHorizontalBox::Slot()
.Padding(2, 0)
.HAlign(HAlign_Right)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(SImage)
.Image(FAppStyle::Get().GetBrush("Icons.ChevronDown"))
]
]
]
];
if (bShowClear)
{
HorizontalBox->AddSlot()
.HAlign(HAlign_Right)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(SSimpleButton)
.Icon(FAppStyle::Get().GetBrush("Icons.X"))
.ToolTipText(LOCTEXT("ClearField", "Clear source selection."))
.Visibility(this, &SSourceSelector::GetClearVisibility)
.OnClicked(this, &SSourceSelector::OnClearSource)
];
}
ChildSlot
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Center)
[
SAssignNew(SourceComboBox, SComboBox<FBindingSource>)
.OptionsSource(&AvailableSources)
.OnGenerateWidget_Lambda([this](FBindingSource Source)
{
return SNew(SSourceEntry)
.TextStyle(TextStyle)
.Source(Source);
})
.OnSelectionChanged(this, &SSourceSelector::OnComboBoxSelectionChanged)
.InitiallySelectedItem(SelectedSource)
[
SAssignNew(SelectedSourceWidget, SSourceEntry)
.TextStyle(TextStyle)
.Source(SelectedSource)
]
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Right)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(SSimpleButton)
.Icon(FAppStyle::Get().GetBrush("Icons.X"))
.ToolTipText(LOCTEXT("ClearField", "Clear source selection."))
.Visibility(this, &SSourceSelector::GetClearVisibility)
.OnClicked(this, &SSourceSelector::OnClearSource)
]
HorizontalBox
];
OnSelectionChanged = Args._OnSelectionChanged;
OnSelectionChangedDelegate = Args._OnSelectionChanged;
}
void SSourceSelector::OnComboBoxSelectionChanged(FBindingSource Selected, ESelectInfo::Type SelectionType)
TSharedRef<SWidget> SSourceSelector::OnGetMenuContent()
{
TSharedRef<SBox> TopLevelBox = SNew(SBox)
.MinDesiredWidth(200)
.MinDesiredHeight(400);
if (bViewModels)
{
ViewModelList = SNew(SListView<FBindingSource>)
.OnGenerateRow_Lambda([this](FBindingSource Source, TSharedRef<STableViewBase> OwnerTable)
{
return SNew(STableRow<FBindingSource>, OwnerTable)
[
SNew(SSourceEntry)
.Source(Source)
.TextStyle(TextStyle)
];
})
.OnSelectionChanged(this, &SSourceSelector::OnViewModelSelectionChanged)
.SelectionMode(ESelectionMode::Single)
.ListItemsSource(&ViewModelSources);
TopLevelBox->SetContent(ViewModelList.ToSharedRef());
}
else
{
WidgetHierarchy = SNew(SReadOnlyHierarchyView, WidgetBlueprint.Get())
.OnSelectionChanged(this, &SSourceSelector::OnWidgetSelectionChanged)
.ShowSearch(false);
TopLevelBox->SetContent(WidgetHierarchy.ToSharedRef());
}
return TopLevelBox;
}
void SSourceSelector::OnViewModelSelectionChanged(FBindingSource Selected, ESelectInfo::Type SelectionType)
{
SelectedSource = Selected;
SelectedSourceWidget->RefreshSource(Selected);
if (SelectedSourceWidget.IsValid())
{
SelectedSourceWidget->RefreshSource(Selected);
}
OnSelectionChangedDelegate.ExecuteIfBound(Selected);
}
void SSourceSelector::OnWidgetSelectionChanged(FName SelectedName, ESelectInfo::Type SelectionType)
{
FBindingSource Source = FBindingSource::CreateForWidget(WidgetBlueprint.Get(), SelectedName);
if (SelectedSourceWidget.IsValid())
{
SelectedSourceWidget->RefreshSource(Source);
}
OnSelectionChangedDelegate.ExecuteIfBound(Source);
OnSelectionChanged.ExecuteIfBound(Selected);
}
void SSourceSelector::Refresh()
{
SelectedSource = SelectedSourceAttribute.Get();
AvailableSources = AvailableSourcesAttribute.Get();
if (SourceComboBox.IsValid())
if (SelectedSourceWidget.IsValid())
{
SourceComboBox->RefreshOptions();
SourceComboBox->SetSelectedItem(SelectedSource);
SelectedSourceWidget->RefreshSource(SelectedSource);
}
TSharedPtr<SWidget> SourcePicker;
if (bViewModels)
{
UMVVMEditorSubsystem* EditorSubsystem = GEditor->GetEditorSubsystem<UMVVMEditorSubsystem>();
if (const UMVVMBlueprintView* View = EditorSubsystem->GetView(WidgetBlueprint.Get()))
{
const TArrayView<const FMVVMBlueprintViewModelContext> ViewModels = View->GetViewModels();
ViewModelSources.Reserve(ViewModels.Num());
for (const FMVVMBlueprintViewModelContext& ViewModel : ViewModels)
{
FBindingSource& Source = ViewModelSources.AddDefaulted_GetRef();
Source.Class = ViewModel.GetViewModelClass();
Source.Name = ViewModel.GetViewModelName();
Source.DisplayName = ViewModel.GetDisplayName();
Source.ViewModelId = ViewModel.GetViewModelId();
}
}
}
if (WidgetHierarchy.IsValid())
{
WidgetHierarchy->Refresh();
}
if (ViewModelList.IsValid())
{
if (SelectedSource.IsValid())
{
ViewModelList->SetItemSelection(SelectedSource, true);
}
else
{
ViewModelList->ClearSelection();
}
}
}
EVisibility SSourceSelector::GetClearVisibility() const
@@ -89,9 +203,9 @@ EVisibility SSourceSelector::GetClearVisibility() const
FReply SSourceSelector::OnClearSource()
{
if (SourceComboBox.IsValid())
if (ViewModelList.IsValid())
{
SourceComboBox->ClearSelection();
ViewModelList->ClearSelection();
}
return FReply::Handled();

View File

@@ -2,11 +2,13 @@
#pragma once
#include "CoreMinimal.h"
#include "Hierarchy/SReadOnlyHierarchyView.h"
#include "Layout/Visibility.h"
#include "Templates/SharedPointer.h"
#include "Types/MVVMBindingSource.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/Input/SComboBox.h"
#include "Widgets/Input/SMenuAnchor.h"
namespace UE::MVVM
{
@@ -23,29 +25,43 @@ public:
{
}
SLATE_STYLE_ARGUMENT(FTextBlockStyle, TextStyle)
SLATE_ARGUMENT_DEFAULT(bool, ShowClear) = true;
SLATE_ARGUMENT_DEFAULT(bool, AutoRefresh) = false;
SLATE_ARGUMENT_DEFAULT(bool, ViewModels) = false;
SLATE_ATTRIBUTE(FBindingSource, SelectedSource)
SLATE_ATTRIBUTE(TArray<FBindingSource>, AvailableSources)
SLATE_EVENT(FSelectionChanged, OnSelectionChanged)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
void Construct(const FArguments& InArgs, const UWidgetBlueprint* InWidgetBlueprint);
void Refresh();
private:
void OnComboBoxSelectionChanged(FBindingSource Selected, ESelectInfo::Type SelectionType);
void OnViewModelSelectionChanged(FBindingSource Selected, ESelectInfo::Type SelectionType);
void OnWidgetSelectionChanged(FName SelectedName, ESelectInfo::Type SelectionType);
TSharedRef<SWidget> OnGetMenuContent();
EVisibility GetClearVisibility() const;
FReply OnClearSource();
private:
FSelectionChanged OnSelectionChanged;
TWeakObjectPtr<const UWidgetBlueprint> WidgetBlueprint;
FSelectionChanged OnSelectionChangedDelegate;
const FTextBlockStyle* TextStyle = nullptr;
TAttribute<TArray<FBindingSource>> AvailableSourcesAttribute;
TAttribute<FBindingSource> SelectedSourceAttribute;
TSharedPtr<SComboBox<FBindingSource>> SourceComboBox;
TArray<FBindingSource> AvailableSources;
TArray<FBindingSource> ViewModelSources;
FBindingSource SelectedSource;
TSharedPtr<SMenuAnchor> MenuAnchor;
TSharedPtr<SListView<FBindingSource>> ViewModelList;
TSharedPtr<SReadOnlyHierarchyView> WidgetHierarchy;
TSharedPtr<SSourceEntry> SelectedSourceWidget;
const FTextBlockStyle* TextStyle = nullptr;
bool bAutoRefresh = false;
bool bViewModels = false;
bool bShowClear = true;
};
} // namespace UE::MVVM