ReflectedPropertyEditorPage.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project
  3. *
  4. * SPDX-License-Identifier: Apache-2.0 OR MIT
  5. *
  6. */
  7. #include "ReflectedPropertyEditorPage.h"
  8. #include <AzQtComponents/Gallery/ui_ReflectedPropertyEditorPage.h>
  9. #include <AzCore/Component/ComponentApplicationBus.h>
  10. #include <AzCore/Serialization/SerializeContext.h>
  11. #include <AzCore/Serialization/EditContext.h>
  12. #include <AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx>
  13. #include <AzQtComponents/Components/Widgets/Card.h>
  14. #include <AzQtComponents/Components/Widgets/CardHeader.h>
  15. #include <QDebug>
  16. #include <QtMath>
  17. #include <QVBoxLayout>
  18. namespace
  19. {
  20. static constexpr int g_propertyLabelWidth = 160;
  21. }
  22. void LevelThree::Reflect(AZ::ReflectContext* context)
  23. {
  24. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  25. if (serialize)
  26. {
  27. serialize->Class<LevelThree, AZ::Component>()
  28. ->Version(1)
  29. ->Field("Bool", &LevelThree::m_bool)
  30. ;
  31. AZ::EditContext* edit = serialize->GetEditContext();
  32. if (edit)
  33. {
  34. edit->Class<LevelThree>("Level 3", "A deeply nested component")
  35. ->DataElement(AZ::Edit::UIHandlers::CheckBox, &LevelThree::m_bool, "Horizontal limit", "A deeply nested CheckBox")
  36. ;
  37. }
  38. }
  39. }
  40. void LevelTwo::Reflect(AZ::ReflectContext* context)
  41. {
  42. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  43. if (serialize)
  44. {
  45. serialize->Class<LevelTwo, AZ::Component>()
  46. ->Version(1)
  47. ->Field("Quaternion", &LevelTwo::m_quaternion)
  48. ->Field("LevelThree", &LevelTwo::m_levelThree)
  49. ;
  50. AZ::EditContext* edit = serialize->GetEditContext();
  51. if (edit)
  52. {
  53. edit->Class<LevelTwo>("Level 2", "A deeply nested component")
  54. ->DataElement(AZ::Edit::UIHandlers::Default, &LevelTwo::m_quaternion, "Quaternion", "An AZ::Edit::UIHandlers::Default example with suffix")
  55. ->Attribute(AZ::Edit::Attributes::Suffix, " Deg")
  56. ->DataElement(AZ::Edit::UIHandlers::Default, &LevelTwo::m_levelThree, "Level 3 - Too cool for school", "A LevelThree component nested in LevelTwo")
  57. ;
  58. }
  59. }
  60. }
  61. void LevelOne::Reflect(AZ::ReflectContext* context)
  62. {
  63. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  64. if (serialize)
  65. {
  66. serialize->Class<LevelOne, AZ::Component>()
  67. ->Version(1)
  68. ->Field("Float", &LevelOne::m_float)
  69. ->Field("LevelTwo", &LevelOne::m_levelTwo)
  70. ;
  71. AZ::EditContext* edit = serialize->GetEditContext();
  72. if (edit)
  73. {
  74. edit->Class<LevelOne>("Level 1", "A deeply nested component")
  75. ->DataElement(AZ::Edit::UIHandlers::SpinBox, &LevelOne::m_float, "Friction", "A deeply nested SpinBox")
  76. ->DataElement(AZ::Edit::UIHandlers::Default, &LevelOne::m_levelTwo, "Level 2 - Great", "A LevelTwo component nested in LevelOne")
  77. ;
  78. }
  79. }
  80. }
  81. void GalleryComponent::onIntMultiplierForSliderChanged() const
  82. {
  83. qDebug() << m_intMultiplierForSlider;
  84. }
  85. void GalleryComponent::onIntMultiplierForSpinBoxChanged() const
  86. {
  87. qDebug() << m_intMultiplierForSpinBox;
  88. }
  89. void GalleryComponent::onFloatMultiplierForSliderChanged() const
  90. {
  91. qDebug() << m_floatMultiplierForSlider;
  92. }
  93. void GalleryComponent::onFloatMultiplierForSpinBoxChanged() const
  94. {
  95. qDebug() << m_floatMultiplierForSpinBox;
  96. }
  97. void GalleryComponent::Reflect(AZ::ReflectContext* context)
  98. {
  99. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  100. if (serialize)
  101. {
  102. serialize->Class<GalleryComponent, AZ::Component>()
  103. ->Version(1)
  104. ->Field("BoolForButton", &GalleryComponent::m_boolForButton)
  105. ->Field("BoolForCheckBox", &GalleryComponent::m_boolForCheckBox)
  106. ->Field("Color", &GalleryComponent::m_color)
  107. ->Field("Mode", &GalleryComponent::m_mode)
  108. ->Field("BoolForRadioButton", &GalleryComponent::m_boolForRadioButton)
  109. ->Field("EntityId", &GalleryComponent::m_entityId)
  110. ->Field("AssetData", &GalleryComponent::m_assetData)
  111. ->Field("AssetDataWithEditButton", &GalleryComponent::m_assetDataWithEditButton)
  112. ->Field("FileTagAsset", &GalleryComponent::m_fileTagAsset)
  113. ->Field("FileTagAssetWithEditButton", &GalleryComponent::m_fileTagAssetWithEditButton)
  114. ->Field("CustomBrowseIconAsset", &GalleryComponent::m_customBrowseIconAsset)
  115. ->Field("StringForLineEdit", &GalleryComponent::m_stringForLineEdit)
  116. ->Field("StringForMultiLineEdit", &GalleryComponent::m_stringForMultiLineEdit)
  117. ->Field("Quaternion", &GalleryComponent::m_quaternion)
  118. ->Field("IntForSlider", &GalleryComponent::m_intForSlider)
  119. ->Field("IntMultiplierForSlider", &GalleryComponent::m_intMultiplierForSlider)
  120. ->Field("IntMultiplierForSpinBox", &GalleryComponent::m_intMultiplierForSpinBox)
  121. ->Field("FloatForSlider", &GalleryComponent::m_floatForSlider)
  122. ->Field("FloatForSliderCurve", &GalleryComponent::m_floatForSliderCurve)
  123. ->Field("FloatMultiplierForSlider", &GalleryComponent::m_floatMultiplierForSlider)
  124. ->Field("FloatForSpinBox", &GalleryComponent::m_floatForSpinBox)
  125. ->Field("FloatMultiplierForSpinBox", &GalleryComponent::m_floatMultiplierForSpinBox)
  126. ->Field("Crc", &GalleryComponent::m_crc)
  127. ->Field("Vector2", &GalleryComponent::m_vector2)
  128. ->Field("Vector3", &GalleryComponent::m_vector3)
  129. ->Field("Vector4", &GalleryComponent::m_vector4)
  130. ->Field("Vector4Suffix", &GalleryComponent::m_vector4Suffix)
  131. ->Field("LevelOne", &GalleryComponent::m_levelOne)
  132. ->Field("BoolForLongLabel", &GalleryComponent::m_boolForLongLabel)
  133. ->Field("Strings", &GalleryComponent::m_strings)
  134. ;
  135. AZ::EditContext* edit = serialize->GetEditContext();
  136. if (edit)
  137. {
  138. edit->Class<GalleryComponent>("Gallery Component", "A component used to demo the ReflectedPropertyEditor.")
  139. ->DataElement(AZ::Edit::UIHandlers::Button, &GalleryComponent::m_boolForButton, "Button", "An AZ::Edit::UIHandlers::Button example")
  140. ->Attribute(AZ::Edit::Attributes::ButtonText, "Button")
  141. ->DataElement(AZ::Edit::UIHandlers::CheckBox, &GalleryComponent::m_boolForCheckBox, "CheckBox", "An AZ::Edit::UIHandlers::CheckBox example")
  142. ->DataElement(AZ::Edit::UIHandlers::Color, &GalleryComponent::m_color, "Color", "An AZ::Edit::UIHandlers::Color example")
  143. ->DataElement(AZ::Edit::UIHandlers::ComboBox, &GalleryComponent::m_mode, "ComboBox", "An AZ::Edit::UIHandlers::ComboBox example")
  144. ->EnumAttribute(GalleryComponent::Mode::Average, "Average")
  145. ->EnumAttribute(GalleryComponent::Mode::Minimum, "Minimum")
  146. ->EnumAttribute(GalleryComponent::Mode::Maximum, "Maximum")
  147. ->EnumAttribute(GalleryComponent::Mode::Multiply, "Multiply")
  148. ->DataElement(AZ::Edit::UIHandlers::RadioButton, &GalleryComponent::m_boolForRadioButton, "RadioButton", "An AZ::Edit::UIHandlers::RadioButton example")
  149. ->DataElement(AZ::Edit::UIHandlers::EntityId, &GalleryComponent::m_entityId, "EntityId", "An AZ::Edit::UIHandlers::EntityId example")
  150. ->DataElement(AZ::Edit::UIHandlers::Default, &GalleryComponent::m_assetData, "AssetData", "An AZ::Edit::UIHandlers::Default example for AZ::Data::Asset<AZ::Data::AssetData>")
  151. ->DataElement(AZ::Edit::UIHandlers::Default, &GalleryComponent::m_assetDataWithEditButton, "AssetData (edit button)", "An AZ::Edit::UIHandlers::Default example for AZ::Data::Asset<AZ::Data::AssetData> with edit default button attributes")
  152. ->Attribute("EditButton", "")
  153. ->Attribute("EditDescription", "Edit button description")
  154. ->DataElement(AZ::Edit::UIHandlers::Default, &GalleryComponent::m_fileTagAsset, "AssetData (registered type)", "An AZ::Edit::UIHandlers::Default example for a registered AZ::Data::Asset<AZ::Data::AssetData> type")
  155. ->DataElement(AZ::Edit::UIHandlers::Default, &GalleryComponent::m_fileTagAssetWithEditButton, "AssetData (edit button)(registered type)", "An AZ::Edit::UIHandlers::Default example for a registered AZ::Data::Asset<AZ::Data::AssetData> type with custom edit button attributes")
  156. ->Attribute("EditButton", ":/Gallery/Rotate.svg")
  157. ->Attribute("EditDescription", "Edit button description")
  158. ->DataElement(AZ::Edit::UIHandlers::Default, &GalleryComponent::m_customBrowseIconAsset, "AssetData (browse icon)(registered type)", "An AZ::Edit::UIHandlers::Default example for a registered AZ::Data::Asset<AZ::Data::AssetData> type with custom browse icon")
  159. ->Attribute("BrowseIcon", ":/Gallery/Settings.svg")
  160. // No AZ::Edit::UIHandlers::LayoutPadding example
  161. ->DataElement(AZ::Edit::UIHandlers::LineEdit, &GalleryComponent::m_stringForLineEdit, "LineEdit", "An AZ::Edit::UIHandlers::LineEdit example")
  162. ->DataElement(AZ::Edit::UIHandlers::MultiLineEdit, &GalleryComponent::m_stringForMultiLineEdit, "MultiLineEdit", "An AZ::Edit::UIHandlers::MultiLineEdit example")
  163. ->DataElement(AZ::Edit::UIHandlers::Quaternion, &GalleryComponent::m_quaternion, "Quaternion", "An AZ::Edit::UIHandlers::Quaternion example")
  164. ->DataElement(AZ::Edit::UIHandlers::Slider, &GalleryComponent::m_intForSlider, "Slider (int)", "An AZ::Edit::UIHandlers::Slider int example")
  165. ->Attribute(AZ::Edit::Attributes::Min, 0)
  166. ->Attribute(AZ::Edit::Attributes::Max, 100)
  167. ->Attribute(AZ::Edit::Attributes::SoftMin, 0)
  168. ->Attribute(AZ::Edit::Attributes::SoftMax, 10)
  169. ->DataElement(AZ::Edit::UIHandlers::Slider, &GalleryComponent::m_intMultiplierForSlider, "Slider with Multiplier (int)", "An AZ::Edit::UIHandlers::Slider int with multiplier example")
  170. ->Attribute(AZ::Edit::Attributes::Min, 0)
  171. ->Attribute(AZ::Edit::Attributes::Max, 120)
  172. ->Attribute("Multiplier", 2)
  173. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GalleryComponent::onIntMultiplierForSliderChanged)
  174. ->DataElement(AZ::Edit::UIHandlers::SpinBox, &GalleryComponent::m_intMultiplierForSpinBox, "SpinBox with Multiplier (int)", "An AZ::Edit::UIHandlers::Slider int with multiplier example")
  175. ->Attribute(AZ::Edit::Attributes::Min, 0)
  176. ->Attribute(AZ::Edit::Attributes::Max, 120)
  177. ->Attribute("Multiplier", 2)
  178. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GalleryComponent::onIntMultiplierForSpinBoxChanged)
  179. ->DataElement(AZ::Edit::UIHandlers::Slider, &GalleryComponent::m_floatForSlider, "Slider (float)", "An AZ::Edit::UIHandlers::Slider float example")
  180. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  181. ->Attribute(AZ::Edit::Attributes::Max, 10.0f)
  182. ->Attribute(AZ::Edit::Attributes::SoftMin, 0.0f)
  183. ->Attribute(AZ::Edit::Attributes::SoftMax, 1.0f)
  184. ->DataElement(AZ::Edit::UIHandlers::Slider, &GalleryComponent::m_floatForSliderCurve, "Slider with curveMidpoint (0.25)", "An AZ::Edit::UIHandlers::Slider float with SliderCurveMidpoint example")
  185. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  186. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  187. ->Attribute(AZ::Edit::Attributes::SliderCurveMidpoint, 0.25)
  188. ->DataElement(AZ::Edit::UIHandlers::Slider, &GalleryComponent::m_floatMultiplierForSlider, "Slider with Multiplier (float)", "An AZ::Edit::UIHandlers::Slider flot with multiplier example")
  189. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  190. ->Attribute(AZ::Edit::Attributes::Max, 120.0f)
  191. ->Attribute("Multiplier", qRadiansToDegrees(1.0f))
  192. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GalleryComponent::onFloatMultiplierForSliderChanged)
  193. ->DataElement(AZ::Edit::UIHandlers::SpinBox, &GalleryComponent::m_floatForSpinBox, "SpinBox", "An AZ::Edit::UIHandlers::SpinBox example")
  194. ->DataElement(AZ::Edit::UIHandlers::SpinBox, &GalleryComponent::m_floatMultiplierForSpinBox, "SpinBox with Multiplier (float)", "An AZ::Edit::UIHandlers::SpinBox float with multiplier example")
  195. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  196. ->Attribute(AZ::Edit::Attributes::Max, 120.0f)
  197. ->Attribute("Multiplier", qRadiansToDegrees(1.0f))
  198. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GalleryComponent::onFloatMultiplierForSpinBoxChanged)
  199. ->DataElement(AZ::Edit::UIHandlers::Crc, &GalleryComponent::m_crc, "Crc", "An AZ::Edit::UIHandlers::Crc example")
  200. ->DataElement(AZ::Edit::UIHandlers::Vector2, &GalleryComponent::m_vector2, "Vector2", "An AZ::Edit::UIHandlers::Vector2 example")
  201. ->DataElement(AZ::Edit::UIHandlers::Vector3, &GalleryComponent::m_vector3, "Vector3", "An AZ::Edit::UIHandlers::Vector3 example")
  202. ->DataElement(AZ::Edit::UIHandlers::Vector4, &GalleryComponent::m_vector4, "Vector4", "An AZ::Edit::UIHandlers::Vector4 example")
  203. ->DataElement(AZ::Edit::UIHandlers::Vector4, &GalleryComponent::m_vector4Suffix, "Vector4 (suffix)", "An AZ::Edit::UIHandlers::Vector4 with suffix example")
  204. ->Attribute(AZ::Edit::Attributes::Suffix, " m")
  205. ->DataElement(AZ::Edit::UIHandlers::Default, &GalleryComponent::m_levelOne, "Level 1", "The first level in deeply nested tree")
  206. ->ClassElement(AZ::Edit::ClassElements::Group, "Collision")
  207. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  208. ->DataElement(AZ::Edit::UIHandlers::CheckBox, &GalleryComponent::m_boolForLongLabel, "Continuous Collision Detection", "An example of a control with a very long label")
  209. ->DataElement(AZ::Edit::UIHandlers::Default, &GalleryComponent::m_strings, "Container", "An AZ::Edit::UIHandlers::Default example for a vector of strings")
  210. ;
  211. }
  212. }
  213. }
  214. ReflectedPropertyEditorPage::ReflectedPropertyEditorPage(QWidget* parent)
  215. : QWidget(parent)
  216. , ui(new Ui::ReflectedPropertyEditorPage)
  217. , m_component(new GalleryComponent)
  218. , m_cardComponent(new GalleryComponent)
  219. , m_disabledCardComponent(new GalleryComponent)
  220. {
  221. ui->setupUi(this);
  222. QVBoxLayout* layout = new QVBoxLayout(ui->contentsContainer);
  223. AZ::SerializeContext* serializeContext = nullptr;
  224. AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
  225. if (!serializeContext)
  226. {
  227. AZ_Error("EMotionFX", false, "Can't get serialize context from component application.");
  228. }
  229. // Reflect our Component so that it can be used in the ReflectedPropertyEditor
  230. LevelThree::Reflect(serializeContext);
  231. LevelTwo::Reflect(serializeContext);
  232. LevelOne::Reflect(serializeContext);
  233. GalleryComponent::Reflect(serializeContext);
  234. // ReflectedPropertyEditor by itself
  235. auto propertyEditor = aznew AzToolsFramework::ReflectedPropertyEditor(this);
  236. propertyEditor->Setup(serializeContext, nullptr/*IPropertyEditorNotify*/, false/*enableScrollbars*/, g_propertyLabelWidth);
  237. layout->addWidget(propertyEditor);
  238. propertyEditor->AddInstance(m_component.get(), azrtti_typeid(m_component.get()));
  239. propertyEditor->InvalidateAll();
  240. propertyEditor->ExpandAll();
  241. // ReflectedPropertyEditor by in a Card
  242. AzQtComponents::Card* card = new AzQtComponents::Card(this);
  243. card->setTitle(QStringLiteral("Card"));
  244. card->header()->setIcon(QIcon(QStringLiteral(":/Gallery/Grid-small.svg")));
  245. auto cardPropertyEditor = aznew AzToolsFramework::ReflectedPropertyEditor(card);
  246. cardPropertyEditor->Setup(serializeContext, nullptr/*IPropertyEditorNotify*/, false/*enableScrollbars*/, g_propertyLabelWidth);
  247. cardPropertyEditor->SetHideRootProperties(true);
  248. cardPropertyEditor->AddInstance(m_cardComponent.get(), azrtti_typeid(m_component.get()));
  249. cardPropertyEditor->InvalidateAll();
  250. cardPropertyEditor->ExpandAll();
  251. card->setContentWidget(cardPropertyEditor);
  252. layout->addWidget(card);
  253. // ReflectedPropertyEditor by in a disabled Card
  254. AzQtComponents::Card* disabledCard = new AzQtComponents::Card(this);
  255. disabledCard->setTitle(QStringLiteral("Disabled card"));
  256. disabledCard->setEnabled(false);
  257. auto disabledCardPropertyEditor = aznew AzToolsFramework::ReflectedPropertyEditor(disabledCard);
  258. disabledCardPropertyEditor->Setup(serializeContext, nullptr/*IPropertyEditorNotify*/, false/*enableScrollbars*/, g_propertyLabelWidth);
  259. disabledCardPropertyEditor->SetHideRootProperties(true);
  260. disabledCardPropertyEditor->AddInstance(m_disabledCardComponent.get(), azrtti_typeid(m_component.get()));
  261. disabledCardPropertyEditor->InvalidateAll();
  262. disabledCardPropertyEditor->ExpandAll();
  263. disabledCard->setContentWidget(disabledCardPropertyEditor);
  264. layout->addWidget(disabledCard);
  265. layout->addStretch();
  266. QString exampleText = R"(
  267. The Reflected Property Editor automatically lays out editable controls for properties reflected to the edit context.
  268. See the documentation linked above for more details.
  269. <pre>
  270. // Create a new Reflected Property Editor
  271. auto propertyEditor = aznew AzToolsFramework::ReflectedPropertyEditor(this);
  272. // RPEs are most commonly used as content widgets for Cards
  273. AzQtComponents::Card* card = new AzQtComponents::Card(this);
  274. auto cardPropertyEditor = aznew AzToolsFramework::ReflectedPropertyEditor(card);
  275. card->setContentWidget(cardPropertyEditor);
  276. </pre>
  277. )";
  278. ui->exampleText->setHtml(exampleText);
  279. ui->hyperlinkLabel->setText(QStringLiteral(R"(<a href="https://docs.o3de.org/docs/user-guide/components/development/reflection/">Reflected Property Editor docs</a>)"));
  280. }
  281. ReflectedPropertyEditorPage::~ReflectedPropertyEditorPage()
  282. {
  283. }