3
0

UiTextComponent.h 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #pragma once
  9. #include <string>
  10. #include <LyShine/IDraw2d.h>
  11. #include <LyShine/UiBase.h>
  12. #include <LyShine/UiComponentTypes.h>
  13. #include <LyShine/Bus/UiVisualBus.h>
  14. #include <LyShine/Bus/UiRenderBus.h>
  15. #include <LyShine/Bus/UiTextBus.h>
  16. #include <LyShine/Bus/UiLayoutCellDefaultBus.h>
  17. #include <LyShine/Bus/UiElementBus.h>
  18. #include <LyShine/Bus/UiCanvasBus.h>
  19. #include <LyShine/Bus/UiAnimateEntityBus.h>
  20. #include <LyShine/UiAssetTypes.h>
  21. #include <LyShine/UiRenderFormats.h>
  22. #include <AzCore/Component/Component.h>
  23. #include <AzCore/Serialization/SerializeContext.h>
  24. #include <AzCore/std/containers/set.h>
  25. #include <Atom/RPI.Reflect/Image/Image.h>
  26. // Only needed for internal unit-testing
  27. #include <LyShine.h>
  28. #include <IFont.h>
  29. #include <ILocalizationManager.h>
  30. #include <TextureAtlas/TextureAtlasBus.h>
  31. #include <TextureAtlas/TextureAtlasNotificationBus.h>
  32. #include <TextureAtlas/TextureAtlas.h>
  33. // Forward declaractions
  34. namespace TextMarkup
  35. {
  36. struct Tag;
  37. #if defined(LYSHINE_INTERNAL_UNIT_TEST)
  38. void UnitTest();
  39. #endif
  40. }
  41. ////////////////////////////////////////////////////////////////////////////////////////////////////
  42. class UiTextComponent
  43. : public AZ::Component
  44. , public UiVisualBus::Handler
  45. , public UiRenderBus::Handler
  46. , public UiTextBus::Handler
  47. , public UiClickableTextBus::Handler
  48. , public UiAnimateEntityBus::Handler
  49. , public UiTransformChangeNotificationBus::Handler
  50. , public UiLayoutCellDefaultBus::Handler
  51. , public FontNotificationBus::Handler
  52. , public LanguageChangeNotificationBus::Handler
  53. , public UiCanvasPixelAlignmentNotificationBus::Handler
  54. , public TextureAtlasNamespace::TextureAtlasNotificationBus::Handler
  55. {
  56. public: //types
  57. using FontEffectComboBoxVec = AZStd::vector < AZStd::pair<unsigned int, AZStd::string> >;
  58. //! An inline image to be displayed within the text
  59. struct InlineImage
  60. {
  61. enum VAlign
  62. {
  63. Baseline,
  64. Top,
  65. Center,
  66. Bottom
  67. };
  68. InlineImage(const AZStd::string& texturePathname,
  69. float height,
  70. float scale,
  71. VAlign vAlign,
  72. float yOffset,
  73. float leftPadding,
  74. float rightPadding);
  75. ~InlineImage();
  76. bool OnAtlasLoaded(const TextureAtlasNamespace::TextureAtlas* atlas);
  77. bool OnAtlasUnloaded(const TextureAtlasNamespace::TextureAtlas* atlas);
  78. AZ::Data::Instance<AZ::RPI::Image> m_texture;
  79. AZ::Vector2 m_size;
  80. VAlign m_vAlign;
  81. float m_yOffset;
  82. float m_leftPadding;
  83. float m_rightPadding;
  84. AZStd::string m_filepath;
  85. const TextureAtlasNamespace::TextureAtlas* m_atlas;
  86. TextureAtlasNamespace::AtlasCoordinates m_coordinates;
  87. };
  88. using InlineImageContainer = AZStd::list < InlineImage* >;
  89. //! Atomic unit of font "state" for drawing text in the renderer.
  90. //! A single line of text can be divided amongst multiple draw batches,
  91. //! allowing that line of text to be rendered with different font
  92. //! stylings, which is used to support FontFamily rendering.
  93. struct DrawBatch
  94. {
  95. enum Type
  96. {
  97. Text,
  98. Image
  99. };
  100. //! Overflow information based on available width. Used for wrapping
  101. struct OverflowInfo
  102. {
  103. int overflowIndex; //!< the index of the character that overflowed
  104. bool overflowCharIsSpace; //!< indicates whether the character that overflowed is a space
  105. float widthUntilOverflowOrTotalWidth; //!< the width of the batch up until the overflow, or the total width if no overflow
  106. float overflowCharWidth; //!< the width of the overflow character
  107. int lastSpaceIndex; //!< the index of the last space character that hasn't overflowed
  108. bool isSpaceAtEnd; //!< indicates whether the space character is the last character to not overflow
  109. };
  110. DrawBatch();
  111. Type GetType() const;
  112. //! Calculate and store the size of the batch content
  113. void CalculateSize(const STextDrawContext& ctx, bool excludeTrailingSpace);
  114. //! Calculate and store the y offset of the batch from the text y position
  115. void CalculateYOffset(float fontSize, float baseline);
  116. //! Get the number of characters that the batch contains. An image is considered to be one character
  117. int GetNumChars() const;
  118. //! Get overflow information based on the available width. Used for wrapping
  119. bool GetOverflowInfo(const STextDrawContext& ctx,
  120. float availableWidth, bool skipFirstChar, OverflowInfo& overflowInfoOut);
  121. //! Split the batch at a specified character index
  122. void Split(int atCharIndex, DrawBatch& newDrawBatchOut);
  123. bool IsClickable() const { return !action.empty() || !data.empty(); }
  124. AZ::Vector3 color;
  125. AZStd::string text;
  126. AZStd::string action; //!< Only used for clickable text. Parsed from "action" attribute in anchor tag (markup).
  127. AZStd::string data; //!< Only used for clickable text. Parsed from "data" attribute in anchor tag (markup).
  128. IFFont* font = nullptr;
  129. InlineImage* image = nullptr;
  130. AZ::Vector2 size; //!< The size in pixels of the batch content
  131. float yOffset; //!< While calculating, the yOffset is set to the offset from the text draw y position.
  132. //!< Once all batches in the line are calculated, the yOffset will become the offset
  133. //!< from the y draw position of the batch line
  134. int clickableId = -1; //!< Only used for clickable text. Each parse anchor tag gets assigned
  135. //!< a unique ID that's shared amongst all draw batches that belong to
  136. //!< the anchor.
  137. };
  138. using DrawBatchContainer = AZStd::list < DrawBatch >;
  139. //! A single line of text that can be composed of multiple DrawBatch objects
  140. struct DrawBatchLine
  141. {
  142. DrawBatchLine();
  143. //! Check whether the line is overflowing and split it into two lines if it is overflowing
  144. bool CheckAndSplitLine(const STextDrawContext& ctx,
  145. float maxWidth,
  146. DrawBatchLine& newDrawBatchLineOut);
  147. DrawBatchContainer drawBatchList; //!< DrawBatches that the line is composed of
  148. AZ::Vector2 lineSize; //!< Pixel size of entire line of text
  149. };
  150. using DrawBatchLineContainer = AZStd::list < DrawBatchLine >;
  151. using FontFamilyRefSet = AZStd::set < FontFamilyPtr >;
  152. //! A collection of batch lines used for multi-line rendering of DrawBatch objects.
  153. //! A single line of text contains a list of batches, and multi-line rendering requires
  154. //! a list of multiple lines of draw batches.
  155. //!
  156. //! Since different Font Familys can be referenced batch-to-batch, we hold a strong
  157. //! reference (shared_ptr) for each Font Family that's referenced. Once this struct
  158. //! goes out of scope, or is cleared, the references are freed.
  159. struct DrawBatchLines
  160. {
  161. ~DrawBatchLines();
  162. //! Clears the batch lines list and releases any Font Family references.
  163. void Clear();
  164. DrawBatchLineContainer batchLines; //!< List of batch lines for drawing, each implicitly separated by a newline.
  165. FontFamilyRefSet fontFamilyRefs; //!< Set of strongly referenced Font Family objects used by draw batches.
  166. InlineImageContainer inlineImages; //!< List of images used by draw batches.
  167. float height; //!< The accumulated height of all the batch lines.
  168. float baseline; //!< The baseline to use when aligning images. Offset from the y draw position of the text.
  169. AZ::Vector2 fontSizeScale = AZ::Vector2(1.0f, 1.0f); //!< A scale that gets applied to the font size when using shrink-to-fit.
  170. bool m_fontEffectHasTransparency = false; //! True if any of the font effects used in the draw batch lines have an alpha less than 1.
  171. };
  172. //! Simple container for left/right AZ::Vector2 offsets.
  173. struct LineOffsets
  174. {
  175. LineOffsets()
  176. : left(AZ::Vector2::CreateZero())
  177. , right(AZ::Vector2::CreateZero())
  178. , batchLineLength(0.0f) {}
  179. AZ::Vector2 left;
  180. AZ::Vector2 right;
  181. float batchLineLength;
  182. };
  183. public: // member functions
  184. AZ_COMPONENT(UiTextComponent, LyShine::UiTextComponentUuid, AZ::Component);
  185. UiTextComponent();
  186. ~UiTextComponent() override;
  187. // UiVisualInterface
  188. void ResetOverrides() override;
  189. void SetOverrideColor(const AZ::Color& color) override;
  190. void SetOverrideAlpha(float alpha) override;
  191. void SetOverrideFont(FontFamilyPtr fontFamily) override;
  192. void SetOverrideFontEffect(unsigned int fontEffectIndex) override;
  193. // ~UiVisualInterface
  194. // UiRenderInterface
  195. void Render(LyShine::IRenderGraph* renderGraph) override;
  196. // ~UiRenderInterface
  197. // UiTextInterface
  198. AZStd::string GetText() override;
  199. void SetText(const AZStd::string& text) override;
  200. AZStd::string GetTextWithFlags(GetTextFlags flags = GetAsIs) override;
  201. void SetTextWithFlags(const AZStd::string& text, SetTextFlags flags = SetAsIs) override;
  202. AZ::Color GetColor() override;
  203. void SetColor(const AZ::Color& color) override;
  204. LyShine::PathnameType GetFont() override;
  205. void SetFont(const LyShine::PathnameType& fontPath) override;
  206. int GetFontEffect() override;
  207. void SetFontEffect(int effectIndex) override;
  208. AZStd::string GetFontEffectName(int effectIndex) override;
  209. void SetFontEffectByName(const AZStd::string& effectName) override;
  210. float GetFontSize() override;
  211. void SetFontSize(float size) override;
  212. void GetTextAlignment(IDraw2d::HAlign& horizontalAlignment,
  213. IDraw2d::VAlign& verticalAlignment) override;
  214. void SetTextAlignment(IDraw2d::HAlign horizontalAlignment,
  215. IDraw2d::VAlign verticalAlignment) override;
  216. IDraw2d::HAlign GetHorizontalTextAlignment() override;
  217. void SetHorizontalTextAlignment(IDraw2d::HAlign alignment) override;
  218. IDraw2d::VAlign GetVerticalTextAlignment() override;
  219. void SetVerticalTextAlignment(IDraw2d::VAlign alignment) override;
  220. float GetCharacterSpacing() override;
  221. //! Expects 1/1000th ems, where 1 em = font size. This will also affect text size, which can lead to
  222. //! formatting changes (with word-wrap enabled for instance).
  223. void SetCharacterSpacing(float characterSpacing) override;
  224. float GetLineSpacing() override;
  225. //! Expects pixels.
  226. void SetLineSpacing(float lineSpacing) override;
  227. int GetCharIndexFromPoint(AZ::Vector2 point, bool mustBeInBoundingBox) override;
  228. int GetCharIndexFromCanvasSpacePoint(AZ::Vector2 point, bool mustBeInBoundingBox) override;
  229. AZ::Vector2 GetPointFromCharIndex(int index) override;
  230. AZ::Color GetSelectionColor() override;
  231. void GetSelectionRange(int& startIndex, int& endIndex) override;
  232. void SetSelectionRange(int startIndex, int endIndex, const AZ::Color& selectionColor) override;
  233. void ClearSelectionRange() override;
  234. AZ::Vector2 GetTextSize() override;
  235. float GetTextWidth() override;
  236. float GetTextHeight() override;
  237. void GetTextBoundingBox(int startIndex, int endIndex, UiTransformInterface::RectPointsArray& rectPoints) override;
  238. DisplayedTextFunction GetDisplayedTextFunction() const override { return m_displayedTextFunction; }
  239. void SetDisplayedTextFunction(const DisplayedTextFunction& displayedTextFunction) override;
  240. OverflowMode GetOverflowMode() override;
  241. void SetOverflowMode(OverflowMode overflowMode) override;
  242. WrapTextSetting GetWrapText() override;
  243. void SetWrapText(WrapTextSetting wrapSetting) override;
  244. ShrinkToFit GetShrinkToFit() override;
  245. void SetShrinkToFit(ShrinkToFit shrinkToFit) override;
  246. void ResetCursorLineHint() override { m_cursorLineNumHint = -1; }
  247. bool GetIsMarkupEnabled() override;
  248. void SetIsMarkupEnabled(bool isEnabled) override;
  249. float GetMinimumShrinkScale() override;
  250. void SetMinimumShrinkScale(float minShrinkScale) override;
  251. // ~UiTextInterface
  252. // UiClickableTextInterface
  253. void GetClickableTextRects(UiClickableTextInterface::ClickableTextRects& clickableTextRects) override;
  254. void SetClickableTextColor(int id, const AZ::Color& color) override;
  255. // ~UiClickableTextInterface
  256. // UiAnimateEntityInterface
  257. void PropertyValuesChanged() override;
  258. // ~UiAnimateEntityInterface
  259. // UiTransformChangeNotificationBus
  260. void OnCanvasSpaceRectChanged(AZ::EntityId entityId, const UiTransformInterface::Rect& oldRect, const UiTransformInterface::Rect& newRect) override;
  261. void OnTransformToViewportChanged() override;
  262. // ~UiTransformChangeNotificationBus
  263. // UiLayoutCellDefaultInterface
  264. float GetMinWidth() override;
  265. float GetMinHeight() override;
  266. float GetTargetWidth(float maxWidth) override;
  267. float GetTargetHeight(float maxHeight) override;
  268. float GetExtraWidthRatio() override;
  269. float GetExtraHeightRatio() override;
  270. // ~UiLayoutCellDefaultInterface
  271. // FontNotifications
  272. void OnFontsReloaded() override;
  273. // ~FontNotifications
  274. // LanguageChangeNotification
  275. void LanguageChanged() override;
  276. // ~LanguageChangeNotification
  277. // UiCanvasTextPixelAlignmentNotification
  278. void OnCanvasTextPixelAlignmentChange() override;
  279. // ~UiCanvasTextPixelAlignmentNotification
  280. // TextureAtlasNotifications
  281. void OnAtlasLoaded(const TextureAtlasNamespace::TextureAtlas* atlas) override;
  282. void OnAtlasUnloaded(const TextureAtlasNamespace::TextureAtlas* atlas) override;
  283. // ~TextureAtlasNotifications
  284. #if defined(LYSHINE_INTERNAL_UNIT_TEST)
  285. static void UnitTest(CLyShine* lyshine, IConsoleCmdArgs* cmdArgs);
  286. static void UnitTestLocalization(CLyShine* lyshine, IConsoleCmdArgs* cmdArgs);
  287. #endif
  288. public: // static member functions
  289. static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  290. {
  291. provided.push_back(AZ_CRC("UiVisualService", 0xa864fdf8));
  292. provided.push_back(AZ_CRC("UiTextService"));
  293. }
  294. static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  295. {
  296. incompatible.push_back(AZ_CRC("UiVisualService", 0xa864fdf8));
  297. incompatible.push_back(AZ_CRC("UiTextService"));
  298. }
  299. static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  300. {
  301. required.push_back(AZ_CRC("UiElementService", 0x3dca7ad4));
  302. required.push_back(AZ_CRC("UiTransformService", 0x3a838e34));
  303. }
  304. static void Reflect(AZ::ReflectContext* context);
  305. protected: // member functions
  306. // AZ::Component
  307. void Init() override;
  308. void Activate() override;
  309. void Deactivate() override;
  310. // ~AZ::Component
  311. //! Called when we know the font needs to be changed
  312. void ChangeFont(const AZStd::string& fontFileName);
  313. //! Implementation of getting bounding box for the given displayed text
  314. void GetTextBoundingBoxPrivate(const DrawBatchLines& drawBatchLines, int startIndex, int endIndex, UiTransformInterface::RectPointsArray& rectPoints);
  315. //! Get the bounding rectangle of the text, in untransformed canvas space
  316. void GetTextRect(UiTransformInterface::RectPoints& rect);
  317. //! Similar to GetTextRect, but allows getting a rect for only a portion of text (via textSize).
  318. //!
  319. //! This method is particularly useful for multi-line text, where text selection can
  320. //! vary line-by-line, or across multiple lines of text, in which case you only want
  321. //! rects for a portion of the displayed text, rather than all of it (which GetTextRect
  322. //! does).
  323. void GetTextRect(UiTransformInterface::RectPoints& rect, const AZ::Vector2& textSize);
  324. //! ChangeNotify callback for text string change
  325. void OnTextChange();
  326. //! ChangeNotify callback for color change
  327. void OnColorChange();
  328. //! ChangeNotify callback for alignment change
  329. void OnAlignmentChange();
  330. //! ChangeNotify callback for overflow settings change
  331. void OnOverflowChange();
  332. //! ChangeNotify callback for font size change
  333. void OnFontSizeChange();
  334. //! ChangeNotify callback for font pathname change
  335. AZ::u32 OnFontPathnameChange();
  336. //! ChangeNotify callback for font effect change
  337. void OnFontEffectChange();
  338. //! ChangeNotify callback for text wrap setting change
  339. void OnWrapTextSettingChange();
  340. //! ChangeNotify callback for shrink-to-fit setting change
  341. void OnShrinkToFitChange();
  342. //! ChangeNotify callback for "minimum shrink scale" setting change
  343. void OnMinShrinkScaleChange();
  344. //! ChangeNotify callback for char spacing change
  345. void OnCharSpacingChange();
  346. //! ChangeNotify callback for line spacing change
  347. void OnLineSpacingChange();
  348. //! ChangeNotify callback for markup enabled change
  349. void OnMarkupEnabledChange();
  350. //! Populate the list for the font effect combo box in the properties pane
  351. FontEffectComboBoxVec PopulateFontEffectList();
  352. //! Returns the amount of pixels the displayed text is adjusted for clipping.
  353. //!
  354. //! Returns zero if text is not large enough to be clipped or clipping
  355. //! isn't enabled.
  356. //!
  357. //! \note This does not simply return m_clipoffset. This method calculates
  358. //! and assigns new values to m_clipOffset and m_clipOffsetMultiplier and
  359. //! returns their product.
  360. float CalculateHorizontalClipOffset();
  361. //! Mark draw batches dirty
  362. void MarkDrawBatchLinesDirty(bool invalidateLayout);
  363. //! Calculate the DrawBatchLines if needed and return a const ref
  364. const DrawBatchLines& GetDrawBatchLines();
  365. //! Calculates draw batch lines
  366. void CalculateDrawBatchLines(
  367. UiTextComponent::DrawBatchLines& drawBatchLinesOut,
  368. bool forceNoWrap = false,
  369. float availableWidth = -1.0f,
  370. bool excludeTrailingSpaceWidth = true
  371. );
  372. //! Renders the text to the render cache
  373. void RenderToCache(float alpha);
  374. //! Add DrawBatch lines to the render graph for rendering
  375. void RenderDrawBatchLines(
  376. const UiTextComponent::DrawBatchLines& drawBatchLines,
  377. const AZ::Vector2& pos,
  378. const UiTransformInterface::RectPoints& points,
  379. const AZ::Matrix4x4& transformToViewport,
  380. STextDrawContext& fontContext);
  381. //! Update the text render batches in the case of a font texture change
  382. void UpdateTextRenderBatchesForFontTextureChange();
  383. //! Returns a prototypical STextDrawContext to be used when interacting with IFont routines..
  384. STextDrawContext GetTextDrawContextPrototype(int requestFontSize, const AZ::Vector2& fontSizeScale) const;
  385. //! Recomputes draw batch lines as appropriate depending on current options when text width properties are modified
  386. void OnTextWidthPropertyChanged();
  387. //! Handles overflow and shrink-to-text settings to text
  388. void HandleOverflowText(UiTextComponent::DrawBatchLines& drawBatchLinesOut);
  389. //! Handles shrink-to-fit for text, if applicable.
  390. void HandleShrinkToFit(UiTextComponent::DrawBatchLines& drawBatchLinesOut, float availableHeight = -1.0f);
  391. //! Handles the "uniform" shrink-to-fit setting.
  392. void HandleUniformShrinkToFitWithScale(UiTextComponent::DrawBatchLines& drawBatchLinesOut, const AZ::Vector2& scaleVec);
  393. //! Handles the shrink-to-fit setting for word-wrapped text.
  394. void HandleShrinkToFitWithWrapping(UiTextComponent::DrawBatchLines& drawBatchLinesOut, const AZ::Vector2& currentElementSize, const AZ::Vector2& textSize);
  395. //! Handles "width only" word-wrapped shrink-to-fit text.
  396. void HandleWidthOnlyShrinkToFitWithWrapping(UiTextComponent::DrawBatchLines& drawBatchLinesOut, const AZ::Vector2& currentElementSize, int maxLinesElementCanHold);
  397. //! Handles "uniform" word-wrapped shrink-to-fit text.
  398. void HandleUniformShrinkToFitWithWrapping(UiTextComponent::DrawBatchLines& drawBatchLinesOut, const AZ::Vector2& currentElementSize, int maxLinesElementCanHold);
  399. //! Inserts ellipsis into overflowing text
  400. void HandleEllipsis(UiTextComponent::DrawBatchLines& drawBatchLinesOut, float availableHeight = -1.0f);
  401. using DrawBatchLineIters = AZStd::vector<DrawBatchLineContainer::iterator>;
  402. //! Returns the draw batch line to ellipsis and the following lines to truncate (if any).
  403. void GetLineToEllipsisAndLinesToTruncate(UiTextComponent::DrawBatchLines& drawBatchLinesOut,
  404. DrawBatchLineContainer::iterator* lineToEllipsis, DrawBatchLineIters& linesToRemove, const AZ::Vector2& currentElementSize);
  405. using DrawBatchStartPosPair = AZStd::pair<DrawBatch*, float>;
  406. using DrawBatchStartPositions = AZStd::vector<DrawBatchStartPosPair>;
  407. //! Returns the "starting" pixel position for each batch on the given line
  408. void GetDrawBatchStartPositions(DrawBatchStartPositions& startPositions, DrawBatchLine* lineToEllipsis, const AZ::Vector2& currentElementSize);
  409. //! Returns the draw batch that will have ellipsis inserted, along with required position information to do so.
  410. DrawBatch* GetDrawBatchToEllipseAndPositions(const char* ellipseText,
  411. const STextDrawContext& ctx,
  412. const AZ::Vector2& currentElementSize,
  413. DrawBatchStartPositions* startPositions,
  414. float* drawBatchStartPos,
  415. float* ellipsisPos);
  416. //! Removes all draw batches following the given DrawBatch on the given DrawBatchLine.
  417. void TruncateDrawBatches(DrawBatchLine* lineToTruncate, const DrawBatch* truncateAfterBatch);
  418. //! Given a draw batch, get the character index where ellipsis should be inserted in the string.
  419. int GetStartEllipseIndexInDrawBatch(const DrawBatch* drawBatchToEllipse,
  420. const STextDrawContext& ctx,
  421. const float drawBatchStartPos,
  422. const float ellipsePos);
  423. //! Inserts the ellipse text into the given draw batch and updates batch and line sizing information
  424. void InsertEllipsisText(const char* ellipseText,
  425. const int ellipsisCharPos,
  426. DrawBatch* drawBatchToEllipse);
  427. //! Ensures that all draw batches on the given batch line have valid font pointers
  428. //!
  429. //! This is primarily used for ellipsis overflow handling, making it easier to make
  430. //! assumptions about which font to use when inserting ellipsis text for a given
  431. //! batch (when that batch is an image batch).
  432. void SetBatchLineFontPointers(DrawBatchLine* batchLine);
  433. //! Returns true if the given text rect overflows the given element size, false otherwise
  434. bool GetTextOverflowsBounds(const AZ::Vector2& textSize, const AZ::Vector2& elementSize) const;
  435. //! Compute the text size from the already computed draw batch lines
  436. AZ::Vector2 GetTextSizeFromDrawBatchLines(const UiTextComponent::DrawBatchLines& drawBatchLines) const;
  437. //! Localize the given text string
  438. AZStd::string GetLocalizedText(const AZStd::string& text);
  439. //! Given rect points and number of lines of text to display, returns the position to display text.
  440. //!
  441. //! The number of lines of text determines the Y offset of the first line to display. For
  442. //! top-aligned text, this offset will be zero (regardless of the number of lines of text)
  443. //! because the first line to display will always be displayed at the top of the rect, while
  444. //! bottom-aligned text will be offset by the number of lines to display, and vertically
  445. //! centered text will be offset by half of that amount.
  446. //!
  447. //! Example: if horizontal alignment is "left" and vertical alignment is
  448. //! "top", this will simply return the top-left point of the rect.
  449. //!
  450. //! This assumes the given rect points are axis-aligned.
  451. AZ::Vector2 CalculateAlignedPositionWithYOffset(const UiTransformInterface::RectPoints& points);
  452. private: // static member functions
  453. static bool VersionConverter(AZ::SerializeContext& context,
  454. AZ::SerializeContext::DataElementNode& classElement);
  455. AZ_DISABLE_COPY_MOVE(UiTextComponent);
  456. //! Calculates the left and right offsets for cursor placement and text selection bounds.
  457. void GetOffsetsFromSelectionInternal(LineOffsets& top, LineOffsets& middle, LineOffsets& bottom, int selectionStart, int selectionEnd);
  458. private: // member functions
  459. //! Given an index into the displayed string, returns the line number that the character is displayed on.
  460. int GetLineNumberFromCharIndex(const DrawBatchLines& drawBatchLines, const int soughtIndex) const;
  461. //! Invalidates the parent and this element's layout
  462. void InvalidateLayout() const;
  463. //! Refresh the transform properties in the editor's properties pane
  464. void CheckLayoutFitterAndRefreshEditorTransformProperties() const;
  465. //! Mark the render cache as dirty, this should be done when any change is made that invalidated the cached data
  466. void MarkRenderCacheDirty();
  467. //! Mark the render graph as dirty, this should be done when any change is made affects the structure of the graph
  468. void MarkRenderGraphDirty();
  469. //! Clear the render cache
  470. void ClearRenderCache();
  471. //! Clear the render cache memory allocations
  472. void FreeRenderCacheMemory();
  473. //! Checks if clipping is enabled for handling overflow, or if specific conditions are met when using ellipsis.
  474. //!
  475. //! When ellipsis overflow handling is enabled, content will become clipped when the text
  476. //! overflows vertically and only one line is displayed.
  477. bool ShouldClip();
  478. //! Calculate m_requestFontSize if needed then return it
  479. int GetRequestFontSize();
  480. private: // types
  481. struct RenderCacheBatch
  482. {
  483. AZ::Vector2 m_position;
  484. AZStd::string m_text;
  485. ColorB m_color;
  486. IFFont* m_font;
  487. uint32 m_fontTextureVersion;
  488. LyShine::UiPrimitive m_cachedPrimitive;
  489. };
  490. struct RenderCacheImageBatch
  491. {
  492. AZ::Data::Instance<AZ::RPI::Image> m_texture;
  493. LyShine::UiPrimitive m_cachedPrimitive;
  494. };
  495. struct RenderCacheData
  496. {
  497. bool m_isDirty = true;
  498. STextDrawContext m_fontContext;
  499. AZStd::vector<RenderCacheBatch*> m_batches;
  500. AZStd::vector<RenderCacheImageBatch*> m_imageBatches;
  501. };
  502. private: // data
  503. AZStd::string m_text;
  504. AZStd::string m_locText; //!< Language-specific localized text (if applicable), keyed by m_text. May contain word-wrap formatting (if enabled).
  505. DrawBatchLines m_drawBatchLines; //!< Lists of DrawBatches across multiple lines for rendering text.
  506. AZ::Color m_color;
  507. float m_alpha;
  508. float m_fontSize;
  509. int m_requestFontSize; //!< The size to request glyphs to be rendered at within the font texture
  510. IDraw2d::HAlign m_textHAlignment;
  511. IDraw2d::VAlign m_textVAlignment;
  512. float m_charSpacing; //!< The spacing (aka "tracking") between characters, defined in 1/1000th ems. 1em is equal to the
  513. //!< font size. In GetTextDrawContextPrototype, this value ultimately gets converted to pixels and
  514. //!< stored in STextDrawContext::m_tracking. This value and STextDrawContext::m_tracking aren't
  515. //!< necessarily 1:1, just as m_fontSize and STextDrawContext::m_size aren't necessarily 1:1.
  516. //!< Although the component values of m_charSpacing and m_fontSize are unaffected by scaling,
  517. //!< scaling (such as scaling performed by shrink-to-fit overflow handling) is applied to these
  518. //!< values and the resulting scaled value is stored in STextDrawContext for rendering. As a result,
  519. //!< it's possible for the value of m_charSpacing to never change, but STextDrawContext::m_tracking
  520. //!< can vary in value independently of m_charSpacing as the font size (and/or scaled font size)
  521. //!< changes over time. See also DrawBatchLines::fontSizeScale.
  522. float m_lineSpacing;
  523. float m_currFontSize; //!< Needed for PropertyValuesChanged method, used for UI animation
  524. float m_currCharSpacing; //!< Needed for PropertyValuesChanged method, used for UI animation
  525. AzFramework::SimpleAssetReference<LyShine::FontAsset> m_fontFilename;
  526. IFFont* m_font;
  527. FontFamilyPtr m_fontFamily;
  528. unsigned int m_fontEffectIndex;
  529. DisplayedTextFunction m_displayedTextFunction; //!< Function object that returns a string to be used for rendering/display.
  530. AZ::Color m_overrideColor;
  531. float m_overrideAlpha;
  532. FontFamilyPtr m_overrideFontFamily;
  533. unsigned int m_overrideFontEffectIndex;
  534. bool m_isColorOverridden;
  535. bool m_isAlphaOverridden;
  536. bool m_isFontFamilyOverridden;
  537. bool m_isFontEffectOverridden;
  538. AZ::Color m_textSelectionColor; //!< color for a selection box drawn as background for a range of text
  539. int m_selectionStart; //!< UTF8 character/element index in the displayed string. This index
  540. //! marks the beggining of a text selection, such as when this component
  541. //! is associated with a text input component. If the displayed string
  542. //! contains UTF8 multi-byte characters, then this index will not
  543. //!< match 1:1 with an index into the raw string buffer.
  544. int m_selectionEnd; //!< UTF8 character/element index in the displayed string. This index
  545. //! marks the end of a text selection, such as when this component
  546. //! is associated with a text input component. If the displayed string
  547. //! contains UTF8 multi-byte characters, then this index will not
  548. //!< match 1:1 with an index into the raw string buffer.
  549. int m_cursorLineNumHint;
  550. OverflowMode m_overflowMode; //!< How text should "fit" within the element
  551. WrapTextSetting m_wrapTextSetting; //!< Drives text-wrap setting
  552. ShrinkToFit m_shrinkToFit = ShrinkToFit::None; //!< Whether text should shrink to fit element bounds when it overflows
  553. float m_minShrinkScale = 0.0f; //!< Limits the scale applied to text when text overflows and ShrinkToFit is used.
  554. float m_clipOffset; //!< Amount of pixels to adjust text draw call to account for clipping rect
  555. float m_clipOffsetMultiplier; //!< Used to adjust clip offset based on horizontal alignment settings
  556. bool m_isMarkupEnabled; //!< Enables markup in the text string. If false string will not be XML parsed
  557. RenderCacheData m_renderCache; //! Cached render data used to optimize rendering when nothing is changing frame to frame
  558. bool m_areDrawBatchLinesDirty = true; //!< Indicates whether m_drawBatchLines needs regenerating before next use
  559. bool m_isRequestFontSizeDirty = true; //!< Indicates whether m_requestFontSize needs calculating before next use
  560. bool m_textNeedsXmlValidation = true; //!< Indicates whether any XML parsing warnings should be displayed when next parsed
  561. };