UiMarkupButtonComponent.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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. #include "UiMarkupButtonComponent.h"
  9. #include <LyShine/Bus/UiCanvasBus.h>
  10. #include <LyShine/Bus/UiMarkupButtonBus.h>
  11. #include <AzCore/Math/Crc.h>
  12. #include <AzCore/Serialization/SerializeContext.h>
  13. #include <AzCore/Serialization/EditContext.h>
  14. #include <AzCore/RTTI/BehaviorContext.h>
  15. namespace
  16. {
  17. //! Given a UI element on a canvas, return the mouse position.
  18. AZ::Vector2 GetMousePosition(AZ::EntityId entityId)
  19. {
  20. AZ::EntityId canvasId;
  21. UiElementBus::EventResult(canvasId, entityId, &UiElementBus::Events::GetCanvasEntityId);
  22. AZ::Vector2 mousePos = AZ::Vector2::CreateZero();
  23. UiCanvasBus::EventResult(mousePos, canvasId, &UiCanvasBus::Events::GetMousePosition);
  24. return mousePos;
  25. }
  26. //! Returns an index to the given list of clickable text rects that contains the given mouse position, otherwise returns negative.
  27. int FindClickableTextRectIndexFromCanvasSpacePoint(const AZ::Vector2& canvasSpacePosition, const UiClickableTextInterface::ClickableTextRects& clickableTextRects)
  28. {
  29. // Iterate through the clickable rects to find one that contains the point
  30. int clickableRectIndex = -1;
  31. const int numClickableRects = static_cast<int>(clickableTextRects.size());
  32. for (int i = 0; i < numClickableRects; ++i)
  33. {
  34. const auto& clickableRect = clickableTextRects[i];
  35. const UiTransformInterface::Rect& rect = clickableRect.rect;
  36. const bool containedX = canvasSpacePosition.GetX() >= rect.left && canvasSpacePosition.GetX() <= rect.right;
  37. if (containedX)
  38. {
  39. const bool containedY = canvasSpacePosition.GetY() >= rect.top && canvasSpacePosition.GetY() <= rect.bottom;
  40. if (containedY)
  41. {
  42. clickableRectIndex = i;
  43. break;
  44. }
  45. }
  46. }
  47. return clickableRectIndex;
  48. }
  49. //! Returns an index to the given list of clickable text rects that contains the given mouse position, otherwise returns negative.
  50. int FindClickableTextRectIndexFromViewportSpacePoint(AZ::EntityId entityId, const AZ::Vector2& mousePos, const UiClickableTextInterface::ClickableTextRects& clickableTextRects)
  51. {
  52. // first transform the mousePos from viewport space to "canvas space no-scale-rotate", which is the space that clickableTextRects
  53. // are stored in.
  54. AZ::Matrix4x4 transformFromViewport;
  55. UiTransformBus::Event(entityId, &UiTransformBus::Events::GetTransformFromViewport, transformFromViewport);
  56. AZ::Vector3 point3(mousePos.GetX(), mousePos.GetY(), 0.0f);
  57. point3 = transformFromViewport * point3;
  58. AZ::Vector2 canvasSpacePosition(point3.GetX(), point3.GetY());
  59. return FindClickableTextRectIndexFromCanvasSpacePoint(canvasSpacePosition, clickableTextRects);
  60. }
  61. }
  62. ////////////////////////////////////////////////////////////////////////////////////////////////////
  63. //! UiMarkupButtonNotificationBus Behavior context handler class
  64. class UiMarkupButtonNotificationBusBehaviorHandler
  65. : public UiMarkupButtonNotificationsBus::Handler
  66. , public AZ::BehaviorEBusHandler
  67. {
  68. public:
  69. AZ_EBUS_BEHAVIOR_BINDER(UiMarkupButtonNotificationBusBehaviorHandler, "{ACCF73DC-86DD-4D1C-85B3-1E016BAAA495}", AZ::SystemAllocator,
  70. OnHoverStart,
  71. OnHoverEnd,
  72. OnPressed,
  73. OnReleased,
  74. OnClick);
  75. void OnHoverStart(int id, const AZStd::string& action, const AZStd::string& data) override
  76. {
  77. Call(FN_OnHoverStart, id, action, data);
  78. }
  79. void OnHoverEnd(int id, const AZStd::string& action, const AZStd::string& data) override
  80. {
  81. Call(FN_OnHoverEnd, id, action, data);
  82. }
  83. void OnPressed(int id, const AZStd::string& action, const AZStd::string& data) override
  84. {
  85. Call(FN_OnPressed, id, action, data);
  86. }
  87. void OnReleased(int id, const AZStd::string& action, const AZStd::string& data) override
  88. {
  89. Call(FN_OnReleased, id, action, data);
  90. }
  91. void OnClick(int id, const AZStd::string& action, const AZStd::string& data) override
  92. {
  93. Call(FN_OnClick, id, action, data);
  94. }
  95. };
  96. ////////////////////////////////////////////////////////////////////////////////////////////////////
  97. // PUBLIC MEMBER FUNCTIONS
  98. ////////////////////////////////////////////////////////////////////////////////////////////////////
  99. ////////////////////////////////////////////////////////////////////////////////////////////////////
  100. UiMarkupButtonComponent::UiMarkupButtonComponent()
  101. {
  102. }
  103. ////////////////////////////////////////////////////////////////////////////////////////////////////
  104. UiMarkupButtonComponent::~UiMarkupButtonComponent()
  105. {
  106. }
  107. ////////////////////////////////////////////////////////////////////////////////////////////////////
  108. AZ::Color UiMarkupButtonComponent::GetLinkColor()
  109. {
  110. return m_linkColor;
  111. }
  112. ////////////////////////////////////////////////////////////////////////////////////////////////////
  113. void UiMarkupButtonComponent::SetLinkColor(const AZ::Color& linkColor)
  114. {
  115. m_linkColor = linkColor;
  116. OnLinkColorChanged();
  117. }
  118. ////////////////////////////////////////////////////////////////////////////////////////////////////
  119. AZ::Color UiMarkupButtonComponent::GetLinkHoverColor()
  120. {
  121. return m_linkHoverColor;
  122. }
  123. ////////////////////////////////////////////////////////////////////////////////////////////////////
  124. void UiMarkupButtonComponent::SetLinkHoverColor(const AZ::Color& linkHoverColor)
  125. {
  126. m_linkHoverColor = linkHoverColor;
  127. OnLinkHoverColorChanged();
  128. }
  129. ////////////////////////////////////////////////////////////////////////////////////////////////////
  130. bool UiMarkupButtonComponent::HandlePressed(AZ::Vector2 point, bool& shouldStayActive)
  131. {
  132. const bool handled = UiInteractableComponent::HandlePressed(point, shouldStayActive);
  133. if (!handled)
  134. {
  135. return false;
  136. }
  137. const int clickableRectIndex = FindClickableTextRectIndexFromViewportSpacePoint(GetEntityId(), point, m_clickableTextRects);
  138. if (clickableRectIndex >= 0)
  139. {
  140. const int clickableId = m_clickableTextRects[clickableRectIndex].id;
  141. const AZStd::string& action = m_clickableTextRects[clickableRectIndex].action;
  142. const AZStd::string& data = m_clickableTextRects[clickableRectIndex].data;
  143. m_clickableRectPressedIndex = clickableRectIndex;
  144. UiMarkupButtonNotificationsBus::Event(GetEntityId(), &UiMarkupButtonNotificationsBus::Events::OnPressed, clickableId, action, data);
  145. }
  146. return handled;
  147. }
  148. ////////////////////////////////////////////////////////////////////////////////////////////////////
  149. bool UiMarkupButtonComponent::HandleReleased(AZ::Vector2 point)
  150. {
  151. const bool handled = UiInteractableComponent::HandleReleased(point);
  152. if (!handled)
  153. {
  154. m_clickableRectPressedIndex = -1;
  155. return false;
  156. }
  157. // This could be negative if the clickable text change since the pressed
  158. // event occurred (OnClickableTextChanged resets the pressed index value).
  159. if (m_clickableRectPressedIndex < 0)
  160. {
  161. UiMarkupButtonNotificationsBus::Event(
  162. GetEntityId(), &UiMarkupButtonNotificationsBus::Events::OnReleased, -1, AZStd::string(), AZStd::string());
  163. }
  164. else
  165. {
  166. const int pressedClickableId = m_clickableTextRects[m_clickableRectPressedIndex].id;
  167. const AZStd::string& action = m_clickableTextRects[m_clickableRectPressedIndex].action;
  168. const AZStd::string& data = m_clickableTextRects[m_clickableRectPressedIndex].data;
  169. UiMarkupButtonNotificationsBus::Event(
  170. GetEntityId(), &UiMarkupButtonNotificationsBus::Events::OnReleased, pressedClickableId, action, data);
  171. bool onClickTriggered = false;
  172. const int releasedClickableRectIndex = FindClickableTextRectIndexFromViewportSpacePoint(GetEntityId(), point, m_clickableTextRects);
  173. if (releasedClickableRectIndex >= 0)
  174. {
  175. // If the release happens on the pressed link ID, trigger a click.
  176. const int releasedClickableId = m_clickableTextRects[releasedClickableRectIndex].id;
  177. if (releasedClickableId == pressedClickableId)
  178. {
  179. UiMarkupButtonNotificationsBus::Event(
  180. GetEntityId(), &UiMarkupButtonNotificationsBus::Events::OnClick, pressedClickableId, action, data);
  181. onClickTriggered = true;
  182. }
  183. }
  184. if (!onClickTriggered)
  185. {
  186. // Clear the hover state now in case this entity is no longer
  187. // being hovered. This can happen when the user releases the
  188. // mouse outside of the clickable text rect.
  189. HandleClickableHoverEnd();
  190. }
  191. }
  192. m_clickableRectPressedIndex = -1;
  193. return handled;
  194. }
  195. ////////////////////////////////////////////////////////////////////////////////////////////////////
  196. void UiMarkupButtonComponent::Update(float deltaTime)
  197. {
  198. UiInteractableComponent::Update(deltaTime);
  199. UpdateHover();
  200. }
  201. ////////////////////////////////////////////////////////////////////////////////////////////////////
  202. void UiMarkupButtonComponent::OnClickableTextChanged()
  203. {
  204. m_clickableTextRects.clear();
  205. UiClickableTextBus::Event(GetEntityId(), &UiClickableTextBus::Events::GetClickableTextRects, m_clickableTextRects);
  206. // Reset all links back to their non-hover color
  207. int lastClickableId = -1;
  208. for (const auto& clickableText : m_clickableTextRects)
  209. {
  210. // Color is assigned by clickable ID and it's possible for
  211. // multiple clickable text rects to share the same ID, so guard
  212. // against unnecessary calls to set the color for IDs that have
  213. // previously been set.
  214. if (lastClickableId != clickableText.id)
  215. {
  216. UiClickableTextBus::Event(GetEntityId(), &UiClickableTextBus::Events::SetClickableTextColor, clickableText.id, m_linkColor);
  217. lastClickableId = clickableText.id;
  218. }
  219. }
  220. // Because the clickable text has changed, our current hover and pressed
  221. // states may no longer apply. Update it again based on the new clickable
  222. // text rects and current mouse position.
  223. m_clickableRectHoverIndex = -1;
  224. m_clickableRectPressedIndex = -1;
  225. UpdateHover();
  226. }
  227. ////////////////////////////////////////////////////////////////////////////////////////////////////
  228. // PROTECTED MEMBER FUNCTIONS
  229. ////////////////////////////////////////////////////////////////////////////////////////////////////
  230. ////////////////////////////////////////////////////////////////////////////////////////////////////
  231. void UiMarkupButtonComponent::Activate()
  232. {
  233. UiInteractableComponent::Activate();
  234. UiMarkupButtonBus::Handler::BusConnect(GetEntityId());
  235. UiClickableTextNotificationsBus::Handler::BusConnect(GetEntityId());
  236. }
  237. ////////////////////////////////////////////////////////////////////////////////////////////////////
  238. void UiMarkupButtonComponent::Deactivate()
  239. {
  240. UiInteractableComponent::Deactivate();
  241. UiMarkupButtonBus::Handler::BusDisconnect(GetEntityId());
  242. UiClickableTextNotificationsBus::Handler::BusDisconnect(GetEntityId());
  243. }
  244. ////////////////////////////////////////////////////////////////////////////////////////////////////
  245. void UiMarkupButtonComponent::UpdateHover()
  246. {
  247. // Don't update hover state when we're actively being pressed. If we ever
  248. // add a pressed color, we could update this logic so that the pressed
  249. // color updates when the mouse moves on/off the clickable text.
  250. if (m_isHandlingEvents && !m_isPressed)
  251. {
  252. AZ::EntityId canvasId;
  253. UiElementBus::EventResult(canvasId, GetEntityId(), &UiElementBus::Events::GetCanvasEntityId);
  254. AZ::EntityId hoverInteractable;
  255. UiCanvasBus::EventResult(hoverInteractable, canvasId, &UiCanvasBus::Events::GetHoverInteractable);
  256. // Similarly, the hover interactable won't updated while another
  257. // element is being pressed - we don't want to update hover state
  258. // of any clickable text (on any entity) while a press is happening.
  259. if (hoverInteractable == GetEntityId())
  260. {
  261. const int rectIndex = FindClickableTextRectIndexFromViewportSpacePoint(GetEntityId(), GetMousePosition(GetEntityId()), m_clickableTextRects);
  262. int rectIndexClickableId = -1;
  263. if (rectIndex >= 0)
  264. {
  265. rectIndexClickableId = m_clickableTextRects[rectIndex].id;
  266. }
  267. int hoverClickableId = -1;
  268. if (m_clickableRectHoverIndex >= 0)
  269. {
  270. hoverClickableId = m_clickableTextRects[m_clickableRectHoverIndex].id;
  271. }
  272. const bool enteringHover = rectIndexClickableId >= 0 && hoverClickableId < 0;
  273. const bool leavingHover = rectIndexClickableId < 0 && hoverClickableId >= 0;
  274. const bool switchingHoverRect = rectIndexClickableId >= 0 && hoverClickableId >= 0 && rectIndexClickableId != hoverClickableId;
  275. if (enteringHover)
  276. {
  277. HandleClickableHoverStart(rectIndex);
  278. }
  279. else if (leavingHover)
  280. {
  281. HandleClickableHoverEnd();
  282. }
  283. else if (switchingHoverRect)
  284. {
  285. HandleClickableHoverEnd();
  286. HandleClickableHoverStart(rectIndex);
  287. }
  288. }
  289. else
  290. {
  291. // Not being pressed or hovered, so reset the hover index element
  292. // just in case it is set (this can occur if we never receive a
  293. // release event for the interactable).
  294. HandleClickableHoverEnd();
  295. }
  296. }
  297. }
  298. ////////////////////////////////////////////////////////////////////////////////////////////////////
  299. void UiMarkupButtonComponent::HandleClickableHoverStart(int clickableRectIndex)
  300. {
  301. m_clickableRectHoverIndex = clickableRectIndex;
  302. const int clickableId = m_clickableTextRects[m_clickableRectHoverIndex].id;
  303. // Set the link color prior to notification being triggered in case listeners want to set
  304. // the color themselves.
  305. UiClickableTextBus::Event(GetEntityId(), &UiClickableTextBus::Events::SetClickableTextColor, clickableId, m_linkHoverColor);
  306. const AZStd::string& action = m_clickableTextRects[m_clickableRectHoverIndex].action;
  307. const AZStd::string& data = m_clickableTextRects[m_clickableRectHoverIndex].data;
  308. UiMarkupButtonNotificationsBus::Event(GetEntityId(), &UiMarkupButtonNotificationsBus::Events::OnHoverStart, clickableId, action, data);
  309. }
  310. ////////////////////////////////////////////////////////////////////////////////////////////////////
  311. void UiMarkupButtonComponent::HandleClickableHoverEnd()
  312. {
  313. if (m_clickableRectHoverIndex >= 0)
  314. {
  315. const int clickableId = m_clickableTextRects[m_clickableRectHoverIndex].id;
  316. // Set the link color prior to notification being triggered in case listeners want to set
  317. // the color themselves.
  318. UiClickableTextBus::Event(GetEntityId(), &UiClickableTextBus::Events::SetClickableTextColor, clickableId, m_linkColor);
  319. const AZStd::string& action = m_clickableTextRects[m_clickableRectHoverIndex].action;
  320. const AZStd::string& data = m_clickableTextRects[m_clickableRectHoverIndex].data;
  321. m_clickableRectHoverIndex = -1;
  322. UiMarkupButtonNotificationsBus::Event(GetEntityId(), &UiMarkupButtonNotificationsBus::Events::OnHoverEnd, clickableId, action, data);
  323. }
  324. }
  325. ////////////////////////////////////////////////////////////////////////////////////////////////////
  326. void UiMarkupButtonComponent::OnLinkColorChanged()
  327. {
  328. // If a link is being hovered (e.g. if SetLinkColor called at runtime while a link is being hovered)
  329. // then we do not want to set the color of that link
  330. int hoverClickableId = -1;
  331. if (m_clickableRectHoverIndex >= 0)
  332. {
  333. hoverClickableId = m_clickableTextRects[m_clickableRectHoverIndex].id;
  334. }
  335. // Set all links to the new link color (unless they are currently being hovered)
  336. int lastClickableId = -1;
  337. for (const auto& clickableText : m_clickableTextRects)
  338. {
  339. // Color is assigned by clickable ID and it's possible for
  340. // multiple clickable text rects to share the same ID, so guard
  341. // against unnecessary calls to set the color for IDs that have
  342. // previously been set.
  343. // We also don't want to set the text to the link color if it is currently being hovered.
  344. if (lastClickableId != clickableText.id && clickableText.id != hoverClickableId)
  345. {
  346. UiClickableTextBus::Event(GetEntityId(), &UiClickableTextBus::Events::SetClickableTextColor, clickableText.id, m_linkColor);
  347. lastClickableId = clickableText.id;
  348. }
  349. }
  350. }
  351. ////////////////////////////////////////////////////////////////////////////////////////////////////
  352. ////////////////////////////////////////////////////////////////////////////////////////////////////
  353. void UiMarkupButtonComponent::OnLinkHoverColorChanged()
  354. {
  355. // If a link is being hovered (e.g. if SetLinkColor called at runtime while a link is being hovered)
  356. // then we want to set the color of that link to the new hover color
  357. int hoverClickableId = -1;
  358. if (m_clickableRectHoverIndex >= 0)
  359. {
  360. hoverClickableId = m_clickableTextRects[m_clickableRectHoverIndex].id;
  361. }
  362. // Set any hovered links to the new link hover color
  363. int lastClickableId = -1;
  364. for (const auto& clickableText : m_clickableTextRects)
  365. {
  366. // Color is assigned by clickable ID and it's possible for
  367. // multiple clickable text rects to share the same ID, so guard
  368. // against unnecessary calls to set the color for IDs that have
  369. // previously been set.
  370. if (lastClickableId != clickableText.id)
  371. {
  372. // If it is currently being hovered then set its color to the new link hover color
  373. if (clickableText.id == hoverClickableId)
  374. {
  375. UiClickableTextBus::Event(
  376. GetEntityId(), &UiClickableTextBus::Events::SetClickableTextColor, clickableText.id, m_linkHoverColor);
  377. }
  378. lastClickableId = clickableText.id;
  379. }
  380. }
  381. }
  382. ////////////////////////////////////////////////////////////////////////////////////////////////////
  383. // PROTECTED STATIC MEMBER FUNCTIONS
  384. ////////////////////////////////////////////////////////////////////////////////////////////////////
  385. ////////////////////////////////////////////////////////////////////////////////////////////////////
  386. void UiMarkupButtonComponent::Reflect(AZ::ReflectContext* context)
  387. {
  388. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  389. if (serializeContext)
  390. {
  391. serializeContext->Class<UiMarkupButtonComponent, UiInteractableComponent>()
  392. ->Version(1, &VersionConverter)
  393. ->Field("LinkColor", &UiMarkupButtonComponent::m_linkColor)
  394. ->Field("LinkHoverColor", &UiMarkupButtonComponent::m_linkHoverColor);
  395. AZ::EditContext* ec = serializeContext->GetEditContext();
  396. if (ec)
  397. {
  398. auto editInfo = ec->Class<UiMarkupButtonComponent>("MarkupButton", "An interactable component for enabling clicks from markup text (mouse support only).");
  399. editInfo->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  400. ->Attribute(AZ::Edit::Attributes::Category, "UI")
  401. // Need to request markup button component icons for LY ML
  402. ->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/UiMarkupButton.png")
  403. ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/UiMarkupButton.png")
  404. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("UI", 0x27ff46b0))
  405. ->Attribute(AZ::Edit::Attributes::AutoExpand, true);
  406. editInfo->DataElement(AZ::Edit::UIHandlers::Color, &UiMarkupButtonComponent::m_linkColor, "Link Color", "Link text color.")
  407. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiMarkupButtonComponent::OnLinkColorChanged);
  408. editInfo->DataElement(AZ::Edit::UIHandlers::Color, &UiMarkupButtonComponent::m_linkHoverColor, "Link Hover Color", "Link text hover color.")
  409. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiMarkupButtonComponent::OnLinkHoverColorChanged);
  410. }
  411. }
  412. AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
  413. if (behaviorContext)
  414. {
  415. behaviorContext->EBus<UiMarkupButtonBus>("UiMarkupButtonBus")
  416. ->Event("GetLinkColor", &UiMarkupButtonBus::Events::GetLinkColor)
  417. ->Event("SetLinkColor", &UiMarkupButtonBus::Events::SetLinkColor)
  418. ->Event("GetLinkHoverColor", &UiMarkupButtonBus::Events::GetLinkHoverColor)
  419. ->Event("SetLinkHoverColor", &UiMarkupButtonBus::Events::SetLinkHoverColor);
  420. behaviorContext->EBus<UiMarkupButtonNotificationsBus>("UiMarkupButtonNotificationsBus")
  421. ->Handler<UiMarkupButtonNotificationBusBehaviorHandler>();
  422. }
  423. }
  424. ////////////////////////////////////////////////////////////////////////////////////////////////////
  425. // PRIVATE MEMBER FUNCTIONS
  426. ////////////////////////////////////////////////////////////////////////////////////////////////////
  427. ////////////////////////////////////////////////////////////////////////////////////////////////////
  428. // PRIVATE STATIC MEMBER FUNCTIONS
  429. ////////////////////////////////////////////////////////////////////////////////////////////////////
  430. ////////////////////////////////////////////////////////////////////////////////////////////////////
  431. bool UiMarkupButtonComponent::VersionConverter([[maybe_unused]] AZ::SerializeContext& context,
  432. [[maybe_unused]] AZ::SerializeContext::DataElementNode& classElement)
  433. {
  434. return true;
  435. }
  436. #include "Tests/internal/test_UiMarkupButtonComponent.cpp"