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

219 lines
8.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Framework/Text/RichTextLayoutMarshaller.h"
#include "Styling/ISlateStyle.h"
#include "Styling/SlateTypes.h"
#include "Framework/Text/SlateTextRun.h"
#include "Framework/Text/IRichTextMarkupWriter.h"
#include "Framework/Text/RichTextMarkupProcessing.h"
#include "Framework/Text/SlateTextLayout.h"
#include "Framework/Text/SlateTextUnderlineLineHighlighter.h"
#if WITH_FANCY_TEXT
TSharedRef< FRichTextLayoutMarshaller > FRichTextLayoutMarshaller::Create(TArray< TSharedRef< ITextDecorator > > InDecorators, const ISlateStyle* const InDecoratorStyleSet)
{
return MakeShareable(new FRichTextLayoutMarshaller(MoveTemp(InDecorators), InDecoratorStyleSet));
}
TSharedRef< FRichTextLayoutMarshaller > FRichTextLayoutMarshaller::Create(TSharedPtr< IRichTextMarkupParser > InParser, TSharedPtr< IRichTextMarkupWriter > InWriter, TArray< TSharedRef< ITextDecorator > > InDecorators, const ISlateStyle* const InDecoratorStyleSet)
{
return MakeShareable(new FRichTextLayoutMarshaller(MoveTemp(InParser), MoveTemp(InWriter), MoveTemp(InDecorators), InDecoratorStyleSet));
}
FRichTextLayoutMarshaller::~FRichTextLayoutMarshaller()
{
}
void FRichTextLayoutMarshaller::SetText(const FString& SourceString, FTextLayout& TargetTextLayout)
{
const FTextBlockStyle& DefaultTextStyle = static_cast<FSlateTextLayout&>(TargetTextLayout).GetDefaultTextStyle();
TArray<FTextLineParseResults> LineParseResultsArray;
FString ProcessedString;
Parser->Process(LineParseResultsArray, SourceString, ProcessedString);
TArray<FTextLayout::FNewLineData> LinesToAdd;
LinesToAdd.Reserve(LineParseResultsArray.Num());
TArray<FTextLineHighlight> LineHighlightsToAdd;
TMap<const FTextBlockStyle*, TSharedPtr<FSlateTextUnderlineLineHighlighter>> CachedUnderlineHighlighters;
TMap<const FTextBlockStyle*, TSharedPtr<FSlateTextStrikeLineHighlighter>> CachedStrikeLineHighlighters;
// Iterate through parsed line results and create processed lines with runs.
for (int32 LineIndex = 0; LineIndex < LineParseResultsArray.Num(); ++LineIndex)
{
const FTextLineParseResults& LineParseResults = LineParseResultsArray[LineIndex];
TSharedRef<FString> ModelString = MakeShareable(new FString());
TArray< TSharedRef< IRun > > Runs;
for (const FTextRunParseResults& RunParseResult : LineParseResults.Runs)
{
AppendRunsForText(LineIndex, RunParseResult, ProcessedString, DefaultTextStyle, ModelString, TargetTextLayout, Runs, LineHighlightsToAdd, CachedUnderlineHighlighters, CachedStrikeLineHighlighters);
}
LinesToAdd.Emplace(MoveTemp(ModelString), MoveTemp(Runs));
}
TargetTextLayout.AddLines(LinesToAdd);
TargetTextLayout.SetLineHighlights(LineHighlightsToAdd);
}
void FRichTextLayoutMarshaller::GetText(FString& TargetString, const FTextLayout& SourceTextLayout)
{
const auto& SourceLineModels = SourceTextLayout.GetLineModels();
TArray<IRichTextMarkupWriter::FRichTextLine> WriterLines;
WriterLines.Reserve(SourceLineModels.Num());
for (const FTextLayout::FLineModel& LineModel : SourceLineModels)
{
IRichTextMarkupWriter::FRichTextLine WriterLine;
WriterLine.Runs.Reserve(LineModel.Runs.Num());
for (const FTextLayout::FRunModel& RunModel : LineModel.Runs)
{
FString RunText;
RunModel.AppendTextTo(RunText);
WriterLine.Runs.Emplace(IRichTextMarkupWriter::FRichTextRun(RunModel.GetRun()->GetRunInfo(), RunText));
}
WriterLines.Add(WriterLine);
}
Writer->Write(WriterLines, TargetString);
}
void FRichTextLayoutMarshaller::SetFontSizeMultiplier(const float NewFontSizeMultiplier)
{
if (ensure(NewFontSizeMultiplier != 0.0f))
{
FontSizeMultiplier = NewFontSizeMultiplier;
}
}
FRichTextLayoutMarshaller::FRichTextLayoutMarshaller(TArray< TSharedRef< ITextDecorator > > InDecorators, const ISlateStyle* const InDecoratorStyleSet)
: Parser(FDefaultRichTextMarkupParser::GetStaticInstance())
, Writer(FDefaultRichTextMarkupWriter::Create())
, Decorators(MoveTemp(InDecorators))
, InlineDecorators()
, DecoratorStyleSet(InDecoratorStyleSet)
{
}
FRichTextLayoutMarshaller::FRichTextLayoutMarshaller(TSharedPtr< IRichTextMarkupParser > InParser, TSharedPtr< IRichTextMarkupWriter > InWriter, TArray< TSharedRef< ITextDecorator > > InDecorators, const ISlateStyle* const InDecoratorStyleSet)
: Parser(MoveTemp(InParser))
, Writer(MoveTemp(InWriter))
, Decorators(MoveTemp(InDecorators))
, InlineDecorators()
, DecoratorStyleSet(InDecoratorStyleSet)
{
}
TSharedPtr< ITextDecorator > FRichTextLayoutMarshaller::TryGetDecorator(const FString& Line, const FTextRunParseResults& TextRun) const
{
for (auto DecoratorIter = InlineDecorators.CreateConstIterator(); DecoratorIter; ++DecoratorIter)
{
if ((*DecoratorIter)->Supports(TextRun, Line))
{
return *DecoratorIter;
}
}
for (auto DecoratorIter = Decorators.CreateConstIterator(); DecoratorIter; ++DecoratorIter)
{
if ((*DecoratorIter)->Supports(TextRun, Line))
{
return *DecoratorIter;
}
}
return nullptr;
}
void FRichTextLayoutMarshaller::AppendRunsForText(
const int32 LineIndex,
const FTextRunParseResults& TextRun,
const FString& ProcessedString,
const FTextBlockStyle& DefaultTextStyle,
const TSharedRef<FString>& InOutModelText,
FTextLayout& TargetTextLayout,
TArray<TSharedRef<IRun>>& Runs,
TArray<FTextLineHighlight>& LineHighlights,
TMap<const FTextBlockStyle*, TSharedPtr<FSlateTextUnderlineLineHighlighter>>& CachedUnderlineHighlighters,
TMap<const FTextBlockStyle*, TSharedPtr<FSlateTextStrikeLineHighlighter>>& CachedStrikeLineHighlighters
)
{
TSharedPtr< ISlateRun > Run;
TSharedPtr< ITextDecorator > Decorator = TryGetDecorator(ProcessedString, TextRun);
if (Decorator.IsValid())
{
// Create run and update model string.
Run = Decorator->Create(TargetTextLayout.AsShared(), TextRun, ProcessedString, InOutModelText, DecoratorStyleSet);
}
else
{
FRunInfo RunInfo(TextRun.Name);
for (const TPair<FString, FTextRange>& Pair : TextRun.MetaData)
{
int32 Length = FMath::Max(0, Pair.Value.EndIndex - Pair.Value.BeginIndex);
RunInfo.MetaData.Add(Pair.Key, ProcessedString.Mid(Pair.Value.BeginIndex, Length));
}
const FTextBlockStyle* TextBlockStyle;
FTextRange ModelRange;
ModelRange.BeginIndex = InOutModelText->Len();
if (!(TextRun.Name.IsEmpty()) && DecoratorStyleSet->HasWidgetStyle< FTextBlockStyle >(FName(*TextRun.Name)))
{
*InOutModelText += ProcessedString.Mid(TextRun.ContentRange.BeginIndex, TextRun.ContentRange.EndIndex - TextRun.ContentRange.BeginIndex);
TextBlockStyle = &(DecoratorStyleSet->GetWidgetStyle< FTextBlockStyle >(FName(*TextRun.Name)));
}
else
{
*InOutModelText += ProcessedString.Mid(TextRun.OriginalRange.BeginIndex, TextRun.OriginalRange.EndIndex - TextRun.OriginalRange.BeginIndex);
TextBlockStyle = &DefaultTextStyle;
}
ModelRange.EndIndex = InOutModelText->Len();
// Create run.
TSharedPtr< FSlateTextRun > SlateTextRun = FSlateTextRun::Create(RunInfo, InOutModelText, *TextBlockStyle, ModelRange);
if (SlateTextRun)
{
// Apply the FontSizeMultiplier at the style use by the IRun
SlateTextRun->ApplyFontSizeMultiplierOnTextStyle(FontSizeMultiplier);
}
Run = SlateTextRun;
if (!TextBlockStyle->UnderlineBrush.GetResourceName().IsNone())
{
TSharedPtr<FSlateTextUnderlineLineHighlighter> UnderlineLineHighlighter = CachedUnderlineHighlighters.FindRef(TextBlockStyle);
if (!UnderlineLineHighlighter.IsValid())
{
UnderlineLineHighlighter = FSlateTextUnderlineLineHighlighter::Create(TextBlockStyle->UnderlineBrush, TextBlockStyle->Font, TextBlockStyle->ColorAndOpacity, TextBlockStyle->ShadowOffset, TextBlockStyle->ShadowColorAndOpacity);
CachedUnderlineHighlighters.Add(TextBlockStyle, UnderlineLineHighlighter);
}
LineHighlights.Add(FTextLineHighlight(LineIndex, ModelRange, FSlateTextUnderlineLineHighlighter::DefaultZIndex, UnderlineLineHighlighter.ToSharedRef()));
}
if (!TextBlockStyle->StrikeBrush.GetResourceName().IsNone())
{
TSharedPtr<FSlateTextStrikeLineHighlighter> StrikeLineHighlighter = CachedStrikeLineHighlighters.FindRef(TextBlockStyle);
if (!StrikeLineHighlighter.IsValid())
{
StrikeLineHighlighter = FSlateTextStrikeLineHighlighter::Create(TextBlockStyle->StrikeBrush, TextBlockStyle->Font, TextBlockStyle->ColorAndOpacity, TextBlockStyle->ShadowOffset, TextBlockStyle->ShadowColorAndOpacity);
CachedStrikeLineHighlighters.Add(TextBlockStyle, StrikeLineHighlighter);
}
LineHighlights.Add(FTextLineHighlight(LineIndex, ModelRange, FSlateTextStrikeLineHighlighter::DefaultZIndex, StrikeLineHighlighter.ToSharedRef()));
}
}
Runs.Add(Run.ToSharedRef());
}
#endif //WITH_FANCY_TEXT