Files
UnrealEngineUWP/Engine/Source/Runtime/UMG/Private/Components/ScrollBox.cpp
Chris Gagnon 930e33cb48 Copying //UE4/Dev-Editor to Dev-Main (//UE4/Dev-Main) for 4.23 From CL 6837861
#rb none

[CL 6838042 by Chris Gagnon in Main branch]
2019-06-04 15:42:48 -04:00

391 lines
10 KiB
C++

// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#include "Components/ScrollBox.h"
#include "Containers/Ticker.h"
#include "Components/ScrollBoxSlot.h"
#include "UObject/EditorObjectVersion.h"
#define LOCTEXT_NAMESPACE "UMG"
/////////////////////////////////////////////////////
// UScrollBox
static FScrollBoxStyle* DefaultScrollBoxStyle = nullptr;
static FScrollBarStyle* DefaultScrollBoxBarStyle = nullptr;
UScrollBox::UScrollBox(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, Orientation(Orient_Vertical)
, ScrollBarVisibility(ESlateVisibility::Visible)
, ConsumeMouseWheel(EConsumeMouseWheel::WhenScrollingPossible)
, ScrollbarThickness(9.0f, 9.0f)
, ScrollbarPadding(2.0f)
, AlwaysShowScrollbar(false)
, AlwaysShowScrollbarTrack(false)
, AllowOverscroll(true)
, NavigationDestination(EDescendantScrollDestination::IntoView)
, NavigationScrollPadding(0.0f)
{
bIsVariable = false;
Visibility = ESlateVisibility::Visible;
Clipping = EWidgetClipping::ClipToBounds;
if (DefaultScrollBoxStyle == nullptr)
{
// HACK: THIS SHOULD NOT COME FROM CORESTYLE AND SHOULD INSTEAD BE DEFINED BY ENGINE TEXTURES/PROJECT SETTINGS
DefaultScrollBoxStyle = new FScrollBoxStyle(FCoreStyle::Get().GetWidgetStyle<FScrollBoxStyle>("ScrollBox"));
// Unlink UMG default colors from the editor settings colors.
DefaultScrollBoxStyle->UnlinkColors();
}
if (DefaultScrollBoxBarStyle == nullptr)
{
// HACK: THIS SHOULD NOT COME FROM CORESTYLE AND SHOULD INSTEAD BE DEFINED BY ENGINE TEXTURES/PROJECT SETTINGS
DefaultScrollBoxBarStyle = new FScrollBarStyle(FCoreStyle::Get().GetWidgetStyle<FScrollBarStyle>("ScrollBar"));
// Unlink UMG default colors from the editor settings colors.
DefaultScrollBoxBarStyle->UnlinkColors();
}
WidgetStyle = *DefaultScrollBoxStyle;
WidgetBarStyle = *DefaultScrollBoxBarStyle;
bAllowRightClickDragScrolling = true;
}
void UScrollBox::ReleaseSlateResources(bool bReleaseChildren)
{
Super::ReleaseSlateResources(bReleaseChildren);
MyScrollBox.Reset();
}
UClass* UScrollBox::GetSlotClass() const
{
return UScrollBoxSlot::StaticClass();
}
void UScrollBox::OnSlotAdded(UPanelSlot* InSlot)
{
// Add the child to the live canvas if it already exists
if ( MyScrollBox.IsValid() )
{
CastChecked<UScrollBoxSlot>(InSlot)->BuildSlot(MyScrollBox.ToSharedRef());
}
}
void UScrollBox::OnSlotRemoved(UPanelSlot* InSlot)
{
// Remove the widget from the live slot if it exists.
if ( MyScrollBox.IsValid() )
{
TSharedPtr<SWidget> Widget = InSlot->Content->GetCachedWidget();
if ( Widget.IsValid() )
{
MyScrollBox->RemoveSlot(Widget.ToSharedRef());
}
}
}
TSharedRef<SWidget> UScrollBox::RebuildWidget()
{
MyScrollBox = SNew(SScrollBox)
.Style(&WidgetStyle)
.ScrollBarStyle(&WidgetBarStyle)
.Orientation(Orientation)
.ConsumeMouseWheel(ConsumeMouseWheel)
.NavigationDestination(NavigationDestination)
.NavigationScrollPadding(NavigationScrollPadding)
.OnUserScrolled(BIND_UOBJECT_DELEGATE(FOnUserScrolled, SlateHandleUserScrolled));
for ( UPanelSlot* PanelSlot : Slots )
{
if ( UScrollBoxSlot* TypedSlot = Cast<UScrollBoxSlot>(PanelSlot) )
{
TypedSlot->Parent = this;
TypedSlot->BuildSlot(MyScrollBox.ToSharedRef());
}
}
return MyScrollBox.ToSharedRef();
}
void UScrollBox::SynchronizeProperties()
{
Super::SynchronizeProperties();
MyScrollBox->SetScrollOffset(DesiredScrollOffset);
MyScrollBox->SetOrientation(Orientation);
MyScrollBox->SetScrollBarVisibility(UWidget::ConvertSerializedVisibilityToRuntime(ScrollBarVisibility));
MyScrollBox->SetScrollBarThickness(ScrollbarThickness);
MyScrollBox->SetScrollBarPadding(ScrollbarPadding);
MyScrollBox->SetScrollBarAlwaysVisible(AlwaysShowScrollbar);
MyScrollBox->SetScrollBarTrackAlwaysVisible(AlwaysShowScrollbarTrack);
MyScrollBox->SetAllowOverscroll(AllowOverscroll ? EAllowOverscroll::Yes : EAllowOverscroll::No);
MyScrollBox->SetScrollBarRightClickDragAllowed(bAllowRightClickDragScrolling);
MyScrollBox->SetConsumeMouseWheel(ConsumeMouseWheel);
}
float UScrollBox::GetScrollOffset() const
{
if ( MyScrollBox.IsValid() )
{
return MyScrollBox->GetScrollOffset();
}
return 0;
}
float UScrollBox::GetScrollOffsetOfEnd() const
{
if (MyScrollBox.IsValid())
{
return MyScrollBox->GetScrollOffsetOfEnd();
}
return 0;
}
float UScrollBox::GetViewOffsetFraction() const
{
if ( MyScrollBox.IsValid() )
{
return MyScrollBox->GetViewOffsetFraction();
}
return 0;
}
void UScrollBox::SetScrollOffset(float NewScrollOffset)
{
DesiredScrollOffset = NewScrollOffset;
if ( MyScrollBox.IsValid() )
{
MyScrollBox->SetScrollOffset(NewScrollOffset);
}
}
void UScrollBox::ScrollToStart()
{
if ( MyScrollBox.IsValid() )
{
MyScrollBox->ScrollToStart();
}
}
void UScrollBox::ScrollToEnd()
{
if ( MyScrollBox.IsValid() )
{
MyScrollBox->ScrollToEnd();
}
}
void UScrollBox::ScrollWidgetIntoView(UWidget* WidgetToFind, bool AnimateScroll, EDescendantScrollDestination InScrollDestination)
{
TSharedPtr<SWidget> SlateWidgetToFind;
if (WidgetToFind)
{
SlateWidgetToFind = WidgetToFind->GetCachedWidget();
}
if (MyScrollBox.IsValid())
{
// NOTE: Pass even if null! This, in effect, cancels a request to scroll which is necessary to avoid warnings/ensures
// when we request to scroll to a widget and later remove that widget!
MyScrollBox->ScrollDescendantIntoView(SlateWidgetToFind, AnimateScroll, InScrollDestination);
}
}
#if WITH_EDITORONLY_DATA
void UScrollBox::Serialize(FArchive& Ar)
{
Ar.UsingCustomVersion(FEditorObjectVersion::GUID);
const bool bDeprecateThickness = Ar.IsLoading() && Ar.CustomVer(FEditorObjectVersion::GUID) < FEditorObjectVersion::ScrollBarThicknessChange;
if (bDeprecateThickness)
{
// Set ScrollbarThickness property to previous default value.
ScrollbarThickness.Set(5.0f, 5.0f);
}
Super::Serialize(Ar);
if (bDeprecateThickness)
{
// Implicit padding of 2 was removed, so ScrollbarThickness value must be incremented by 4.
ScrollbarThickness += FVector2D(4.0f, 4.0f);
}
}
void UScrollBox::PostLoad()
{
Super::PostLoad();
if ( GetLinkerUE4Version() < VER_UE4_DEPRECATE_UMG_STYLE_ASSETS )
{
if ( Style_DEPRECATED != nullptr )
{
const FScrollBoxStyle* StylePtr = Style_DEPRECATED->GetStyle<FScrollBoxStyle>();
if ( StylePtr != nullptr )
{
WidgetStyle = *StylePtr;
}
Style_DEPRECATED = nullptr;
}
if ( BarStyle_DEPRECATED != nullptr )
{
const FScrollBarStyle* StylePtr = BarStyle_DEPRECATED->GetStyle<FScrollBarStyle>();
if ( StylePtr != nullptr )
{
WidgetBarStyle = *StylePtr;
}
BarStyle_DEPRECATED = nullptr;
}
}
}
#endif // if WITH_EDITORONLY_DATA
void UScrollBox::SetConsumeMouseWheel(EConsumeMouseWheel NewConsumeMouseWheel)
{
ConsumeMouseWheel = NewConsumeMouseWheel;
if (MyScrollBox.IsValid())
{
MyScrollBox->SetConsumeMouseWheel(NewConsumeMouseWheel);
}
}
void UScrollBox::SetOrientation(EOrientation NewOrientation)
{
Orientation = NewOrientation;
if (MyScrollBox.IsValid())
{
MyScrollBox->SetOrientation(Orientation);
}
}
void UScrollBox::SetScrollBarVisibility(ESlateVisibility NewScrollBarVisibility)
{
ScrollBarVisibility = NewScrollBarVisibility;
if (MyScrollBox.IsValid())
{
switch (ScrollBarVisibility)
{
case ESlateVisibility::Collapsed: MyScrollBox->SetScrollBarVisibility(EVisibility::Collapsed); break;
case ESlateVisibility::Hidden: MyScrollBox->SetScrollBarVisibility(EVisibility::Hidden); break;
case ESlateVisibility::HitTestInvisible: MyScrollBox->SetScrollBarVisibility(EVisibility::HitTestInvisible); break;
case ESlateVisibility::SelfHitTestInvisible: MyScrollBox->SetScrollBarVisibility(EVisibility::SelfHitTestInvisible); break;
case ESlateVisibility::Visible: MyScrollBox->SetScrollBarVisibility(EVisibility::Visible); break;
}
}
}
void UScrollBox::SetScrollbarThickness(const FVector2D& NewScrollbarThickness)
{
ScrollbarThickness = NewScrollbarThickness;
if (MyScrollBox.IsValid())
{
MyScrollBox->SetScrollBarThickness(ScrollbarThickness);
}
}
void UScrollBox::SetScrollbarPadding(const FMargin& NewScrollbarPadding)
{
ScrollbarPadding = NewScrollbarPadding;
if (MyScrollBox.IsValid())
{
MyScrollBox->SetScrollBarPadding(ScrollbarPadding);
}
}
void UScrollBox::SetAlwaysShowScrollbar(bool NewAlwaysShowScrollbar)
{
AlwaysShowScrollbar = NewAlwaysShowScrollbar;
if (MyScrollBox.IsValid())
{
MyScrollBox->SetScrollBarAlwaysVisible(AlwaysShowScrollbar);
}
}
void UScrollBox::SetAllowOverscroll(bool NewAllowOverscroll)
{
AllowOverscroll = NewAllowOverscroll;
if (MyScrollBox.IsValid())
{
MyScrollBox->SetAllowOverscroll(AllowOverscroll ? EAllowOverscroll::Yes : EAllowOverscroll::No);
}
}
void UScrollBox::EndInertialScrolling()
{
if (MyScrollBox.IsValid())
{
MyScrollBox->EndInertialScrolling();
}
}
void UScrollBox::SlateHandleUserScrolled(float CurrentOffset)
{
OnUserScrolled.Broadcast(CurrentOffset);
}
#if WITH_EDITOR
const FText UScrollBox::GetPaletteCategory()
{
return LOCTEXT("Panel", "Panel");
}
void UScrollBox::OnDescendantSelectedByDesigner( UWidget* DescendantWidget )
{
UWidget* SelectedChild = UWidget::FindChildContainingDescendant( this, DescendantWidget );
if ( SelectedChild )
{
ScrollWidgetIntoView( SelectedChild, true );
if ( TickHandle.IsValid() )
{
FTicker::GetCoreTicker().RemoveTicker( TickHandle );
TickHandle.Reset();
}
}
}
void UScrollBox::OnDescendantDeselectedByDesigner( UWidget* DescendantWidget )
{
if ( TickHandle.IsValid() )
{
FTicker::GetCoreTicker().RemoveTicker( TickHandle );
TickHandle.Reset();
}
// because we get a deselect before we get a select, we need to delay this call until we're sure we didn't scroll to another widget.
TickHandle = FTicker::GetCoreTicker().AddTicker( FTickerDelegate::CreateLambda( [=]( float ) -> bool
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_UScrollBox_ScrollToStart_LambdaTick);
this->ScrollToStart();
return false;
} ) );
}
#endif
/////////////////////////////////////////////////////
#undef LOCTEXT_NAMESPACE