UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
FrameNumberNumericInterface.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreMinimal.h"
8#include "Misc/FrameRate.h"
10#include "Misc/Timecode.h"
14
31{
43
45 virtual int32 GetMinFractionalDigits() const override
46 {
47 return 0;
48 }
49 virtual int32 GetMaxFractionalDigits() const override
50 {
51 return 0;
52 }
53
55 virtual void SetMinFractionalDigits(const TAttribute<TOptional<int32>>& NewValue) override {}
56
57 virtual void SetMaxFractionalDigits(const TAttribute<TOptional<int32>>& NewValue) override {}
58
60 virtual bool IsCharacterValid(TCHAR InChar) const override
61 {
62 auto IsValidLocalizedCharacter = [InChar]() -> bool
63 {
65 return InChar == NumberFormattingRules.GroupingSeparatorCharacter
66 || InChar == NumberFormattingRules.DecimalSeparatorCharacter
67 || Algo::Find(NumberFormattingRules.DigitCharacters, InChar) != 0;
68 };
69
70 static const FString ValidChars = TEXT("1234567890()-+=\\/.,*^%%hrmsf[]:; ");
71 return InChar != 0 && (ValidChars.GetCharArray().Contains(InChar) || IsValidLocalizedCharacter());
72 }
73
74 virtual FString ToString(const double& Value) const override
75 {
76 FFrameRate SourceFrameRate = TickResolutionAttr.Get();
77 FFrameRate DestinationFrameRate = DisplayRateAttr.Get();
78 EFrameNumberDisplayFormats Format = DisplayFormatAttr.Get();
79
80 // If they want Drop Frame Timecode format but we're in an unsupported frame rate, we'll override it and say they want non drop frame.
82 if (Format == EFrameNumberDisplayFormats::DropFrameTimecode && !bIsValidRateForDropFrame)
83 {
84 Format = EFrameNumberDisplayFormats::NonDropFrameTimecode;
85 }
86
87 switch (Format)
88 {
90 {
91 // Convert from sequence resolution into display rate frames.
93 FString SubframeSuffix = FMath::IsNearlyZero(DisplayTime.GetSubFrame()) ? TEXT("") : SubframeIndicator;
94
95 return FString::Printf(TEXT("%0*d%s"), ZeroPadFramesAttr.Get(), DisplayTime.GetFrame().Value, *SubframeSuffix);
96 }
98 {
99 double TimeInSeconds = SourceFrameRate.AsSeconds(FFrameTime::FromDecimal(Value));
100
102 .SetUseGrouping(false)
104 .SetMaximumFractionalDigits(ZeroPadFramesAttr.Get());
106 }
107 case EFrameNumberDisplayFormats::NonDropFrameTimecode:
108 case EFrameNumberDisplayFormats::DropFrameTimecode:
109 {
112 FString SubframeSuffix = FMath::IsNearlyZero(DisplayTime.GetSubFrame()) ? TEXT("") : SubframeIndicator;
113
114 bool bIsDropTimecode = Format == EFrameNumberDisplayFormats::DropFrameTimecode;
115
117 return FString::Printf(TEXT("[%s%s]"), *AsNonDropTimecode.ToString(false), *SubframeSuffix);
118 }
119 default:
120 return FString(TEXT("Unsupported Format"));
121 }
122 }
123
124 virtual TOptional<double> FromString(const FString& InString, const double& InExistingValue) override
125 {
126 FFrameRate SourceFrameRate = DisplayRateAttr.Get();
127 FFrameRate DestinationFrameRate = TickResolutionAttr.Get();
128 EFrameNumberDisplayFormats FallbackFormat = DisplayFormatAttr.Get();
129
130 // We allow input in any format (time, frames or timecode) and we just convert it into into the internal sequence resolution.
131 // The user's input can be ambiguous though (does "5" mean 5 frames or 5 seconds?) so when we check each possible result we
132 // also check to see if they explicitly specified that format, or if the evaluator just happens to be able to parse that.
133
134 // All of these will convert into the frame resolution from the user's input before returning.
136 bool bWasTimecodeText;
138 bool bWasFrameText;
140 bool bWasTimeText;
142
143
144 // All three formats support ambiguous conversion where the user can enter "5" and wants it in the logical unit based on the current
145 // display format. This means 5 -> 5f, 5 ->5s, and 5 -> 5 frames (in timecode). We also support specifically specifying in a different
146 // format than your current display, ie if your display is in frames and you enter 1s, you get 1s in frames or 30 (at 30fps play rate).
148 {
149 // They've entered an ambiguous number, so we'll check the display format and see if we did successfully parse as that type. If it
150 // was able to parse the input for the given display format, we return that.
151 if (TimecodeResult.IsValid() && (FallbackFormat == EFrameNumberDisplayFormats::DropFrameTimecode || FallbackFormat == EFrameNumberDisplayFormats::NonDropFrameTimecode))
152 {
153 return TOptional<double>(TimecodeResult.GetValue().GetFrame().Value);
154 }
155 else if (TimeResult.IsValid() && FallbackFormat == EFrameNumberDisplayFormats::Seconds)
156 {
157 return TOptional<double>(TimeResult.GetValue().GetFrame().Value);
158 }
159 else if (FrameResult.IsValid() && FallbackFormat == EFrameNumberDisplayFormats::Frames)
160 {
161 return TOptional<double>(FrameResult.GetValue().GetFrame().Value);
162 }
163
164 static FBasicMathExpressionEvaluator Parser;
165
166 // If not parsed, try the math expression evaluator
167 if (FallbackFormat == EFrameNumberDisplayFormats::Seconds)
168 {
169 double TimeInSeconds = DestinationFrameRate.AsSeconds(FFrameTime::FromDecimal(InExistingValue));
170
171 TValueOrError<double, FExpressionError> Result = Parser.Evaluate(*InString, TimeInSeconds);
172 if (Result.IsValid())
173 {
174 FFrameTime ResultTime = DestinationFrameRate.AsFrameTime(Result.GetValue());
175
176 return TOptional<double>(ResultTime.GetFrame().Value);
177 }
178 }
179 else if (FallbackFormat == EFrameNumberDisplayFormats::Frames)
180 {
182
183 TValueOrError<double, FExpressionError> Result = Parser.Evaluate(*InString, (double)(ExistingTime.GetFrame().Value));
184 if (Result.IsValid())
185 {
187
188 return TOptional<double>(ResultTime.GetFrame().Value);
189 }
190 }
191
192 // Whatever they entered wasn't understood by any of our parsers, so it was probably malformed or had letters, etc.
193 return TOptional<double>();
194 }
195
196 // If we've gotten here then they did explicitly specify a timecode so we return that.
198 {
199 return TOptional<double>(TimecodeResult.GetValue().GetFrame().Value);
200 }
201 else if (bWasTimeText)
202 {
203 return TOptional<double>(TimeResult.GetValue().GetFrame().Value);
204 }
205 else if (bWasFrameText)
206 {
207 return TOptional<double>(FrameResult.GetValue().GetFrame().Value);
208 }
209
210 // We're not sure what they typed in
211 return TOptional<double>();
212 }
213
215 FString GetSubframeIndicator() const
216 {
217 return SubframeIndicator;
218 }
219
222 {
223 SubframeIndicator = InSubframeIndicator;
224 }
225
227 {
228 OnSettingChangedEvent.Broadcast();
229 }
230
232 {
233 return &OnSettingChangedEvent;
234 }
235
236private:
238 TAttribute<FFrameRate> TickResolutionAttr;
239 TAttribute<FFrameRate> DisplayRateAttr;
240 TAttribute<uint8> ZeroPadFramesAttr;
241
242 FString SubframeIndicator;
243
244 FOnSettingChanged OnSettingChangedEvent;
245};
#define check(expr)
Definition AssertionMacros.h:314
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
EFrameNumberDisplayFormats
Definition FrameNumberDisplayFormat.h:10
Definition BasicMathExpressionEvaluator.h:83
CORE_API TValueOrError< double, FExpressionError > Evaluate(const TCHAR *InExpression, double InExistingValue=0) const
Definition BasicMathExpressionEvaluator.cpp:224
Definition Attribute.h:17
const ObjectType & Get() const
Definition Attribute.h:241
Definition ValueOrError.h:58
UE_REWRITE constexpr auto Find(RangeType &&Range, const ValueType &Value) -> decltype(AlgoImpl::FindBy(Forward< RangeType >(Range), Value, FIdentityFunctor()))
Definition Find.h:52
const FDecimalNumberFormattingRules & GetLocalizedNumberFormattingRules()
Definition BasicMathExpressionEvaluator.cpp:28
void NumberToString(const T InVal, const FDecimalNumberFormattingRules &InFormattingRules, const FNumberFormattingOptions &InFormattingOptions, FString &OutString)
Definition FastDecimalFormat.h:113
Definition FastDecimalFormat.h:16
Definition FrameNumberNumericInterface.h:31
virtual void SetMinFractionalDigits(const TAttribute< TOptional< int32 > > &NewValue) override
Definition FrameNumberNumericInterface.h:55
void SetSubframeIndicator(const FString &InSubframeIndicator)
Definition FrameNumberNumericInterface.h:221
void DisplayFormatChanged()
Definition FrameNumberNumericInterface.h:226
virtual FOnSettingChanged * GetOnSettingChanged() override
Definition FrameNumberNumericInterface.h:231
virtual FString ToString(const double &Value) const override
Definition FrameNumberNumericInterface.h:74
FString GetSubframeIndicator() const
Definition FrameNumberNumericInterface.h:215
virtual void SetMaxFractionalDigits(const TAttribute< TOptional< int32 > > &NewValue) override
Definition FrameNumberNumericInterface.h:57
FFrameNumberInterface(const TAttribute< EFrameNumberDisplayFormats > &InDisplayFormatAttr, const TAttribute< uint8 > &InOnGetZeroPadFrameNumber, const TAttribute< FFrameRate > &InTickResolutionAttr, const TAttribute< FFrameRate > &InDisplayRateAttr)
Definition FrameNumberNumericInterface.h:32
virtual bool IsCharacterValid(TCHAR InChar) const override
Definition FrameNumberNumericInterface.h:60
virtual int32 GetMinFractionalDigits() const override
Definition FrameNumberNumericInterface.h:45
virtual TOptional< double > FromString(const FString &InString, const double &InExistingValue) override
Definition FrameNumberNumericInterface.h:124
virtual int32 GetMaxFractionalDigits() const override
Definition FrameNumberNumericInterface.h:49
Definition FrameNumberTimeEvaluator.h:25
int32 Value
Definition FrameNumber.h:77
Definition FrameRate.h:21
static FFrameTime TransformTime(FFrameTime SourceTime, FFrameRate SourceRate, FFrameRate DestinationRate)
Definition FrameRate.h:302
Definition FrameTime.h:16
static FFrameTime FromDecimal(double InDecimalFrame)
Definition FrameTime.h:313
FFrameNumber FloorToFrame() const
Definition FrameTime.h:290
UE_FORCEINLINE_HINT float GetSubFrame() const
Definition FrameTime.h:64
UE_FORCEINLINE_HINT FFrameNumber GetFrame() const
Definition FrameTime.h:56
static UE_FORCEINLINE_HINT bool IsNearlyZero(float Value, float ErrorTolerance=UE_SMALL_NUMBER)
Definition UnrealMathUtility.h:407
Definition Text.h:199
FNumberFormattingOptions & SetUseGrouping(bool InValue)
Definition Text.h:206
FNumberFormattingOptions & SetMaximumFractionalDigits(int32 InValue)
Definition Text.h:224
FNumberFormattingOptions & SetMinimumFractionalDigits(int32 InValue)
Definition Text.h:221
Definition Timecode.h:19
static bool IsDropFormatTimecodeSupported(const double InRate)
Definition Timecode.h:308
static FTimecode FromFrameNumber(const FFrameNumber &InFrameNumber, const FFrameRate &InFrameRate, bool InbDropFrame)
Definition Timecode.h:161
Definition NumericTypeInterface.h:21
Definition Optional.h:131