PropertyHandlerOffset.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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 "EditorCommon.h"
  9. #include "PropertyHandlerOffset.h"
  10. #include <AzQtComponents/Components/Widgets/SpinBox.h>
  11. #include <LyShine/Bus/UiTransform2dBus.h>
  12. #include <LyShine/Bus/UiLayoutFitterBus.h>
  13. #include <QLabel>
  14. Q_DECLARE_METATYPE(UiTransform2dInterface::Anchors);
  15. void PropertyHandlerOffset::ConsumeAttribute(AzQtComponents::VectorInput* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
  16. {
  17. UIVectorPropertyHandlerBase::ConsumeAttribute(GUI, attrib, attrValue, debugName);
  18. if (attrib == AZ_CRC_CE("LayoutFitterType"))
  19. {
  20. UiLayoutFitterInterface::FitType fitType = UiLayoutFitterInterface::FitType::None;
  21. if (attrValue->Read<UiLayoutFitterInterface::FitType>(fitType))
  22. {
  23. bool horizFit = (fitType == UiLayoutFitterInterface::FitType::HorizontalAndVertical || fitType == UiLayoutFitterInterface::FitType::HorizontalOnly);
  24. bool vertFit = (fitType == UiLayoutFitterInterface::FitType::HorizontalAndVertical || fitType == UiLayoutFitterInterface::FitType::VerticalOnly);
  25. AzQtComponents::VectorElement** elements = GUI->getElements();
  26. elements[2]->getSpinBox()->setEnabled(!horizFit);
  27. elements[3]->getSpinBox()->setEnabled(!vertFit);
  28. }
  29. else
  30. {
  31. // emit a warning!
  32. AZ_WarningOnce("AzToolsFramework", false, "Failed to read 'LayoutFitterType' attribute from property '%s' into string box", debugName);
  33. }
  34. }
  35. }
  36. void PropertyHandlerOffset::WriteGUIValuesIntoProperty(size_t index, AzQtComponents::VectorInput* GUI, UiTransform2dInterface::Offsets& instance, AzToolsFramework::InstanceDataNode* node)
  37. {
  38. AZ::EntityId id = GetParentEntityId(node, index);
  39. UiTransform2dInterface::Anchors anchors;
  40. UiTransform2dBus::EventResult(anchors, id, &UiTransform2dBus::Events::GetAnchors);
  41. AZ::Vector2 pivot;
  42. UiTransformBus::EventResult(pivot, id, &UiTransformBus::Events::GetPivot);
  43. AZStd::string labels[4];
  44. GetLabels(anchors, labels);
  45. AzQtComponents::VectorElement** elements = GUI->getElements();
  46. UiTransform2dInterface::Offsets guiDisplayedOffset = ExtractValuesFromGUI(GUI);
  47. // Set the new display offsets for the element being edited
  48. UiTransform2dInterface::Offsets newDisplayedOffset = InternalOffsetToDisplayedOffset(instance, anchors, pivot);
  49. int idx = 0;
  50. if (elements[idx]->wasValueEditedByUser())
  51. {
  52. QLabel* label = elements[idx]->getLabelWidget();
  53. if (label && (label->text() == labels[idx].c_str()))
  54. {
  55. newDisplayedOffset.m_left = guiDisplayedOffset.m_left;
  56. }
  57. }
  58. idx++;
  59. if (elements[idx]->wasValueEditedByUser())
  60. {
  61. QLabel* label = elements[idx]->getLabelWidget();
  62. if (label && (label->text() == labels[idx].c_str()))
  63. {
  64. newDisplayedOffset.m_top = guiDisplayedOffset.m_top;
  65. }
  66. }
  67. idx++;
  68. if (elements[idx]->wasValueEditedByUser())
  69. {
  70. QLabel* label = elements[idx]->getLabelWidget();
  71. if (label && (label->text() == labels[idx].c_str()))
  72. {
  73. newDisplayedOffset.m_right = guiDisplayedOffset.m_right;
  74. }
  75. }
  76. idx++;
  77. if (elements[idx]->wasValueEditedByUser())
  78. {
  79. QLabel* label = elements[idx]->getLabelWidget();
  80. if (label && (label->text() == labels[idx].c_str()))
  81. {
  82. newDisplayedOffset.m_bottom = guiDisplayedOffset.m_bottom;
  83. }
  84. }
  85. UiTransform2dInterface::Offsets newInternalOffset;
  86. newInternalOffset = DisplayedOffsetToInternalOffset(newDisplayedOffset, anchors, pivot);
  87. // IMPORTANT: This will indirectly update "instance".
  88. UiTransform2dBus::Event(id, &UiTransform2dBus::Events::SetOffsets, newInternalOffset);
  89. }
  90. bool PropertyHandlerOffset::ReadValuesIntoGUI([[maybe_unused]] size_t index, AzQtComponents::VectorInput* GUI, const UiTransform2dInterface::Offsets& instance, AzToolsFramework::InstanceDataNode* node)
  91. {
  92. // IMPORTANT: We DON'T need to do validation of data here because that's
  93. // done for us BEFORE we get here. We DO need to set the labels here.
  94. AZ::EntityId id = GetParentEntityId(node, index);
  95. UiTransform2dInterface::Anchors anchors;
  96. UiTransform2dBus::EventResult(anchors, id, &UiTransform2dBus::Events::GetAnchors);
  97. // Set the labels.
  98. {
  99. SetLabels(GUI, anchors);
  100. }
  101. GUI->blockSignals(true);
  102. {
  103. AZ::Vector2 pivot;
  104. UiTransformBus::EventResult(pivot, id, &UiTransformBus::Events::GetPivot);
  105. UiTransform2dInterface::Offsets displayedOffset = InternalOffsetToDisplayedOffset(instance, anchors, pivot);
  106. InsertValuesIntoGUI(GUI, displayedOffset);
  107. }
  108. GUI->blockSignals(false);
  109. return false;
  110. }
  111. void PropertyHandlerOffset::GetLabels(UiTransform2dInterface::Anchors& anchors, AZStd::string* labelsOut)
  112. {
  113. labelsOut[0] = "Left";
  114. labelsOut[1] = "Top";
  115. labelsOut[2] = "Right";
  116. labelsOut[3] = "Bottom";
  117. // If the left and right anchors are the same, allow editing x position and width
  118. if (anchors.m_left == anchors.m_right)
  119. {
  120. labelsOut[0] = "X Pos";
  121. labelsOut[2] = "Width";
  122. }
  123. // If the top and bottom anchors are the same, allow editing y position and height
  124. if (anchors.m_top == anchors.m_bottom)
  125. {
  126. labelsOut[1] = "Y Pos";
  127. labelsOut[3] = "Height";
  128. }
  129. }
  130. void PropertyHandlerOffset::SetLabels(AzQtComponents::VectorInput* ctrl,
  131. UiTransform2dInterface::Anchors& anchors)
  132. {
  133. AZStd::string labels[4];
  134. GetLabels(anchors, labels);
  135. for (int i = 0; i < 4; i++)
  136. {
  137. ctrl->setLabel(i, labels[i].c_str());
  138. }
  139. }
  140. AZ::EntityId PropertyHandlerOffset::GetParentEntityId(AzToolsFramework::InstanceDataNode* node, size_t index)
  141. {
  142. while (node)
  143. {
  144. if ((node->GetClassMetadata()) && (node->GetClassMetadata()->m_azRtti))
  145. {
  146. if (node->GetClassMetadata()->m_azRtti->IsTypeOf(AZ::Component::RTTI_Type()))
  147. {
  148. return static_cast<AZ::Component*>(node->GetInstance(index))->GetEntityId();
  149. }
  150. }
  151. node = node->GetParent();
  152. }
  153. return AZ::EntityId();
  154. }
  155. UiTransform2dInterface::Offsets PropertyHandlerOffset::InternalOffsetToDisplayedOffset(UiTransform2dInterface::Offsets internalOffset,
  156. const UiTransform2dInterface::Anchors& anchors,
  157. const AZ::Vector2& pivot)
  158. {
  159. // This is complex because the X offsets can be displayed
  160. // as either left & right or as xpos & width and the Y offsets can be displayed
  161. // as either top & bottom or as ypos and height.
  162. UiTransform2dInterface::Offsets displayedOffset = internalOffset;
  163. // If the left and right anchors are the same, allow editing x position and width
  164. if (anchors.m_left == anchors.m_right)
  165. {
  166. float width = internalOffset.m_right - internalOffset.m_left;
  167. // width
  168. displayedOffset.m_right = width;
  169. // X Pos
  170. displayedOffset.m_left = internalOffset.m_left + pivot.GetX() * width;
  171. }
  172. // If the top and bottom anchors are the same, allow editing y position and height
  173. if (anchors.m_top == anchors.m_bottom)
  174. {
  175. float height = internalOffset.m_bottom - internalOffset.m_top;
  176. // height
  177. displayedOffset.m_bottom = height;
  178. // Y Pos
  179. displayedOffset.m_top = internalOffset.m_top + pivot.GetY() * height;
  180. }
  181. return displayedOffset;
  182. }
  183. UiTransform2dInterface::Offsets PropertyHandlerOffset::DisplayedOffsetToInternalOffset(UiTransform2dInterface::Offsets displayedOffset,
  184. const UiTransform2dInterface::Anchors& anchors,
  185. const AZ::Vector2& pivot)
  186. {
  187. UiTransform2dInterface::Offsets internalOffset = displayedOffset;
  188. if (anchors.m_left == anchors.m_right)
  189. {
  190. // flipping of offsets is not allowed, so if width is negative make it zero
  191. float xPos = displayedOffset.m_left;
  192. float width = AZ::GetMax(0.0f, displayedOffset.m_right);
  193. internalOffset.m_left = xPos - pivot.GetX() * width;
  194. internalOffset.m_right = internalOffset.m_left + width;
  195. }
  196. if (anchors.m_top == anchors.m_bottom)
  197. {
  198. // flipping of offsets is not allowed, so if height is negative make it zero
  199. float yPos = displayedOffset.m_top;
  200. float height = AZ::GetMax(0.0f, displayedOffset.m_bottom);
  201. internalOffset.m_top = yPos - pivot.GetY() * height;
  202. internalOffset.m_bottom = internalOffset.m_top + height;
  203. }
  204. return internalOffset;
  205. }
  206. void PropertyHandlerOffset::Register()
  207. {
  208. qRegisterMetaType<UiTransform2dInterface::Anchors>("UiTransform2dInterface::Anchors");
  209. AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(
  210. &AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Events::RegisterPropertyType, aznew PropertyHandlerOffset());
  211. }