3#include "Internationalization/TextNamespaceUtil.h"
4#include "Widgets/SBoxPanel.h"
5#include "Widgets/Images/SImage.h"
6#include "Widgets/Text/STextBlock.h"
7#include "Widgets/Layout/SBox.h"
8#include "Widgets/Layout/SGridPanel.h"
9#include "Widgets/Layout/SUniformGridPanel.h"
10#include "Widgets/Input/SButton.h"
11#include "Widgets/Input/SMultiLineEditableTextBox.h"
12#include "Widgets/Input/SEditableTextBox.h"
13#include "Widgets/Input/SComboButton.h"
14#include "Widgets/Input/SComboBox.h"
15#include "Widgets/Input/SCheckBox.h"
16#include "EditorStyleSet.h"
17#include "AssetRegistryModule.h"
18#include "Internationalization/StringTable.h"
19#include "Internationalization/TextPackageNamespaceUtil.h"
20#include "Internationalization/StringTableCore.h"
21#include "Internationalization/StringTableRegistry.h"
22#include "Serialization/TextReferenceCollector.h"
25#define LOCTEXT_NAMESPACE "STextPropertyEditableTextBox"
30 const FArguments& InArgs,
31 const TSharedRef<IEditableTextProperty>& InEditableTextProperty,
32 const TSharedRef<IPropertyHandle>& InPropertyHandle
39 TSharedPtr<SHorizontalBox> HorizontalBox;
47 SAssignNew(HorizontalBox, SHorizontalBox)
48 +SHorizontalBox::Slot()
52 .MinDesiredWidth(InArgs._MinDesiredWidth)
53 .MaxDesiredHeight(InArgs._MaxDesiredHeight)
60 .ForegroundColor(InArgs._ForegroundColor)
61 .ReadOnlyForegroundColor(InArgs._ReadOnlyForegroundColor)
62 .SelectAllTextWhenFocused(InArgs._SelectAllTextWhenFocused)
63 .ClearKeyboardFocusOnCommit(InArgs._ClearKeyboardFocusOnCommit)
64 .SelectAllTextOnCommit(InArgs._SelectAllTextOnCommit)
68 .AutoWrapText(InArgs._AutoWrapText)
69 .WrapTextAt(InArgs._WrapTextAt)
70 .ModiferKeyForNewLine(InArgs._ModiferKeyForNewLine)
84 HorizontalBox->AddSlot()
88 .HAlign(HAlign_Center)
89 .VAlign(VAlign_Center)
90 .ContentPadding(FMargin(4, 0))
91 .ButtonStyle(FEditorStyle::Get(),
"HoverHintOnly")
92 .ForegroundColor(FSlateColor::UseForeground())
93 .ToolTipText(LOCTEXT(
"AdvancedTextSettingsComboToolTip",
"Edit advanced text settings."))
104 +SGridPanel::Slot(0, 0)
108 .VAlign(VAlign_Center)
111 .TextStyle(FEditorStyle::Get(),
"LargeText")
112 .Text(LOCTEXT(
"TextInlineTextLabel",
"Inline Text"))
116 +SGridPanel::Slot(0, 1)
118 .HAlign(HAlign_Right)
119 .VAlign(VAlign_Center)
122 .Text(LOCTEXT(
"TextLocalizableLabel",
"Localizable:"))
124 +SGridPanel::Slot(1, 1)
129 +SHorizontalBox::Slot()
133 SNew(SUniformGridPanel)
134 .SlotPadding(FMargin(0, 0, 4, 0))
136 +SUniformGridPanel::Slot(0, 0)
139 .Style(FEditorStyle::Get(),
"ToggleButtonCheckbox")
140 .ToolTipText(LOCTEXT(
"TextLocalizableToggleYesToolTip",
"Assign this text a key and allow it to be gathered for localization."))
141 .Padding(FMargin(4, 2))
142 .HAlign(HAlign_Center)
148 .Text(LOCTEXT(
"TextLocalizableToggleYes",
"Yes"))
152 +SUniformGridPanel::Slot(1, 0)
155 .Style(FEditorStyle::Get(),
"ToggleButtonCheckbox")
156 .ToolTipText(LOCTEXT(
"TextLocalizableToggleNoToolTip",
"Mark this text as 'culture invariant' to prevent it being gathered for localization."))
157 .Padding(FMargin(4, 2))
158 .HAlign(HAlign_Center)
164 .Text(LOCTEXT(
"TextLocalizableToggleNo",
"No"))
170#if USE_STABLE_LOCALIZATION_KEYS
172 +SGridPanel::Slot(0, 2)
174 .HAlign(HAlign_Right)
175 .VAlign(VAlign_Center)
178 .Text(LOCTEXT(
"TextPackageLabel",
"Package:"))
181 +SGridPanel::Slot(1, 2)
184 SNew(SEditableTextBox)
185 .Text(
this, &Self::GetPackageValue)
192 +SGridPanel::Slot(0, 3)
194 .HAlign(HAlign_Right)
195 .VAlign(VAlign_Center)
198 .Text(LOCTEXT(
"TextNamespaceLabel",
"Namespace:"))
201 +SGridPanel::Slot(1, 3)
206 .SelectAllTextWhenFocused(
true)
207 .ClearKeyboardFocusOnCommit(
false)
210 .SelectAllTextOnCommit(
true)
216 +SGridPanel::Slot(2, 3)
220 .Image(FCoreStyle::Get().GetBrush(
"Icons.Warning"))
222 .ToolTipText(LOCTEXT(
"NamespaceOverridenWarningToolTip",
"The namespace will be overriden on Save.\nTo change this bevahiour go to Project Settings -> (Editors) Dialogue -> Localization"))
226 +SGridPanel::Slot(0, 4)
228 .HAlign(HAlign_Right)
229 .VAlign(VAlign_Center)
232 .Text(LOCTEXT(
"TextKeyLabel",
"Key:"))
235 +SGridPanel::Slot(1, 4)
241#if USE_STABLE_LOCALIZATION_KEYS
242 .SelectAllTextWhenFocused(
true)
243 .ClearKeyboardFocusOnCommit(
false)
244 .OnTextChanged(
this, &Self::OnKeyChanged)
245 .OnTextCommitted(
this, &Self::OnKeyCommitted)
246 .SelectAllTextOnCommit(
true)
254 +SGridPanel::Slot(0, 5)
258 .VAlign(VAlign_Center)
261 .TextStyle(FEditorStyle::Get(),
"LargeText")
262 .Text(LOCTEXT(
"TextReferencedTextLabel",
"Referenced Text"))
267 +SGridPanel::Slot(0, 6)
269 .HAlign(HAlign_Right)
270 .VAlign(VAlign_Center)
273 .Text(LOCTEXT(
"TextStringTableLabel",
"String Table:"))
276 +SGridPanel::Slot(1, 6)
279 SNew(STextPropertyEditableStringTableReference, InEditableTextProperty)
288 HorizontalBox->AddSlot()
289 .VAlign(VAlign_Center)
290 .HAlign(HAlign_Center)
294 .Image(FCoreStyle::Get().GetBrush(
"Icons.Warning"))
296 .ToolTipText(LOCTEXT(
"TextNotLocalizedWarningToolTip",
"This text is marked as 'culture invariant' and won't be gathered for localization.\nYou can change this by editing the advanced text settings."))
304 HorizontalBox->AddSlot()
306 .VAlign(VAlign_Center)
312 .ButtonStyle(FEditorStyle::Get(),
"NoBorder")
319 .Image(FEditorStyle::GetBrush(
"PropertyWindow.DiffersFromDefault"))
329 FString Tooltip = NSLOCTEXT(
"PropertyEditor",
"ResetToDefaultToolTip",
"Reset to Default").ToString();
332 const FString DefaultLabel =
PropertyHandle->GetResetToDefaultLabel().ToString();
333 if (DefaultLabel.Len() > 0)
336 Tooltip += DefaultLabel;
340 return FText::FromString(Tooltip);
347 return PropertyHandle->DiffersFromDefault() ? EVisibility::Visible : EVisibility::Hidden;
350 return EVisibility::Visible;
360 return FReply::Handled();
370 return PropertyValue.IsCultureInvariant() ? EVisibility::Collapsed : EVisibility::Visible;
372 return EVisibility::Visible;
379 OutMinDesiredWidth = 250.0f;
383 OutMinDesiredWidth = 125.0f;
386 OutMaxDesiredWidth = 600.0f;
397 return FReply::Handled().SetUserFocus(
PrimaryWidget.ToSharedRef(), InFocusEvent.GetCause());
402 const float CurrentHeight = AllottedGeometry.GetLocalSize().Y;
412 const bool bIsReadOnly = FTextLocalizationManager::Get().IsLocalizationLocked() ||
EditableTextProperty->IsReadOnly();
433 if (TextValue.IsFromStringTable())
464 if (!TextValue.ShouldGatherForLocalization())
475 FText LocalizedTextToolTip;
481 if (TextValue.IsFromStringTable())
485 FStringTableRegistry::Get().FindTableIdAndKey(TextValue, TableId, Key);
487 LocalizedTextToolTip = FText::Format(
488 LOCTEXT(
"StringTableTextToolTipFmt",
"--- String Table Reference ---\nTable ID: {0}\nKey: {1}"),
489 FText::FromName(TableId), FText::FromString(Key)
494 bool bIsLocalized =
false;
497 const FString* SourceString = FTextInspector::GetSourceString(TextValue);
499 if (SourceString && TextValue.ShouldGatherForLocalization())
501 bIsLocalized = FTextLocalizationManager::Get().FindNamespaceAndKeyFromDisplayString(FTextInspector::GetSharedDisplayString(TextValue), Namespace, Key);
506 const FString PackageNamespace = TextNamespaceUtil::ExtractPackageNamespace(Namespace);
507 const FString TextNamespace = TextNamespaceUtil::StripPackageNamespace(Namespace);
509 LocalizedTextToolTip = FText::Format(
510 LOCTEXT(
"LocalizedTextToolTipFmt",
"--- Localized Text ---\nPackage: {0}\nNamespace: {1}\nKey: {2}\nSource: {3}"),
511 FText::FromString(PackageNamespace), FText::FromString(TextNamespace), FText::FromString(Key), FText::FromString(*SourceString)
518 if (FTextLocalizationManager::Get().IsLocalizationLocked())
520 const FText LockdownToolTip = FTextLocalizationManager::Get().IsGameLocalizationPreviewEnabled()
521 ? LOCTEXT(
"LockdownToolTip_Preview",
"Localization is locked down due to the active game localization preview")
522 : LOCTEXT(
"LockdownToolTip_Other",
"Localization is locked down");
523 BaseToolTipText = BaseToolTipText.IsEmptyOrWhitespace() ? LockdownToolTip : FText::Format(LOCTEXT(
"ToolTipLockdownFmt",
"!!! {0} !!!\n\n{1}"), LockdownToolTip, BaseToolTipText);
526 if (LocalizedTextToolTip.IsEmptyOrWhitespace())
528 return BaseToolTipText;
530 if (BaseToolTipText.IsEmptyOrWhitespace())
532 return LocalizedTextToolTip;
535 return FText::Format(LOCTEXT(
"ToolTipCompleteFmt",
"{0}\n\n{1}"), BaseToolTipText, LocalizedTextToolTip);
547 else if (NumTexts > 1)
570 if (NumTexts > 0 && (NumTexts == 1 || NewText.ToString().Equals(
MultipleValuesText.ToString(), ESearchCase::CaseSensitive)))
585 if (NumTexts > 0 && (NumTexts == 1 || !NewText.ToString().Equals(
MultipleValuesText.ToString(), ESearchCase::CaseSensitive)))
600 const FString& SourceString = NewText.ToString();
601 for (int32 TextIndex = 0; TextIndex < NumTexts; ++TextIndex)
606 if (PropertyValue.ToString().Equals(NewText.ToString(), ESearchCase::CaseSensitive))
612 if (NewText.IsEmpty())
619 if (PropertyValue.IsCultureInvariant())
625 FString NewNamespace;
627#if USE_STABLE_LOCALIZATION_KEYS
630 const FString* TextSource = FTextInspector::GetSourceString(PropertyValue);
633 IEditableTextProperty::ETextPropertyEditAction::EditedSource,
634 TextSource ? *TextSource : FString(),
635 FTextInspector::GetNamespace(PropertyValue).Get(FString()),
636 FTextInspector::GetKey(PropertyValue).Get(FString()),
648 if (FGuid::Parse(FTextInspector::GetKey(PropertyValue).Get(FString()), TmpGUID))
650 NewNamespace = FTextInspector::GetNamespace(PropertyValue).Get(FString());
654 NewKey = FGuid::NewGuid().ToString();
658 const FText FinalText = FText::ChangeKey(NewNamespace, NewKey, NewText);
680 FText NamespaceValue;
686 TOptional<FString> FoundNamespace = FTextInspector::GetNamespace(PropertyValue);
687 if (FoundNamespace.IsSet())
689 NamespaceValue = FText::FromString(TextNamespaceUtil::StripPackageNamespace(FoundNamespace.GetValue()));
692 else if (NumTexts > 1)
697 return NamespaceValue;
703 const FText ErrorCtx = LOCTEXT(
"TextNamespaceErrorCtx",
"Namespace");
719 if (NumTexts > 0 && (NumTexts == 1 || NewText.ToString() !=
MultipleValuesText.ToString()))
721 const FString& TextNamespace = NewText.ToString();
722 for (int32 TextIndex = 0; TextIndex < NumTexts; ++TextIndex)
727 const FString CurrentTextNamespace = TextNamespaceUtil::StripPackageNamespace(FTextInspector::GetNamespace(PropertyValue).Get(FString()));
728 if (CurrentTextNamespace.Equals(TextNamespace, ESearchCase::CaseSensitive))
734 FString NewNamespace;
736#if USE_STABLE_LOCALIZATION_KEYS
738 const FString* TextSource = FTextInspector::GetSourceString(PropertyValue);
741 IEditableTextProperty::ETextPropertyEditAction::EditedNamespace,
742 TextSource ? *TextSource : FString(),
744 FTextInspector::GetKey(PropertyValue).Get(FString()),
751 NewNamespace = TextNamespace;
754 NewKey = FTextInspector::GetKey(PropertyValue).Get(FString());
757 if (!FGuid::Parse(NewKey, TmpGuid))
759 NewKey = FGuid::NewGuid().ToString();
765 EditableTextProperty->SetText(TextIndex, FText::ChangeKey(NewNamespace, NewKey, PropertyValue));
778 TOptional<FString> FoundKey = FTextInspector::GetKey(PropertyValue);
779 if (FoundKey.IsSet())
781 KeyValue = FText::FromString(FoundKey.GetValue());
784 else if (NumTexts > 1)
792#if USE_STABLE_LOCALIZATION_KEYS
794void SDialogueTextPropertyEditableTextBox::OnKeyChanged(
const FText& NewText)
797 const FText ErrorCtx = LOCTEXT(
"TextKeyErrorCtx",
"Key");
798 const bool bIsValidName =
IsValidIdentity(NewText, &ErrorMessage, &ErrorCtx);
800 if (NewText.IsEmptyOrWhitespace())
802 ErrorMessage = LOCTEXT(
"TextKeyEmptyErrorMsg",
"Key cannot be empty so a new key will be assigned");
804 else if (bIsValidName)
812 const FString TextNamespace = FTextInspector::GetNamespace(PropertyValue).Get(FString());
813 const FString TextKey = NewText.ToString();
817 FString NewNamespace;
819 const FString* TextSource = FTextInspector::GetSourceString(PropertyValue);
822 IEditableTextProperty::ETextPropertyEditAction::EditedKey,
823 TextSource ? *TextSource : FString(),
830 if (TextNamespace.Equals(NewNamespace, ESearchCase::CaseSensitive) && !TextKey.Equals(NewKey, ESearchCase::CaseSensitive))
832 ErrorMessage = LOCTEXT(
"TextKeyConflictErrorMsg",
"Identity (namespace & key) is being used by a different text within this package so a new key will be assigned");
840void SDialogueTextPropertyEditableTextBox::OnKeyCommitted(
const FText& NewText, ETextCommit::Type CommitInfo)
850 if (NumTexts > 0 && (NumTexts == 1 || NewText.ToString() !=
MultipleValuesText.ToString()))
852 const FString& TextKey = NewText.ToString();
853 for (int32 TextIndex = 0; TextIndex < NumTexts; ++TextIndex)
858 const FString CurrentTextKey = FTextInspector::GetKey(PropertyValue).Get(FString());
859 if (CurrentTextKey.Equals(TextKey, ESearchCase::CaseSensitive))
865 FString NewNamespace;
867 const FString* TextSource = FTextInspector::GetSourceString(PropertyValue);
870 IEditableTextProperty::ETextPropertyEditAction::EditedKey,
871 TextSource ? *TextSource : FString(),
872 FTextInspector::GetNamespace(PropertyValue).Get(FString()),
878 EditableTextProperty->SetText(TextIndex, FText::ChangeKey(NewNamespace, NewKey, PropertyValue));
883FText SDialogueTextPropertyEditableTextBox::GetPackageValue()
const
891 TOptional<FString> FoundNamespace = FTextInspector::GetNamespace(PropertyValue);
892 if (FoundNamespace.IsSet())
894 PackageValue = FText::FromString(TextNamespaceUtil::ExtractPackageNamespace(FoundNamespace.GetValue()));
897 else if (NumTexts > 1)
914 const bool bIsLocalized = !PropertyValue.IsCultureInvariant();
915 return bIsLocalized == bActiveState ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
918 return ECheckBoxState::Undetermined;
927 for (int32 TextIndex = 0; TextIndex < NumTexts; ++TextIndex)
932 if (PropertyValue.IsCultureInvariant())
935 FString NewNamespace;
939 IEditableTextProperty::ETextPropertyEditAction::EditedKey,
940 PropertyValue.ToString(),
947 EditableTextProperty->SetText(TextIndex, FInternationalization::Get().ForUseOnlyByLocMacroAndGraphNodeTextLiterals_CreateText(*PropertyValue.ToString(), *NewNamespace, *NewKey));
953 for (int32 TextIndex = 0; TextIndex < NumTexts; ++TextIndex)
958 if (!PropertyValue.IsCultureInvariant())
960 const FString* TextSource = FTextInspector::GetSourceString(PropertyValue);
972 return EVisibility::Collapsed;
985 return PropertyValue.IsCultureInvariant() ? EVisibility::Visible : EVisibility::Collapsed;
988 return EVisibility::Collapsed;
993 const FString InvalidIdentityChars = FString::Printf(TEXT(
"%s%c%c"), INVALID_NAME_CHARACTERS, TextNamespaceUtil::PackageNamespaceStartMarker, TextNamespaceUtil::PackageNamespaceEndMarker);
994 return FName::IsValidXName(InIdentity.ToString(), InvalidIdentityChars, OutReason, InErrorCtx);
997#undef LOCTEXT_NAMESPACE
static bool WillTextNamespaceBeUpdated(const FText &Text)
TSharedPtr< SMultiLineEditableTextBox > MultiLineWidget
static FText MultipleValuesText
FText GetKeyValue() const
void Tick(const FGeometry &AllottedGeometry, double InCurrentTime, float InDeltaTime) override
TSharedPtr< SEditableTextBox > NamespaceEditableTextBox
bool bAddResetToDefaultWidget
FText GetNamespaceValue() const
void OnTextCommitted(const FText &NewText, ETextCommit::Type CommitInfo)
EVisibility GetDiffersFromDefaultAsVisibility() const
bool IsNamespaceReadOnly() const
void OnNamespaceCommitted(const FText &NewText, ETextCommit::Type CommitInfo)
TSharedPtr< SEditableTextBox > KeyEditableTextBox
void SetTextError(const FText &InErrorMsg)
EVisibility GetTextWarningImageVisibility() const
FText GetTextValue() const
void OnTextChanged(const FText &NewText)
FDialogueTextCommitedDelegate TextCommittedEvent
TSharedPtr< SWidget > PrimaryWidget
EVisibility GetNamespaceOverridenWarningImageVisibility() const
TSharedPtr< IEditableTextProperty > EditableTextProperty
bool IsIdentityReadOnly() const
bool SupportsKeyboardFocus() const override
TOptional< float > PreviousHeight
bool IsSourceTextReadOnly() const
ECheckBoxState GetLocalizableCheckState(bool bActiveState) const
EVisibility GetLocalizableVisibility() const
void OnNamespaceChanged(const FText &NewText)
FDialogueTextChangedDelegate TextChangedEvent
void SetTextValue(const FText &NewValue)
TSharedPtr< IPropertyHandle > PropertyHandle
void HandleLocalizableCheckStateChanged(ECheckBoxState InCheckboxState, bool bActiveState)
bool IsValidIdentity(const FText &InIdentity, FText *OutReason=nullptr, const FText *InErrorCtx=nullptr) const
void GetDesiredWidth(float &OutMinDesiredWidth, float &OutMaxDesiredWidth)
FReply OnFocusReceived(const FGeometry &MyGeometry, const FFocusEvent &InFocusEvent) override
FText GetResetToolTip() const
FText GetToolTipText() const
bool WillNamespaceBeUpdated() const
bool IsKeyReadOnly() const
bool IsCultureInvariantFlagEnabled() const
void Construct(const FArguments &Arguments, const TSharedRef< IEditableTextProperty > &InEditableTextProperty, const TSharedRef< IPropertyHandle > &InPropertyHandle)