Files
UnrealEngineUWP/Engine/Source/Runtime/UMG/Private/Components/ListView.cpp
daren cheng 4af0ec6765 Fix editor utility widget style changes not saving due to UMG style CDO comparisions reverting changes.
Also fixes issue where any 32x32 button texture would get shrunk to zero on editor utility widgets.

#preflight 620441552f56bd0ebf9fc84e
#rb vincent.gauthier lauren.barnes
#lockdown JeanMichel.Dignard


#ROBOMERGE-AUTHOR: daren.cheng
#ROBOMERGE-SOURCE: CL 18926528 via CL 18926776 via CL 18928248 via CL 18929495
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v916-18915374)

[CL 18929501 by daren cheng in ue5-main branch]
2022-02-09 19:39:40 -05:00

370 lines
8.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Components/ListView.h"
#include "Widgets/Views/SListView.h"
#include "Engine/World.h"
#include "TimerManager.h"
#include "Blueprint/ListViewDesignerPreviewItem.h"
#include "Styling/UMGCoreStyle.h"
#include "UMGPrivate.h"
#define LOCTEXT_NAMESPACE "UMG"
/////////////////////////////////////////////////////
// UListView
static FTableViewStyle* DefaultListViewStyle = nullptr;
static FScrollBarStyle* DefaultListViewScrollBarStyle = nullptr;
#if WITH_EDITOR
static FTableViewStyle* EditorListViewStyle = nullptr;
static FScrollBarStyle* EditorListViewScrollBarStyle = nullptr;
#endif
UListView::UListView(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, Orientation(EOrientation::Orient_Vertical)
{
if (DefaultListViewStyle == nullptr)
{
DefaultListViewStyle = new FTableViewStyle(FUMGCoreStyle::Get().GetWidgetStyle<FTableViewStyle>("ListView"));
// Unlink UMG default colors.
DefaultListViewStyle->UnlinkColors();
}
if (DefaultListViewScrollBarStyle == nullptr)
{
DefaultListViewScrollBarStyle = new FScrollBarStyle(FUMGCoreStyle::Get().GetWidgetStyle<FScrollBarStyle>("Scrollbar"));
// Unlink UMG default colors.
DefaultListViewScrollBarStyle->UnlinkColors();
}
WidgetStyle = *DefaultListViewStyle;
ScrollBarStyle = *DefaultListViewScrollBarStyle;
#if WITH_EDITOR
if (EditorListViewStyle == nullptr)
{
EditorListViewStyle = new FTableViewStyle(FAppStyle::Get().GetWidgetStyle<FTableViewStyle>("ListView"));
// Unlink UMG default colors.
EditorListViewStyle->UnlinkColors();
}
if (EditorListViewScrollBarStyle == nullptr)
{
EditorListViewScrollBarStyle = new FScrollBarStyle(FCoreStyle::Get().GetWidgetStyle<FScrollBarStyle>("Scrollbar"));
// Unlink UMG default colors.
EditorListViewScrollBarStyle->UnlinkColors();
}
if (IsEditorWidget())
{
WidgetStyle = *EditorListViewStyle;
ScrollBarStyle = *EditorListViewScrollBarStyle;
}
#endif // WITH_EDITOR
}
void UListView::ReleaseSlateResources(bool bReleaseChildren)
{
Super::ReleaseSlateResources(bReleaseChildren);
MyListView.Reset();
}
#if WITH_EDITOR
void UListView::OnRefreshDesignerItems()
{
RefreshDesignerItems<UObject*>(ListItems, [this] () {return NewObject<UListViewDesignerPreviewItem>(this); });
}
#endif
void UListView::AddItem(UObject* Item)
{
if (Item == nullptr)
{
FFrame::KismetExecutionMessage(TEXT("Cannot add null item into ListView."), ELogVerbosity::Warning, "NullListViewItem");
return;
}
if (ListItems.Contains(Item))
{
FFrame::KismetExecutionMessage(TEXT("Cannot add duplicate item into ListView."), ELogVerbosity::Warning, "DuplicateListViewItem");
return;
}
ListItems.Add(Item);
const TArray<UObject*> Added = { Item };
const TArray<UObject*> Removed;
OnItemsChanged(Added, Removed);
RequestRefresh();
}
void UListView::RemoveItem(UObject* Item)
{
ListItems.Remove(Item);
const TArray<UObject*> Added;
const TArray<UObject*> Removed = { Item };
OnItemsChanged(Added, Removed);
RequestRefresh();
}
UObject* UListView::GetItemAt(int32 Index) const
{
return ListItems.IsValidIndex(Index) ? ListItems[Index] : nullptr;
}
int32 UListView::GetNumItems() const
{
return ListItems.Num();
}
int32 UListView::GetIndexForItem(const UObject* Item) const
{
return ListItems.IndexOfByKey(Item);
}
void UListView::ClearListItems()
{
const TArray<UObject*> Added;
const TArray<UObject*> Removed = MoveTemp(ListItems);
ListItems.Reset();
OnItemsChanged(Added, Removed);
RequestRefresh();
}
void UListView::SetSelectionMode(TEnumAsByte<ESelectionMode::Type> InSelectionMode)
{
SelectionMode = InSelectionMode;
if (MyListView)
{
MyListView->SetSelectionMode(InSelectionMode);
}
}
int32 UListView::BP_GetNumItemsSelected() const
{
return GetNumItemsSelected();
}
void UListView::BP_SetListItems(const TArray<UObject*>& InListItems)
{
SetListItems(InListItems);
}
UObject* UListView::BP_GetSelectedItem() const
{
return GetSelectedItem();
}
void UListView::HandleOnEntryInitializedInternal(UObject* Item, const TSharedRef<ITableRow>& TableRow)
{
BP_OnEntryInitialized.Broadcast(Item, GetEntryWidgetFromItem(Item));
}
bool UListView::BP_GetSelectedItems(TArray<UObject*>& Items) const
{
return GetSelectedItems(Items) > 0;
}
bool UListView::BP_IsItemVisible(UObject* Item) const
{
return IsItemVisible(Item);
}
void UListView::BP_NavigateToItem(UObject* Item)
{
if (Item)
{
RequestNavigateToItem(Item);
}
}
void UListView::NavigateToIndex(int32 Index)
{
RequestNavigateToItem(GetItemAt(Index));
}
void UListView::BP_ScrollItemIntoView(UObject* Item)
{
if (Item)
{
RequestScrollItemIntoView(Item);
}
}
void UListView::ScrollIndexIntoView(int32 Index)
{
BP_ScrollItemIntoView(GetItemAt(Index));
}
void UListView::BP_CancelScrollIntoView()
{
if (MyListView.IsValid())
{
MyListView->CancelScrollIntoView();
}
}
bool UListView::IsRefreshPending() const
{
if (MyListView.IsValid())
{
return MyListView->IsPendingRefresh();
}
return false;
}
void UListView::BP_SetSelectedItem(UObject* Item)
{
if (MyListView.IsValid())
{
MyListView->SetSelection(Item, ESelectInfo::Direct);
}
}
void UListView::SetSelectedItem(const UObject* Item)
{
ITypedUMGListView<UObject*>::SetSelectedItem(const_cast<UObject*>(Item));
}
void UListView::SetSelectedIndex(int32 Index)
{
SetSelectedItem(GetItemAt(Index));
}
void UListView::BP_SetItemSelection(UObject* Item, bool bSelected)
{
SetItemSelection(Item, bSelected);
}
void UListView::BP_ClearSelection()
{
ClearSelection();
}
void UListView::OnItemsChanged(const TArray<UObject*>& AddedItems, const TArray<UObject*>& RemovedItems)
{
// Allow subclasses to do special things when objects are added or removed from the list.
// Keep track of references to Actors and make sure to release them when Actors are about to be removed
for (UObject* AddedItem : AddedItems)
{
if (AActor* AddedActor = Cast<AActor>(AddedItem))
{
AddedActor->OnEndPlay.AddDynamic(this, &UListView::OnListItemEndPlayed);
}
else if (AActor* AddedItemOuterActor = AddedItem->GetTypedOuter<AActor>())
{
// Unique so that we don't spam events for shared actor outers but this also means we can't
// unsubscribe when processing RemovedItems
AddedItemOuterActor->OnEndPlay.AddUniqueDynamic(this, &UListView::OnListItemOuterEndPlayed);
}
}
for (UObject* RemovedItem : RemovedItems)
{
if (AActor* RemovedActor = Cast<AActor>(RemovedItem))
{
RemovedActor->OnEndPlay.RemoveDynamic(this, &UListView::OnListItemEndPlayed);
}
}
}
void UListView::OnListItemEndPlayed(AActor* Item, EEndPlayReason::Type EndPlayReason)
{
RemoveItem(Item);
}
void UListView::OnListItemOuterEndPlayed(AActor* ItemOuter, EEndPlayReason::Type EndPlayReason)
{
for (int32 ItemIndex = ListItems.Num() - 1; ItemIndex >= 0; --ItemIndex)
{
UObject* Item = ListItems[ItemIndex];
if (Item->IsIn(ItemOuter))
{
RemoveItem(Item);
}
}
}
TSharedRef<STableViewBase> UListView::RebuildListWidget()
{
return ConstructListView<SListView>();
}
void UListView::HandleListEntryHovered(UUserWidget& EntryWidget)
{
if (UObject* const* ListItem = ItemFromEntryWidget(EntryWidget))
{
OnItemIsHoveredChanged().Broadcast(*ListItem, true);
BP_OnItemIsHoveredChanged.Broadcast(*ListItem, true);
}
}
void UListView::HandleListEntryUnhovered(UUserWidget& EntryWidget)
{
if (UObject* const* ListItem = ItemFromEntryWidget(EntryWidget))
{
OnItemIsHoveredChanged().Broadcast(*ListItem, false);
BP_OnItemIsHoveredChanged.Broadcast(*ListItem, false);
}
}
FMargin UListView::GetDesiredEntryPadding(UObject* Item) const
{
if (ListItems.Num() > 0 && ListItems[0] != Item)
{
if (Orientation == EOrientation::Orient_Horizontal)
{
// For all entries after the first one, add the spacing as left padding
return FMargin(EntrySpacing, 0.f, 0.0f, 0.f);
}
else
{
// For all entries after the first one, add the spacing as top padding
return FMargin(0.f, EntrySpacing, 0.f, 0.f);
}
}
return FMargin(0.f);
}
UUserWidget& UListView::OnGenerateEntryWidgetInternal(UObject* Item, TSubclassOf<UUserWidget> DesiredEntryClass, const TSharedRef<STableViewBase>& OwnerTable)
{
return GenerateTypedEntry(DesiredEntryClass, OwnerTable);
}
void UListView::OnItemClickedInternal(UObject* ListItem)
{
BP_OnItemClicked.Broadcast(ListItem);
}
void UListView::OnItemDoubleClickedInternal(UObject* ListItem)
{
BP_OnItemDoubleClicked.Broadcast(ListItem);
}
void UListView::OnSelectionChangedInternal(UObject* FirstSelectedItem)
{
BP_OnItemSelectionChanged.Broadcast(FirstSelectedItem, FirstSelectedItem != nullptr);
}
void UListView::OnItemScrolledIntoViewInternal(UObject* ListItem, UUserWidget& EntryWidget)
{
BP_OnItemScrolledIntoView.Broadcast(ListItem, &EntryWidget);
}
/////////////////////////////////////////////////////
#undef LOCTEXT_NAMESPACE