Files
UnrealEngine/Engine/Source/Runtime/UMG/Public/Components/ListView.h
2025-05-18 13:04:45 +08:00

354 lines
16 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Components/ListViewBase.h"
#include "Widgets/Views/SListView.h"
#include "ListView.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSimpleListItemEventDynamic, UObject*, Item);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnListEntryInitializedDynamic, UObject*, Item, UUserWidget*, Widget);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnListItemSelectionChangedDynamic, UObject*, Item, bool, bIsSelected);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnItemIsHoveredChangedDynamic, UObject*, Item, bool, bIsHovered);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnListItemScrolledIntoViewDynamic, UObject*, Item, UUserWidget*, Widget);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnListViewScrolledDynamic, float, ItemOffset, float, DistanceRemaining);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnListViewFinishedScrollingDynamic);
DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(bool, FOnIsItemSelectableOrNavigableDynamic, UObject*, Item);
/**
* A virtualized list that allows up to thousands of items to be displayed.
*
* An important distinction to keep in mind here is "Item" vs. "Entry"
* The list itself is based on a list of n items, but only creates as many entry widgets as can fit on screen.
* For example, a scrolling ListView of 200 items with 5 currently visible will only have created 5 entry widgets.
*
* To make a widget usable as an entry in a ListView, it must inherit from the IUserObjectListEntry interface.
*/
UCLASS(meta = (EntryInterface = "/Script/UMG.UserObjectListEntry"), MinimalAPI)
class UListView : public UListViewBase, public ITypedUMGListView<UObject*>
{
GENERATED_BODY()
IMPLEMENT_TYPED_UMG_LIST(UObject*, MyListView)
public:
UMG_API UListView(const FObjectInitializer& Initializer);
UMG_API virtual void ReleaseSlateResources(bool bReleaseChildren) override;
UMG_API virtual void PostLoad() override;
/** Set the list of items to display within this listview */
template <typename ItemObjectT, typename AllocatorType = FDefaultAllocator>
void SetListItems(const TArray<ItemObjectT, AllocatorType>& InListItems)
{
ClearListItems();
ListItems.Reserve(InListItems.Num());
for (const ItemObjectT ListItem : InListItems)
{
if (ListItem != nullptr)
{
ListItems.Add(ListItem);
}
}
OnItemsChanged(ListItems, TArray<UObject*>());
RequestRefresh();
}
ESelectionMode::Type GetSelectionMode() const { return SelectionMode; }
EOrientation GetOrientation() const { return Orientation; }
template <typename RowWidgetT = UUserWidget>
RowWidgetT* GetEntryWidgetFromItem(const UObject* Item) const
{
return Item ? ITypedUMGListView<UObject*>::GetEntryWidgetFromItem<RowWidgetT>(const_cast<UObject*>(Item)) : nullptr;
}
UMG_API void SetSelectedItem(const UObject* Item);
/** Gets the first selected item, if any; recommended that you only use this for single selection lists. */
template <typename ObjectT = UObject>
ObjectT* GetSelectedItem() const
{
return Cast<ObjectT>(ITypedUMGListView<UObject*>::GetSelectedItem());
}
/**
* Gets the list of all items in the list.
* Note that each of these items only has a corresponding entry widget when visible. Use GetDisplayedEntryWidgets to get the currently displayed widgets.
*/
UFUNCTION(BlueprintCallable, Category = ListView)
const TArray<UObject*>& GetListItems() const { return ListItems; }
/** Adds an the item to the list */
UFUNCTION(BlueprintCallable, Category = ListView)
UMG_API void AddItem(UObject* Item);
/** Removes an the item from the list */
UFUNCTION(BlueprintCallable, Category = ListView)
UMG_API void RemoveItem(UObject* Item);
/** Returns the item at the given index */
UFUNCTION(BlueprintCallable, Category = ListView)
UMG_API UObject* GetItemAt(int32 Index) const;
/** Returns the total number of items */
UFUNCTION(BlueprintCallable, Category = ListView)
UMG_API int32 GetNumItems() const;
/** Returns the index that the specified item is at. Will return the first found, or -1 for not found */
UFUNCTION(BlueprintCallable, Category = ListView)
UMG_API int32 GetIndexForItem(const UObject* Item) const;
/** Removes all items from the list */
UFUNCTION(BlueprintCallable, Category = ListView)
UMG_API void ClearListItems();
/** Sets the new selection mode, preserving the current selection where possible. */
UFUNCTION(BlueprintCallable, Category = ListView)
UMG_API void SetSelectionMode(TEnumAsByte<ESelectionMode::Type> SelectionMode);
/* Sets ScrollIntoViewAlignment which allows to stick the selected item to either side or center */
UFUNCTION(BlueprintCallable, Category = ListView)
UMG_API void SetScrollIntoViewAlignment (EScrollIntoViewAlignment NewScrollIntoViewAlignment);
/** Sets padding around the scrollbar. */
UFUNCTION(Category = ListView)
UMG_API void SetScrollBarPadding(const FMargin& InScrollBarPadding);
/** Returns true if a refresh is pending and the list will be rebuilt on the next tick */
UFUNCTION(BlueprintCallable, Category = ListView)
UMG_API bool IsRefreshPending() const;
/** Requests that the item at the given index is scrolled into view */
UFUNCTION(BlueprintCallable, Category = ListView)
UMG_API void ScrollIndexIntoView(int32 Index);
/** Sets the item at the given index as the sole selected item. */
UFUNCTION(BlueprintCallable, Category = ListView)
UMG_API void SetSelectedIndex(int32 Index);
/** Requests that the item at the given index navigated to, scrolling it into view if needed. */
UFUNCTION(BlueprintCallable, Category = ListView)
UMG_API void NavigateToIndex(int32 Index);
UMG_API virtual UObject* GetListObjectFromEntry(UUserWidget& EntryWidget) override;
protected:
UMG_API virtual void OnItemsChanged(const TArray<UObject*>& AddedItems, const TArray<UObject*>& RemovedItems);
UFUNCTION()
UMG_API void OnListItemEndPlayed(AActor* Item, EEndPlayReason::Type EndPlayReason);
UFUNCTION()
UMG_API void OnListItemOuterEndPlayed(AActor* ItemOuter, EEndPlayReason::Type EndPlayReason);
UMG_API virtual TSharedRef<STableViewBase> RebuildListWidget() override;
UMG_API virtual void HandleListEntryHovered(UUserWidget& EntryWidget) override;
UMG_API virtual void HandleListEntryUnhovered(UUserWidget& EntryWidget) override;
#if WITH_EDITOR
UMG_API virtual void OnRefreshDesignerItems() override;
#endif
UMG_API virtual UUserWidget& OnGenerateEntryWidgetInternal(UObject* Item, TSubclassOf<UUserWidget> DesiredEntryClass, const TSharedRef<STableViewBase>& OwnerTable) override;
UMG_API virtual FMargin GetDesiredEntryPadding(UObject* Item) const override;
UMG_API virtual void OnItemClickedInternal(UObject* Item) override;
UMG_API virtual void OnItemDoubleClickedInternal(UObject* Item) override;
UMG_API virtual void OnSelectionChangedInternal(UObject* FirstSelectedItem) override;
UMG_API virtual void OnItemScrolledIntoViewInternal(UObject* Item, UUserWidget& EntryWidget) override;
UMG_API virtual void OnListViewScrolledInternal(float ItemOffset, float DistanceRemaining) override;
UMG_API virtual void OnListViewFinishedScrollingInternal() override;
UMG_API virtual bool OnIsSelectableOrNavigableInternal(UObject* FirstSelectedItem) override;
UMG_API void HandleOnEntryInitializedInternal(UObject* Item, const TSharedRef<ITableRow>& TableRow);
/** SListView construction helper - useful if using a custom STreeView subclass */
template <template<typename> class ListViewT = SListView>
TSharedRef<ListViewT<UObject*>> ConstructListView()
{
FListViewConstructArgs Args;
Args.bAllowFocus = bIsFocusable;
Args.SelectionMode = SelectionMode;
Args.bClearSelectionOnClick = bClearSelectionOnClick;
Args.ConsumeMouseWheel = ConsumeMouseWheel;
Args.bReturnFocusToSelection = bReturnFocusToSelection;
Args.bClearScrollVelocityOnSelection = bClearScrollVelocityOnSelection;
Args.Orientation = Orientation;
Args.ListViewStyle = &WidgetStyle;
Args.ScrollBarStyle = &ScrollBarStyle;
Args.ScrollBarPadding = ScrollBarPadding;
Args.ScrollIntoViewAlignment = ScrollIntoViewAlignment;
MyListView = ITypedUMGListView<UObject*>::ConstructListView<ListViewT>(this, ListItems, Args);
MyListView->SetOnEntryInitialized(SListView<UObject*>::FOnEntryInitialized::CreateUObject(this, &UListView::HandleOnEntryInitializedInternal));
return StaticCastSharedRef<ListViewT<UObject*>>(MyListView.ToSharedRef());
}
protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = ListView, meta = (DisplayName = "Style"))
FTableViewStyle WidgetStyle;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = ListView)
FScrollBarStyle ScrollBarStyle;
/**
* The scroll & layout orientation of the list. ListView and TileView only.
* Vertical will scroll vertically and arrange tiles into rows.
* Horizontal will scroll horizontally and arrange tiles into columns.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = ListView)
TEnumAsByte<EOrientation> Orientation;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = ListView)
TEnumAsByte<ESelectionMode::Type> SelectionMode = ESelectionMode::Single;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = ListView)
EConsumeMouseWheel ConsumeMouseWheel = EConsumeMouseWheel::WhenScrollingPossible;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = ListView)
bool bClearSelectionOnClick = false;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = ListView)
bool bIsFocusable = true;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = ListView)
bool bClearScrollVelocityOnSelection = true;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = ListView)
bool bReturnFocusToSelection = false;
/** Sets where to scroll a widget to when using explicit navigation */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Scrolling)
EScrollIntoViewAlignment ScrollIntoViewAlignment = EScrollIntoViewAlignment::CenterAligned;
UPROPERTY(Transient)
TArray<TObjectPtr<UObject>> ListItems;
TSharedPtr<SListView<UObject*>> MyListView;
#if WITH_EDITORONLY_DATA
/**
* This deprecated property was originally BlueprintReadOnly. To satisfy the compiler requirment to have a BlueprintGetter for this property,
* it relies on the newly added UFunction GetHorizontalEntrySpacing() to act as its BlueprintGetter.
*/
UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "EntrySpacing has been deprecated. Please use HorizontalEntrySpacing and VerticalEntrySpacing."), BlueprintReadOnly, BlueprintGetter = "GetHorizontalEntrySpacing", Category = ListView, meta = (ClampMin = 0))
float EntrySpacing = 0.f;
#endif // WITH_EDITOR
private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, Category = ListView, meta = (ClampMin = 0, AllowPrivateAccess = "true"))
float HorizontalEntrySpacing = 0.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, Category = ListView, meta = (ClampMin = 0, AllowPrivateAccess = "true"))
float VerticalEntrySpacing = 0.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, Category = ListView, meta = (AllowPrivateAccess = "true", DisplayAfter="ScrollBarStyle"))
FMargin ScrollBarPadding;
public:
/** Get the horizontal spacing between entries. */
UFUNCTION(BlueprintCallable, Category = ListView)
float GetHorizontalEntrySpacing() const { return HorizontalEntrySpacing; }
/** Get the vertical spacing between entries. */
UFUNCTION(BlueprintCallable, Category = ListView)
float GetVerticalEntrySpacing() const { return VerticalEntrySpacing; }
/** Gets padding around the scrollbar. */
UFUNCTION(Category = ListView)
FMargin GetScrollBarPadding() const { return ScrollBarPadding; }
/** Set the vertical spacing between entries. */
UMG_API void SetVerticalEntrySpacing(float InVerticalEntrySpacing);
/** Set the horizontal spacing between entries. */
UMG_API void SetHorizontalEntrySpacing(float InHorizontalEntrySpacing);
protected:
UE_DEPRECATED(5.6, "InitHorizontalEntrySpacing is deprecated, please use SetHorizontalEntrySpacing instead.")
UMG_API void InitHorizontalEntrySpacing(float InHorizontalEntrySpacing);
UE_DEPRECATED(5.6, "InitVerticalEntrySpacing is deprecated, please use SetVerticalEntrySpacing instead.")
UMG_API void InitVerticalEntrySpacing(float InVerticalEntrySpacing);
private:
// BP exposure of ITypedUMGListView API
/** Sets the given item as the sole selected item. */
UFUNCTION(BlueprintCallable, Category = ListView, meta = (AllowPrivateAccess = true, DisplayName = "Set Selected Item"))
UMG_API void BP_SetSelectedItem(UObject* Item);
/** Sets whether the given item is selected. */
UFUNCTION(BlueprintCallable, Category = ListView, meta = (AllowPrivateAccess = true, DisplayName = "Set Item Selection"))
UMG_API void BP_SetItemSelection(UObject* Item, bool bSelected);
/** Clear selection */
UFUNCTION(BlueprintCallable, Category = ListView, meta = (AllowPrivateAccess = true, DisplayName = "Clear Selection"))
UMG_API void BP_ClearSelection();
/** Gets the number of items currently selected in the list */
UFUNCTION(BlueprintCallable, Category = ListView, meta = (AllowPrivateAccess = true, DisplayName = "Get Num Items Selected"))
UMG_API int32 BP_GetNumItemsSelected() const;
/** Gets a list of all the currently selected items */
UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = ListView, meta = (AllowPrivateAccess = true, DisplayName = "GetSelectedItems"))
UMG_API bool BP_GetSelectedItems(TArray<UObject*>& Items) const;
/** Gets whether the entry for the given object is currently visible in the list */
UFUNCTION(BlueprintCallable, Category = ListView, meta = (AllowPrivateAccess = true, DisplayName = "Is Item Visible"))
UMG_API bool BP_IsItemVisible(UObject* Item) const;
/** Requests that the given item is navigated to, scrolling it into view if needed. */
UFUNCTION(BlueprintCallable, Category = ListView, meta = (AllowPrivateAccess = true, DisplayName = "Navigate To Item"))
UMG_API void BP_NavigateToItem(UObject* Item);
/** Requests that the given item is scrolled into view */
UFUNCTION(BlueprintCallable, Category = ListView, meta = (AllowPrivateAccess = true, DisplayName = "Scroll Item Into View"))
UMG_API void BP_ScrollItemIntoView(UObject* Item);
/** Cancels a previous request to scroll and item into view. */
UFUNCTION(BlueprintCallable, Category = ListView, meta = (AllowPrivateAccess = true, DisplayName = "Cancel Scroll Into View"))
UMG_API void BP_CancelScrollIntoView();
/** Sets the array of objects to display rows for in the list */
UFUNCTION(BlueprintCallable, Category = ListView, meta = (AllowPrivateAccess = true, DisplayName = "Set List Items", ViewmodelBlueprintWidgetExtension = "EntryViewModel"))
UMG_API void BP_SetListItems(const TArray<UObject*>& InListItems);
/** Gets the first selected item, if any; recommended that you only use this for single selection lists. */
UFUNCTION(BlueprintCallable, Category = ListView, meta = (DisplayName = "Get Selected Item", AllowPrivateAccess = true))
UMG_API UObject* BP_GetSelectedItem() const;
private:
/** Called when a row widget is generated for a list item */
UPROPERTY(BlueprintAssignable, Category = Events, meta = (DisplayName = "On Entry Initialized"))
FOnListEntryInitializedDynamic BP_OnEntryInitialized;
UPROPERTY(BlueprintAssignable, Category = Events, meta = (DisplayName = "On Item Clicked"))
FSimpleListItemEventDynamic BP_OnItemClicked;
UPROPERTY(BlueprintAssignable, Category = Events, meta = (DisplayName = "On Item Double Clicked"))
FSimpleListItemEventDynamic BP_OnItemDoubleClicked;
UPROPERTY(BlueprintAssignable, Category = Events, meta = (DisplayName = "On Item Is Hovered Changed"))
FOnItemIsHoveredChangedDynamic BP_OnItemIsHoveredChanged;
UPROPERTY(BlueprintAssignable, Category = Events, meta = (DisplayName = "On Item Selection Changed"))
FOnListItemSelectionChangedDynamic BP_OnItemSelectionChanged;
UPROPERTY(BlueprintAssignable, Category = Events, meta = (DisplayName = "On Item Scrolled Into View"))
FOnListItemScrolledIntoViewDynamic BP_OnItemScrolledIntoView;
UPROPERTY(BlueprintAssignable, Category = Events, meta = (DisplayName = "On List View Scrolled"))
FOnListViewScrolledDynamic BP_OnListViewScrolled;
UPROPERTY(BlueprintAssignable, Category = Events, meta = (DisplayName = "On List View Finished Scrolling"))
FOnListViewFinishedScrollingDynamic BP_OnListViewFinishedScrolling;
UPROPERTY(BlueprintReadWrite, Category = Events, meta = (AllowPrivateAccess, DisplayName = "On Is Item Selectable Or Navigable"))
FOnIsItemSelectableOrNavigableDynamic BP_OnIsItemSelectableOrNavigable;
};