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 FirstItem = this->ItemsSource->IsValidIndex(FirstItemIndex) ? (*this->ItemsSource)[FirstItemIndex] : TOptional<ItemType>{};
111 ConditionallyPaginate();
114template <
class ItemType>
115void SPaginateListWidget<ItemType>::ConditionallyPaginate()
118 if (!DoPaginate.IsBound() || PaginationRequestState == EHttpRequestState::Started)
124 if (this->GetItemCount() == 0)
130 const EPaginationDirection Directions = GetDirections();
131 if (Directions == EPaginationDirection::None)
137 if (!EnumHasAnyFlags(Directions, PaginationDirection))
143 if (EnumHasAllFlags(EndedPaginationDirections, Directions))
148 Paginate(Directions);
151template <
class ItemType>
152void SPaginateListWidget<ItemType>::Paginate(
const EPaginationDirection Directions)
154 SetPaginationRequestState(EHttpRequestState::Started, Directions);
158 [WeakThis = TWeakPtr<SWidget>(this->AsShared()), OrigWidgetCount = GetItemCount(), Directions]
160 if (!WeakThis.IsValid())
164 TSharedPtr<SPaginateListWidget> This = StaticCastSharedPtr<SPaginateListWidget>(WeakThis.Pin());
166 const uint32 DeltaChildrenCount = This->GetItemCount() - OrigWidgetCount;
167 if (DeltaChildrenCount == 0 || DeltaChildrenCount < This->Limit)
170 This->EndedPaginationDirections |= Directions;
173 This->SetPaginationRequestState(EHttpRequestState::Ended, Directions);
175 if (This->FirstItem.IsSet())
177 const float FirstOffset = FMath::Fractional(This->DesiredScrollOffset);
178 const int32 NewIndex = This->ItemsSource->Find(This->FirstItem.GetValue());
179 This->ScrollTo(static_cast<float>(NewIndex) + FirstOffset);
184template <
class ItemType>
185void SPaginateListWidget<ItemType>::SetPaginationRequestState(
const EHttpRequestState RequestState,
const EPaginationDirection Direction)
187 PaginationRequestState = RequestState;
188 OnPaginating.ExecuteIfBound(Direction, RequestState);
191template <
class ItemType>
192EPaginationDirection SPaginateListWidget<ItemType>::GetDirections()
const
194 EPaginationDirection Directions = EPaginationDirection::None;
195 const float Height = this->GetCachedGeometry().GetLocalSize().Y;
201 const float TopOffset = this->ScrollBar->DistanceFromTop() * Height;
202 const float BottomOffset = this->ScrollBar->DistanceFromBottom() * Height;
203 if (TopOffset < PaginateScrollThreshold)
205 Directions |= EPaginationDirection::Top;
207 if (BottomOffset < PaginateScrollThreshold)
209 Directions |= EPaginationDirection::Bottom;
214template <
class ItemType>
215uint32 SPaginateListWidget<ItemType>::GetItemCount()
const
217 return this->ItemsSource->Num();