UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
SListView.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreMinimal.h"
8#include "InputCoreTypes.h"
9#include "Input/Reply.h"
10#include "Layout/Visibility.h"
11#include "Styling/SlateTypes.h"
12#include "Styling/AppStyle.h"
20#include "Widgets/SOverlay.h"
28#if WITH_ACCESSIBILITY
33#endif
34
64template <typename ItemType>
65class SListView : public STableViewBase, TListTypeTraits<ItemType>::SerializerType, public ITypedTableView< ItemType >
66{
67public:
71
73
81
83
84 DECLARE_DELEGATE_OneParam( FOnWidgetToBeRemoved, const TSharedRef<ITableRow>& );
85
87
88public:
128
129 SLATE_STYLE_ARGUMENT( FTableViewStyle, ListViewStyle )
130
132
133 SLATE_ARGUMENT( bool, bEnableShadowBoxStyle)
134
136
138
140
142
143 SLATE_EVENT( FOnWidgetToBeRemoved, OnRowReleased )
144
145 SLATE_EVENT( FOnTableViewScrolled, OnListViewScrolled )
146
148
150
152
153 SLATE_ATTRIBUTE_DEPRECATED( float, ItemHeight, 5.5, "The ItemHeight is only used for Tile. See ShouldArrangeAsTiles")
154
156
158
160
162
164
166
168
170
172
174
176
178
180
182
184
186
188
190
192
193 SLATE_ARGUMENT(bool, PreventThrottling);
194
196
198
200
201 SLATE_ARGUMENT( FMargin, ScrollBarPadding );
202
204
206
208
210
212
214
217
219
222
224
230 void Construct(const typename SListView<ItemType>::FArguments& InArgs)
231 {
232 this->Clipping = InArgs._Clipping;
233
234 this->OnGenerateRow = InArgs._OnGenerateRow;
235 this->OnGeneratePinnedRow = InArgs._OnGeneratePinnedRow;
236 this->OnRefreshRow = InArgs._OnRefreshRow;
237 this->OnEntryInitialized = InArgs._OnEntryInitialized;
238 this->OnRowReleased = InArgs._OnRowReleased;
239 this->OnItemScrolledIntoView = InArgs._OnItemScrolledIntoView;
240 this->OnFinishedScrolling = InArgs._OnFinishedScrolling;
241
242 this->SetItemsSource(InArgs.MakeListItemsSource(this->SharedThis(this)));
243 this->OnContextMenuOpening = InArgs._OnContextMenuOpening;
244 this->OnItemsRebuilt = InArgs._OnItemsRebuilt;
245 this->OnClick = InArgs._OnMouseButtonClick;
246 this->OnDoubleClick = InArgs._OnMouseButtonDoubleClick;
247 this->OnSelectionChanged = InArgs._OnSelectionChanged;
248 this->OnIsSelectableOrNavigable = InArgs._OnIsSelectableOrNavigable;
249 this->SelectionMode = InArgs._SelectionMode;
250
251 this->bClearSelectionOnClick = InArgs._ClearSelectionOnClick;
252
253 this->AllowOverscroll = InArgs._AllowOverscroll;
254 this->ConsumeMouseWheel = InArgs._ConsumeMouseWheel;
255 this->WheelScrollMultiplier = InArgs._WheelScrollMultiplier;
256 this->NavigationScrollOffset = InArgs._NavigationScrollOffset;
257
258 this->bHandleGamepadEvents = InArgs._HandleGamepadEvents;
259 this->bHandleDirectionalNavigation = InArgs._HandleDirectionalNavigation;
260 this->bHandleSpacebarSelection = InArgs._HandleSpacebarSelection;
261 this->IsFocusable = InArgs._IsFocusable;
262
263 this->bReturnFocusToSelection = InArgs._ReturnFocusToSelection;
264
265 this->bClearScrollVelocityOnSelection = InArgs._ClearScrollVelocityOnSelection;
266
267 this->bEnableAnimatedScrolling = InArgs._EnableAnimatedScrolling;
268 this->FixedLineScrollOffset = InArgs._FixedLineScrollOffset;
269 this->ScrollIntoViewAlignment = InArgs._ScrollIntoViewAlignment;
270
271 this->OnItemToString_Debug = InArgs._OnItemToString_Debug.IsBound()
272 ? InArgs._OnItemToString_Debug
274 this->OnEnteredBadState = InArgs._OnEnteredBadState;
275
276 this->OnKeyDownHandler = InArgs._OnKeyDownHandler;
277
278 this->SetStyle(InArgs._ListViewStyle);
279
280 this->bShouldUseShadowBoxStyle = InArgs._bEnableShadowBoxStyle;
281
282 this->SetShadowBoxStyle(InArgs._ShadowBoxStyle);
283
284 this->MaxPinnedItems = InArgs._MaxPinnedItems;
285 this->DefaultMaxPinnedItems = InArgs._MaxPinnedItems;
286 this->ScrollBarSlotPadding = InArgs._ScrollBarPadding;
287
288 // Check for any parameters that the coder forgot to specify.
289 FString ErrorString;
290 {
291 if ( !this->OnGenerateRow.IsBound() )
292 {
293 ErrorString += TEXT("Please specify an OnGenerateRow. \n");
294 }
295
296 if ( !this->HasValidItemsSource() )
297 {
298 ErrorString += TEXT("Please specify a ListItemsSource. \n");
299 }
300 }
301
302 if (ErrorString.Len() > 0)
303 {
304 // Let the coder know what they forgot
305 this->ChildSlot
307 .VAlign(VAlign_Center)
308 [
310 .Text(FText::FromString(ErrorString))
311 ];
312 }
313 else
314 {
315 // Make the ListView
316 ConstructChildren( 0.0f, 0.0f, EListItemAlignment::LeftAligned, InArgs._HeaderRow, InArgs._ExternalScrollbar, InArgs._Orientation, InArgs._OnListViewScrolled, InArgs._ScrollBarStyle, InArgs._PreventThrottling );
317 if(this->ScrollBar.IsValid())
318 {
319 this->ScrollBar->SetDragFocusCause(InArgs._ScrollbarDragFocusCause);
320 this->ScrollBar->SetUserVisibility(InArgs._ScrollbarVisibility);
321 }
323 }
324 }
325
329 , WidgetGenerator(this)
331 , SelectorItem(TListTypeTraits<ItemType>::MakeNullPtr())
332 , RangeSelectionStart(TListTypeTraits<ItemType>::MakeNullPtr())
333 , ItemsSource(nullptr)
334 , ItemToScrollIntoView(TListTypeTraits<ItemType>::MakeNullPtr())
336 , ItemToNotifyWhenInView(TListTypeTraits<ItemType>::MakeNullPtr())
339 {
340#if WITH_ACCESSIBILITY
341 AccessibleBehavior = EAccessibleBehavior::Auto;
342 bCanChildrenBeAccessible = true;
343#endif
344 }
346
347public:
348
349 //~ SWidget overrides
350
351 virtual bool SupportsKeyboardFocus() const override
352 {
353 return IsFocusable.Get();
354 }
355
356 virtual FReply OnKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent ) override
357 {
358 if (OnKeyDownHandler.IsBound())
359 {
361 if (Reply.IsEventHandled())
362 {
363 return Reply;
364 }
365 }
367 }
368
369protected:
371 {
373
374 // Don't respond to key-presses containing "Alt" as a modifier
375 if ( ItemsSourceRef.Num() > 0 && !InKeyEvent.IsAltDown() )
376 {
377 bool bWasHandled = false;
379
380 // Check for selection manipulation keys (Up, Down, Home, End, PageUp, PageDown)
381 if ( InKeyEvent.GetKey() == EKeys::Home )
382 {
383 // Select the first item
385 bWasHandled = true;
386 }
387 else if ( InKeyEvent.GetKey() == EKeys::End )
388 {
389 // Select the last item
391 bWasHandled = true;
392 }
393 else if ( InKeyEvent.GetKey() == EKeys::PageUp )
394 {
395 int32 SelectionIndex = 0;
397 {
399 }
400
401 int32 NumItemsInAPage = FMath::TruncToInt(GetNumLiveWidgets());
403 NumItemsInAPage -= Remainder;
404
405 if ( SelectionIndex >= NumItemsInAPage )
406 {
407 // Select an item on the previous page
409 }
410 else
411 {
413 }
414
415 bWasHandled = true;
416 }
417 else if ( InKeyEvent.GetKey() == EKeys::PageDown )
418 {
419 int32 SelectionIndex = 0;
421 {
423 }
424
425 int32 NumItemsInAPage = FMath::TruncToInt(GetNumLiveWidgets());
427 NumItemsInAPage -= Remainder;
428
429 if ( SelectionIndex < ItemsSourceRef.Num() - NumItemsInAPage )
430 {
431 // Select an item on the next page
433 }
434 else
435 {
437 }
438
439 bWasHandled = true;
440 }
441
443 {
446 }
447 else
448 {
449 // Change selected status of item.
451 {
453
454 // Deselect.
455 if (InKeyEvent.IsControlDown() || SelectionMode.Get() == ESelectionMode::SingleToggle)
456 {
457 this->Private_SetItemSelection(SelectorItemDereference, !(this->Private_IsItemSelected(SelectorItemDereference)), true);
459 bWasHandled = true;
460 }
461 else
462 {
463 // Already selected, don't handle.
464 if (this->Private_IsItemSelected(SelectorItemDereference))
465 {
466 bWasHandled = false;
467 }
468 // Select.
469 else
470 {
471 this->Private_SetItemSelection(SelectorItemDereference, true, true);
473 bWasHandled = true;
474 }
475 }
476
478
479 // If the selector is not in the view, scroll it into view.
480 TSharedPtr<ITableRow> WidgetForItem = this->WidgetGenerator.GetWidgetForItem(SelectorItemDereference);
481 if (!WidgetForItem.IsValid())
482 {
483 this->RequestScrollIntoView(SelectorItemDereference, InKeyEvent.GetUserIndex());
484 }
485 }
486 // Select all items
487 else if ( (!InKeyEvent.IsShiftDown() && !InKeyEvent.IsAltDown() && InKeyEvent.IsControlDown() && InKeyEvent.GetKey() == EKeys::A) && SelectionMode.Get() == ESelectionMode::Multi )
488 {
490
491 for ( int32 ItemIdx = 0; ItemIdx < ItemsSourceRef.Num(); ++ItemIdx )
492 {
493 this->Private_SetItemSelection( ItemsSourceRef[ItemIdx], true );
494 }
495
497
498 bWasHandled = true;
499 }
500 }
501
502 if (bWasHandled)
503 {
504 return FReply::Handled();
505 }
506 }
507
509 }
510public:
511
513 {
515
517 {
519
523
524 const EUINavigation NavType = InNavigationEvent.GetNavigationType();
527 {
528 // Nav backward by a line
530 }
533 {
535
536 // The list might be jagged so attempt to determine if there's a partially filled row we can move to
537 if (!ItemsSourceRef.IsValidIndex(AttemptSelectIndex))
538 {
539 const int32 NumItems = ItemsSourceRef.Num();
540 if (NumItems > 0)
541 {
542 // NumItemsWide should never be 0, ensuring for sanity
544
545 // calculate total number of rows and row of current index (1 index)
546 const int32 NumLines = FMath::CeilToInt((float)NumItems / (float)NumItemsPerLine);
547 const int32 CurLine = FMath::CeilToInt((float)(CurSelectionIndex + 1) / (float)NumItemsPerLine);
548
549 // if not on final row, assume a jagged list and select the final item
550 if (CurLine < NumLines)
551 {
552 AttemptSelectIndex = NumItems - 1;
553 }
554 }
555 }
556 }
557
558 // If it's valid we'll scroll it into view and return an explicit widget in the FNavigationReply
559 if (ItemsSourceRef.IsValidIndex(AttemptSelectIndex) && this->bIsGamepadScrollingEnabled)
560 {
562 if (ItemToSelect.IsSet())
563 {
565 return FNavigationReply::Explicit(nullptr);
566 }
567 }
568 }
569
571 }
572
574 {
577 && MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton
578 && !MouseEvent.IsControlDown()
579 && !MouseEvent.IsShiftDown()
580 )
581 {
582 // Left clicking on a list (but not an item) will clear the selection on mouse button down.
583 // Right clicking is handled on mouse up.
584 if ( this->Private_GetNumSelectedItems() > 0 )
585 {
588 }
589
590 return FReply::Handled();
591 }
592
594 }
595
597 {
600 && MouseEvent.GetEffectingButton() == EKeys::RightMouseButton
601 && !MouseEvent.IsControlDown()
602 && !MouseEvent.IsShiftDown()
603 && !this->IsRightClickScrolling()
604 )
605 {
606 // Right clicking on a list (but not an item) will clear the selection on mouse button up.
607 // Left clicking is handled on mouse down
608 if ( this->Private_GetNumSelectedItems() > 0 )
609 {
612 }
613 }
614
616 }
617
618#if WITH_ACCESSIBILITY
619protected:
620 friend class FSlateAccessibleListView;
628 , public IAccessibleTable
629 {
630 public:
633 {
634
635 }
636
637 // IAccessibleWidget
638 virtual IAccessibleTable* AsTable()
639 {
640 return this;
641 }
642 // ~
643
644 // IAccessibleTable
645 virtual TArray<TSharedPtr<IAccessibleWidget>> GetSelectedItems() const
646 {
648 if (Widget.IsValid())
649 {
651 SelectedItemsArray.Empty(ListView ->SelectedItems.Num());
652 for (typename TItemSet::TConstIterator SelectedItemIt(ListView ->SelectedItems); SelectedItemIt; ++SelectedItemIt)
653 {
654 const ItemType& CurrentItem = *SelectedItemIt;
655 // This is only valid if the item is visible
656 TSharedPtr < ITableRow> TableRow = ListView->WidgetGenerator.GetWidgetForItem(CurrentItem);
657 if (TableRow.IsValid())
658 {
660 TSharedPtr<IAccessibleWidget> AccessibleTableRow = FSlateAccessibleWidgetCache::GetAccessibleWidgetChecked(TableRowWidget);
661 // it's possible for the accessible widget to still be in the process of generating
662 // in the slate accessibility tree
663 if (AccessibleTableRow.IsValid())
664 {
666 }
667 }
668 }
669 }
670 return SelectedItemsArray;
671 }
672
673 virtual bool CanSupportMultiSelection() const
674 {
675 if (Widget.IsValid())
676 {
678 return ListView->SelectionMode.Get() == ESelectionMode::Multi;
679 }
680 return false;
681 }
682
683 virtual bool IsSelectionRequired() const
684 {
685 return false;
686 }
687 // ~
688 };
689public:
691 {
692 // @TODOAccessibility: Add support for the different types of tables e.g tree and tile
693 // We hardcode to list for now
694 EAccessibleWidgetType WidgetType = EAccessibleWidgetType::List;
696 }
697
699 {
700 // current behaviour will red out the templated type of the listwhich is verbose and unhelpful
701 // This will read out list twice, but it's the best we can do for now if no label is found
702 // @TODOAccessibility: Give a better name
703 static FString Name(TEXT("List"));
704 return FText::FromString(Name);
705 }
706#endif
707private:
708
709 friend class FWidgetGenerator;
715 class FWidgetGenerator
716 {
717 public:
718 FWidgetGenerator(SListView<ItemType>* InOwnerList)
719 : OwnerList(InOwnerList)
720 {
721 }
722
729 [[nodiscard]] TSharedPtr<ITableRow> GetWidgetForItem( const ItemType& Item ) const
730 {
731 const TSharedRef<ITableRow>* LookupResult = ItemToWidgetMap.Find(Item);
733 }
734
741 void OnItemSeen( ItemType InItem, TSharedRef<ITableRow> InGeneratedWidget)
742 {
744 TSharedRef<ITableRow>* LookupResult = ItemToWidgetMap.Find( InItem );
745 const bool bWidgetIsNewlyGenerated = (LookupResult == nullptr);
747 {
748 // It's a newly generated item!
749 ItemToWidgetMap.Add( InItem, InGeneratedWidget );
750 WidgetMapToItem.Add( &InGeneratedWidget.Get(), InItem );
751
752 // Now that the item-widget association is established, the generated row can fully initialize itself
753 InGeneratedWidget->InitializeRow();
754 OwnerList->Private_OnEntryInitialized(InItem, InGeneratedWidget);
755 }
756
757 // We should not clean up this item's widgets because it is in view.
758 ItemsToBeCleanedUp.Remove(InItem);
759 ItemsWithGeneratedWidgets.Add(InItem);
760 }
761
768 void OnBeginGenerationPass()
769 {
770 // Assume all the previously generated items need to be cleaned up.
771 ItemsToBeCleanedUp = ItemsWithGeneratedWidgets;
772 ItemsWithGeneratedWidgets.Empty();
773 }
774
779 void OnEndGenerationPass()
780 {
781 ProcessItemCleanUp();
782 ValidateWidgetGeneration();
783 }
784
786 void Clear()
787 {
788 ItemsToBeCleanedUp = ItemsWithGeneratedWidgets;
789 ItemsWithGeneratedWidgets.Empty();
790 ProcessItemCleanUp();
791 }
792
793 void ProcessItemCleanUp()
794 {
795
796 for (int32 ItemIndex = 0; ItemIndex < ItemsToBeCleanedUp.Num(); ++ItemIndex)
797 {
798 ItemType ItemToBeCleanedUp = ItemsToBeCleanedUp[ItemIndex];
799 const TSharedRef<ITableRow>* FindResult = ItemToWidgetMap.Find(ItemToBeCleanedUp);
800 if (FindResult != nullptr)
801 {
803 ItemToWidgetMap.Remove(ItemToBeCleanedUp);
804 WidgetMapToItem.Remove(&WidgetToCleanUp.Get());
805
806 if (ensureMsgf(OwnerList, TEXT("OwnerList is null, something is wrong.")))
807 {
808 WidgetToCleanUp->ResetRow();
809 OwnerList->OnRowReleased.ExecuteIfBound(WidgetToCleanUp);
810 }
811 }
813 {
814 // If we get here, it means we have an invalid object. We will need to remove that object from both maps.
815 // This may happen for example when ItemType is a UObject* and the object is garbage collected.
816 auto Widget = WidgetMapToItem.FindKey(ItemToBeCleanedUp);
817 if (Widget != nullptr)
818 {
819 for (auto WidgetItemPair = ItemToWidgetMap.CreateIterator(); WidgetItemPair; ++WidgetItemPair)
820 {
821 const ITableRow* Item = &(WidgetItemPair.Value().Get());
822 if (Item == *Widget)
823 {
824 WidgetItemPair.RemoveCurrent();
825 break;
826 }
827 }
828
829 WidgetMapToItem.Remove(*Widget);
830 }
831 }
832 }
833
834 ItemsToBeCleanedUp.Reset();
835 }
836
837 void ValidateWidgetGeneration()
838 {
839 const bool bMapsMismatch = ItemToWidgetMap.Num() != WidgetMapToItem.Num();
840 const bool bGeneratedWidgetsSizeMismatch = WidgetMapToItem.Num() != ItemsWithGeneratedWidgets.Num();
841 if (bMapsMismatch)
842 {
843 UE_LOG(LogSlate, Warning, TEXT("ItemToWidgetMap length (%d) does not match WidgetMapToItem length (%d) in %s. Diagnostics follow. "),
844 ItemToWidgetMap.Num(),
845 WidgetMapToItem.Num(),
846 OwnerList ? *OwnerList->ToString() : TEXT("null"));
847 }
848
850 {
852 TEXT("WidgetMapToItem length (%d) does not match ItemsWithGeneratedWidgets length (%d). This is often because the same item is in the list more than once in %s. Diagnostics follow."),
853 WidgetMapToItem.Num(),
854 ItemsWithGeneratedWidgets.Num(),
855 OwnerList ? *OwnerList->ToString() : TEXT("null"));
856 }
857
859 {
860 if (OwnerList->OnItemToString_Debug.IsBound())
861 {
863 UE_LOG(LogSlate, Warning, TEXT("ItemToWidgetMap :"));
864 for (auto ItemWidgetPair = ItemToWidgetMap.CreateConstIterator(); ItemWidgetPair; ++ItemWidgetPair)
865 {
866 const TSharedRef<SWidget> RowAsWidget = ItemWidgetPair.Value()->AsWidget();
867 UE_LOG(LogSlate, Warning, TEXT("%s -> 0x%08" UPTRINT_x_FMT " @ %s"), *OwnerList->OnItemToString_Debug.Execute(ItemWidgetPair.Key()), &RowAsWidget.Get(), *RowAsWidget->ToString() );
868 }
869
871 UE_LOG(LogSlate, Warning, TEXT("WidgetMapToItem:"))
872 for (auto WidgetItemPair = WidgetMapToItem.CreateConstIterator(); WidgetItemPair; ++WidgetItemPair)
873 {
874 UE_LOG(LogSlate, Warning, TEXT("0x%08" UPTRINT_x_FMT " -> %s"), WidgetItemPair.Key(), *OwnerList->OnItemToString_Debug.Execute(WidgetItemPair.Value()) );
875 }
876
878 UE_LOG(LogSlate, Warning, TEXT("ItemsWithGeneratedWidgets:"));
879 for (int i = 0; i < ItemsWithGeneratedWidgets.Num(); ++i)
880 {
881 UE_LOG(LogSlate, Warning, TEXT("[%d] %s"),i, *OwnerList->OnItemToString_Debug.Execute(ItemsWithGeneratedWidgets[i]));
882 }
883 }
884 else
885 {
886 UE_LOG(LogSlate, Warning, TEXT("Provide custom 'OnItemToString_Debug' for diagnostics dump."));
887 }
888
889 OwnerList->OnEnteredBadState.ExecuteIfBound();
890
891 checkf( false, TEXT("%s detected a critical error. See diagnostic dump above. Provide a custom 'OnItemToString_Debug' for more detailed diagnostics."), *OwnerList->ToString() );
892 }
893 }
894
895 public:
897 SListView<ItemType>* OwnerList;
898
901
904
906 TArray< TObjectPtrWrapTypeOf<ItemType> > ItemsWithGeneratedWidgets;
907
909 int32 TotalItemsLastGeneration;
910
912 TArray<ItemType> ItemsToBeCleanedUp;
913 };
914
915public:
916
917 // A low-level interface for use various widgets generated by ItemsWidgets(Lists, Trees, etc).
918 // These handle selection, expansion, and other such properties common to ItemsWidgets.
919 //
920
925
926 virtual void Private_SetItemSelection( ItemType TheItem, bool bShouldBeSelected, bool bWasUserDirected = false ) override
927 {
929 {
930 return;
931 }
932
933 if ( bShouldBeSelected )
934 {
935 SelectedItems.Add( TheItem );
936 }
937 else
938 {
939 SelectedItems.Remove( TheItem );
940 }
941
942 // Move the selector item and range selection start if the user directed this change in selection or if the list view is single selection
944 {
947 }
948
950 {
952 }
953
954#if WITH_ACCESSIBILITY
955 // On certain platforms, we need to pass accessibility focus to a widget for screen readers to announce
956 // accessibility information. STableRows cannot accept keyboard focus,
957 // so we have to manually raise a focus change event for the selected table row
958 if (bShouldBeSelected)
959 {
961 if (TableRow.IsValid())
962 {
964 // We don't need to worry about raising a focus change event for the
965 // widget with accessibility focus as FSlateAccessibleMessageHandler will take care of signalling a focus lost event
966 // @TODOAccessibility: Technically we need to pass in the user Id that selected the row so the event can be routed to the correct user.
967 // But we don't want to change the Slate API drastically right now
968 FSlateApplicationBase::Get().GetAccessibleMessageHandler()->OnWidgetEventRaised(FSlateAccessibleMessageHandler::FSlateWidgetAccessibleEventArgs(TableRowWidget, EAccessibleEvent::FocusChange, false, true));
969 }
970 }
971#endif
972 }
973
974 virtual void Private_ClearSelection() override
975 {
976 SelectedItems.Empty();
977
979 {
981 }
982 }
983
985 {
987 {
988 return;
989 }
990
992 // The InRangeSelectionEnd come from the WidgetGenerator (previous tick). Maybe it is not in the current ItemsSource list.
993 //RangeSelectionStart, maybe it is not in the current ItemsSource list.
994 if (ItemsSourceRef.Num() != 0)
995 {
998 {
1000 }
1001
1003
1006
1007 // Respect the direction of selection when ordering, ie if selecting upwards then make sure the top element is last-selected
1008 const int32 Direction = (RangeEndIndex > RangeStartIndex) ? 1 : -1;
1009
1010 int32 ItemIndex = RangeStartIndex;
1011 for (; ItemIndex != RangeEndIndex; ItemIndex += Direction)
1012 {
1013 SelectedItems.Add(ItemsSourceRef[ItemIndex]);
1014 }
1015 // The above loop won't add the last item, so manually add it here
1016 SelectedItems.Add(ItemsSourceRef[ItemIndex]);
1017 }
1018
1020 {
1022 }
1023 }
1024
1026 {
1028 {
1029 return;
1030 }
1031
1032 if( OnSelectionChanged.IsBound() )
1033 {
1034 TObjectPtrWrapTypeOf<NullableItemType> SelectedItem = (SelectedItems.Num() > 0)
1035 ? (*typename TItemSet::TIterator(SelectedItems))
1037
1038 OnSelectionChanged.ExecuteIfBound(SelectedItem, SelectInfo );
1039 }
1040 }
1041
1043 {
1045 return LookupResult == nullptr ? PinnedWidgetGenerator.WidgetMapToItem.Find(TheWidget) : LookupResult;
1046 }
1047
1048 virtual bool Private_UsesSelectorFocus() const override
1049 {
1050 return true;
1051 }
1052
1053 virtual bool Private_HasSelectorFocus( const ItemType& TheItem ) const override
1054 {
1055 return SelectorItem == TheItem;
1056 }
1057
1058 virtual bool Private_IsItemSelected( const ItemType& TheItem ) const override
1059 {
1060 return nullptr != SelectedItems.Find(TheItem);
1061 }
1062
1063 virtual bool Private_IsItemHighlighted(const ItemType& TheItem) const override
1064 {
1065 return nullptr != HighlightedItems.Find(TheItem);
1066 }
1067
1068 virtual bool Private_IsItemExpanded( const ItemType& TheItem ) const override
1069 {
1070 // List View does not support item expansion.
1071 return false;
1072 }
1073
1074 virtual bool Private_IsItemSelectableOrNavigable(const ItemType& TheItem) const override
1075 {
1076 return OnIsSelectableOrNavigable.IsBound() ? OnIsSelectableOrNavigable.Execute(TheItem) : true;
1077 }
1078
1079 virtual void Private_SetItemExpansion( ItemType TheItem, bool bShouldBeExpanded ) override
1080 {
1081 // Do nothing; you cannot expand an item in a list!
1082 }
1083
1084 virtual void Private_OnExpanderArrowShiftClicked( ItemType TheItem, bool bShouldBeExpanded ) override
1085 {
1086 // Do nothing; you cannot expand an item in a list!
1087 }
1088
1090 {
1091 // List View items cannot have children
1092 return false;
1093 }
1094
1095 virtual int32 Private_GetNumSelectedItems() const override
1096 {
1097 return SelectedItems.Num();
1098 }
1099
1100 virtual void Private_SetItemHighlighted(ItemType TheItem, bool bShouldBeHighlighted) override
1101 {
1103 {
1105 }
1106 else
1107 {
1108 HighlightedItems.Remove(TheItem);
1109 }
1110 }
1111
1112 virtual void Private_ClearHighlightedItems() override
1113 {
1114 HighlightedItems.Empty();
1115 }
1116
1118 {
1119 // List View items are not indented
1120 return 0;
1121 }
1122
1124 {
1126 }
1127
1128 virtual bool Private_IsLastChild(int32 ItemIndexInList) const override
1129 {
1130 return false;
1131 }
1132
1134 {
1135 return SelectionMode.Get();
1136 }
1137
1138 virtual EOrientation Private_GetOrientation() const override
1139 {
1140 return Orientation;
1141 }
1142
1143 virtual bool Private_IsPendingRefresh() const override
1144 {
1145 return IsPendingRefresh();
1146 }
1147
1148 virtual void Private_OnItemRightClicked( ItemType TheItem, const FPointerEvent& MouseEvent ) override
1149 {
1150 this->OnRightMouseButtonUp( MouseEvent );
1151 }
1152
1153 virtual bool Private_OnItemClicked(ItemType TheItem) override
1154 {
1155 if (OnClick.ExecuteIfBound(TheItem))
1156 {
1157 return true; // Handled
1158 }
1159
1160 return false; // Not handled
1161 }
1162
1163 virtual bool Private_OnItemDoubleClicked( ItemType TheItem ) override
1164 {
1165 if( OnDoubleClick.ExecuteIfBound( TheItem ) )
1166 {
1167 return true; // Handled
1168 }
1169
1170 return false; // Not handled
1171 }
1172
1174 {
1175 return TableViewMode;
1176 }
1177
1179 {
1180 return SharedThis(this);
1181 }
1182
1183private:
1184
1186
1187 // Private class that acts as a wrapper around PinnedRows, to allow for customized styling
1189 {
1190 public:
1191 SLATE_BEGIN_ARGS(SListViewPinnedRowWidget) {}
1192
1194
1195 void Construct(const FArguments& InArgs, TSharedPtr<ITableRow> InPinnedItemRow, TSharedRef<SListView> InOwnerListView, const int32 ItemIndex, const int32 NumPinnedItems)
1196 {
1197 PinnedItemRow = InPinnedItemRow;
1198 OwnerListView = InOwnerListView;
1199
1201
1202 // If the PinnedRow inherits from STableRow (i.e has a custom border already), remove it since we will be adding our own border
1203 // Also set the expander arrow to Hidden so it is not available for pinned rows, but still occupies the same space
1204 if (PinnedRow.IsValid())
1205 {
1206 PinnedRow->SetBorderImage(FAppStyle::Get().GetBrush("NoBrush"));
1207 PinnedRow->SetExpanderArrowVisibility(EVisibility::Hidden);
1208 }
1209
1212
1213 ChildSlot
1214 [
1215 SNew(SOverlay)
1216 .Visibility(TAttribute<EVisibility>::CreateSP(this, &SListViewPinnedRowWidget::SetPinnedItemVisibility, ItemIndex, NumPinnedItems))
1217
1218 + SOverlay::Slot()
1219 .Padding(FMargin(0.0f, 0.0f, 0.0f, 0.0f))
1220 [
1221 SNew(SBorder)
1222 .BorderImage_Lambda([this]()
1223 {
1224 return this->IsHovered() ? FAppStyle::Get().GetBrush("Brushes.Hover") : FAppStyle::Get().GetBrush("Brushes.Header");
1225 })
1226 .Padding(0.f)
1227 .Content()
1228 [
1231 .AutoWidth()
1232 [
1234 ]
1236 .FillWidth(1.0f)
1237 .Padding(2.0f, 2.0f, 0.0f, 0.0f)
1238 [
1239 // Text Block for ellipses, shows up when some items in the pinned list are collapsed when the number of items > MaxPinnedItems
1240 SNew(STextBlock).Text(NSLOCTEXT("SListView", "Ellipses", "..."))
1241 .Visibility(this, &SListViewPinnedRowWidget::SetPinnedItemEllipsesVisibility, ItemIndex)
1242 ]
1243 ]
1244 ]
1245 + SOverlay::Slot()
1246 .HAlign(HAlign_Fill)
1247 .VAlign(VAlign_Top)
1248 [
1249 // A shadow to indicate parent/child relationship
1250 SNew(SImage)
1252 .Image(FAppStyle::Get().GetBrush("ListView.PinnedItemShadow"))
1253 ]
1254
1255 ];
1256
1257 }
1258
1259 protected:
1260
1261 virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override
1262 {
1263 if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
1264 {
1265 const TObjectPtrWrapTypeOf<ItemType>* PinnedItem = OwnerListView->ItemFromWidget(PinnedItemRow.Get());
1266
1267 if (PinnedItem)
1268 {
1269 // Select the pinned item on click
1270 OwnerListView->NavigationSelect(*PinnedItem, MouseEvent);
1271 return FReply::Handled();
1272 }
1273 }
1274
1275 return FReply::Unhandled();
1276 }
1277
1278 private:
1279
1280 EVisibility SetPinnedItemVisibility(const int32 IndexInList, const int32 NumPinnedItems) const
1281 {
1282 // If the hierarchy is not collapsed (i.e all items are visible)
1283 if (!OwnerListView->bIsHierarchyCollapsed)
1284 {
1285 return EVisibility::Visible;
1286 }
1287
1288 int32 CurrentMaxPinnedItems = OwnerListView->MaxPinnedItems.Get();
1289
1290 // If this is the last item, it is visible
1291 if (IndexInList == NumPinnedItems - 1)
1292 {
1293 return EVisibility::Visible;
1294 }
1295 // Only show a limited number of items depending on MaxPinnedItems
1296 else if (IndexInList < CurrentMaxPinnedItems - 1)
1297 {
1298 return EVisibility::Visible;
1299 }
1300
1302 }
1303
1304 EVisibility SetPinnedItemEllipsesVisibility(const int32 IndexInList) const
1305 {
1306 // If all items are visible, the ...'s are never visible
1307 if (!OwnerListView->bIsHierarchyCollapsed)
1308 {
1310 }
1311
1312 int32 CurrentMaxPinnedItems = OwnerListView->MaxPinnedItems.Get();
1313
1314 // If the hierarchy is collapsed, the last item before the collapsed items gets the ellipses
1316 }
1317
1318 private:
1319 // A pointer to the ListView that owns this widget
1320 TSharedPtr<SListView> OwnerListView;
1321
1322 // A pointer to the row contained by this widget
1323 TSharedPtr<ITableRow> PinnedItemRow;
1324 };
1325
1326public:
1327
1333
1338
1341 {
1342 OnEntryInitialized = Delegate;
1343 }
1344
1348 virtual void UpdateSelectionSet() override
1349 {
1350 // Trees take care of this update in a different way.
1352 {
1353 bool bSelectionChanged = false;
1354 if ( !HasValidItemsSource() )
1355 {
1356 // We are no longer observing items so there is no more selection.
1357 this->Private_ClearSelection();
1358 bSelectionChanged = true;
1359 }
1360 else
1361 {
1362 // We are observing some items; they are potentially different.
1363 // Unselect any that are no longer being observed.
1365 const TArrayView<const ItemType> Items = GetItems();
1366 for ( int32 ItemIndex = 0; ItemIndex < Items.Num(); ++ItemIndex )
1367 {
1368 ItemType CurItem = Items[ItemIndex];
1369 const bool bItemIsSelected = ( nullptr != SelectedItems.Find( CurItem ) );
1370 if ( bItemIsSelected )
1371 {
1373 }
1374 }
1375
1376 // Look for items that were removed from the selection.
1377 TItemSet SetDifference = SelectedItems.Difference( NewSelectedItems );
1378 bSelectionChanged = (SetDifference.Num()) > 0;
1379
1380 // Update the selection to reflect the removal of any items from the ItemsSource.
1382 }
1383
1385 {
1387 }
1388 }
1389 }
1390
1396 {
1397 auto DoubleFractional = [](double Value) -> double
1398 {
1399 return Value - FMath::TruncToDouble(Value);
1400 };
1401
1402 // Clear all the items from our panel. We will re-add them in the correct order momentarily.
1403 this->ClearWidgets();
1404
1405 // Ensure that we always begin and clean up a generation pass.
1406 FGenerationPassGuard GenerationPassGuard(WidgetGenerator);
1407
1408 const TArrayView<const ItemType> Items = GetItems();
1409 if (Items.Num() > 0)
1410 {
1411 // Items in view, including fractional items
1412 float ItemsInView = 0.0f;
1413
1414 // Total length of widgets generated so far (height for vertical lists, width for horizontal)
1415 float LengthGeneratedSoFar = 0.0f;
1416
1417 // Length of generated widgets that in the bounds of the view.
1418 float ViewLengthUsedSoFar = 0.0f;
1419
1420 // Index of the item at which we start generating based on how far scrolled down we are
1421 // Note that we must generate at LEAST one item.
1422 int32 StartIndex = FMath::Clamp( (int32)(FMath::FloorToDouble(CurrentScrollOffset)), 0, Items.Num() - 1 );
1423
1424 // Length of the first item that is generated. This item is at the location where the user requested we scroll
1425 float FirstItemLength = 0.0f;
1426
1427 // Generate widgets assuming scenario a.
1428 bool bHasFilledAvailableArea = false;
1429 bool bAtEndOfList = false;
1430
1431 const float LayoutScaleMultiplier = MyGeometry.GetAccumulatedLayoutTransform().GetScale();
1433
1434 for( int32 ItemIndex = StartIndex; !bHasFilledAvailableArea && ItemIndex < Items.Num(); ++ItemIndex )
1435 {
1436 const ItemType& CurItem = Items[ItemIndex];
1437
1439 {
1440 // Don't bother generating widgets for invalid items
1441 continue;
1442 }
1443
1444 const float ItemLength = GenerateWidgetForItem(CurItem, ItemIndex, StartIndex, LayoutScaleMultiplier);
1445
1446 const bool bIsFirstItem = ItemIndex == StartIndex;
1447
1448 if (bIsFirstItem)
1449 {
1451 }
1452
1453 // Track the number of items in the view, including fractions.
1454 if (bIsFirstItem)
1455 {
1456 // The first item may not be fully visible (but cannot exceed 1)
1457 // FirstItemFractionScrolledIntoView is the fraction of the item that is visible after taking into account anything that may be scrolled off the top/left of the list view
1458 const float FirstItemFractionScrolledIntoView = 1.0f - (float)FMath::Max(DoubleFractional(CurrentScrollOffset), 0.0);
1459
1460 // FirstItemLengthScrolledIntoView is the length of the item, ignoring anything that is scrolled off the top/left of the list view
1462
1463 // FirstItemVisibleFraction is either: The visible item length as a fraction of the available list view length (if the item size is larger than the available size, otherwise this will be >1), or just FirstItemFractionScrolledIntoView (which can never be >1)
1465
1467 }
1468 else if (ViewLengthUsedSoFar + ItemLength > MyDimensions.ScrollAxis)
1469 {
1470 // The last item may not be fully visible either
1472 }
1473 else
1474 {
1475 ItemsInView += 1;
1476 }
1477
1479
1481 ? ItemLength * ItemsInView // For the first item, ItemsInView <= 1.0f
1482 : ItemLength;
1483
1484 bAtEndOfList = ItemIndex >= Items.Num() - 1;
1485
1486 if (bIsFirstItem && ViewLengthUsedSoFar >= MyDimensions.ScrollAxis)
1487 {
1488 // Since there was no sum of floating points, make sure we correctly detect the case where one element
1489 // fills up the space.
1491 }
1492 else
1493 {
1494 // Note: To account for accrued error from floating point truncation and addition in our sum of dimensions used,
1495 // we pad the allotted axis just a little to be sure we have filled the available space.
1496 const float FloatPrecisionOffset = 0.001f;
1498 }
1499 }
1500
1501 // Handle scenario b.
1502 // We may have stopped because we got to the end of the items, but we may still have space to fill!
1504 {
1505 double NewScrollOffsetForBackfill = static_cast<double>(StartIndex) + (LengthGeneratedSoFar - MyDimensions.ScrollAxis) / FirstItemLength;
1506
1507 for (int32 ItemIndex = StartIndex - 1; LengthGeneratedSoFar < MyDimensions.ScrollAxis && ItemIndex >= 0; --ItemIndex)
1508 {
1509 const ItemType& CurItem = Items[ItemIndex];
1511 {
1512 const float ItemLength = GenerateWidgetForItem(CurItem, ItemIndex, StartIndex, LayoutScaleMultiplier);
1513
1514 if (LengthGeneratedSoFar + ItemLength > MyDimensions.ScrollAxis && ItemLength > 0.f)
1515 {
1516 // Generated the item that puts us over the top.
1517 // Count the fraction of this item that will stick out beyond the list
1518 NewScrollOffsetForBackfill = static_cast<double>(ItemIndex) + (LengthGeneratedSoFar + ItemLength - MyDimensions.ScrollAxis) / ItemLength;
1519 }
1520
1521 // The widget used up some of the available vertical space.
1523 }
1524 }
1525
1527 }
1528
1530 }
1531
1532 return FReGenerateResults(0.0f, 0.0f, 0.0f, false);
1533 }
1534
1535 float GenerateWidgetForItem( const ItemType& CurItem, int32 ItemIndex, int32 StartIndex, float LayoutScaleMultiplier )
1536 {
1538 // Find a previously generated Widget for this item, if one exists.
1540 if ( !WidgetForItem.IsValid() )
1541 {
1542 // We couldn't find an existing widgets, meaning that this data item was not visible before.
1543 // Make a new widget for it.
1544 WidgetForItem = this->GenerateNewWidget(CurItem);
1545 }
1546 else
1547 {
1548 if (OnRefreshRow.IsBound())
1549 {
1550 OnRefreshRow.Execute(CurItem);
1551 }
1552 }
1553
1554 // It is useful to know the item's index that the widget was generated from.
1555 // Helps with even/odd coloring
1556 WidgetForItem->SetIndexInList(ItemIndex);
1557
1558 // Let the item generator know that we encountered the current Item and associated Widget.
1559 WidgetGenerator.OnItemSeen( CurItem, WidgetForItem.ToSharedRef() );
1560
1561 // We rely on the widgets desired size in order to determine how many will fit on screen.
1563 NewlyGeneratedWidget->MarkPrepassAsDirty();
1564 NewlyGeneratedWidget->SlatePrepass(LayoutScaleMultiplier);
1565
1566 // We have a widget for this item; add it to the panel so that it is part of the UI.
1567 if (ItemIndex >= StartIndex)
1568 {
1569 // Generating widgets downward
1570 this->AppendWidget( WidgetForItem.ToSharedRef() );
1571 }
1572 else
1573 {
1574 // Backfilling widgets; going upward
1575 this->InsertWidget( WidgetForItem.ToSharedRef() );
1576 }
1577
1578 const bool bIsVisible = NewlyGeneratedWidget->GetVisibility().IsVisible();
1581 }
1582
1584 {
1585 const float LayoutScaleMultiplier = MyGeometry.GetAccumulatedLayoutTransform().GetScale();
1586
1588
1589 // Ensure that we always begin and clean up a generation pass.
1590 FGenerationPassGuard GenerationPassGuard(PinnedWidgetGenerator);
1591
1592 // Check if the User provided an override for MaxPinnedItems, valid until the next time ReGeneratePinnedItems is called
1593 if (MaxPinnedItemsOverride != -1)
1594 {
1596 }
1597 else
1598 {
1599 // Reset it back to the default value if there is no override
1601 }
1602
1604 // There are more items than what we allow to show
1605 if (InItems.Num() > CurrentMaxPinnedItems)
1606 {
1607 bIsHierarchyCollapsed = true;
1608 }
1609 else
1610 {
1611 bIsHierarchyCollapsed = false;
1612 }
1613
1614
1616
1617 for (int32 ItemIndex = 0; ItemIndex < InItems.Num(); ++ItemIndex)
1618 {
1619 GeneratePinnedWidgetForItem(InItems[ItemIndex], ItemIndex, InItems.Num(), LayoutScaleMultiplier);
1620
1621 // Deselect any pinned items that were previously selected, since pinned items can only be navigated to on click and not selected
1623 {
1624 if (InItems[ItemIndex] == SelectorItem)
1625 {
1627 }
1628 }
1629
1630 }
1631
1632 }
1633
1634 void GeneratePinnedWidgetForItem(const ItemType& CurItem, int32 ItemIndex, int32 NumPinnedItems, float LayoutScaleMultiplier)
1635 {
1637 // Find a previously generated Widget for this item, if one exists.
1639 if (!WidgetForItem.IsValid())
1640 {
1641 // We couldn't find an existing widgets, meaning that this data item was not visible before.
1642 // Make a new widget for it.
1643 WidgetForItem = this->GenerateNewPinnedWidget(CurItem, ItemIndex, NumPinnedItems);
1644 }
1645
1646 // It is useful to know the item's index that the widget was generated from.
1647 // Helps with even/odd coloring
1648 WidgetForItem->SetIndexInList(ItemIndex);
1649
1650 // Let the item generator know that we encountered the current Item and associated Widget.
1651 PinnedWidgetGenerator.OnItemSeen(CurItem, WidgetForItem.ToSharedRef());
1652
1653 // We wrap the row widget around an SListViewPinnedRowWidget for custom styling
1655 NewListItemWidget->MarkPrepassAsDirty();
1656 NewListItemWidget->SlatePrepass(LayoutScaleMultiplier);
1657
1658 // We have a widget for this item; add it to the panel so that it is part of the UI.
1659 this->AppendPinnedWidget(NewListItemWidget);
1660 }
1661
1663 virtual int32 GetNumItemsBeingObserved() const override
1664 {
1665 return GetItems().Num();
1666 }
1667
1669 {
1670 if (OnGeneratePinnedRow.IsBound())
1671 {
1672 return OnGeneratePinnedRow.Execute(InItem, SharedThis(this));
1673 }
1674 else
1675 {
1676 // The programmer did not provide an OnGeneratePinnedRow() handler; let them know.
1679 .Content()
1680 [
1681 SNew(STextBlock).Text(NSLOCTEXT("SListView", "OnGeneratePinnedRowNotAssignedMessage", "OnGeneratePinnedRow() not assigned."))
1682 ];
1683
1684 return NewListItemWidget;
1685 }
1686
1687 }
1688
1697 {
1698 if ( OnGenerateRow.IsBound() )
1699 {
1700 return OnGenerateRow.Execute( InItem, SharedThis(this) );
1701 }
1702 else
1703 {
1704 // The programmer did not provide an OnGenerateRow() handler; let them know.
1707 .Content()
1708 [
1709 SNew(STextBlock) .Text( NSLOCTEXT("SListView", "OnGenerateWidgetNotAssignedMessage", "OnGenerateWidget() not assigned.") )
1710 ];
1711
1712 return NewListItemWidget;
1713 }
1714
1715 }
1716
1722 {
1723 ensureMsgf(InListItemsSource, TEXT("The ListItems is invalid."));
1724 if (ViewSource == nullptr || !ViewSource->IsSame(reinterpret_cast<const void*>(InListItemsSource)))
1725 {
1727 {
1729 }
1730 else
1731 {
1733 }
1734 }
1735 }
1736
1743 {
1744 if (ViewSource == nullptr || !ViewSource->IsSame(reinterpret_cast<const void*>(&InListItemsSource.Get())))
1745 {
1747 }
1748 }
1749
1755 {
1756 if (IsConstructed())
1757 {
1760 ClearWidgets();
1761
1762 ViewSource = MoveTemp(Provider);
1763
1764 RebuildList();
1765 }
1766 else
1767 {
1768 ViewSource = MoveTemp(Provider);
1769 }
1770 }
1771
1776
1778 {
1780 }
1781
1782public:
1783
1784 UE_DEPRECATED(5.2, "SetListItemsSource is deprecated. Please use the correct SetItemsSource implementation.")
1789
1791 {
1792 return ViewSource != nullptr;
1793 }
1794
1796 {
1797 return ViewSource ? ViewSource->GetItems() : TArrayView<const ItemType>();
1798 }
1799
1807 const TObjectPtrWrapTypeOf<ItemType>* ItemFromWidget( const ITableRow* WidgetToFind ) const
1808 {
1809 return Private_ItemFromWidget( WidgetToFind );
1810 }
1811
1819 bool IsItemSelected( const ItemType& InItem ) const
1820 {
1822 {
1823 return false;
1824 }
1825
1827 }
1828
1837 {
1839 {
1840 return;
1841 }
1842
1845 }
1846
1855 {
1856 if ( InItems.Num() == 0 || SelectionMode.Get() == ESelectionMode::None )
1857 {
1858 return;
1859 }
1860
1861 for (const ItemType & Item : InItems)
1862 {
1864
1865 // Any item after the first one selected will be direct
1867 }
1869 }
1870
1875 {
1877 {
1878 return;
1879 }
1880
1881 if ( SelectedItems.Num() == 0 )
1882 {
1883 return;
1884 }
1885
1888 }
1889
1890
1891
1902
1910
1917 {
1918 return SelectedItems.Num();
1919 }
1920
1921 virtual void RebuildList() override
1922 {
1923 WidgetGenerator.Clear();
1924 PinnedWidgetGenerator.Clear();
1926 }
1927
1933 virtual TArray< ItemType > GetSelectedItems() const override
1934 {
1937 for( typename TItemSet::TConstIterator SelectedItemIt( SelectedItems ); SelectedItemIt; ++SelectedItemIt )
1938 {
1940 }
1941 return SelectedItemArray;
1942 }
1943
1945 {
1946 SelectedItemArray.Empty(SelectedItems.Num());
1947 for (typename TItemSet::TConstIterator SelectedItemIt(SelectedItems); SelectedItemIt; ++SelectedItemIt)
1948 {
1950 }
1951 return SelectedItems.Num();
1952 }
1953
1961 bool IsItemVisible( ItemType Item ) const
1962 {
1963 return WidgetGenerator.GetWidgetForItem(Item).IsValid();
1964 }
1965
1971 void RequestScrollIntoView( ItemType ItemToView, const uint32 UserIndex = 0)
1972 {
1974 UserRequestingScrollIntoView = UserIndex;
1976 }
1977
1978 UE_DEPRECATED(4.20, "RequestScrollIntoView no longer takes parameter bNavigateOnScrollIntoView. Call RequestNavigateToItem instead of RequestScrollIntoView if navigation is required.")
1980 {
1982 {
1984 }
1985 else
1986 {
1988 }
1989 }
1990
1996 void RequestNavigateToItem(ItemType Item, const uint32 UserIndex = 0)
1997 {
1999 if (FirstValidItem.IsSet())
2000 {
2001 Private_RequestNavigateToItem(FirstValidItem.GetValue(), UserIndex);
2002 }
2003 }
2004
2005private:
2006 void Private_RequestNavigateToItem(ItemType Item, const uint32 UserIndex)
2007 {
2009 RequestScrollIntoView(Item, UserIndex);
2010 }
2011
2012public:
2013
2023
2038
2039private:
2040 void Private_SetSelection(ItemType SoleSelectedItem, ESelectInfo::Type SelectInfo)
2041 {
2042 SelectedItems.Empty();
2044 }
2045
2046public:
2047
2054 {
2058 if (PreviousMode != NewMode)
2059 {
2061 {
2063 }
2065 {
2066 // We've gone to a single-selection mode, so if we already had a single item selected, preserve it
2067 if (SelectedItems.Num() == 1)
2068 {
2069 SetSelection(*SelectedItems.CreateIterator());
2070 }
2071 else
2072 {
2073 // Otherwise, there's no way to know accurately which item was selected most recently, so just wipe it all
2074 // The caller responsible for changing the mode can decide themselves which item they want to be selected
2076 }
2077 }
2078 }
2079 }
2080
2081 /* Sets ScrollIntoViewAlignment which allows to stick the selected item to either side or center */
2086
2094 virtual TSharedPtr<ITableRow> WidgetFromItem( const ItemType& InItem ) const override
2095 {
2097
2098 return ItemWidget != nullptr ? ItemWidget : PinnedWidgetGenerator.GetWidgetForItem(InItem);
2099 }
2100
2108 {
2109 TListTypeTraits<ItemType>::AddReferencedObjects( Collector, WidgetGenerator.ItemsWithGeneratedWidgets, SelectedItems, WidgetGenerator.WidgetMapToItem );
2110 }
2111 virtual FString GetReferencerName() const
2112 {
2113 return TEXT("SListView");
2114 }
2115
2125 {
2127
2128 for (auto It = WidgetGenerator.WidgetMapToItem.CreateConstIterator(); It; ++It)
2129 {
2130 const ITableRow* TableRow = It.Key();
2131 FVector2D NewMaxSize = TableRow->GetRowSizeForColumn(ColumnId);
2132
2133 // We'll return the full size, but we only take into consideration the asked axis for the calculation of the size
2134 if (NewMaxSize.Component(ColumnOrientation) > MaxSize.Component(ColumnOrientation))
2135 {
2137 }
2138 }
2139
2140 return MaxSize;
2141 }
2142
2143protected:
2144
2146 {
2147 return FOnItemToString_Debug::CreateStatic(TListTypeTraits<ItemType>::DebugDump);
2148 }
2149
2156 {
2158 {
2159 const TArrayView<const ItemType> Items = GetItems();
2161 if (IndexOfItem != INDEX_NONE)
2162 {
2164 if (NumLiveWidgets == 0. && IsPendingRefresh())
2165 {
2166 // Use the last number of widgets on screen to estimate if we actually need to scroll.
2168
2169 // If we still don't have any widgets, we're not in a situation where we can scroll an item into view
2170 // (probably as nothing has been generated yet), so we'll defer this again until the next frame
2171 if (NumLiveWidgets == 0)
2172 {
2174 }
2175 }
2176
2178
2179 const int32 NumFullEntriesInView = (int32)(FMath::FloorToDouble(CurrentScrollOffset + NumLiveWidgets) - FMath::CeilToDouble(CurrentScrollOffset));
2180
2181 // Only scroll the item into view if it's not already in the visible range
2182 // When navigating, we don't want to scroll partially visible existing rows all the way to the center, so we count partially displayed indices in the displayed range
2183 const double MinDisplayedIndex = bNavigateOnScrollIntoView ? FMath::FloorToDouble(CurrentScrollOffset) : FMath::CeilToDouble(CurrentScrollOffset);
2188 {
2189 // Scroll the top of the listview to the item in question
2190 double NewScrollOffset = IndexOfItem;
2191
2193 {
2195 // Center the list view on the item in question.
2196 NewScrollOffset -= (NumLiveWidgets / 2.0);
2197 break;
2198
2201 {
2202 // Bring the new item in question to the bottom
2203 NewScrollOffset -= (NumLiveWidgets - 1.0);
2204 }
2205
2206 // The alternative is that IndexOfItem < MinDisplayedIndex, and NewScrollOffset is already correct for that case
2207 break;
2208
2210 // Set NewScrollOffset to exactly IndexOfItem to ensure it's at the top/left
2211 NewScrollOffset = IndexOfItem;
2212 break;
2213
2215 // Set NewScrollOffset to position the item at the bottom/right
2216 NewScrollOffset = IndexOfItem - (NumLiveWidgets - 1.0);
2217 break;
2218 }
2219
2220 // Limit offset to top and bottom of the list.
2221 const double MaxScrollOffset = FMath::Max(0.0, static_cast<double>(Items.Num()) - NumLiveWidgets);
2222 NewScrollOffset = FMath::Clamp<double>(NewScrollOffset, 0.0, MaxScrollOffset);
2223
2224 SetScrollOffset((float)NewScrollOffset);
2225 }
2227 {
2229 {
2230 const FGeometry& WidgetGeometry = TableRow->AsWidget()->GetCachedGeometry();
2233
2234 double NewScrollOffset = DesiredScrollOffset;
2235 // Make sure the existing entry for this item is fully in view
2236 if (WidgetTopLeft.ScrollAxis < ListViewTopLeft.ScrollAxis)
2237 {
2238 // This entry is clipped at the top/left, so simply set it as the new scroll offset target to bump it down into view
2239 NewScrollOffset = static_cast<double>(IndexOfItem) - NavigationScrollOffset;
2240 }
2241 else
2242 {
2243 const FVector2D BottomRight(1.f, 1.f);
2246
2247 if (WidgetBottomRight.ScrollAxis > ListViewBottomRight.ScrollAxis)
2248 {
2249 // This entry is clipped at the end, so we need to determine the exact item offset required to get it fully into view
2250 // To do so, we need to push the current offset down by the clipped amount translated into number of items
2251 float DistanceRemaining = WidgetBottomRight.ScrollAxis - ListViewBottomRight.ScrollAxis;
2252 float AdditionalOffset = 0.f;
2253 for (const ItemType& ItemWithWidget : WidgetGenerator.ItemsWithGeneratedWidgets)
2254 {
2255 FTableViewDimensions WidgetAbsoluteDimensions(this->Orientation, WidgetGenerator.GetWidgetForItem(ItemWithWidget)->AsWidget()->GetCachedGeometry().GetAbsoluteSize());
2256 if (WidgetAbsoluteDimensions.ScrollAxis < DistanceRemaining)
2257 {
2259 AdditionalOffset += 1.f;
2260 }
2261 else
2262 {
2264 DistanceRemaining = 0.f;
2265 break;
2266 }
2267 }
2268
2270 }
2271 }
2272
2273 SetScrollOffset((float)NewScrollOffset);
2274 }
2275 }
2276
2278
2280 }
2281
2283 }
2284
2286 {
2287 if (this->bEnableAnimatedScrolling)
2288 {
2289 // When we have a target item we're shooting for, we haven't succeeded with the scroll until a widget for it exists
2292 }
2293 }
2294 else
2295 {
2297 }
2299 }
2300
2326
2327 virtual void NotifyFinishedScrolling() override
2328 {
2329 OnFinishedScrolling.ExecuteIfBound();
2330 }
2331
2333 {
2334 auto DoubleFractional = [](double Value) -> double
2335 {
2336 return Value - FMath::TruncToDouble(Value);
2337 };
2338
2340 {
2341 //check if we are on the top of the list and want to scroll up
2343 {
2344 return 0.0f;
2345 }
2346
2347 //check if we are on the bottom of the list and want to scroll down
2349 {
2350 return 0.0f;
2351 }
2352 }
2353
2354 float AbsScrollByAmount = FMath::Abs( ScrollByAmountInSlateUnits );
2356 double NewScrollOffset = DesiredScrollOffset;
2357
2360 {
2363 if (ActuallyScrolledBy != 0.0f)
2364 {
2365 this->RequestLayoutRefresh();
2366 }
2367 return ActuallyScrolledBy;
2368 }
2369 else if (!bWholeListVisible)
2370 {
2371 // We know how far we want to scroll in SlateUnits, but we store scroll offset in "number of widgets".
2372 // Challenge: each widget can be a different height/width.
2373 // Strategy:
2374 // Scroll "one widget's length" at a time until we've scrolled as far as the user asked us to.
2375 // Generate widgets on demand so we can figure out how big they are.
2376
2377 const TArrayView<const ItemType> Items = GetItems();
2378 if (Items.Num() > 0)
2379 {
2380 int32 ItemIndex = StartingItemIndex;
2381 const float LayoutScaleMultiplier = MyGeometry.GetAccumulatedLayoutTransform().GetScale();
2382 while( AbsScrollByAmount != 0 && ItemIndex < Items.Num() && ItemIndex >= 0 )
2383 {
2384 const ItemType& CurItem = Items[ItemIndex];
2386 {
2387 // If the CurItem is not valid, we do not generate a new widget for it, we skip it.
2388 ++ItemIndex;
2389 continue;
2390 }
2391
2393 if (!RowWidget.IsValid())
2394 {
2395 // We couldn't find an existing widgets, meaning that this data item was not visible before.
2396 // Make a new widget for it.
2397 RowWidget = this->GenerateNewWidget( CurItem );
2398
2399 // It is useful to know the item's index that the widget was generated from.
2400 // Helps with even/odd coloring
2401 RowWidget->SetIndexInList(ItemIndex);
2402
2403 // Let the item generator know that we encountered the current Item and associated Widget.
2404 WidgetGenerator.OnItemSeen( CurItem, RowWidget.ToSharedRef() );
2405
2406 RowWidget->AsWidget()->SlatePrepass(LayoutScaleMultiplier);
2407 }
2408
2409 const FTableViewDimensions WidgetDimensions(this->Orientation, RowWidget->AsWidget()->GetDesiredSize());
2411 {
2412 const float RemainingDistance = WidgetDimensions.ScrollAxis * (float)(1.0 - DoubleFractional(NewScrollOffset));
2413
2415 {
2416 if (ItemIndex != Items.Num())
2417 {
2419 NewScrollOffset = 1.0 + (int32)NewScrollOffset;
2420 ++ItemIndex;
2421 }
2422 else
2423 {
2424 NewScrollOffset = Items.Num();
2425 break;
2426 }
2427 }
2429 {
2430 NewScrollOffset = 1.0 + (int32)NewScrollOffset;
2431 break;
2432 }
2433 else
2434 {
2435 NewScrollOffset = (int32)NewScrollOffset + (1.0 - ((RemainingDistance - AbsScrollByAmount) / WidgetDimensions.ScrollAxis));
2436 break;
2437 }
2438 }
2439 else
2440 {
2441 float Fractional = FMath::Fractional( (float)NewScrollOffset );
2442 if ( FMath::IsNearlyEqual(Fractional, 0.f) )
2443 {
2444 Fractional = 1.0f;
2445 --NewScrollOffset;
2446 }
2447
2448 const float PrecedingDistance = WidgetDimensions.ScrollAxis * Fractional;
2449
2451 {
2452 if ( ItemIndex != 0 )
2453 {
2455 NewScrollOffset -= DoubleFractional( NewScrollOffset );
2456 --ItemIndex;
2457 }
2458 else
2459 {
2460 NewScrollOffset = 0.0;
2461 break;
2462 }
2463 }
2465 {
2466 NewScrollOffset -= DoubleFractional( NewScrollOffset );
2467 break;
2468 }
2469 else
2470 {
2471 NewScrollOffset = float(FMath::TruncToInt32(NewScrollOffset)) + ((PrecedingDistance - AbsScrollByAmount) / WidgetDimensions.ScrollAxis);
2472 break;
2473 }
2474 }
2475 }
2476 }
2477
2478
2479 return ScrollTo( (float)NewScrollOffset );
2480 }
2481
2482 return 0;
2483 }
2484
2485protected:
2486
2488 {
2489 ItemType ItemToSelect = InItemToSelect;
2490
2491 if (OnIsSelectableOrNavigable.IsBound())
2492 {
2493 // Walk through the list until we either find a navigable item or run out of entries.
2494 const TArrayView<const ItemType> Items = GetItems();
2495 while (!OnIsSelectableOrNavigable.Execute(ItemToSelect))
2496 {
2497 SelectionIdx += (bSelectForward ? 1 : -1);
2498 if (Items.IsValidIndex(SelectionIdx))
2499 {
2500 ItemToSelect = Items[SelectionIdx];
2501 }
2502 else
2503 {
2504 // Failed to find a valid item to select
2505 return TOptional<ItemType>();
2506 }
2507 }
2508 }
2509
2511 }
2512
2514 {
2515 ItemType ItemToSelect = InItemToSelect;
2516
2517 if (OnIsSelectableOrNavigable.IsBound())
2518 {
2520 {
2521 const TArrayView<const ItemType> Items = GetItems();
2523
2524 // By default, we walk forward
2525 bool bSelectNextItem = true;
2526 if (SelectedItems.Num() == 1)
2527 {
2528 // If the last selected item is after the item to select, we'll want to walk backwards
2531 {
2534
2536 }
2537 }
2538
2539 // Walk through the list until we either find a navigable item or run out of entries.
2540 do
2541 {
2542 NewSelectionIdx += (bSelectNextItem ? 1 : -1);
2543 if (Items.IsValidIndex(NewSelectionIdx))
2544 {
2546 }
2547 else
2548 {
2549 // Failed to find a valid item to select
2550 return TOptional<ItemType>();
2551 }
2552 } while (!OnIsSelectableOrNavigable.Execute(ItemToSelect));
2553 }
2554 }
2555
2557 }
2558
2566 virtual void NavigationSelect(const ItemType& InItemToSelect, const FInputEvent& InInputEvent)
2567 {
2569 if (!ItemToSelect.IsSet())
2570 {
2571 return;
2572 }
2573
2575
2577 {
2578 // Must be set before signaling selection changes because sometimes new items will be selected that need to stomp this value
2579 SelectorItem = ItemToSelect.GetValue();
2580
2581 // Always request scroll into view, otherwise partially visible items will be selected - also do this before signaling selection for similar stomp-allowing reasons
2582 Private_RequestNavigateToItem(ItemToSelect.GetValue(), InInputEvent.GetUserIndex());
2583
2585 {
2586 if (CurrentSelectionMode == ESelectionMode::Multi && (InInputEvent.IsShiftDown() || InInputEvent.IsControlDown()))
2587 {
2588 // Range select.
2589 if (InInputEvent.IsShiftDown())
2590 {
2591 // Holding control makes the range select bidirectional, where as it is normally unidirectional.
2592 if (!(InInputEvent.IsControlDown()))
2593 {
2594 this->Private_ClearSelection();
2595 }
2596
2597 this->Private_SelectRangeFromCurrentTo(ItemToSelect.GetValue());
2598 }
2599 // For ctrl select, simply add the item to the list of currently selected items
2600 else
2601 {
2602 this->Private_SetItemSelection(ItemToSelect.GetValue(), true, true);
2603 }
2604
2606 }
2607 else
2608 {
2609 // Single select.
2610 this->Private_SetSelection(ItemToSelect.GetValue(), ESelectInfo::OnNavigation);
2611 }
2612 }
2613 }
2614 }
2615
2620 {
2622
2623 // If the navigation requested a scroll into view, then set navigation type
2625 }
2626
2627
2628protected:
2631
2634
2637
2640
2643
2646
2649
2652
2653
2654 FOnWidgetToBeRemoved OnRowReleased;
2655
2658
2661
2664
2667
2670
2673
2674 UE_DEPRECATED(5.2, "Protected access to ItemsSource is deprecated. Please use GetItems, SetItemsSource or HasValidItemsSource.")
2676 const TArray<ItemType>* ItemsSource;
2677
2680
2683
2686
2689
2692
2695
2698
2701
2704
2707
2710
2713
2716
2719
2722
2725
2728
2731
2734
2737
2740
2743
2746
2747private:
2749 TUniquePtr<UE::Slate::ItemsSource::IItemsSource<ItemType>> ViewSource;
2750
2751private:
2752 struct FGenerationPassGuard
2753 {
2754 FWidgetGenerator& Generator;
2755 FGenerationPassGuard( FWidgetGenerator& InGenerator )
2756 : Generator(InGenerator)
2757 {
2758 // Let the WidgetGenerator that we are starting a pass so that it can keep track of data items and widgets.
2759 Generator.OnBeginGenerationPass();
2760 }
2761
2762 ~FGenerationPassGuard()
2763 {
2764 // We have completed the generation pass. The WidgetGenerator will clean up unused Widgets when it goes out of scope.
2765 Generator.OnEndGenerationPass();
2766 }
2767 };
2768};
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
#define UPTRINT_x_FMT
Definition AndroidPlatformString.h:54
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
#define ensure( InExpression)
Definition AssertionMacros.h:464
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
TSharedRef< InObjectType, InMode > MakeShared(InArgTypes &&... Args)
Definition SharedPointer.h:2009
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define SLATE_STYLE_ARGUMENT(ArgType, ArgName)
Definition DeclarativeSyntaxSupport.h:280
#define SNew(WidgetType,...)
Definition DeclarativeSyntaxSupport.h:37
#define SLATE_ATTRIBUTE(AttrType, AttrName)
Definition DeclarativeSyntaxSupport.h:192
#define SLATE_BEGIN_ARGS(InWidgetType)
Definition DeclarativeSyntaxSupport.h:63
#define SLATE_ATTRIBUTE_DEPRECATED(AttrType, AttrName, DeprecationVersion, DeprecationMessage)
Definition DeclarativeSyntaxSupport.h:199
#define SLATE_EVENT(DelegateName, EventName)
Definition DeclarativeSyntaxSupport.h:458
#define SLATE_END_ARGS()
Definition DeclarativeSyntaxSupport.h:116
#define SLATE_ARGUMENT(ArgType, ArgName)
Definition DeclarativeSyntaxSupport.h:208
EFocusCause
Definition Events.h:25
return true
Definition ExternalRpcRegistry.cpp:601
#define PRAGMA_ENABLE_DEPRECATION_WARNINGS
Definition GenericPlatformCompilerPreSetup.h:12
#define PRAGMA_DISABLE_DEPRECATION_WARNINGS
Definition GenericPlatformCompilerPreSetup.h:8
#define SLATE_ITEMS_SOURCE_ARGUMENT(ArgType, ArgName)
Definition IItemsSource.h:20
#define NSLOCTEXT(InNamespace, InKey, InTextLiteral)
Definition Internationalization.h:300
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
typename UE::Core::Private::TObjectPtrWrapTypeOf< T >::Type TObjectPtrWrapTypeOf
Definition ObjectPtr.h:1761
EAllowOverscroll
Definition Overscroll.h:12
virtual FReply OnMouseButtonDown(const FGeometry &MyGeometry, const FPointerEvent &MouseEvent)
EScrollIntoViewAlignment
Definition STableViewBase.h:60
EAccessibleType
Definition SWidget.h:76
USkinnedMeshComponent float
Definition SkinnedMeshComponent.h:60
float GetGlobalScrollAmount()
Definition SlateConstants.h:10
EOrientation
Definition SlateEnums.h:261
EUINavigation
Definition SlateEnums.h:99
EConsumeMouseWheel
Definition SlateTypes.h:26
UE_FORCEINLINE_HINT TUniquePtr< T > MakeUnique(TArgs &&... Args)
Definition UniquePtr.h:918
#define UE_KINDA_SMALL_NUMBER
Definition UnrealMathUtility.h:131
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition AppStyle.h:24
static SLATECORE_API const ISlateStyle & Get()
Definition AppStyle.cpp:10
Definition ContainerAllocationPolicies.h:1660
SLATE_API void ClearScrollVelocity(bool bInShouldStopScrollNow=false)
Definition InertialScrollManager.cpp:78
Definition NameTypes.h:617
Definition NavigationReply.h:43
static FNavigationReply Explicit(TSharedPtr< SWidget > InFocusRecipient)
Definition NavigationReply.h:63
Definition UObjectGlobals.h:2492
bool IsEventHandled() const
Definition ReplyBase.h:19
Definition Reply.h:24
static FReply Unhandled()
Definition Reply.h:241
static FReply Handled()
Definition Reply.h:233
static FSlateApplicationBase & Get()
Definition SlateApplicationBase.h:552
static SLATECORE_API const FSlateBrush * GetNoBrush()
Definition StyleDefaults.cpp:6
static CORE_API FText FromString(const ANSICHAR *String)
Definition Text.cpp:1081
virtual const FSlateBrush * GetBrush(const FName PropertyName, const ANSICHAR *Specifier=nullptr, const ISlateStyle *RequestingStyle=nullptr) const =0
Definition ITableRow.h:15
Definition ITypedTableView.h:48
Definition SBorder.h:31
Definition SCompoundWidget.h:22
FCompoundWidgetOneChildSlot ChildSlot
Definition SCompoundWidget.h:113
Definition SHeaderRow.h:103
Definition SBoxPanel.h:171
static FSlot::FSlotArguments Slot()
Definition SBoxPanel.h:272
Definition SImage.h:29
Definition SListView.h:66
void SetShadowBoxStyle(const FScrollBoxStyle *InScrollBoxStyle)
Definition SListView.h:1334
TOptional< ItemType > Private_FindNextSelectableOrNavigableWithIndexAndDirection(const ItemType &InItemToSelect, int32 SelectionIdx, bool bSelectForward)
Definition SListView.h:2487
TItemSet HighlightedItems
Definition SListView.h:2672
void SetListItemsSource(const TArray< ItemType > &InListItemsSource)
Definition SListView.h:1785
bool IsItemSelected(const ItemType &InItem) const
Definition SListView.h:1819
virtual void Private_OnItemRightClicked(ItemType TheItem, const FPointerEvent &MouseEvent) override
Definition SListView.h:1148
virtual FString GetReferencerName() const
Definition SListView.h:2111
bool HasValidItemsSource() const
Definition SListView.h:1790
virtual const TObjectPtrWrapTypeOf< ItemType > * Private_ItemFromWidget(const ITableRow *TheWidget) const override
Definition SListView.h:1042
TAttribute< int32 > DefaultMaxPinnedItems
Definition SListView.h:2742
TArrayView< const ItemType > GetItems() const
Definition SListView.h:1795
virtual void Private_OnExpanderArrowShiftClicked(ItemType TheItem, bool bShouldBeExpanded) override
Definition SListView.h:1084
void SetScrollIntoViewAlignment(EScrollIntoViewAlignment NewScrollIntoViewAlignment)
Definition SListView.h:2082
FOnGenerateRow OnGeneratePinnedRow
Definition SListView.h:2642
void SetItemSelection(const ItemType &InItem, bool bSelected, ESelectInfo::Type SelectInfo=ESelectInfo::Direct)
Definition SListView.h:1836
void SetSelection(ItemType SoleSelectedItem, ESelectInfo::Type SelectInfo=ESelectInfo::Direct)
Definition SListView.h:2030
FOnKeyDown OnKeyDownHandler
Definition SListView.h:2703
void SetStyle(const FTableViewStyle *InStyle)
Definition SListView.h:1328
FOnRefreshRow OnRefreshRow
Definition SListView.h:2645
PRAGMA_DISABLE_DEPRECATION_WARNINGS SListView(ETableViewMode::Type InListMode=ETableViewMode::List)
Definition SListView.h:327
virtual bool SupportsKeyboardFocus() const override
Definition SListView.h:351
TOptional< ItemType > Private_FindNextSelectableOrNavigable(const ItemType &InItemToSelect)
Definition SListView.h:2513
typename TListTypeTraits< ItemType >::NullableType NullableItemType
Definition SListView.h:68
void SetSelectionMode(const TAttribute< ESelectionMode::Type > &NewSelectionMode)
Definition SListView.h:2053
friend class SListViewPinnedRowWidget
Definition SListView.h:1185
virtual void Private_SignalSelectionChanged(ESelectInfo::Type SelectInfo) override
Definition SListView.h:1025
virtual bool Private_UsesSelectorFocus() const override
Definition SListView.h:1048
virtual void Private_SetItemExpansion(ItemType TheItem, bool bShouldBeExpanded) override
Definition SListView.h:1079
void ReGeneratePinnedItems(const TArray< ItemType > &InItems, const FGeometry &MyGeometry, int32 MaxPinnedItemsOverride=-1)
Definition SListView.h:1583
virtual void Private_ClearHighlightedItems() override
Definition SListView.h:1112
FOnItemToString_Debug OnItemToString_Debug
Definition SListView.h:2648
NullableItemType RangeSelectionStart
Definition SListView.h:2669
FIsSelectableOrNavigable OnIsSelectableOrNavigable
Definition SListView.h:2694
void BindToRefreshRow(const FOnRefreshRow &Binding)
Definition SListView.h:1777
const TObjectPtrWrapTypeOf< ItemType > * ItemFromWidget(const ITableRow *WidgetToFind) const
Definition SListView.h:1807
FOnEntryInitialized OnEntryInitialized
Definition SListView.h:2636
virtual bool Private_DoesItemHaveChildren(int32 ItemIndexInList) const override
Definition SListView.h:1089
virtual EScrollIntoViewResult ScrollIntoView(const FGeometry &ListViewGeometry) override
Definition SListView.h:2155
static FOnItemToString_Debug GetDefaultDebugDelegate()
Definition SListView.h:2145
void RequestScrollIntoView(ItemType ItemToView, const uint32 UserIndex=0)
Definition SListView.h:1971
typename TSlateDelegates< ItemType >::FOnItemScrolledIntoView FOnItemScrolledIntoView
Definition SListView.h:76
FWidgetGenerator WidgetGenerator
Definition SListView.h:2630
FOnWidgetToBeRemoved OnRowReleased
Definition SListView.h:2654
TAttribute< bool > IsFocusable
Definition SListView.h:2706
int32 GetSelectedItems(TArray< ItemType > &SelectedItemArray) const
Definition SListView.h:1944
NullableItemType ItemToScrollIntoView
Definition SListView.h:2679
virtual void NavigationSelect(const ItemType &InItemToSelect, const FNavigationEvent &InNavigationEvent)
Definition SListView.h:2619
bool IsItemVisible(ItemType Item) const
Definition SListView.h:1961
typename TSlateDelegates< NullableItemType >::FOnSelectionChanged FOnSelectionChanged
Definition SListView.h:77
DECLARE_DELEGATE_OneParam(FOnWidgetToBeRemoved, const TSharedRef< ITableRow > &)
virtual void Private_ClearSelection() override
Definition SListView.h:974
typename TSlateDelegates< ItemType >::FOnGenerateRow FOnGenerateRow
Definition SListView.h:74
typename TListTypeTraits< ItemType >::MapKeyFuncsSparse MapKeyFuncsSparse
Definition SListView.h:70
FOnItemScrolledIntoView OnItemScrolledIntoView
Definition SListView.h:2657
virtual ESelectionMode::Type Private_GetSelectionMode() const override
Definition SListView.h:1133
const FTableViewStyle * Style
Definition SListView.h:2736
NullableItemType SelectorItem
Definition SListView.h:2666
FOnMouseButtonClick OnClick
Definition SListView.h:2697
virtual bool Private_IsPendingRefresh() const override
Definition SListView.h:1143
FOnMouseButtonDoubleClick OnDoubleClick
Definition SListView.h:2700
void CancelScrollIntoView()
Definition SListView.h:2017
FOnTableViewBadState OnEnteredBadState
Definition SListView.h:2651
virtual void Private_SelectRangeFromCurrentTo(ItemType InRangeSelectionEnd) override
Definition SListView.h:984
float GenerateWidgetForItem(const ItemType &CurItem, int32 ItemIndex, int32 StartIndex, float LayoutScaleMultiplier)
Definition SListView.h:1535
void Private_OnEntryInitialized(ItemType TheItem, const TSharedRef< ITableRow > &TableRow)
Definition SListView.h:921
bool bNavigateOnScrollIntoView
Definition SListView.h:2730
bool bHandleDirectionalNavigation
Definition SListView.h:2718
FVector2D GetMaxRowSizeForColumn(const FName &ColumnId, EOrientation ColumnOrientation)
Definition SListView.h:2124
virtual void NotifyFinishedScrolling() override
Definition SListView.h:2327
typename TSlateDelegates< ItemType >::FOnMouseButtonDoubleClick FOnMouseButtonDoubleClick
Definition SListView.h:80
EUINavigation NavigationTypeOnScrollIntoView
Definition SListView.h:2733
virtual void Private_SetItemSelection(ItemType TheItem, bool bShouldBeSelected, bool bWasUserDirected=false) override
Definition SListView.h:926
const TArray< ItemType > * ItemsSource
Definition SListView.h:2676
virtual EOrientation Private_GetOrientation() const override
Definition SListView.h:1138
virtual bool Private_IsItemSelectableOrNavigable(const ItemType &TheItem) const override
Definition SListView.h:1074
void SetItemsSource(const TArray< ItemType > *InListItemsSource)
Definition SListView.h:1721
void SetItemsSource(TUniquePtr< UE::Slate::ItemsSource::IItemsSource< ItemType > > Provider)
Definition SListView.h:1754
virtual void Private_SetItemHighlighted(ItemType TheItem, bool bShouldBeHighlighted) override
Definition SListView.h:1100
FOnGenerateRow OnGenerateRow
Definition SListView.h:2639
void GeneratePinnedWidgetForItem(const ItemType &CurItem, int32 ItemIndex, int32 NumPinnedItems, float LayoutScaleMultiplier)
Definition SListView.h:1634
virtual bool Private_IsItemSelected(const ItemType &TheItem) const override
Definition SListView.h:1058
virtual bool Private_IsItemExpanded(const ItemType &TheItem) const override
Definition SListView.h:1068
virtual TSharedRef< SWidget > AsWidget() override
Definition SListView.h:1178
DECLARE_DELEGATE_TwoParams(FOnEntryInitialized, ItemType, const TSharedRef< ITableRow > &)
virtual int32 GetNumItemsBeingObserved() const override
Definition SListView.h:1663
virtual bool Private_IsLastChild(int32 ItemIndexInList) const override
Definition SListView.h:1128
virtual void UpdateSelectionSet() override
Definition SListView.h:1348
virtual bool Private_OnItemDoubleClicked(ItemType TheItem) override
Definition SListView.h:1163
void Construct(const typename SListView< ItemType >::FArguments &InArgs)
Definition SListView.h:230
TItemSet SelectedItems
Definition SListView.h:2663
EScrollIntoViewAlignment ScrollIntoViewAlignment
Definition SListView.h:2688
virtual FReply OnMouseButtonUp(const FGeometry &MyGeometry, const FPointerEvent &MouseEvent) override
Definition SListView.h:596
virtual bool Private_IsItemHighlighted(const ItemType &TheItem) const override
Definition SListView.h:1063
bool bClearScrollVelocityOnSelection
Definition SListView.h:2727
void SetItemSelection(TConstArrayView< ItemType > InItems, bool bSelected, ESelectInfo::Type SelectInfo=ESelectInfo::Direct)
Definition SListView.h:1854
FOnFinishedScrolling OnFinishedScrolling
Definition SListView.h:2660
virtual TSharedRef< ITableRow > GenerateNewPinnedWidget(ItemType InItem, const int32 ItemIndex, const int32 NumPinnedItems)
Definition SListView.h:1668
FReply OnKeyDown_Internal(const FGeometry &MyGeometry, const FKeyEvent &InKeyEvent)
Definition SListView.h:370
SLATE_BEGIN_ARGS(SListView< ItemType >)
Definition SListView.h:89
friend class FWidgetGenerator
Definition SListView.h:709
virtual void RebuildList() override
Definition SListView.h:1921
virtual void NotifyItemScrolledIntoView() override
Definition SListView.h:2301
NullableItemType ItemToNotifyWhenInView
Definition SListView.h:2685
bool bReturnFocusToSelection
Definition SListView.h:2724
void SetItemHighlighted(const ItemType &TheItem, bool bHighlighted)
Definition SListView.h:1898
virtual const TBitArray & Private_GetWiresNeededByDepth(int32 ItemIndexInList) const override
Definition SListView.h:1123
void ClearSelection()
Definition SListView.h:1874
void ClearItemsSource()
Definition SListView.h:1772
virtual FReply OnKeyDown(const FGeometry &MyGeometry, const FKeyEvent &InKeyEvent) override
Definition SListView.h:356
virtual bool Private_OnItemClicked(ItemType TheItem) override
Definition SListView.h:1153
virtual float ScrollBy(const FGeometry &MyGeometry, float ScrollByAmountInSlateUnits, EAllowOverscroll InAllowOverscroll) override
Definition SListView.h:2332
virtual TSharedPtr< ITableRow > WidgetFromItem(const ItemType &InItem) const override
Definition SListView.h:2094
void SetItemsSource(TSharedRef<::UE::Slate::Containers::TObservableArray< ItemType > > InListItemsSource)
Definition SListView.h:1742
virtual FNavigationReply OnNavigation(const FGeometry &MyGeometry, const FNavigationEvent &InNavigationEvent) override
Definition SListView.h:512
virtual int32 Private_GetNumSelectedItems() const override
Definition SListView.h:1095
TSlateDelegates< ItemType >::FOnItemToString_Debug FOnItemToString_Debug
Definition SListView.h:82
FOnSelectionChanged OnSelectionChanged
Definition SListView.h:2691
int32 GetNumItemsSelected() const
Definition SListView.h:1916
virtual void NavigationSelect(const ItemType &InItemToSelect, const FInputEvent &InInputEvent)
Definition SListView.h:2566
void ClearHighlightedItems()
Definition SListView.h:1906
uint32 UserRequestingScrollIntoView
Definition SListView.h:2682
bool bHandleGamepadEvents
Definition SListView.h:2715
virtual TArray< ItemType > GetSelectedItems() const override
Definition SListView.h:1933
typename TSlateDelegates< ItemType >::FOnRefreshRow FOnRefreshRow
Definition SListView.h:75
TAttribute< int32 > MaxPinnedItems
Definition SListView.h:2739
virtual FReGenerateResults ReGenerateItems(const FGeometry &MyGeometry) override
Definition SListView.h:1395
virtual TSharedRef< ITableRow > GenerateNewWidget(ItemType InItem)
Definition SListView.h:1696
typename TListTypeTraits< ItemType >::MapKeyFuncs MapKeyFuncs
Definition SListView.h:69
virtual FReply OnMouseButtonDown(const FGeometry &MyGeometry, const FPointerEvent &MouseEvent) override
Definition SListView.h:573
typename TSlateDelegates< ItemType >::FOnMouseButtonClick FOnMouseButtonClick
Definition SListView.h:79
virtual ETableViewMode::Type GetTableViewMode() const override
Definition SListView.h:1173
FWidgetGenerator PinnedWidgetGenerator
Definition SListView.h:2633
float NavigationScrollOffset
Definition SListView.h:2709
bool bClearSelectionOnClick
Definition SListView.h:2712
virtual bool Private_HasSelectorFocus(const ItemType &TheItem) const override
Definition SListView.h:1053
bool bIsHierarchyCollapsed
Definition SListView.h:2745
bool bHandleSpacebarSelection
Definition SListView.h:2721
virtual int32 Private_GetNestingDepth(int32 ItemIndexInList) const override
Definition SListView.h:1117
TSet< TObjectPtrWrapTypeOf< ItemType >, typename TListTypeTraits< TObjectPtrWrapTypeOf< ItemType > >::SetKeyFuncs > TItemSet
Definition SListView.h:72
virtual void AddReferencedObjects(FReferenceCollector &Collector)
Definition SListView.h:2107
void SetOnEntryInitialized(const FOnEntryInitialized &Delegate)
Definition SListView.h:1340
typename TSlateDelegates< ItemType >::FIsSelectableOrNavigable FIsSelectableOrNavigable
Definition SListView.h:78
void RequestNavigateToItem(ItemType Item, const uint32 UserIndex=0)
Definition SListView.h:1996
Definition SOverlay.h:44
static SLATECORE_API FOverlaySlot::FSlotArguments Slot(int32 ZOrder=0)
Definition SOverlay.cpp:120
Definition SScrollBar.h:29
void SetUserVisibility(TAttribute< EVisibility > InUserVisibility)
Definition SScrollBar.h:136
SLATE_API void SetDragFocusCause(EFocusCause InDragFocusCause)
Definition SScrollBar.cpp:394
Definition STableRow.h:87
Definition STableViewBase.h:110
virtual SLATE_API float GetNumLiveWidgets() const
Definition STableViewBase.cpp:1242
virtual SLATE_API FReply OnMouseButtonDown(const FGeometry &MyGeometry, const FPointerEvent &MouseEvent) override
Definition STableViewBase.cpp:526
TAttribute< ESelectionMode::Type > SelectionMode
Definition STableViewBase.h:526
const FScrollBoxStyle * ShadowBoxStyle
Definition STableViewBase.h:559
SLATE_API void AppendWidget(const TSharedRef< ITableRow > &WidgetToAppend)
Definition STableViewBase.cpp:1173
TSharedPtr< SHeaderRow > HeaderRow
Definition STableViewBase.h:529
FOverscroll Overscroll
Definition STableViewBase.h:586
FMargin ScrollBarSlotPadding
Definition STableViewBase.h:446
FReGenerateResults LastGenerateResults
Definition STableViewBase.h:511
virtual SLATE_API FReply OnMouseButtonUp(const FGeometry &MyGeometry, const FPointerEvent &MouseEvent) override
Definition STableViewBase.cpp:567
double DesiredScrollOffset
Definition STableViewBase.h:496
virtual SLATE_API FReply OnKeyDown(const FGeometry &MyGeometry, const FKeyEvent &InKeyEvent) override
Definition STableViewBase.cpp:716
SLATE_API void NavigateToWidget(const uint32 UserIndex, const TSharedPtr< SWidget > &NavigationDestination, ENavigationSource NavigationSource=ENavigationSource::FocusedWidget, EUINavigation NavigationType=EUINavigation::Invalid) const
Definition STableViewBase.cpp:1260
virtual SLATE_API float ScrollTo(float InScrollOffset)
Definition STableViewBase.cpp:1007
bool bWasAtEndOfList
Definition STableViewBase.h:514
bool bShouldUseShadowBoxStyle
Definition STableViewBase.h:556
float WheelScrollMultiplier
Definition STableViewBase.h:541
FSimpleDelegate OnItemsRebuilt
Definition STableViewBase.h:523
virtual SLATE_API void RequestListRefresh()
Definition STableViewBase.cpp:837
EAllowOverscroll AllowOverscroll
Definition STableViewBase.h:589
virtual SLATE_API int32 GetNumItemsPerLine() const
Definition STableViewBase.cpp:1247
SLATE_API void SetScrollOffset(const float InScrollOffset)
Definition STableViewBase.cpp:1027
SLATE_API void EndInertialScrolling(const bool bInShouldStopScrollNow=false)
Definition STableViewBase.cpp:1038
bool bSelectItemOnNavigation
Definition STableViewBase.h:486
SLATE_API void ClearPinnedWidgets()
Definition STableViewBase.cpp:1209
FOnContextMenuOpening OnContextMenuOpening
Definition STableViewBase.h:520
EOrientation Orientation
Definition STableViewBase.h:550
EScrollIntoViewResult
Definition STableViewBase.h:401
FInertialScrollManager InertialScrollManager
Definition STableViewBase.h:532
virtual SLATE_API FReply OnMouseButtonDoubleClick(const FGeometry &InMyGeometry, const FPointerEvent &InMouseEvent) override
Definition STableViewBase.cpp:555
SLATE_API void ClearWidgets()
Definition STableViewBase.cpp:1181
SLATE_API bool IsPendingRefresh() const
Definition STableViewBase.cpp:842
TSharedPtr< SScrollBar > ScrollBar
Definition STableViewBase.h:443
double CurrentScrollOffset
Definition STableViewBase.h:489
SLATE_API void SetBackgroundBrush(const TAttribute< const FSlateBrush * > &InBackgroundBrush)
Definition STableViewBase.cpp:1160
EConsumeMouseWheel ConsumeMouseWheel
Definition STableViewBase.h:592
SLATE_API void RequestLayoutRefresh()
Definition STableViewBase.cpp:1310
SLATE_API void InsertWidget(const TSharedRef< ITableRow > &WidgetToInset)
Definition STableViewBase.cpp:1165
virtual SLATE_API void OnRightMouseButtonUp(const FPointerEvent &MouseEvent)
Definition STableViewBase.cpp:1278
bool bEnableAnimatedScrolling
Definition STableViewBase.h:471
const ETableViewMode::Type TableViewMode
Definition STableViewBase.h:158
SLATE_API void AppendPinnedWidget(const TSharedRef< SWidget > &WidgetToAppend)
Definition STableViewBase.cpp:1200
SLATE_API void ConstructChildren(const TAttribute< float > &InItemWidth, const TAttribute< float > &InItemHeight, const TAttribute< EListItemAlignment > &InItemAlignment, const TSharedPtr< SHeaderRow > &InHeaderRow, const TSharedPtr< SScrollBar > &InScrollBar, EOrientation InScrollOrientation, const FOnTableViewScrolled &InOnTableViewScrolled, const FScrollBarStyle *InScrollBarStyle=nullptr, const bool bInPreventThrottling=false)
Definition STableViewBase.cpp:130
TOptional< double > FixedLineScrollOffset
Definition STableViewBase.h:468
Definition STextBlock.h:45
EWidgetClipping Clipping
Definition SWidget.h:1827
bool IsHovered() const
Definition SWidget.h:983
virtual SLATECORE_API FNavigationReply OnNavigation(const FGeometry &MyGeometry, const FNavigationEvent &InNavigationEvent)
Definition SWidget.cpp:644
void AddMetadata(const TSharedRef< MetaDataType > &AddMe)
Definition SWidget.h:1383
bool IsConstructed() const
Definition SWidget.h:1560
MixedIntoType & HAlign(EHorizontalAlignment InHAlignment)
Definition BasicLayoutWidgetSlot.h:149
Definition ArrayView.h:139
UE_FORCEINLINE_HINT constexpr SizeType Num() const
Definition ArrayView.h:380
UE_FORCEINLINE_HINT constexpr bool IsValidIndex(SizeType Index) const
Definition ArrayView.h:359
constexpr bool Find(const ElementType &Item, SizeType &Index) const
Definition ArrayView.h:517
Definition Array.h:670
void Empty(SizeType Slack=0)
Definition Array.h:2273
Definition Attribute.h:17
const ObjectType & Get() const
Definition Attribute.h:241
void Set(const OtherType &InNewValue)
Definition Attribute.h:210
Definition UnrealString.h.inl:34
static UE_FORCEINLINE_HINT TSharedRef< OtherType, Mode > SharedThis(OtherType *ThisPtr)
Definition SharedPointer.h:1780
Definition SharedPointer.h:692
TSharedRef< ObjectType, Mode > ToSharedRef() const &
Definition SharedPointer.h:1028
UE_FORCEINLINE_HINT const bool IsValid() const
Definition SharedPointer.h:1085
Definition SharedPointer.h:153
Definition SlateDelegates.h:134
Definition TableViewMetadata.h:20
Definition UniquePtr.h:107
Definition SharedPointer.h:1295
Definition IItemsSource.h:106
Definition IItemsSource.h:91
@ ListView
Definition EdGraphNode.h:140
Type
Definition SlateEnums.h:311
@ OnNavigation
Definition SlateEnums.h:315
@ OnMouseClick
Definition SlateEnums.h:317
@ Direct
Definition SlateEnums.h:319
@ OnKeyPress
Definition SlateEnums.h:313
Definition ITypedTableView.h:14
Type
Definition ITypedTableView.h:16
@ None
Definition ITypedTableView.h:18
@ Single
Definition ITypedTableView.h:21
@ Multi
Definition ITypedTableView.h:27
@ SingleToggle
Definition ITypedTableView.h:24
Type
Definition ITypedTableView.h:37
@ List
Definition ITypedTableView.h:38
@ Tree
Definition ITypedTableView.h:40
Definition SScissorRectBox.cpp:10
SLATE_API const TBitArray & GetEmptyBitArray()
Definition STableViewBase.cpp:1402
Definition AdvancedWidgetsModule.cpp:13
@ false
Definition radaudio_common.h:23
static INPUTCORE_API const FKey End
Definition InputCoreTypes.h:316
static INPUTCORE_API const FKey PageUp
Definition InputCoreTypes.h:314
static INPUTCORE_API const FKey RightMouseButton
Definition InputCoreTypes.h:301
static INPUTCORE_API const FKey LeftMouseButton
Definition InputCoreTypes.h:300
static INPUTCORE_API const FKey PageDown
Definition InputCoreTypes.h:315
static INPUTCORE_API const FKey Home
Definition InputCoreTypes.h:317
static INPUTCORE_API const FKey A
Definition InputCoreTypes.h:338
static INPUTCORE_API const FKey SpaceBar
Definition InputCoreTypes.h:313
Definition Visibility.h:12
static SLATECORE_API const EVisibility Hidden
Definition Visibility.h:20
static SLATECORE_API const EVisibility HitTestInvisible
Definition Visibility.h:23
static SLATECORE_API const EVisibility Visible
Definition Visibility.h:14
static SLATECORE_API const EVisibility Collapsed
Definition Visibility.h:17
Definition Geometry.h:40
UE::Slate::FDeprecateVector2DResult GetLocalSize() const
Definition Geometry.h:510
UE::Slate::FDeprecateVector2DResult GetAbsolutePositionAtCoordinates(const UE::Slate::FDeprecateVector2DParameter &NormalCoordinates) const
Definition Geometry.h:560
Definition Events.h:155
Definition Events.h:431
Definition Margin.h:17
static UE_FORCEINLINE_HINT bool IsNearlyEqual(float A, float B, float ErrorTolerance=UE_SMALL_NUMBER)
Definition UnrealMathUtility.h:388
static constexpr UE_FORCEINLINE_HINT T Clamp(const T X, const T MinValue, const T MaxValue)
Definition UnrealMathUtility.h:592
Definition Events.h:1148
ENavigationGenesis GetNavigationGenesis() const
Definition Events.h:1178
SLATE_API float ScrollBy(const FGeometry &AllottedGeometry, float LocalDeltaScroll)
Definition Overscroll.cpp:14
SLATE_API bool ShouldApplyOverscroll(const bool bIsAtStartOfList, const bool bIsAtEndOfList, const float ScrollDelta) const
Definition Overscroll.cpp:61
Definition Events.h:695
Definition SlateTypes.h:932
Definition SlateTypes.h:2023
Definition STableViewBase.h:80
float ScrollAxis
Definition STableViewBase.h:98
Definition SlateTypes.h:1606
FSlateBrush BackgroundBrush
Definition SlateTypes.h:1622
Definition STableViewBase.h:365
double ExactNumLinesOnScreen
Definition STableViewBase.h:380
Definition TableViewTypeTraits.h:121
Definition Optional.h:131
constexpr OptionalType & GetValue()
Definition Optional.h:443
constexpr bool IsSet() const
Definition Optional.h:69
static CORE_API const TVector2< double > ZeroVector
Definition Vector2D.h:63
Definition ObservableArray.h:187