// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. #pragma once namespace TutorialTextHelpers { extern void OnBrowserLinkClicked(const FSlateHyperlinkRun::FMetadata& Metadata); extern void OnDocLinkClicked(const FSlateHyperlinkRun::FMetadata& Metadata); extern void OnTutorialLinkClicked(const FSlateHyperlinkRun::FMetadata& Metadata); extern void OnCodeLinkClicked(const FSlateHyperlinkRun::FMetadata& Metadata); extern void OnAssetLinkClicked(const FSlateHyperlinkRun::FMetadata& Metadata); } namespace EHyperlinkType { enum Type { Browser, UDN, Tutorial, Code, Asset }; } /** Text style and name to display in the UI */ struct FTextStyleAndName { /** Legacy: Flags controlling which TTF or OTF font should be picked from the given font family */ struct EFontStyle { typedef uint8 Flags; enum Flag { Regular = 0, Bold = 1<<0, Italic = 1<<1, }; }; FTextStyleAndName(FName InStyle, FText InDisplayName) : Style(InStyle) , DisplayName(InDisplayName) {} FRunInfo CreateRunInfo() const { FRunInfo RunInfo(TEXT("TextStyle")); RunInfo.MetaData.Add(TEXT("Style"), Style.ToString()); return RunInfo; } static FName GetStyleFromRunInfo(const FRunInfo& InRunInfo) { const FString* const StyleString = InRunInfo.MetaData.Find(TEXT("Style")); if(StyleString) { return **StyleString; } else { // legacy styling support - try to map older flexible styles to new fixed styles int32 FontSize = 11; const FString* const FontSizeString = InRunInfo.MetaData.Find(TEXT("FontSize")); if(FontSizeString) { FontSize = static_cast(FPlatformString::Atoi(**FontSizeString)); } if(FontSize > 24) { return TEXT("Tutorials.Content.HeaderText2"); } else if(FontSize > 11 && FontSize <= 24) { return TEXT("Tutorials.Content.HeaderText1"); } else { EFontStyle::Flags FontStyle = EFontStyle::Regular; const FString* const FontStyleString = InRunInfo.MetaData.Find(TEXT("FontStyle")); if(FontStyleString) { if(*FontStyleString == TEXT("Bold")) { FontStyle = EFontStyle::Bold; } else if(*FontStyleString == TEXT("Italic")) { FontStyle = EFontStyle::Italic; } else if(*FontStyleString == TEXT("BoldItalic")) { FontStyle = EFontStyle::Bold | EFontStyle::Italic; } } FLinearColor FontColor = FLinearColor::Black; const FString* const FontColorString = InRunInfo.MetaData.Find(TEXT("FontColor")); if(FontColorString && !FontColor.InitFromString(*FontColorString)) { FontColor = FLinearColor::Black; } if(FontStyle != EFontStyle::Regular || FontColor != FLinearColor::Black) { return TEXT("Tutorials.Content.TextBold"); } else { return TEXT("Tutorials.Content.Text"); } } } return NAME_None; } FTextBlockStyle CreateTextBlockStyle() const { return FEditorStyle::Get().GetWidgetStyle(Style); } static FTextBlockStyle CreateTextBlockStyle(const FRunInfo& InRunInfo) { return FEditorStyle::Get().GetWidgetStyle(GetStyleFromRunInfo(InRunInfo)); } /** The style identifier */ FName Style; /** The text to display for this style */ FText DisplayName; }; /** * This is a custom decorator used to allow arbitrary styling of text within a rich-text editor * This is required since normal text styling can only work with known styles from a given Slate style-set */ class FTextStyleDecorator : public ITextDecorator { public: static TSharedRef Create() { return MakeShareable(new FTextStyleDecorator()); } virtual ~FTextStyleDecorator() { } virtual bool Supports(const FTextRunParseResults& RunParseResult, const FString& Text) const override { return (RunParseResult.Name == TEXT("TextStyle")); } virtual TSharedRef Create(const TSharedRef& TextLayout, const FTextRunParseResults& RunParseResult, const FString& OriginalText, const TSharedRef< FString >& InOutModelText, const ISlateStyle* Style) override { FRunInfo RunInfo(RunParseResult.Name); for(const TPair& Pair : RunParseResult.MetaData) { RunInfo.MetaData.Add(Pair.Key, OriginalText.Mid(Pair.Value.BeginIndex, Pair.Value.EndIndex - Pair.Value.BeginIndex)); } FTextRange ModelRange; ModelRange.BeginIndex = InOutModelText->Len(); *InOutModelText += OriginalText.Mid(RunParseResult.ContentRange.BeginIndex, RunParseResult.ContentRange.EndIndex - RunParseResult.ContentRange.BeginIndex); ModelRange.EndIndex = InOutModelText->Len(); return FSlateTextRun::Create(RunInfo, InOutModelText, FTextStyleAndName::CreateTextBlockStyle(RunInfo), ModelRange); } }; /** Helper struct to hold info about hyperlink types */ struct FHyperlinkTypeDesc { FHyperlinkTypeDesc(EHyperlinkType::Type InType, const FText& InText, const FText& InTooltipText, const FString& InId, FSlateHyperlinkRun::FOnClick InOnClickedDelegate) : Type(InType) , Id(InId) , Text(InText) , TooltipText(InTooltipText) , OnClickedDelegate(InOnClickedDelegate) { } /** The type of the link */ EHyperlinkType::Type Type; /** Tag used by this hyperlink's run */ FString Id; /** Text to display in the UI */ FText Text; /** Tooltip text to display in the UI */ FText TooltipText; /** Delegate to execute for this hyperlink's run */ FSlateHyperlinkRun::FOnClick OnClickedDelegate; }; class STutorialEditableText : public SCompoundWidget { public: SLATE_BEGIN_ARGS( STutorialEditableText ){} SLATE_ATTRIBUTE(FText, Text) SLATE_ARGUMENT(FOnTextCommitted, OnTextCommitted) SLATE_ARGUMENT(FOnTextChanged, OnTextChanged) SLATE_END_ARGS() /** * Construct the widget * * @param InArgs Declaration from which to construct the widget */ void Construct(const FArguments& InArgs); virtual bool SupportsKeyboardFocus() const override { return true; } protected: TSharedPtr GetCurrentRun() const; void HandleRichEditableTextChanged(const FText& Text); void HandleRichEditableTextCommitted(const FText& Text, ETextCommit::Type Type); void HandleRichEditableTextCursorMoved(const FTextLocation& NewCursorPosition ); FText GetActiveStyleName() const; void OnActiveStyleChanged(TSharedPtr NewValue, ESelectInfo::Type); TSharedRef GenerateStyleComboEntry(TSharedPtr SourceEntry); void StyleSelectedText(); void HandleHyperlinkComboOpened(); bool IsHyperlinkComboEnabled() const; FReply HandleInsertHyperLinkClicked(); EVisibility GetToolbarVisibility() const; FText GetHyperlinkButtonText() const; void OnActiveHyperlinkChanged(TSharedPtr NewValue, ESelectInfo::Type SelectionType); TSharedRef GenerateHyperlinkComboEntry(TSharedPtr SourceEntry); FText GetActiveHyperlinkName() const; FText GetActiveHyperlinkTooltip() const; TSharedPtr GetHyperlinkTypeFromId(const FString& InId) const; EVisibility GetOpenAssetVisibility() const; void HandleOpenAssetCheckStateChanged(ESlateCheckBoxState::Type InCheckState); ESlateCheckBoxState::Type IsOpenAssetChecked() const; protected: TSharedPtr RichEditableTextBox; FSlateHyperlinkRun::FOnClick OnBrowserLinkClicked; FSlateHyperlinkRun::FOnClick OnDocLinkClicked; FSlateHyperlinkRun::FOnClick OnTutorialLinkClicked; FSlateHyperlinkRun::FOnClick OnCodeLinkClicked; FSlateHyperlinkRun::FOnClick OnAssetLinkClicked; TSharedPtr HyperlinkComboButton; TSharedPtr>> FontComboBox; TSharedPtr HyperlinkNameTextBlock; TSharedPtr HyperlinkURLTextBox; TSharedPtr ActiveStyle; TSharedPtr HyperlinkStyle; TArray> StylesAndNames; FOnTextCommitted OnTextCommitted; FOnTextChanged OnTextChanged; TArray> HyperlinkDescs; TSharedPtr CurrentHyperlinkType; bool bOpenAsset; bool bNewHyperlink; };