From 0c92bcbaa81f143925aa2a796167e8b1cae63e41 Mon Sep 17 00:00:00 2001 From: Steve Streeting Date: Tue, 11 Apr 2023 12:24:07 +0100 Subject: [PATCH] Fix typewriter text size calculation being wrong just after first construction --- .../Private/StevesUI/TypewriterTextWidget.cpp | 43 ++++++++++++++++--- .../Public/StevesUI/TypewriterTextWidget.h | 4 ++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/Source/StevesUEHelpers/Private/StevesUI/TypewriterTextWidget.cpp b/Source/StevesUEHelpers/Private/StevesUI/TypewriterTextWidget.cpp index 26813a7..f79cd2e 100644 --- a/Source/StevesUEHelpers/Private/StevesUI/TypewriterTextWidget.cpp +++ b/Source/StevesUEHelpers/Private/StevesUI/TypewriterTextWidget.cpp @@ -110,17 +110,39 @@ void UTypewriterTextWidget::PlayLine(const FText& InLine, float Speed) bHasFinishedPlaying = false; LineText->SetText(FText()); - CalculateWrappedString(); - - FTimerDelegate Delegate; - Delegate.BindUObject(this, &ThisClass::PlayNextLetter); - TimerManager.SetTimer(LetterTimer, Delegate, LetterPlayTime/CurrentPlaySpeed, true); - - SetVisibility(ESlateVisibility::SelfHitTestInvisible); + if (bFirstPlayLine) + { + // Delay the very first PlayLine after construction, CalculateWrappedString is not reliable until a couple + // of UI geometry updates. At first the geometry is 0, then it's just wrong, and then finally it settles. + FTimerHandle TempHandle; + FTimerDelegate DelayDelegate; + DelayDelegate.BindUObject(this, &ThisClass::StartPlayLine); + TimerManager.SetTimer(TempHandle, DelayDelegate, 0.2f, false); + } + else + { + StartPlayLine(); + } } } +void UTypewriterTextWidget::StartPlayLine() +{ + CalculateWrappedString(); + + FTimerDelegate Delegate; + Delegate.BindUObject(this, &ThisClass::PlayNextLetter); + + FTimerManager& TimerManager = GetWorld()->GetTimerManager(); + TimerManager.SetTimer(LetterTimer, Delegate, LetterPlayTime/CurrentPlaySpeed, true); + + SetVisibility(ESlateVisibility::SelfHitTestInvisible); + + bFirstPlayLine = false; + +} + void UTypewriterTextWidget::SkipToLineEnd() { FTimerManager& TimerManager = GetWorld()->GetTimerManager(); @@ -137,6 +159,13 @@ void UTypewriterTextWidget::SkipToLineEnd() OnLineFinishedPlaying(); } +void UTypewriterTextWidget::NativeConstruct() +{ + Super::NativeConstruct(); + + bFirstPlayLine = true; +} + void UTypewriterTextWidget::PlayNextLetter() { // Incorporate pauses as a multiple of play timer (may not be exact but close enough) diff --git a/Source/StevesUEHelpers/Public/StevesUI/TypewriterTextWidget.h b/Source/StevesUEHelpers/Public/StevesUI/TypewriterTextWidget.h index b090c78..e7e5815 100644 --- a/Source/StevesUEHelpers/Public/StevesUI/TypewriterTextWidget.h +++ b/Source/StevesUEHelpers/Public/StevesUI/TypewriterTextWidget.h @@ -109,6 +109,8 @@ public: const FString& GetCurrentRunName() const { return CurrentRunName; } protected: + virtual void NativeConstruct() override; + /// Called when on or more letters are added, if subclasses want to override UFUNCTION(BlueprintImplementableEvent, Category = "Typewriter") void OnPlayLetter(); @@ -128,6 +130,7 @@ private: void CalculateWrappedString(); FString CalculateSegments(FString* OutCurrentRunName); + void StartPlayLine(); UPROPERTY() FText CurrentLine; @@ -159,4 +162,5 @@ private: FTimerHandle LetterTimer; float CurrentPlaySpeed = 1; float PauseTime = 0; + bool bFirstPlayLine = true; }; \ No newline at end of file