Added smooth changing progress bar

This commit is contained in:
Steve Streeting 2024-10-30 16:02:00 +00:00
parent 88b5a5dcaf
commit e7c9c373c3
5 changed files with 141 additions and 1 deletions

View File

@ -0,0 +1,62 @@
#include "StevesUI/SmoothChangingProgressBar.h"
void USmoothChangingProgressBar::SetPercentSmoothly(float InPercent)
{
UnregisterTimer();
TargetPercent = InPercent;
const float Curr = GetPercent();
if (!FMath::IsNearlyEqual(Curr, TargetPercent))
{
if (FMath::IsNearlyZero(PercentChangeSpeed) || !MyProgressBar.IsValid())
{
SetPercent(InPercent);
}
else
{
SmoothChangeHandle = MyProgressBar->RegisterActiveTimer(
PercentChangeFrequency,
FWidgetActiveTimerDelegate::CreateUObject(this, &USmoothChangingProgressBar::TickPercent));
}
}
}
void USmoothChangingProgressBar::StopSmoothPercentChange()
{
UnregisterTimer();
}
void USmoothChangingProgressBar::BeginDestroy()
{
Super::BeginDestroy();
UnregisterTimer();
}
void USmoothChangingProgressBar::UnregisterTimer()
{
if (SmoothChangeHandle.IsValid() && MyProgressBar.IsValid())
{
MyProgressBar->UnRegisterActiveTimer(SmoothChangeHandle.Pin().ToSharedRef());
SmoothChangeHandle.Reset();
}
}
EActiveTimerReturnType USmoothChangingProgressBar::TickPercent(double CurrTime, float DeltaTime)
{
const float CurrPercent = GetPercent();
const float Direction = FMath::Sign(TargetPercent - CurrPercent);
const float Change = DeltaTime * Direction * PercentChangeSpeed;
const float NewPercent = Direction > 0
? FMath::Min(CurrPercent + Change, TargetPercent)
: FMath::Max(CurrPercent + Change, TargetPercent);
SetPercent(NewPercent);
// Stop this if reached target (will unregister itself)
if (FMath::IsNearlyEqual(TargetPercent, GetPercent()))
{
return EActiveTimerReturnType::Stop;
}
return EActiveTimerReturnType::Continue;
}

View File

@ -0,0 +1,54 @@
//
#pragma once
#include "CoreMinimal.h"
#include "Components/ProgressBar.h"
#include "SmoothChangingProgressBar.generated.h"
/**
* A specialised progress bar that can be told to change its percent smoothly instead of all at once.
* Note: Because SetPercent isn't virtual on UProgressBar, you need to use the alternate SetPercentSmoothly
* function instead, and call StopSmoothPercentChange to interrupt it if you need to manually set it using
* SetPercent.
*/
UCLASS()
class STEVESUEHELPERS_API USmoothChangingProgressBar : public UProgressBar
{
GENERATED_BODY()
protected:
TWeakPtr<FActiveTimerHandle> SmoothChangeHandle;
float TargetPercent;
void UnregisterTimer();
EActiveTimerReturnType TickPercent(double CurrTime, float DeltaTime);
public:
/// The speed at which the progress bar changes. This value means the max percentage changes
/// in one second. Set this to 0 to make changes instant. Changes to this value only affect
/// the next call to SetPercentSmoothly.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Progress")
float PercentChangeSpeed = 1.0f;
/// The frequency at which we should update the bar. Set this to 0 to update every frame,
/// or > 0 to update every X seconds (useful to save tick time for slow updates).
/// Changes to this value only affect the next call to SetPercentSmoothly.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Progress")
float PercentChangeFrequency = 0.0f;
/// Changes the bar percentage smoothly from its current value.
/// Automatically interrupts any existing smooth change.
UFUNCTION(BlueprintCallable, Category="Progress")
void SetPercentSmoothly(float InPercent);
/// Stop any pending smooth changes to percent
/// Call this if you need to interrupt any current smooth change and
UFUNCTION(BlueprintCallable, Category="Progress")
void StopSmoothPercentChange();
virtual void BeginDestroy() override;
};

View File

@ -107,4 +107,5 @@ Alternatives are:
## See Also ## See Also
* [Input Image](InputImage.md) * [Input Image](InputImage.md)
* [Widgets](Widgets.md)

View File

@ -0,0 +1,19 @@
# Smooth Changing Progress Bar
This is a fairly simple extension to Progress Bar to allow it to change smoothly
rather than jumping.
You configure this as follows:
* Set `PercentChangeSpeed` to the amount of percent change per second
* Optionally set `PercentChangeFrequency`; at 0, it updates every frame, otherwise
it can update less frequently by setting this to a number of seconds
* Call `SetPercentSmoothly` instead of `SetPercent`
* (`SetPercent` is not virtual in `UProgressBar` so we cannot override that. This
also means that if you want to interrupt the smooth change, you need to call
`StopSmoothPercentChange`)
## See Also
* [Widgets](Widgets.md)

View File

@ -66,3 +66,7 @@ Several custom widgets are supplied to assist with some common challenges:
and also remembers the last focus widget if you switch away & back and also remembers the last focus widget if you switch away & back
without destroying it. without destroying it.
* [Smooth Changing Progress Bar](SmoothChangingProgress.md)
A ProgressBar subclass which adds the ability to smoothly change rather than
jumping straight to the target value.