5#include "Channel/ChatChannel.h"
6#include "CoreMinimal.h"
7#include "SStreamListView.h"
9template <
class ItemType>
10class SPaginateListWidget :
public SStreamListView<ItemType>
12 using FSuperArguments =
typename SStreamListView<ItemType>::FArguments;
13 using FCreateListViewWidgetDelegate =
typename SStreamListView<ItemType>::FCreateListViewWidgetDelegate;
15 DECLARE_DELEGATE_TwoParams(FOnPaginatingDelegate, EPaginationDirection, EHttpRequestState);
16 DECLARE_DELEGATE_TwoParams(FDoPaginateDelegate, EPaginationDirection, TFunction<
void()>);
19 SLATE_BEGIN_ARGS(SPaginateListWidget<ItemType>)
21 , _PaginateScrollThreshold{100.f}
22 , _PaginationDirection{EPaginationDirection::Bottom}
25 , _ListItemsSource{nullptr}
26 , _CreateListViewWidget{}
30 SLATE_ARGUMENT(uint32, Limit)
31 SLATE_ARGUMENT(
float, PaginateScrollThreshold)
32 SLATE_ARGUMENT(EPaginationDirection, PaginationDirection)
33 SLATE_EVENT(FDoPaginateDelegate, DoPaginate);
34 SLATE_EVENT(FOnPaginatingDelegate, OnPaginating);
35 SLATE_ARGUMENT(
const TArray<ItemType>*, ListItemsSource)
36 SLATE_EVENT(FCreateListViewWidgetDelegate, CreateListViewWidget);
40 void Construct(const FArguments& InArgs);
41 virtual STableViewBase::FReGenerateResults ReGenerateItems(const FGeometry& MyGeometry) override;
44 void OnScroll(const
double CurrentOffset);
45 void ConditionallyPaginate();
46 void Paginate(const EPaginationDirection Directions);
51 float PaginateScrollThreshold = 100.f;
53 EPaginationDirection PaginationDirection = EPaginationDirection::Bottom;
55 FDoPaginateDelegate DoPaginate;
57 FOnPaginatingDelegate OnPaginating;
60 void SetPaginationRequestState(const EHttpRequestState RequestState, const EPaginationDirection Direction);
61 EPaginationDirection GetDirections() const;
62 uint32 GetItemCount() const;
64 EPaginationDirection EndedPaginationDirections = EPaginationDirection::
None;
65 EHttpRequestState PaginationRequestState = EHttpRequestState::Ended;
66 TOptional<ItemType> FirstItem;
69template <class ItemType>
70void SPaginateListWidget<ItemType>::Construct(const FArguments& InArgs)
72 SStreamListView<ItemType>::Construct(FSuperArguments()
73 .ListItemsSource(InArgs._ListItemsSource)
74 .CreateListViewWidget(InArgs._CreateListViewWidget)
75 .OnListViewScrolled(
this, &SPaginateListWidget<ItemType>::OnScroll));
77 this->Limit = InArgs._Limit;
78 this->PaginateScrollThreshold = InArgs._PaginateScrollThreshold;
79 this->PaginationDirection = InArgs._PaginationDirection;
80 this->DoPaginate = InArgs._DoPaginate;
81 this->OnPaginating = InArgs._OnPaginating;
84template <
class ItemType>
85STableViewBase::FReGenerateResults SPaginateListWidget<ItemType>::ReGenerateItems(
const FGeometry& MyGeometry)
87 const STableViewBase::FReGenerateResults Result = SListView<ItemType>::ReGenerateItems(MyGeometry);
90 if (!FirstItem.IsSet() && Result.LengthOfGeneratedItems > 0.)
92 if (PaginationDirection == EPaginationDirection::Top)
94 this->ScrollToBottom();
96 else if (PaginationDirection == EPaginationDirection::Bottom)
99 OnScroll(this->CurrentScrollOffset);
105template <
class ItemType>
106void SPaginateListWidget<ItemType>::OnScroll(
const double CurrentOffset)
108 const int32 FirstItemIndex = FMath::TruncToInt(CurrentOffset);
109 const TArrayView<const ItemType> Items = this->GetItems();
110 FirstItem = Items.IsValidIndex(FirstItemIndex) ? Items[FirstItemIndex] : TOptional<ItemType>{};
112 ConditionallyPaginate();
115template <
class ItemType>
116void SPaginateListWidget<ItemType>::ConditionallyPaginate()
119 if (!DoPaginate.IsBound() || PaginationRequestState == EHttpRequestState::Started)
125 if (this->GetItemCount() == 0)
131 const EPaginationDirection Directions = GetDirections();
132 if (Directions == EPaginationDirection::None)
138 if (!EnumHasAnyFlags(Directions, PaginationDirection))
144 if (EnumHasAllFlags(EndedPaginationDirections, Directions))
149 Paginate(Directions);
152template <
class ItemType>
153void SPaginateListWidget<ItemType>::Paginate(
const EPaginationDirection Directions)
155 SetPaginationRequestState(EHttpRequestState::Started, Directions);
159 [WeakThis = TWeakPtr<SWidget>(this->AsShared()), OrigWidgetCount = GetItemCount(), Directions]
161 if (!WeakThis.IsValid())
165 TSharedPtr<SPaginateListWidget> This = StaticCastSharedPtr<SPaginateListWidget>(WeakThis.Pin());
167 const uint32 DeltaChildrenCount = This->GetItemCount() - OrigWidgetCount;
168 if (DeltaChildrenCount == 0 || DeltaChildrenCount < This->Limit)
171 This->EndedPaginationDirections |= Directions;
174 This->SetPaginationRequestState(EHttpRequestState::Ended, Directions);
176 if (This->FirstItem.IsSet())
178 const float FirstOffset = FMath::Fractional(This->DesiredScrollOffset);
179 const int32 NewIndex = This->GetItems().Find(This->FirstItem.GetValue());
180 This->ScrollTo(
static_cast<float>(NewIndex) + FirstOffset);
185template <
class ItemType>
186void SPaginateListWidget<ItemType>::SetPaginationRequestState(
const EHttpRequestState RequestState,
const EPaginationDirection Direction)
188 PaginationRequestState = RequestState;
189 OnPaginating.ExecuteIfBound(Direction, RequestState);
192template <
class ItemType>
193EPaginationDirection SPaginateListWidget<ItemType>::GetDirections()
const
195 EPaginationDirection Directions = EPaginationDirection::None;
196 const float Height = this->GetCachedGeometry().GetLocalSize().Y;
202 const float TopOffset = this->ScrollBar->DistanceFromTop() * Height;
203 const float BottomOffset = this->ScrollBar->DistanceFromBottom() * Height;
204 if (TopOffset < PaginateScrollThreshold)
206 Directions |= EPaginationDirection::Top;
208 if (BottomOffset < PaginateScrollThreshold)
210 Directions |= EPaginationDirection::Bottom;
215template <
class ItemType>
216uint32 SPaginateListWidget<ItemType>::GetItemCount()
const
218 return this->GetItems().Num();