788 lines
24 KiB
C++
788 lines
24 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "UObject/ObjectMacros.h"
|
|
#include "Misc/Attribute.h"
|
|
#include "Layout/Margin.h"
|
|
#include "Framework/Text/TextRunRenderer.h"
|
|
#include "Framework/Text/TextLineHighlight.h"
|
|
#include "Framework/Text/IRun.h"
|
|
#include "Styling/SlateTypes.h"
|
|
|
|
#include "TextLayout.generated.h"
|
|
|
|
#define TEXT_LAYOUT_DEBUG 0
|
|
|
|
class IBreakIterator;
|
|
class ILayoutBlock;
|
|
class ILineHighlighter;
|
|
class IRunRenderer;
|
|
enum class ETextHitPoint : uint8;
|
|
enum class ETextShapingMethod : uint8;
|
|
|
|
UENUM( BlueprintType )
|
|
namespace ETextJustify
|
|
{
|
|
enum Type : int
|
|
{
|
|
/**
|
|
* Justify the text logically to the left.
|
|
* When text is flowing left-to-right, this will align text visually to the left.
|
|
* When text is flowing right-to-left, this will align text visually to the right.
|
|
*/
|
|
Left,
|
|
|
|
/**
|
|
* Justify the text in the center.
|
|
* Text flow direction has no impact on this justification mode.
|
|
*/
|
|
Center,
|
|
|
|
/**
|
|
* Justify the text logically to the right.
|
|
* When text is flowing left-to-right, this will align text visually to the right.
|
|
* When text is flowing right-to-left, this will align text visually to the left.
|
|
*/
|
|
Right,
|
|
|
|
/**
|
|
* Always justify the text to the left, regardless of the flow direction of the current culture.
|
|
*/
|
|
InvariantLeft,
|
|
|
|
/**
|
|
* Always justify the text to the right, regardless of the flow direction of the current culture.
|
|
*/
|
|
InvariantRight,
|
|
};
|
|
}
|
|
|
|
|
|
/**
|
|
* The different methods that can be used if a word is too long to be broken by the default line-break iterator.
|
|
*/
|
|
UENUM( BlueprintType )
|
|
enum class ETextWrappingPolicy : uint8
|
|
{
|
|
/** No fallback, just use the given line-break iterator */
|
|
DefaultWrapping = 0,
|
|
|
|
/** Fallback to per-character wrapping if a word is too long */
|
|
AllowPerCharacterWrapping,
|
|
};
|
|
|
|
/**
|
|
* The different directions that text can flow within a paragraph of text.
|
|
* @note If you change this enum, make sure and update CVarDefaultTextFlowDirection and GetDefaultTextFlowDirection.
|
|
*/
|
|
UENUM( BlueprintType )
|
|
enum class ETextFlowDirection : uint8
|
|
{
|
|
/** Automatically detect the flow direction for each paragraph from its text */
|
|
Auto = 0,
|
|
|
|
/** Force text to be flowed left-to-right */
|
|
LeftToRight,
|
|
|
|
/** Force text to be flowed right-to-left */
|
|
RightToLeft,
|
|
|
|
/** Uses the set culture to determine if text should flow left-to-right or right-to-left. By comparison, Auto will use the text itself to determine it. */
|
|
Culture,
|
|
};
|
|
|
|
/** Get the default text flow direction (from the "Slate.DefaultTextFlowDirection" CVar) */
|
|
SLATE_API ETextFlowDirection GetDefaultTextFlowDirection();
|
|
|
|
/** Location within the text model. */
|
|
struct FTextLocation
|
|
{
|
|
public:
|
|
FTextLocation( const int32 InLineIndex = 0, const int32 InOffset = 0 )
|
|
: LineIndex( InLineIndex )
|
|
, Offset( InOffset )
|
|
{
|
|
|
|
}
|
|
|
|
FTextLocation( const FTextLocation& InLocation, const int32 InOffset )
|
|
: LineIndex( InLocation.GetLineIndex() )
|
|
, Offset(FMath::Max(InLocation.GetOffset() + InOffset, 0))
|
|
{
|
|
|
|
}
|
|
|
|
bool operator==( const FTextLocation& Other ) const
|
|
{
|
|
return
|
|
LineIndex == Other.LineIndex &&
|
|
Offset == Other.Offset;
|
|
}
|
|
|
|
bool operator!=( const FTextLocation& Other ) const
|
|
{
|
|
return
|
|
LineIndex != Other.LineIndex ||
|
|
Offset != Other.Offset;
|
|
}
|
|
|
|
bool operator<( const FTextLocation& Other ) const
|
|
{
|
|
return this->LineIndex < Other.LineIndex || (this->LineIndex == Other.LineIndex && this->Offset < Other.Offset);
|
|
}
|
|
|
|
int32 GetLineIndex() const { return LineIndex; }
|
|
int32 GetOffset() const { return Offset; }
|
|
bool IsValid() const { return LineIndex != INDEX_NONE && Offset != INDEX_NONE; }
|
|
|
|
friend FORCEINLINE uint32 GetTypeHash(const FTextLocation& InSubject)
|
|
{
|
|
return HashCombine(InSubject.LineIndex, InSubject.Offset);
|
|
}
|
|
|
|
private:
|
|
int32 LineIndex;
|
|
int32 Offset;
|
|
};
|
|
|
|
class FTextSelection
|
|
{
|
|
|
|
public:
|
|
|
|
FTextLocation LocationA;
|
|
|
|
FTextLocation LocationB;
|
|
|
|
public:
|
|
|
|
FTextSelection()
|
|
: LocationA(INDEX_NONE)
|
|
, LocationB(INDEX_NONE)
|
|
{
|
|
}
|
|
|
|
FTextSelection(const FTextLocation& InLocationA, const FTextLocation& InLocationB)
|
|
: LocationA(InLocationA)
|
|
, LocationB(InLocationB)
|
|
{
|
|
}
|
|
|
|
const FTextLocation& GetBeginning() const
|
|
{
|
|
if (LocationA.GetLineIndex() == LocationB.GetLineIndex())
|
|
{
|
|
if (LocationA.GetOffset() < LocationB.GetOffset())
|
|
{
|
|
return LocationA;
|
|
}
|
|
|
|
return LocationB;
|
|
}
|
|
else if (LocationA.GetLineIndex() < LocationB.GetLineIndex())
|
|
{
|
|
return LocationA;
|
|
}
|
|
|
|
return LocationB;
|
|
}
|
|
|
|
const FTextLocation& GetEnd() const
|
|
{
|
|
if (LocationA.GetLineIndex() == LocationB.GetLineIndex())
|
|
{
|
|
if (LocationA.GetOffset() > LocationB.GetOffset())
|
|
{
|
|
return LocationA;
|
|
}
|
|
|
|
return LocationB;
|
|
}
|
|
else if (LocationA.GetLineIndex() > LocationB.GetLineIndex())
|
|
{
|
|
return LocationA;
|
|
}
|
|
|
|
return LocationB;
|
|
}
|
|
};
|
|
|
|
class FTextLayout
|
|
: public TSharedFromThis<FTextLayout>
|
|
{
|
|
public:
|
|
|
|
struct FBlockDefinition
|
|
{
|
|
/** Range inclusive of trailing whitespace, as used to visually display and interact with the text */
|
|
FTextRange ActualRange;
|
|
/** The render to use with this run (if any) */
|
|
TSharedPtr< IRunRenderer > Renderer;
|
|
};
|
|
|
|
struct FBreakCandidate
|
|
{
|
|
/** Range inclusive of trailing whitespace, as used to visually display and interact with the text */
|
|
FTextRange ActualRange;
|
|
/** Range exclusive of trailing whitespace, as used to perform wrapping on a word boundary */
|
|
FTextRange TrimmedRange;
|
|
/** Measured size inclusive of trailing whitespace, as used to visually display and interact with the text */
|
|
FVector2D ActualSize;
|
|
/** Measured width exclusive of trailing whitespace, as used to perform wrapping on a word boundary */
|
|
float TrimmedWidth;
|
|
/** If this break candidate has trailing whitespace, this is the width of the first character of the trailing whitespace */
|
|
float FirstTrailingWhitespaceCharWidth;
|
|
|
|
int16 MaxAboveBaseline;
|
|
int16 MaxBelowBaseline;
|
|
|
|
int8 Kerning;
|
|
|
|
#if TEXT_LAYOUT_DEBUG
|
|
FString DebugSlice;
|
|
#endif
|
|
};
|
|
|
|
class FRunModel
|
|
{
|
|
public:
|
|
|
|
SLATE_API FRunModel( const TSharedRef< IRun >& InRun);
|
|
|
|
public:
|
|
|
|
SLATE_API TSharedRef< IRun > GetRun() const;;
|
|
|
|
SLATE_API void BeginLayout();
|
|
SLATE_API void EndLayout();
|
|
|
|
SLATE_API FTextRange GetTextRange() const;
|
|
SLATE_API void SetTextRange( const FTextRange& Value );
|
|
|
|
SLATE_API int16 GetBaseLine( float Scale ) const;
|
|
SLATE_API int16 GetMaxHeight( float Scale ) const;
|
|
|
|
SLATE_API FVector2D Measure( int32 BeginIndex, int32 EndIndex, float Scale, const FRunTextContext& InTextContext );
|
|
|
|
SLATE_API int8 GetKerning( int32 CurrentIndex, float Scale, const FRunTextContext& InTextContext );
|
|
|
|
static SLATE_API int32 BinarySearchForBeginIndex( const TArray< FTextRange >& Ranges, int32 BeginIndex );
|
|
|
|
static SLATE_API int32 BinarySearchForEndIndex( const TArray< FTextRange >& Ranges, int32 RangeBeginIndex, int32 EndIndex );
|
|
|
|
SLATE_API TSharedRef< ILayoutBlock > CreateBlock( const FBlockDefinition& BlockDefine, float InScale, const FLayoutBlockTextContext& InTextContext ) const;
|
|
|
|
SLATE_API void ClearCache();
|
|
|
|
SLATE_API void AppendTextTo(FString& Text) const;
|
|
SLATE_API void AppendTextTo(FString& Text, const FTextRange& Range) const;
|
|
|
|
private:
|
|
|
|
TSharedRef< IRun > Run;
|
|
TArray< FTextRange > MeasuredRanges;
|
|
TArray< FVector2D > MeasuredRangeSizes;
|
|
};
|
|
|
|
struct ELineModelDirtyState
|
|
{
|
|
typedef uint8 Flags;
|
|
enum Enum
|
|
{
|
|
None = 0,
|
|
WrappingInformation = 1<<0,
|
|
TextBaseDirection = 1<<1,
|
|
ShapingCache = 1<<2,
|
|
All = WrappingInformation | TextBaseDirection | ShapingCache,
|
|
};
|
|
};
|
|
|
|
struct FLineModel
|
|
{
|
|
public:
|
|
|
|
SLATE_API FLineModel( const TSharedRef< FString >& InText );
|
|
|
|
TSharedRef< FString > Text;
|
|
FShapedTextCacheRef ShapedTextCache;
|
|
TextBiDi::ETextDirection TextBaseDirection;
|
|
TArray< FRunModel > Runs;
|
|
TArray< FBreakCandidate > BreakCandidates;
|
|
TArray< FTextRunRenderer > RunRenderers;
|
|
TArray< FTextLineHighlight > LineHighlights;
|
|
ELineModelDirtyState::Flags DirtyFlags;
|
|
};
|
|
|
|
struct FLineViewHighlight
|
|
{
|
|
/** Offset for this highlight, relative to the FLineView::Offset that contains it */
|
|
FVector2D Offset;
|
|
/** Width for this highlight, the height will be either FLineView::Size.Y or FLineView::TextHeight depending on whether you want to highlight the entire line, or just the text within the line */
|
|
float Width;
|
|
/** Custom highlighter implementation used to do the painting */
|
|
TSharedPtr< ILineHighlighter > Highlighter;
|
|
};
|
|
|
|
struct FLineView
|
|
{
|
|
TArray< TSharedRef< ILayoutBlock > > Blocks;
|
|
TArray< FLineViewHighlight > UnderlayHighlights;
|
|
TArray< FLineViewHighlight > OverlayHighlights;
|
|
FVector2D Offset;
|
|
FVector2D Size;
|
|
float TextHeight;
|
|
float JustificationWidth;
|
|
FTextRange Range;
|
|
TextBiDi::ETextDirection TextBaseDirection;
|
|
int32 ModelIndex;
|
|
};
|
|
|
|
/** A mapping between the offsets into the text as a flat string (with line-breaks), and the internal lines used within a text layout */
|
|
struct FTextOffsetLocations
|
|
{
|
|
friend class FTextLayout;
|
|
|
|
public:
|
|
SLATE_API int32 TextLocationToOffset(const FTextLocation& InLocation) const;
|
|
SLATE_API FTextLocation OffsetToTextLocation(const int32 InOffset) const;
|
|
SLATE_API int32 GetTextLength() const;
|
|
|
|
private:
|
|
struct FOffsetEntry
|
|
{
|
|
FOffsetEntry(const int32 InFlatStringIndex, const int32 InDocumentLineLength)
|
|
: FlatStringIndex(InFlatStringIndex)
|
|
, DocumentLineLength(InDocumentLineLength)
|
|
{
|
|
}
|
|
|
|
/** Index in the flat string for this entry */
|
|
int32 FlatStringIndex;
|
|
|
|
/** The length of the line in the document (not including any trailing \n character) */
|
|
int32 DocumentLineLength;
|
|
};
|
|
|
|
/** This array contains one entry for each line in the document;
|
|
the array index is the line number, and the entry contains the index in the flat string that marks the start of the line,
|
|
along with the length of the line (not including any trailing \n character) */
|
|
TArray<FOffsetEntry> OffsetData;
|
|
};
|
|
|
|
public:
|
|
|
|
SLATE_API virtual ~FTextLayout();
|
|
|
|
FORCEINLINE const TArray< FTextLayout::FLineView >& GetLineViews() const { return LineViews; }
|
|
FORCEINLINE const TArray< FTextLayout::FLineModel >& GetLineModels() const { return LineModels; }
|
|
|
|
/**
|
|
* Get the size of the text layout, including any lines which extend beyond the wrapping boundaries (eg, lines with lots of trailing whitespace, or lines with no break candidates)
|
|
* @note This value is unscaled
|
|
*/
|
|
SLATE_API FVector2D GetSize() const;
|
|
|
|
/**
|
|
* Get the size of the text layout that can actually be seen from the parent widget
|
|
*/
|
|
SLATE_API FVector2D GetViewSize() const;
|
|
|
|
/**
|
|
* Get the size of the text layout, including any lines which extend beyond the wrapping boundaries (eg, lines with lots of trailing whitespace, or lines with no break candidates)
|
|
* @note This value is scaled
|
|
*/
|
|
SLATE_API FVector2D GetDrawSize() const;
|
|
|
|
/**
|
|
* Get the size of the text layout after the text has been wrapped, and including the first piece of trailing whitespace for any given soft-wrapped line
|
|
* @note This value is unscaled
|
|
*/
|
|
SLATE_API FVector2D GetWrappedSize() const;
|
|
|
|
/**
|
|
* Get the size of the text layout after the text has been wrapped, and including the first piece of trailing whitespace for any given soft-wrapped line
|
|
* @note This value is scaled
|
|
*/
|
|
SLATE_API FVector2D GetWrappedDrawSize() const;
|
|
|
|
FORCEINLINE float GetWrappingWidth() const { return WrappingWidth; }
|
|
SLATE_API void SetWrappingWidth( float Value );
|
|
|
|
FORCEINLINE ETextWrappingPolicy GetWrappingPolicy() const { return WrappingPolicy; }
|
|
SLATE_API void SetWrappingPolicy(ETextWrappingPolicy Value);
|
|
|
|
FORCEINLINE float GetLineHeightPercentage() const { return LineHeightPercentage; }
|
|
SLATE_API void SetLineHeightPercentage( float Value );
|
|
|
|
FORCEINLINE bool GetApplyLineHeightToBottomLine() const { return ApplyLineHeightToBottomLine; }
|
|
SLATE_API void SetApplyLineHeightToBottomLine( bool Value );
|
|
|
|
FORCEINLINE ETextJustify::Type GetJustification() const { return Justification; }
|
|
SLATE_API void SetJustification( ETextJustify::Type Value );
|
|
|
|
/** Get the visual justification for this document (based on the visual justification used by the first line of text) */
|
|
SLATE_API ETextJustify::Type GetVisualJustification() const;
|
|
|
|
/** @note This option is destructive to the model text, so changing it requires refreshing the text layout from its marshaller */
|
|
FORCEINLINE ETextTransformPolicy GetTransformPolicy() const { return TransformPolicy; }
|
|
SLATE_API void SetTransformPolicy(ETextTransformPolicy Value);
|
|
|
|
FORCEINLINE float GetScale() const { return Scale; }
|
|
SLATE_API void SetScale( float Value );
|
|
|
|
FORCEINLINE ETextShapingMethod GetTextShapingMethod() const { return TextShapingMethod; }
|
|
SLATE_API void SetTextShapingMethod( const ETextShapingMethod InTextShapingMethod );
|
|
|
|
FORCEINLINE ETextFlowDirection GetTextFlowDirection() const { return TextFlowDirection; }
|
|
SLATE_API void SetTextFlowDirection( const ETextFlowDirection InTextFlowDirection );
|
|
|
|
SLATE_API void SetTextOverflowPolicy(const TOptional<ETextOverflowPolicy> InTextOverflowPolicy);
|
|
|
|
FORCEINLINE FMargin GetMargin() const { return Margin; }
|
|
SLATE_API void SetMargin( const FMargin& InMargin );
|
|
|
|
SLATE_API void SetVisibleRegion( const FVector2D& InViewSize, const FVector2D& InScrollOffset );
|
|
|
|
/** Set the iterator to use to detect appropriate soft-wrapping points for lines (or null to go back to using the default) */
|
|
SLATE_API void SetLineBreakIterator( TSharedPtr<IBreakIterator> InLineBreakIterator );
|
|
|
|
/** Set the information used to help identify who owns this text layout in the case of an error */
|
|
SLATE_API void SetDebugSourceInfo(const TAttribute<FString>& InDebugSourceInfo);
|
|
|
|
SLATE_API void ClearLines();
|
|
|
|
struct FNewLineData
|
|
{
|
|
FNewLineData(TSharedRef<FString> InText, TArray<TSharedRef<IRun>> InRuns)
|
|
: Text(MoveTemp(InText))
|
|
, Runs(MoveTemp(InRuns))
|
|
{
|
|
}
|
|
|
|
TSharedRef<FString> Text;
|
|
TArray<TSharedRef<IRun>> Runs;
|
|
};
|
|
|
|
SLATE_API void AddLine( const FNewLineData& NewLine );
|
|
|
|
SLATE_API void AddLines( const TArray<FNewLineData>& NewLines );
|
|
|
|
/**
|
|
* Clears all run renderers
|
|
*/
|
|
SLATE_API void ClearRunRenderers();
|
|
|
|
/**
|
|
* Replaces the current set of run renderers with the provided renderers.
|
|
*/
|
|
SLATE_API void SetRunRenderers( const TArray< FTextRunRenderer >& Renderers );
|
|
|
|
/**
|
|
* Adds a single run renderer to the existing set of renderers.
|
|
*/
|
|
SLATE_API void AddRunRenderer( const FTextRunRenderer& Renderer );
|
|
|
|
/**
|
|
* Removes a single run renderer to the existing set of renderers.
|
|
*/
|
|
SLATE_API void RemoveRunRenderer( const FTextRunRenderer& Renderer );
|
|
|
|
/**
|
|
* Clears all line highlights
|
|
*/
|
|
SLATE_API void ClearLineHighlights();
|
|
|
|
/**
|
|
* Replaces the current set of line highlights with the provided highlights.
|
|
*/
|
|
SLATE_API void SetLineHighlights( const TArray< FTextLineHighlight >& Highlights );
|
|
|
|
/**
|
|
* Adds a single line highlight to the existing set of highlights.
|
|
*/
|
|
SLATE_API void AddLineHighlight( const FTextLineHighlight& Highlight );
|
|
|
|
/**
|
|
* Removes a single line highlight to the existing set of highlights.
|
|
*/
|
|
SLATE_API void RemoveLineHighlight( const FTextLineHighlight& Highlight );
|
|
|
|
/**
|
|
* Updates the TextLayout's if any changes have occurred since the last update.
|
|
*/
|
|
SLATE_API virtual void UpdateIfNeeded();
|
|
|
|
SLATE_API virtual void UpdateLayout();
|
|
|
|
SLATE_API virtual void UpdateHighlights();
|
|
|
|
SLATE_API void DirtyRunLayout(const TSharedRef<const IRun>& Run);
|
|
|
|
SLATE_API void DirtyLayout();
|
|
|
|
SLATE_API bool IsLayoutDirty() const;
|
|
|
|
SLATE_API int32 GetLineViewIndexForTextLocation(const TArray< FTextLayout::FLineView >& LineViews, const FTextLocation& Location, const bool bPerformInclusiveBoundsCheck) const;
|
|
|
|
/**
|
|
*
|
|
*/
|
|
SLATE_API FTextLocation GetTextLocationAt( const FVector2D& Relative, ETextHitPoint* const OutHitPoint = nullptr ) const;
|
|
|
|
SLATE_API FTextLocation GetTextLocationAt( const FLineView& LineView, const FVector2D& Relative, ETextHitPoint* const OutHitPoint = nullptr ) const;
|
|
|
|
SLATE_API FVector2D GetLocationAt( const FTextLocation& Location, const bool bPerformInclusiveBoundsCheck ) const;
|
|
|
|
SLATE_API bool SplitLineAt(const FTextLocation& Location);
|
|
|
|
SLATE_API bool JoinLineWithNextLine(int32 LineIndex);
|
|
|
|
SLATE_API bool InsertAt(const FTextLocation& Location, TCHAR Character);
|
|
|
|
SLATE_API bool InsertAt(const FTextLocation& Location, const FString& Text);
|
|
|
|
SLATE_API bool InsertAt(const FTextLocation& Location, TSharedRef<IRun> InRun, const bool bAlwaysKeepRightRun = false);
|
|
|
|
SLATE_API bool RemoveAt(const FTextLocation& Location, int32 Count = 1);
|
|
|
|
SLATE_API bool RemoveLine(int32 LineIndex);
|
|
|
|
SLATE_API bool IsEmpty() const;
|
|
|
|
SLATE_API int32 GetLineCount() const;
|
|
|
|
SLATE_API void GetAsText(FString& DisplayText, FTextOffsetLocations* const OutTextOffsetLocations = nullptr) const;
|
|
|
|
SLATE_API void GetAsText(FText& DisplayText, FTextOffsetLocations* const OutTextOffsetLocations = nullptr) const;
|
|
|
|
/** Constructs an array containing the mappings between the text that would be returned by GetAsText, and the internal FTextLocation points used within this text layout */
|
|
SLATE_API void GetTextOffsetLocations(FTextOffsetLocations& OutTextOffsetLocations) const;
|
|
|
|
SLATE_API void GetSelectionAsText(FString& DisplayText, const FTextSelection& Selection) const;
|
|
|
|
SLATE_API FTextSelection GetGraphemeAt(const FTextLocation& Location) const;
|
|
|
|
SLATE_API FTextSelection GetWordAt(const FTextLocation& Location) const;
|
|
|
|
protected:
|
|
|
|
SLATE_API FTextLayout();
|
|
|
|
/**
|
|
* Calculates the text direction for each line based upon the current shaping method and document flow direction
|
|
* When changing the shaping method, or document flow direction, all the lines need to be dirtied (see DirtyAllLineModels(ELineModelDirtyState::TextBaseDirection))
|
|
*/
|
|
SLATE_API void CalculateTextDirection();
|
|
|
|
/**
|
|
* Calculates the text direction for the given line based upon the current shaping method and document flow direction
|
|
*/
|
|
SLATE_API void CalculateLineTextDirection(FLineModel& LineModel) const;
|
|
|
|
/**
|
|
* Calculates the visual justification for the given line view
|
|
*/
|
|
SLATE_API ETextJustify::Type CalculateLineViewVisualJustification(const FLineView& LineView) const;
|
|
|
|
/**
|
|
* Create the wrapping cache for the current text based upon the current scale
|
|
* Each line keeps its own cached state, so needs to be cleared when changing the text within a line
|
|
* When changing the scale, all the lines need to be cleared (see DirtyAllLineModels(ELineModelDirtyState::WrappingInformation))
|
|
*/
|
|
SLATE_API void CreateWrappingCache();
|
|
|
|
/**
|
|
* Create the wrapping cache for the given line based upon the current scale
|
|
*/
|
|
SLATE_API void CreateLineWrappingCache(FLineModel& LineModel);
|
|
|
|
/**
|
|
* Flushes the text shaping cache for each line
|
|
*/
|
|
SLATE_API void FlushTextShapingCache();
|
|
|
|
/**
|
|
* Flushes the text shaping cache for the given line
|
|
*/
|
|
SLATE_API void FlushLineTextShapingCache(FLineModel& LineModel);
|
|
|
|
/**
|
|
* Set the given dirty flags on all line models in this layout
|
|
*/
|
|
SLATE_API void DirtyAllLineModels(const ELineModelDirtyState::Flags InDirtyFlags);
|
|
|
|
/**
|
|
* Clears the current layouts view information.
|
|
*/
|
|
SLATE_API void ClearView();
|
|
|
|
/**
|
|
* Transform the given line model text based on the active transform policy.
|
|
* @note This is destructive to the model text!
|
|
*/
|
|
SLATE_API void TransformLineText(FLineModel& LineModel) const;
|
|
|
|
/**
|
|
* Notifies all Runs that we are beginning to generate a new layout.
|
|
*/
|
|
SLATE_API virtual void BeginLayout();
|
|
|
|
/**
|
|
* Notifies all Runs on the given line is beginning to have a new layout generated.
|
|
*/
|
|
SLATE_API void BeginLineLayout(FLineModel& LineModel);
|
|
|
|
/**
|
|
* Notifies all Runs that the layout has finished generating.
|
|
*/
|
|
SLATE_API virtual void EndLayout();
|
|
|
|
/**
|
|
* Notifies all Runs on the given line has finished having a new layout generated.
|
|
*/
|
|
SLATE_API void EndLineLayout(FLineModel& LineModel);
|
|
|
|
/**
|
|
* Called to generate a new empty text run for this text layout
|
|
*/
|
|
virtual TSharedRef<IRun> CreateDefaultTextRun(const TSharedRef<FString>& NewText, const FTextRange& NewRange) const = 0;
|
|
|
|
private:
|
|
|
|
SLATE_API float GetWrappingDrawWidth() const;
|
|
|
|
SLATE_API void FlowLayout();
|
|
SLATE_API void MarginLayout();
|
|
|
|
SLATE_API void FlowLineLayout(const int32 LineModelIndex, const float WrappingDrawWidth, TArray<TSharedRef<ILayoutBlock>>& SoftLine);
|
|
|
|
SLATE_API void FlowHighlights();
|
|
|
|
SLATE_API void JustifyLayout();
|
|
|
|
SLATE_API void CreateLineViewBlocks( int32 LineModelIndex, const int32 StopIndex, const float WrappedLineWidth, const TOptional<float>& JustificationWidth, int32& OutRunIndex, int32& OutRendererIndex, int32& OutPreviousBlockEnd, TArray< TSharedRef< ILayoutBlock > >& OutSoftLine );
|
|
|
|
SLATE_API FBreakCandidate CreateBreakCandidate( int32& OutRunIndex, FLineModel& Line, int32 PreviousBreak, int32 CurrentBreak );
|
|
|
|
SLATE_API void GetAsTextAndOffsets(FString* const OutDisplayText, FTextOffsetLocations* const OutTextOffsetLocations) const;
|
|
|
|
protected:
|
|
|
|
struct ETextLayoutDirtyState
|
|
{
|
|
typedef uint8 Flags;
|
|
enum Enum
|
|
{
|
|
None = 0,
|
|
Layout = 1<<0,
|
|
Highlights = 1<<1,
|
|
All = Layout | Highlights,
|
|
};
|
|
};
|
|
|
|
struct FTextLayoutSize
|
|
{
|
|
FTextLayoutSize()
|
|
: DrawWidth(0.0f)
|
|
, WrappedWidth(0.0f)
|
|
, Height(0.0f)
|
|
{
|
|
}
|
|
|
|
FVector2D GetDrawSize() const
|
|
{
|
|
return FVector2D(DrawWidth, Height);
|
|
}
|
|
|
|
FVector2D GetWrappedSize() const
|
|
{
|
|
return FVector2D(WrappedWidth, Height);
|
|
}
|
|
|
|
/** Width of the text layout, including any lines which extend beyond the wrapping boundaries (eg, lines with lots of trailing whitespace, or lines with no break candidates) */
|
|
float DrawWidth;
|
|
|
|
/** Width of the text layout after the text has been wrapped, and including the first piece of trailing whitespace for any given soft-wrapped line */
|
|
float WrappedWidth;
|
|
|
|
/** Height of the text layout */
|
|
float Height;
|
|
};
|
|
|
|
int32 CachedLayoutGeneration = 0;
|
|
|
|
/** The models for the lines of text. A LineModel represents a single string with no manual breaks. */
|
|
TArray< FLineModel > LineModels;
|
|
|
|
/** The views for the lines of text. A LineView represents a single visual line of text. Multiple LineViews can map to the same LineModel, if for example wrapping occurs. */
|
|
TArray< FLineView > LineViews;
|
|
|
|
/** The indices for all of the line views that require justification. */
|
|
TSet< int32 > LineViewsToJustify;
|
|
|
|
/** Whether parameters on the layout have changed which requires the view be updated. */
|
|
ETextLayoutDirtyState::Flags DirtyFlags;
|
|
|
|
/** The method used to shape the text within this layout */
|
|
ETextShapingMethod TextShapingMethod;
|
|
|
|
/** How should the text within this layout be flowed? */
|
|
ETextFlowDirection TextFlowDirection;
|
|
|
|
/** The scale to draw the text at */
|
|
float Scale;
|
|
|
|
/** The width that the text should be wrap at. If 0 or negative no wrapping occurs. */
|
|
float WrappingWidth;
|
|
|
|
/** The wrapping policy used by this text layout. */
|
|
ETextWrappingPolicy WrappingPolicy;
|
|
|
|
/** The transform policy used by this text layout. */
|
|
ETextTransformPolicy TransformPolicy;
|
|
|
|
/** The size of the margins to put about the text. This is an unscaled value. */
|
|
FMargin Margin;
|
|
|
|
/** How the text should be aligned with the margin. */
|
|
ETextJustify::Type Justification;
|
|
|
|
/** The percentage to modify a line height by. */
|
|
float LineHeightPercentage;
|
|
|
|
/** Whether or not line height should be applied to the last line. */
|
|
bool ApplyLineHeightToBottomLine;
|
|
|
|
/** The final size of the text layout on screen. */
|
|
FTextLayoutSize TextLayoutSize;
|
|
|
|
/** Extra height of the last line due to line height. */
|
|
float OverHeight;
|
|
|
|
/** The size of the text layout that can actually be seen from the parent widget */
|
|
FVector2D ViewSize;
|
|
|
|
/** The scroll offset of the text layout from the parent widget */
|
|
FVector2D ScrollOffset;
|
|
|
|
/** The iterator to use to detect appropriate soft-wrapping points for lines */
|
|
TSharedPtr<IBreakIterator> LineBreakIterator;
|
|
|
|
/** The iterator to use to detect grapheme cluster boundaries */
|
|
TSharedRef<IBreakIterator> GraphemeBreakIterator;
|
|
|
|
/** The iterator to use to detect word boundaries */
|
|
TSharedRef<IBreakIterator> WordBreakIterator;
|
|
|
|
/** Unicode BiDi text detection */
|
|
TUniquePtr<TextBiDi::ITextBiDi> TextBiDiDetection;
|
|
|
|
/** Information given to use by our an external source (typically our owner widget) to help identify who owns this text layout in the case of an error */
|
|
TAttribute<FString> DebugSourceInfo;
|
|
|
|
/** Override for the text overflow policy. If unset, the style is used */
|
|
TOptional<ETextOverflowPolicy> TextOverflowPolicyOverride;
|
|
|
|
};
|