2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2018-05-23 21:04:31 -04:00
# include "Components/ListViewBase.h"
# include "UMGPrivate.h"
# include "Widgets/Text/STextBlock.h"
# include "TimerManager.h"
2018-11-14 19:05:13 -05:00
# include "Engine/Blueprint.h"
2019-01-29 07:17:05 -05:00
# include "Editor/WidgetCompilerLog.h"
2018-05-23 21:04:31 -04:00
# define LOCTEXT_NAMESPACE "UMG"
UListViewBase : : UListViewBase ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
, EntryWidgetPool ( * this )
{
bIsVariable = true ;
2022-05-10 13:53:03 -04:00
SetClipping ( EWidgetClipping : : ClipToBounds ) ;
2018-05-23 21:04:31 -04:00
}
# if WITH_EDITOR
const FText UListViewBase : : GetPaletteCategory ( )
{
return LOCTEXT ( " Lists " , " Lists " ) ;
}
2019-01-29 07:17:05 -05:00
void UListViewBase : : ValidateCompiledDefaults ( IWidgetCompilerLog & CompileLog ) const
2018-05-23 21:04:31 -04:00
{
if ( ! EntryWidgetClass )
{
2019-01-29 07:17:05 -05:00
CompileLog . Error ( FText : : Format ( LOCTEXT ( " Error_ListViewBase_MissingEntryClass " , " {0} has no EntryWidgetClass specified - required for any UListViewBase to function. " ) , FText : : FromString ( GetName ( ) ) ) ) ;
2018-05-23 21:04:31 -04:00
}
2019-06-04 15:42:48 -04:00
else if ( ! EntryWidgetClass - > ImplementsInterface ( UUserListEntry : : StaticClass ( ) ) )
{
CompileLog . Error ( FText : : Format ( LOCTEXT ( " Error_ListViewBase_EntryClassNotImplementingInterface " , " '{0}' has EntryWidgetClass property set to'{1}' and that Class doesn't implement User List Entry Interface - required for any UListViewBase to function. " ) , FText : : FromString ( GetName ( ) ) , FText : : FromString ( EntryWidgetClass - > GetName ( ) ) ) ) ;
}
2018-05-23 21:04:31 -04:00
}
# endif
void UListViewBase : : RegenerateAllEntries ( )
{
EntryWidgetPool . ReleaseAll ( ) ;
GeneratedEntriesToAnnounce . Reset ( ) ;
if ( MyTableViewBase . IsValid ( ) )
{
MyTableViewBase - > RebuildList ( ) ;
}
}
void UListViewBase : : ScrollToTop ( )
{
if ( MyTableViewBase . IsValid ( ) )
{
MyTableViewBase - > ScrollToTop ( ) ;
}
}
void UListViewBase : : ScrollToBottom ( )
{
if ( MyTableViewBase . IsValid ( ) )
{
MyTableViewBase - > ScrollToBottom ( ) ;
}
}
2019-09-24 14:16:56 -04:00
void UListViewBase : : SetScrollOffset ( const float InScrollOffset )
{
if ( MyTableViewBase . IsValid ( ) )
{
MyTableViewBase - > SetScrollOffset ( InScrollOffset ) ;
}
}
Unblocking robomerge
- Merge was a little involved, ran SlateViewer and things seem to be working as expected
ListView improvements
- Added horizontal layout option to both SListView and STileView.
- Added smooth inertial scrolling. Doing so naturally requires more refreshes, so it's not intended for use in perf-sensitive scenarios and is disabled by default.
- Added option to establish a consistent fixed offset when scrolling (to, for example, ensure the top item is always flush with the top of the list, or that the bottom 25% of the preceeding item is always visible above). Note that enabling this will override the NavigationScrollOffset property, as the two concepts fully conflict.
- Exposed all new functionality to the UMG counterparts of the slate lists
- Updated SlateViewer's ListView testing tab to include a horizontal list, a horizontal tile view, and options for enabling animated scrolling and fixed offsets. Also tinkered a bit with the default sizing and open tab, as the default size seemed universally too small.
#rb Matt.Loesby, Josh.Gross, Nick.Darnell
[FYI] Matt.Kuhlenschmidt, Chris.Gagnon, Stephan.Jiang, Saad.Nader, Philip.Buuck, Don.Eubanks, Matt.Stone, Geoff.Wong, Ryan.Reed
#ROBOMERGE-OWNER: dan.hertzka
#ROBOMERGE-AUTHOR: dan.hertzka
#ROBOMERGE-SOURCE: CL 7634094 via CL 7642338
#ROBOMERGE-BOT: (v372-7473910)
[CL 7642344 by dan hertzka in Main branch]
2019-07-26 16:57:25 -04:00
void UListViewBase : : SetWheelScrollMultiplier ( float NewWheelScrollMultiplier )
{
WheelScrollMultiplier = NewWheelScrollMultiplier ;
if ( MyTableViewBase )
{
MyTableViewBase - > SetWheelScrollMultiplier ( GetGlobalScrollAmount ( ) * NewWheelScrollMultiplier ) ;
}
}
2018-11-14 19:05:13 -05:00
void UListViewBase : : SetScrollbarVisibility ( ESlateVisibility InVisibility )
{
if ( MyTableViewBase )
{
MyTableViewBase - > SetScrollbarVisibility ( UWidget : : ConvertSerializedVisibilityToRuntime ( InVisibility ) ) ;
}
}
2018-05-23 21:04:31 -04:00
const TArray < UUserWidget * > & UListViewBase : : GetDisplayedEntryWidgets ( ) const
{
return EntryWidgetPool . GetActiveWidgets ( ) ;
}
2021-09-06 12:23:53 -04:00
float UListViewBase : : GetScrollOffset ( ) const
{
if ( MyTableViewBase . IsValid ( ) )
{
return MyTableViewBase - > GetScrollOffset ( ) ;
}
return 0.0f ;
}
2018-05-23 21:04:31 -04:00
TSharedRef < SWidget > UListViewBase : : RebuildWidget ( )
{
2018-11-14 19:05:13 -05:00
FText ErrorText ;
2018-05-23 21:04:31 -04:00
if ( ! EntryWidgetClass )
2018-11-14 19:05:13 -05:00
{
ErrorText = LOCTEXT ( " Error_MissingEntryWidgetClass " , " No EntryWidgetClass specified on this list. \n Even if doing custom stuff, this is always required as a fallback. " ) ;
}
# if WITH_EDITOR
2021-04-29 19:32:06 -04:00
// if the BP was cooked already, then the ClassGeneratedBy will be null, so nothing to check
else if ( ! EntryWidgetClass - > bCooked )
2018-11-14 19:05:13 -05:00
{
UBlueprint * EntryWidgetBP = Cast < UBlueprint > ( EntryWidgetClass - > ClassGeneratedBy ) ;
if ( ! EntryWidgetBP )
{
ErrorText = FText : : Format ( LOCTEXT ( " Error_NonBPEntryWidget " , " EntryWidgetClass [{0}] is not a Blueprint class " ) , FText : : FromString ( EntryWidgetClass - > GetName ( ) ) ) ;
}
else if ( EntryWidgetBP - > Status = = BS_Error )
{
2019-01-21 15:19:14 -05:00
ErrorText = FText : : Format ( LOCTEXT ( " Error_CompilationError " , " EntryWidget BP [{0}] has not compiled successfully " ) , FText : : FromString ( EntryWidgetBP - > GetName ( ) ) ) ;
2018-11-14 19:05:13 -05:00
}
}
# endif
if ( ! ErrorText . IsEmpty ( ) )
2018-05-23 21:04:31 -04:00
{
return SNew ( STextBlock )
2018-11-14 19:05:13 -05:00
. Text ( ErrorText ) ;
2018-05-23 21:04:31 -04:00
}
MyTableViewBase = RebuildListWidget ( ) ;
Unblocking robomerge
- Merge was a little involved, ran SlateViewer and things seem to be working as expected
ListView improvements
- Added horizontal layout option to both SListView and STileView.
- Added smooth inertial scrolling. Doing so naturally requires more refreshes, so it's not intended for use in perf-sensitive scenarios and is disabled by default.
- Added option to establish a consistent fixed offset when scrolling (to, for example, ensure the top item is always flush with the top of the list, or that the bottom 25% of the preceeding item is always visible above). Note that enabling this will override the NavigationScrollOffset property, as the two concepts fully conflict.
- Exposed all new functionality to the UMG counterparts of the slate lists
- Updated SlateViewer's ListView testing tab to include a horizontal list, a horizontal tile view, and options for enabling animated scrolling and fixed offsets. Also tinkered a bit with the default sizing and open tab, as the default size seemed universally too small.
#rb Matt.Loesby, Josh.Gross, Nick.Darnell
[FYI] Matt.Kuhlenschmidt, Chris.Gagnon, Stephan.Jiang, Saad.Nader, Philip.Buuck, Don.Eubanks, Matt.Stone, Geoff.Wong, Ryan.Reed
#ROBOMERGE-OWNER: dan.hertzka
#ROBOMERGE-AUTHOR: dan.hertzka
#ROBOMERGE-SOURCE: CL 7634094 via CL 7642338
#ROBOMERGE-BOT: (v372-7473910)
[CL 7642344 by dan hertzka in Main branch]
2019-07-26 16:57:25 -04:00
MyTableViewBase - > SetIsScrollAnimationEnabled ( bEnableScrollAnimation ) ;
2021-09-06 12:23:53 -04:00
MyTableViewBase - > SetIsRightClickScrollingEnabled ( bEnableRightClickScrolling ) ;
Unblocking robomerge
- Merge was a little involved, ran SlateViewer and things seem to be working as expected
ListView improvements
- Added horizontal layout option to both SListView and STileView.
- Added smooth inertial scrolling. Doing so naturally requires more refreshes, so it's not intended for use in perf-sensitive scenarios and is disabled by default.
- Added option to establish a consistent fixed offset when scrolling (to, for example, ensure the top item is always flush with the top of the list, or that the bottom 25% of the preceeding item is always visible above). Note that enabling this will override the NavigationScrollOffset property, as the two concepts fully conflict.
- Exposed all new functionality to the UMG counterparts of the slate lists
- Updated SlateViewer's ListView testing tab to include a horizontal list, a horizontal tile view, and options for enabling animated scrolling and fixed offsets. Also tinkered a bit with the default sizing and open tab, as the default size seemed universally too small.
#rb Matt.Loesby, Josh.Gross, Nick.Darnell
[FYI] Matt.Kuhlenschmidt, Chris.Gagnon, Stephan.Jiang, Saad.Nader, Philip.Buuck, Don.Eubanks, Matt.Stone, Geoff.Wong, Ryan.Reed
#ROBOMERGE-OWNER: dan.hertzka
#ROBOMERGE-AUTHOR: dan.hertzka
#ROBOMERGE-SOURCE: CL 7634094 via CL 7642338
#ROBOMERGE-BOT: (v372-7473910)
[CL 7642344 by dan hertzka in Main branch]
2019-07-26 16:57:25 -04:00
MyTableViewBase - > SetFixedLineScrollOffset ( bEnableFixedLineOffset ? TOptional < double > ( FixedLineScrollOffset ) : TOptional < double > ( ) ) ;
MyTableViewBase - > SetWheelScrollMultiplier ( GetGlobalScrollAmount ( ) * WheelScrollMultiplier ) ;
2018-05-23 21:04:31 -04:00
return MyTableViewBase . ToSharedRef ( ) ;
}
void UListViewBase : : ReleaseSlateResources ( bool bReleaseChildren )
{
Super : : ReleaseSlateResources ( bReleaseChildren ) ;
MyTableViewBase . Reset ( ) ;
EntryWidgetPool . ResetPool ( ) ;
GeneratedEntriesToAnnounce . Reset ( ) ;
}
void UListViewBase : : SynchronizeProperties ( )
{
Super : : SynchronizeProperties ( ) ;
Unblocking robomerge
- Merge was a little involved, ran SlateViewer and things seem to be working as expected
ListView improvements
- Added horizontal layout option to both SListView and STileView.
- Added smooth inertial scrolling. Doing so naturally requires more refreshes, so it's not intended for use in perf-sensitive scenarios and is disabled by default.
- Added option to establish a consistent fixed offset when scrolling (to, for example, ensure the top item is always flush with the top of the list, or that the bottom 25% of the preceeding item is always visible above). Note that enabling this will override the NavigationScrollOffset property, as the two concepts fully conflict.
- Exposed all new functionality to the UMG counterparts of the slate lists
- Updated SlateViewer's ListView testing tab to include a horizontal list, a horizontal tile view, and options for enabling animated scrolling and fixed offsets. Also tinkered a bit with the default sizing and open tab, as the default size seemed universally too small.
#rb Matt.Loesby, Josh.Gross, Nick.Darnell
[FYI] Matt.Kuhlenschmidt, Chris.Gagnon, Stephan.Jiang, Saad.Nader, Philip.Buuck, Don.Eubanks, Matt.Stone, Geoff.Wong, Ryan.Reed
#ROBOMERGE-OWNER: dan.hertzka
#ROBOMERGE-AUTHOR: dan.hertzka
#ROBOMERGE-SOURCE: CL 7634094 via CL 7642338
#ROBOMERGE-BOT: (v372-7473910)
[CL 7642344 by dan hertzka in Main branch]
2019-07-26 16:57:25 -04:00
if ( MyTableViewBase )
{
MyTableViewBase - > SetIsScrollAnimationEnabled ( bEnableScrollAnimation ) ;
2021-09-06 12:23:53 -04:00
MyTableViewBase - > SetIsRightClickScrollingEnabled ( bEnableRightClickScrolling ) ;
2021-11-18 19:39:55 -05:00
MyTableViewBase - > SetAllowOverscroll ( AllowOverscroll ? EAllowOverscroll : : Yes : EAllowOverscroll : : No ) ;
Unblocking robomerge
- Merge was a little involved, ran SlateViewer and things seem to be working as expected
ListView improvements
- Added horizontal layout option to both SListView and STileView.
- Added smooth inertial scrolling. Doing so naturally requires more refreshes, so it's not intended for use in perf-sensitive scenarios and is disabled by default.
- Added option to establish a consistent fixed offset when scrolling (to, for example, ensure the top item is always flush with the top of the list, or that the bottom 25% of the preceeding item is always visible above). Note that enabling this will override the NavigationScrollOffset property, as the two concepts fully conflict.
- Exposed all new functionality to the UMG counterparts of the slate lists
- Updated SlateViewer's ListView testing tab to include a horizontal list, a horizontal tile view, and options for enabling animated scrolling and fixed offsets. Also tinkered a bit with the default sizing and open tab, as the default size seemed universally too small.
#rb Matt.Loesby, Josh.Gross, Nick.Darnell
[FYI] Matt.Kuhlenschmidt, Chris.Gagnon, Stephan.Jiang, Saad.Nader, Philip.Buuck, Don.Eubanks, Matt.Stone, Geoff.Wong, Ryan.Reed
#ROBOMERGE-OWNER: dan.hertzka
#ROBOMERGE-AUTHOR: dan.hertzka
#ROBOMERGE-SOURCE: CL 7634094 via CL 7642338
#ROBOMERGE-BOT: (v372-7473910)
[CL 7642344 by dan hertzka in Main branch]
2019-07-26 16:57:25 -04:00
MyTableViewBase - > SetFixedLineScrollOffset ( bEnableFixedLineOffset ? TOptional < double > ( FixedLineScrollOffset ) : TOptional < double > ( ) ) ;
MyTableViewBase - > SetWheelScrollMultiplier ( GetGlobalScrollAmount ( ) * WheelScrollMultiplier ) ;
}
2018-05-23 21:04:31 -04:00
# if WITH_EDITORONLY_DATA
2018-11-14 19:05:13 -05:00
if ( IsDesignTime ( ) & & MyTableViewBase . IsValid ( ) )
2018-05-23 21:04:31 -04:00
{
bNeedsToCallRefreshDesignerItems = true ;
OnRefreshDesignerItems ( ) ;
if ( ! ensureMsgf ( ! bNeedsToCallRefreshDesignerItems , TEXT ( " [%s] does not call RefreshDesignerItems<T> from within OnRefreshDesignerItems. Please do so to support design-time previewing of list entries. " ) , * GetClass ( ) - > GetName ( ) ) )
{
bNeedsToCallRefreshDesignerItems = false ;
}
}
# endif
}
TSharedRef < STableViewBase > UListViewBase : : RebuildListWidget ( )
{
ensureMsgf ( false , TEXT ( " All children of UListViewBase must implement RebuildListWidget using one of the static ITypedUMGListView<T>::ConstructX functions " ) ) ;
return SNew ( SListView < TSharedPtr < FString > > ) ;
}
void UListViewBase : : RequestRefresh ( )
{
if ( MyTableViewBase . IsValid ( ) )
{
MyTableViewBase - > RequestListRefresh ( ) ;
}
}
void UListViewBase : : HandleRowReleased ( const TSharedRef < ITableRow > & Row )
{
UUserWidget * EntryWidget = StaticCastSharedRef < IObjectTableRow > ( Row ) - > GetUserWidget ( ) ;
if ( ensure ( EntryWidget ) )
{
EntryWidgetPool . Release ( EntryWidget ) ;
if ( ! IsDesignTime ( ) )
{
GeneratedEntriesToAnnounce . Remove ( EntryWidget ) ;
OnEntryWidgetReleased ( ) . Broadcast ( * EntryWidget ) ;
BP_OnEntryReleased . Broadcast ( EntryWidget ) ;
}
}
}
void UListViewBase : : FinishGeneratingEntry ( UUserWidget & GeneratedEntry )
{
if ( ! IsDesignTime ( ) )
{
// Announcing the row generation now is just a bit too soon, as we haven't finished generating the row as far as the underlying list is concerned.
// So we cache the row/item pair here and announce their generation on the next tick
GeneratedEntriesToAnnounce . AddUnique ( & GeneratedEntry ) ;
if ( ! EntryGenAnnouncementTimerHandle . IsValid ( ) )
{
if ( UWorld * World = GetWorld ( ) )
{
2020-08-11 01:36:57 -04:00
EntryGenAnnouncementTimerHandle = World - > GetTimerManager ( ) . SetTimerForNextTick ( this , & UListViewBase : : HandleAnnounceGeneratedEntries ) ;
2018-05-23 21:04:31 -04:00
}
}
}
}
void UListViewBase : : HandleAnnounceGeneratedEntries ( )
{
EntryGenAnnouncementTimerHandle . Invalidate ( ) ;
for ( TWeakObjectPtr < UUserWidget > EntryWidget : GeneratedEntriesToAnnounce )
{
if ( EntryWidget . IsValid ( ) )
{
OnEntryWidgetGenerated ( ) . Broadcast ( * EntryWidget ) ;
BP_OnEntryGenerated . Broadcast ( EntryWidget . Get ( ) ) ;
}
}
GeneratedEntriesToAnnounce . Empty ( ) ;
}
# undef LOCTEXT_NAMESPACE