Files
UnrealEngine/Engine/Source/Runtime/Slate/Private/Framework/Layout/Overscroll.cpp
2025-05-18 13:04:45 +08:00

76 lines
2.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Framework/Layout/Overscroll.h"
float FOverscroll::Looseness(50.0f);
float FOverscroll::OvershootLooseMax(100.0f);
float FOverscroll::OvershootBounceRate(1500.0f);
FOverscroll::FOverscroll()
: OverscrollAmount(0.0f)
{
}
float FOverscroll::ScrollBy(const FGeometry& AllottedGeometry, float LocalDeltaScroll)
{
const float ScreenDeltaScroll = LocalDeltaScroll / AllottedGeometry.Scale;
const float ValueBeforeDeltaApplied = OverscrollAmount;
OverscrollAmount += ScreenDeltaScroll;
// Don't allow an interaction to change from positive <-> negative overscroll
const bool bCrossedOverscrollBoundary = FMath::Sign(ValueBeforeDeltaApplied) != FMath::Sign(OverscrollAmount);
if ( bCrossedOverscrollBoundary && ValueBeforeDeltaApplied != 0.f )
{
OverscrollAmount = 0.f;
}
return ValueBeforeDeltaApplied - OverscrollAmount;
}
float FOverscroll::GetOverscroll(const FGeometry& AllottedGeometry) const
{
// We apply the resistance when observers attempt to read the overscroll.
// First we calculate the origin shift for the looseness factor, by default,
// straight up Log would be too tight, so we scale the result, the problem is that shifts
// the inflection point of the log function, so we subtract the shift amount to correct it.
const float OriginShift = FOverscroll::Looseness * FMath::Loge(FOverscroll::Looseness);
// Scale the log of the current overscroll and shift the origin so that the overscroll the resistance is continuous.
const float AbsElasticOverscroll = FOverscroll::Looseness * FMath::Loge(FMath::Abs(OverscrollAmount) + FOverscroll::Looseness) - OriginShift;
const float AbsOverscroll = FMath::Sign(OverscrollAmount) * AbsElasticOverscroll;
return AbsOverscroll * AllottedGeometry.Scale;
}
void FOverscroll::UpdateOverscroll(float InDeltaTime)
{
const float PullForce = FMath::Abs(OverscrollAmount) + 1.0f;
const float EasedDelta = FOverscroll::OvershootBounceRate * InDeltaTime * FMath::Max(1.0f, PullForce / FOverscroll::OvershootLooseMax);
if ( OverscrollAmount > 0 )
{
OverscrollAmount = FMath::Max(0.0f, OverscrollAmount - EasedDelta);
}
else
{
OverscrollAmount = FMath::Min(0.0f, OverscrollAmount + EasedDelta);
}
}
bool FOverscroll::ShouldApplyOverscroll(const bool bIsAtStartOfList, const bool bIsAtEndOfList, const float ScrollDelta) const
{
const bool bShouldApplyOverscroll =
// We can scroll past the edge of the list only if we are at the edge
( bIsAtStartOfList && ScrollDelta < 0 ) || ( bIsAtEndOfList && ScrollDelta > 0 ) ||
// ... or if we are already past the edge and are scrolling in the opposite direction.
( OverscrollAmount > 0 && ScrollDelta < 0 ) || ( OverscrollAmount < 0 && ScrollDelta > 0 );
return bShouldApplyOverscroll;
}
void FOverscroll::ResetOverscroll()
{
OverscrollAmount = 0.0f;
}