UiLayoutColumnComponent.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  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 "UiLayoutColumnComponent.h"
  9. #include <AzCore/Serialization/SerializeContext.h>
  10. #include <AzCore/Serialization/EditContext.h>
  11. #include <AzCore/RTTI/BehaviorContext.h>
  12. #include <LyShine/Bus/UiElementBus.h>
  13. #include <LyShine/Bus/UiTransform2dBus.h>
  14. #include <LyShine/Bus/UiLayoutManagerBus.h>
  15. #include "UiSerialize.h"
  16. ////////////////////////////////////////////////////////////////////////////////////////////////////
  17. // PUBLIC MEMBER FUNCTIONS
  18. ////////////////////////////////////////////////////////////////////////////////////////////////////
  19. ////////////////////////////////////////////////////////////////////////////////////////////////////
  20. UiLayoutColumnComponent::UiLayoutColumnComponent()
  21. : m_padding(UiLayoutInterface::Padding())
  22. , m_spacing(5)
  23. , m_order(UiLayoutInterface::VerticalOrder::TopToBottom)
  24. , m_childHAlignment(IDraw2d::HAlign::Left)
  25. , m_childVAlignment(IDraw2d::VAlign::Top)
  26. , m_ignoreDefaultLayoutCells(true)
  27. {
  28. }
  29. ////////////////////////////////////////////////////////////////////////////////////////////////////
  30. UiLayoutColumnComponent::~UiLayoutColumnComponent()
  31. {
  32. }
  33. ////////////////////////////////////////////////////////////////////////////////////////////////////
  34. void UiLayoutColumnComponent::ApplyLayoutWidth()
  35. {
  36. // Get the layout rect inside the padding
  37. AZ::Vector2 layoutRectSize(0.0f, 0.0f);
  38. UiLayoutHelpers::GetSizeInsidePadding(GetEntityId(), m_padding, layoutRectSize);
  39. // First, calculate and set the child elements' widths.
  40. // Min/target/extra heights may depend on element widths
  41. ApplyLayoutWidth(layoutRectSize.GetX());
  42. }
  43. ////////////////////////////////////////////////////////////////////////////////////////////////////
  44. void UiLayoutColumnComponent::ApplyLayoutHeight()
  45. {
  46. // Get the layout rect inside the padding
  47. AZ::Vector2 layoutRectSize(0.0f, 0.0f);
  48. UiLayoutHelpers::GetSizeInsidePadding(GetEntityId(), m_padding, layoutRectSize);
  49. // Calculate and set the child elements' heights
  50. ApplyLayoutHeight(layoutRectSize.GetY());
  51. }
  52. ////////////////////////////////////////////////////////////////////////////////////////////////////
  53. bool UiLayoutColumnComponent::IsUsingLayoutCellsToCalculateLayout()
  54. {
  55. return true;
  56. }
  57. ////////////////////////////////////////////////////////////////////////////////////////////////////
  58. bool UiLayoutColumnComponent::GetIgnoreDefaultLayoutCells()
  59. {
  60. return m_ignoreDefaultLayoutCells;
  61. }
  62. ////////////////////////////////////////////////////////////////////////////////////////////////////
  63. void UiLayoutColumnComponent::SetIgnoreDefaultLayoutCells(bool ignoreDefaultLayoutCells)
  64. {
  65. m_ignoreDefaultLayoutCells = ignoreDefaultLayoutCells;
  66. InvalidateLayout();
  67. InvalidateParentLayout();
  68. }
  69. ////////////////////////////////////////////////////////////////////////////////////////////////////
  70. IDraw2d::HAlign UiLayoutColumnComponent::GetHorizontalChildAlignment()
  71. {
  72. return m_childHAlignment;
  73. }
  74. ////////////////////////////////////////////////////////////////////////////////////////////////////
  75. void UiLayoutColumnComponent::SetHorizontalChildAlignment(IDraw2d::HAlign alignment)
  76. {
  77. m_childHAlignment = alignment;
  78. InvalidateLayout();
  79. }
  80. ////////////////////////////////////////////////////////////////////////////////////////////////////
  81. IDraw2d::VAlign UiLayoutColumnComponent::GetVerticalChildAlignment()
  82. {
  83. return m_childVAlignment;
  84. }
  85. ////////////////////////////////////////////////////////////////////////////////////////////////////
  86. void UiLayoutColumnComponent::SetVerticalChildAlignment(IDraw2d::VAlign alignment)
  87. {
  88. m_childVAlignment = alignment;
  89. InvalidateLayout();
  90. }
  91. ////////////////////////////////////////////////////////////////////////////////////////////////////
  92. bool UiLayoutColumnComponent::IsControllingChild(AZ::EntityId childId)
  93. {
  94. return UiLayoutHelpers::IsControllingChild(GetEntityId(), childId);
  95. }
  96. ////////////////////////////////////////////////////////////////////////////////////////////////////
  97. AZ::Vector2 UiLayoutColumnComponent::GetSizeToFitChildElements(const AZ::Vector2& childElementSize, int numChildElements)
  98. {
  99. AZ::Vector2 size(0.0f, 0.0f);
  100. if (numChildElements > 0)
  101. {
  102. size.SetY((childElementSize.GetY() * numChildElements) + (m_spacing * (numChildElements - 1)) + m_padding.m_top + m_padding.m_bottom);
  103. }
  104. else
  105. {
  106. size.SetY(0.0f);
  107. }
  108. // Check if anchors are together
  109. UiTransform2dInterface::Anchors anchors;
  110. UiTransform2dBus::EventResult(anchors, GetEntityId(), &UiTransform2dBus::Events::GetAnchors);
  111. if (anchors.m_left == anchors.m_right)
  112. {
  113. size.SetX(numChildElements > 0 ? childElementSize.GetX() : 0.0f);
  114. }
  115. else
  116. {
  117. // Anchors are apart, so width remains untouched
  118. AZ::Vector2 curSize(0.0f, 0.0f);
  119. UiTransformBus::EventResult(curSize, GetEntityId(), &UiTransformBus::Events::GetCanvasSpaceSizeNoScaleRotate);
  120. size.SetX(curSize.GetX());
  121. }
  122. return size;
  123. }
  124. ////////////////////////////////////////////////////////////////////////////////////////////////////
  125. UiLayoutInterface::Padding UiLayoutColumnComponent::GetPadding()
  126. {
  127. return m_padding;
  128. }
  129. ////////////////////////////////////////////////////////////////////////////////////////////////////
  130. void UiLayoutColumnComponent::SetPadding(UiLayoutInterface::Padding padding)
  131. {
  132. m_padding = padding;
  133. InvalidateLayout();
  134. InvalidateParentLayout();
  135. }
  136. ////////////////////////////////////////////////////////////////////////////////////////////////////
  137. float UiLayoutColumnComponent::GetSpacing()
  138. {
  139. return m_spacing;
  140. }
  141. ////////////////////////////////////////////////////////////////////////////////////////////////////
  142. void UiLayoutColumnComponent::SetSpacing(float spacing)
  143. {
  144. m_spacing = spacing;
  145. InvalidateLayout();
  146. InvalidateParentLayout();
  147. }
  148. ////////////////////////////////////////////////////////////////////////////////////////////////////
  149. UiLayoutInterface::VerticalOrder UiLayoutColumnComponent::GetOrder()
  150. {
  151. return m_order;
  152. }
  153. ////////////////////////////////////////////////////////////////////////////////////////////////////
  154. void UiLayoutColumnComponent::SetOrder(UiLayoutInterface::VerticalOrder order)
  155. {
  156. m_order = order;
  157. InvalidateLayout();
  158. }
  159. ////////////////////////////////////////////////////////////////////////////////////////////////////
  160. float UiLayoutColumnComponent::GetMinWidth()
  161. {
  162. float width = 0.0f;
  163. // Minimum layout width is padding + maximum child element min width
  164. AZStd::vector<float> minWidths = UiLayoutHelpers::GetLayoutCellMinWidths(GetEntityId(), m_ignoreDefaultLayoutCells);
  165. if (minWidths.size() > 0)
  166. {
  167. width += m_padding.m_left + m_padding.m_right;
  168. float maxChildWidth = 0.0f;
  169. for (auto minWidth : minWidths)
  170. {
  171. if (maxChildWidth < minWidth)
  172. {
  173. maxChildWidth = minWidth;
  174. }
  175. }
  176. width += maxChildWidth;
  177. }
  178. return width;
  179. }
  180. ////////////////////////////////////////////////////////////////////////////////////////////////////
  181. float UiLayoutColumnComponent::GetMinHeight()
  182. {
  183. float height = 0.0f;
  184. // Minimum layout height is padding + spacing + sum of all child element min heights
  185. AZStd::vector<float> minHeights = UiLayoutHelpers::GetLayoutCellMinHeights(GetEntityId(), m_ignoreDefaultLayoutCells);
  186. if (minHeights.size() > 0)
  187. {
  188. height += m_padding.m_top + m_padding.m_bottom + (m_spacing * (minHeights.size() - 1));
  189. for (auto minHeight : minHeights)
  190. {
  191. height += minHeight;
  192. }
  193. }
  194. return height;
  195. }
  196. ////////////////////////////////////////////////////////////////////////////////////////////////////
  197. float UiLayoutColumnComponent::GetTargetWidth(float /*maxWidth*/)
  198. {
  199. float width = 0.0f;
  200. // Target layout width is padding + maximum child element target width
  201. AZStd::vector<float> targetWidths = UiLayoutHelpers::GetLayoutCellTargetWidths(GetEntityId(), m_ignoreDefaultLayoutCells);
  202. if (targetWidths.size() > 0)
  203. {
  204. width += m_padding.m_left + m_padding.m_right;
  205. float maxChildWidth = 0.0f;
  206. for (auto targetWidth : targetWidths)
  207. {
  208. if (maxChildWidth < targetWidth)
  209. {
  210. maxChildWidth = targetWidth;
  211. }
  212. }
  213. width += maxChildWidth;
  214. }
  215. return width;
  216. }
  217. ////////////////////////////////////////////////////////////////////////////////////////////////////
  218. float UiLayoutColumnComponent::GetTargetHeight(float /*maxHeight*/)
  219. {
  220. float height = 0.0f;
  221. // Target layout height is padding + spacing + sum of all child element target heights
  222. AZStd::vector<float> targetHeights = UiLayoutHelpers::GetLayoutCellTargetHeights(GetEntityId(), m_ignoreDefaultLayoutCells);
  223. if (targetHeights.size() > 0)
  224. {
  225. height += m_padding.m_top + m_padding.m_bottom + (m_spacing * (targetHeights.size() - 1));
  226. for (auto targetHeight : targetHeights)
  227. {
  228. height += targetHeight;
  229. }
  230. }
  231. return height;
  232. }
  233. ////////////////////////////////////////////////////////////////////////////////////////////////////
  234. float UiLayoutColumnComponent::GetExtraWidthRatio()
  235. {
  236. return 1.0f;
  237. }
  238. ////////////////////////////////////////////////////////////////////////////////////////////////////
  239. float UiLayoutColumnComponent::GetExtraHeightRatio()
  240. {
  241. return 1.0f;
  242. }
  243. ////////////////////////////////////////////////////////////////////////////////////////////////////
  244. void UiLayoutColumnComponent::OnCanvasSpaceRectChanged([[maybe_unused]] AZ::EntityId entityId, const UiTransformInterface::Rect& oldRect, const UiTransformInterface::Rect& newRect)
  245. {
  246. // If old rect equals new rect, size changed due to initialization
  247. bool sizeChanged = (oldRect == newRect) || (!oldRect.GetSize().IsClose(newRect.GetSize(), 0.05f));
  248. if (sizeChanged)
  249. {
  250. InvalidateLayout();
  251. }
  252. }
  253. ////////////////////////////////////////////////////////////////////////////////////////////////////
  254. // PUBLIC STATIC MEMBER FUNCTIONS
  255. ////////////////////////////////////////////////////////////////////////////////////////////////////
  256. void UiLayoutColumnComponent::Reflect(AZ::ReflectContext* context)
  257. {
  258. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  259. if (serializeContext)
  260. {
  261. serializeContext->Class<UiLayoutColumnComponent, AZ::Component>()
  262. ->Version(2, &VersionConverter)
  263. ->Field("Padding", &UiLayoutColumnComponent::m_padding)
  264. ->Field("Spacing", &UiLayoutColumnComponent::m_spacing)
  265. ->Field("Order", &UiLayoutColumnComponent::m_order)
  266. ->Field("ChildHAlignment", &UiLayoutColumnComponent::m_childHAlignment)
  267. ->Field("ChildVAlignment", &UiLayoutColumnComponent::m_childVAlignment)
  268. ->Field("IgnoreDefaultLayoutCells", &UiLayoutColumnComponent::m_ignoreDefaultLayoutCells);
  269. AZ::EditContext* ec = serializeContext->GetEditContext();
  270. if (ec)
  271. {
  272. auto editInfo = ec->Class<UiLayoutColumnComponent>("LayoutColumn", "A layout component that arranges its children in a column");
  273. editInfo->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  274. ->Attribute(AZ::Edit::Attributes::Category, "UI")
  275. ->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/UiLayoutColumn.png")
  276. ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/UiLayoutColumn.png")
  277. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("UI", 0x27ff46b0))
  278. ->Attribute(AZ::Edit::Attributes::AutoExpand, true);
  279. editInfo->DataElement(AZ::Edit::UIHandlers::LayoutPadding, &UiLayoutColumnComponent::m_padding, "Padding", "The layout padding")
  280. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Show) // needed because sub-elements are hidden
  281. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiLayoutColumnComponent::InvalidateLayout)
  282. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiLayoutColumnComponent::InvalidateParentLayout)
  283. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiLayoutColumnComponent::CheckLayoutFitterAndRefreshEditorTransformProperties);
  284. editInfo->DataElement(AZ::Edit::UIHandlers::SpinBox, &UiLayoutColumnComponent::m_spacing, "Spacing", "The spacing between children")
  285. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  286. ->Attribute(AZ::Edit::Attributes::Step, 1.0f)
  287. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiLayoutColumnComponent::InvalidateLayout)
  288. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiLayoutColumnComponent::InvalidateParentLayout)
  289. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiLayoutColumnComponent::CheckLayoutFitterAndRefreshEditorTransformProperties);
  290. editInfo->DataElement(AZ::Edit::UIHandlers::ComboBox, &UiLayoutColumnComponent::m_order, "Order", "Which direction the column fills")
  291. ->EnumAttribute(UiLayoutInterface::VerticalOrder::TopToBottom, "Top to bottom")
  292. ->EnumAttribute(UiLayoutInterface::VerticalOrder::BottomToTop, "Bottom to top")
  293. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiLayoutColumnComponent::InvalidateLayout);
  294. editInfo->DataElement(AZ::Edit::UIHandlers::CheckBox, &UiLayoutColumnComponent::m_ignoreDefaultLayoutCells, "Ignore Default Cells",
  295. "When checked, fixed default layout cell values are used for child elements with no LayoutCell\n"
  296. "component rather than using defaults calculated by other components on the child.")
  297. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiLayoutColumnComponent::InvalidateLayout)
  298. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiLayoutColumnComponent::InvalidateParentLayout)
  299. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiLayoutColumnComponent::CheckLayoutFitterAndRefreshEditorTransformProperties);
  300. // Alignment
  301. {
  302. editInfo->ClassElement(AZ::Edit::ClassElements::Group, "Child Alignment")
  303. ->Attribute(AZ::Edit::Attributes::AutoExpand, true);
  304. editInfo->DataElement(AZ::Edit::UIHandlers::ComboBox, &UiLayoutColumnComponent::m_childHAlignment, "Horizontal",
  305. "How to align the children if they don't take up all the available width")
  306. ->EnumAttribute(IDraw2d::HAlign::Left, "Left")
  307. ->EnumAttribute(IDraw2d::HAlign::Center, "Center")
  308. ->EnumAttribute(IDraw2d::HAlign::Right, "Right")
  309. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiLayoutColumnComponent::InvalidateLayout);
  310. editInfo->DataElement(AZ::Edit::UIHandlers::ComboBox, &UiLayoutColumnComponent::m_childVAlignment, "Vertical",
  311. "How to align the children if they don't take up all the available height")
  312. ->EnumAttribute(IDraw2d::VAlign::Top, "Top")
  313. ->EnumAttribute(IDraw2d::VAlign::Center, "Center")
  314. ->EnumAttribute(IDraw2d::VAlign::Bottom, "Bottom")
  315. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiLayoutColumnComponent::InvalidateLayout);
  316. }
  317. }
  318. }
  319. AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
  320. if (behaviorContext)
  321. {
  322. behaviorContext->EBus<UiLayoutColumnBus>("UiLayoutColumnBus")
  323. ->Event("GetPadding", &UiLayoutColumnBus::Events::GetPadding)
  324. ->Event("SetPadding", &UiLayoutColumnBus::Events::SetPadding)
  325. ->Event("GetSpacing", &UiLayoutColumnBus::Events::GetSpacing)
  326. ->Event("SetSpacing", &UiLayoutColumnBus::Events::SetSpacing)
  327. ->Event("GetOrder", &UiLayoutColumnBus::Events::GetOrder)
  328. ->Event("SetOrder", &UiLayoutColumnBus::Events::SetOrder)
  329. ->VirtualProperty("Padding", "GetPadding", "SetPadding")
  330. ->VirtualProperty("Spacing", "GetSpacing", "SetSpacing");
  331. behaviorContext->Class<UiLayoutColumnComponent>()->RequestBus("UiLayoutColumnBus");
  332. }
  333. }
  334. ////////////////////////////////////////////////////////////////////////////////////////////////////
  335. // PROTECTED MEMBER FUNCTIONS
  336. ////////////////////////////////////////////////////////////////////////////////////////////////////
  337. ////////////////////////////////////////////////////////////////////////////////////////////////////
  338. void UiLayoutColumnComponent::Activate()
  339. {
  340. UiLayoutBus::Handler::BusConnect(m_entity->GetId());
  341. UiLayoutControllerBus::Handler::BusConnect(m_entity->GetId());
  342. UiLayoutColumnBus::Handler::BusConnect(m_entity->GetId());
  343. UiLayoutCellDefaultBus::Handler::BusConnect(m_entity->GetId());
  344. UiTransformChangeNotificationBus::Handler::BusConnect(m_entity->GetId());
  345. // If this is the first time the entity has been activated this has no effect since the canvas
  346. // is not known. But if a LayoutColumn component has just been pasted onto an existing entity
  347. // we need to invalidate the layout in case that affects things.
  348. InvalidateLayout();
  349. InvalidateParentLayout();
  350. }
  351. ////////////////////////////////////////////////////////////////////////////////////////////////////
  352. void UiLayoutColumnComponent::Deactivate()
  353. {
  354. UiLayoutBus::Handler::BusDisconnect();
  355. UiLayoutControllerBus::Handler::BusDisconnect();
  356. UiLayoutColumnBus::Handler::BusDisconnect();
  357. UiLayoutCellDefaultBus::Handler::BusDisconnect();
  358. UiTransformChangeNotificationBus::Handler::BusDisconnect();
  359. // We could be about to remove this component and then reactivate the entity
  360. // which could affect the layout if there is a parent layout component
  361. InvalidateLayout();
  362. InvalidateParentLayout();
  363. }
  364. ////////////////////////////////////////////////////////////////////////////////////////////////////
  365. void UiLayoutColumnComponent::InvalidateLayout()
  366. {
  367. UiLayoutHelpers::InvalidateLayout(GetEntityId());
  368. }
  369. ////////////////////////////////////////////////////////////////////////////////////////////////////
  370. void UiLayoutColumnComponent::InvalidateParentLayout()
  371. {
  372. UiLayoutHelpers::InvalidateParentLayout(GetEntityId());
  373. }
  374. ////////////////////////////////////////////////////////////////////////////////////////////////////
  375. void UiLayoutColumnComponent::CheckLayoutFitterAndRefreshEditorTransformProperties() const
  376. {
  377. UiLayoutHelpers::CheckFitterAndRefreshEditorTransformProperties(GetEntityId());
  378. }
  379. ////////////////////////////////////////////////////////////////////////////////////////////////////
  380. void UiLayoutColumnComponent::ApplyLayoutWidth(float availableWidth)
  381. {
  382. // Get the child element cell widths
  383. UiLayoutHelpers::LayoutCellSizes layoutCells;
  384. UiLayoutHelpers::GetLayoutCellWidths(GetEntityId(), m_ignoreDefaultLayoutCells, layoutCells);
  385. int numChildren = static_cast<int>(layoutCells.size());
  386. if (numChildren > 0)
  387. {
  388. // Set the child elements' transform properties based on the calculated child widths
  389. UiTransform2dInterface::Anchors anchors(0.0f, 0.0f, 0.0f, 0.0f);
  390. AZStd::vector<AZ::EntityId> childEntityIds;
  391. UiElementBus::EventResult(childEntityIds, GetEntityId(), &UiElementBus::Events::GetChildEntityIds);
  392. int childIndex = 0;
  393. for (auto child : childEntityIds)
  394. {
  395. // Set the anchors
  396. UiTransform2dBus::Event(child, &UiTransform2dBus::Events::SetAnchors, anchors, false, false);
  397. // Calculate occupied width
  398. float width = UiLayoutHelpers::CalculateSingleElementSize(layoutCells[childIndex], availableWidth);
  399. // Calculate alignment
  400. float alignmentOffset = UiLayoutHelpers::GetHorizontalAlignmentOffset(m_childHAlignment, availableWidth, width);
  401. // Set the offsets
  402. UiTransform2dInterface::Offsets offsets;
  403. UiTransform2dBus::EventResult(offsets, child, &UiTransform2dBus::Events::GetOffsets);
  404. offsets.m_left = m_padding.m_left + alignmentOffset;
  405. offsets.m_right = offsets.m_left + width;
  406. UiTransform2dBus::Event(child, &UiTransform2dBus::Events::SetOffsets, offsets);
  407. childIndex++;
  408. }
  409. }
  410. }
  411. ////////////////////////////////////////////////////////////////////////////////////////////////////
  412. void UiLayoutColumnComponent::ApplyLayoutHeight(float availableHeight)
  413. {
  414. // Get the child element cell heights
  415. UiLayoutHelpers::LayoutCellSizes layoutCells;
  416. UiLayoutHelpers::GetLayoutCellHeights(GetEntityId(), m_ignoreDefaultLayoutCells, layoutCells);
  417. int numChildren = static_cast<int>(layoutCells.size());
  418. if (numChildren > 0)
  419. {
  420. // Calculate child heights
  421. AZStd::vector<float> finalHeights(numChildren, 0.0f);
  422. UiLayoutHelpers::CalculateElementSizes(layoutCells, availableHeight, m_spacing, finalHeights);
  423. // Calculate occupied height
  424. float childrenRectHeight = (numChildren - 1) * m_spacing;
  425. for (auto height : finalHeights)
  426. {
  427. childrenRectHeight += height;
  428. }
  429. // Calculate alignment
  430. float alignmentOffset = UiLayoutHelpers::GetVerticalAlignmentOffset(m_childVAlignment, availableHeight, childrenRectHeight);
  431. // Set the child elements' transform properties based on the calculated child heights
  432. AZStd::vector<AZ::EntityId> childEntityIds;
  433. UiElementBus::EventResult(childEntityIds, GetEntityId(), &UiElementBus::Events::GetChildEntityIds);
  434. float curY = alignmentOffset;
  435. switch (m_order)
  436. {
  437. case UiLayoutInterface::VerticalOrder::TopToBottom:
  438. curY += m_padding.m_top;
  439. break;
  440. case UiLayoutInterface::VerticalOrder::BottomToTop:
  441. curY += m_padding.m_top + childrenRectHeight;
  442. break;
  443. default:
  444. AZ_Assert(0, "Unrecognized VerticalOrder type in UiLayoutColumnComponent");
  445. break;
  446. }
  447. int childIndex = 0;
  448. for (auto child : childEntityIds)
  449. {
  450. // Set the offsets
  451. UiTransform2dInterface::Offsets offsets;
  452. UiTransform2dBus::EventResult(offsets, child, &UiTransform2dBus::Events::GetOffsets);
  453. switch (m_order)
  454. {
  455. case UiLayoutInterface::VerticalOrder::TopToBottom:
  456. offsets.m_top = curY;
  457. curY += finalHeights[childIndex];
  458. offsets.m_bottom = curY;
  459. curY += m_spacing;
  460. break;
  461. case UiLayoutInterface::VerticalOrder::BottomToTop:
  462. offsets.m_bottom = curY;
  463. curY -= finalHeights[childIndex];
  464. offsets.m_top = curY;
  465. curY -= m_spacing;
  466. break;
  467. default:
  468. AZ_Assert(0, "Unrecognized VerticalOrder type in UiLayoutColumnComponent");
  469. break;
  470. }
  471. UiTransform2dBus::Event(child, &UiTransform2dBus::Events::SetOffsets, offsets);
  472. childIndex++;
  473. }
  474. }
  475. }
  476. ////////////////////////////////////////////////////////////////////////////////////////////////////
  477. // PRIVATE STATIC MEMBER FUNCTIONS
  478. ////////////////////////////////////////////////////////////////////////////////////////////////////
  479. ////////////////////////////////////////////////////////////////////////////////////////////////////
  480. bool UiLayoutColumnComponent::VersionConverter(AZ::SerializeContext& context,
  481. AZ::SerializeContext::DataElementNode& classElement)
  482. {
  483. // conversion from version 1 to 2:
  484. // - Need to convert default m_ignoreDefaultLayoutCells to true
  485. if (classElement.GetVersion() < 2)
  486. {
  487. // Add a flag and set it to a value that's different from the default value for new components
  488. const char* subElementName = "IgnoreDefaultLayoutCells";
  489. int newElementIndex = classElement.AddElement<bool>(context, subElementName);
  490. if (newElementIndex == -1)
  491. {
  492. // Error adding the new sub element
  493. AZ_Error("Serialization", false, "AddElement failed for element %s", subElementName);
  494. return false;
  495. }
  496. classElement.GetSubElement(newElementIndex).SetData(context, true);
  497. }
  498. return true;
  499. }