PropertyLinked.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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 "PropertyLinked.h"
  9. #include "PlatformSettings_common.h"
  10. #include "ValidationHandler.h"
  11. #include <QLayout>
  12. #include <QPushButton>
  13. #include <QLineEdit>
  14. namespace ProjectSettingsTool
  15. {
  16. PropertyLinkedCtrl::PropertyLinkedCtrl(QWidget* pParent)
  17. : PropertyFuncValLineEditCtrl(pParent)
  18. , m_linkButton(nullptr)
  19. , m_linkedProperty(nullptr)
  20. , m_linkEnabled(false)
  21. {
  22. connect(this, &PropertyFuncValLineEditCtrl::ValueChangedByUser, this, &PropertyLinkedCtrl::MirrorToLinkedProperty);
  23. }
  24. void PropertyLinkedCtrl::SetLinkedProperty(PropertyLinkedCtrl* property)
  25. {
  26. m_linkedProperty = property;
  27. m_linkEnabled = true;
  28. }
  29. void PropertyLinkedCtrl::SetLinkTooltip(const QString& tip)
  30. {
  31. if (m_linkButton != nullptr)
  32. {
  33. m_linkButton->setToolTip("Linked to " + tip);
  34. }
  35. }
  36. void PropertyLinkedCtrl::MakeLinkButton()
  37. {
  38. QLayout* myLayout = layout();
  39. QIcon icon;
  40. icon.addFile("://link.svg", QSize(), QIcon::Normal, QIcon::On);
  41. icon.addFile("://broken_link.svg", QSize(), QIcon::Normal, QIcon::Off);
  42. m_linkButton = new QPushButton(this);
  43. m_linkButton->setIcon(icon);
  44. m_linkButton->setCheckable(true);
  45. m_linkButton->setFlat(true);
  46. m_linkButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  47. m_linkButton->setFixedSize(QSize(16, 16));
  48. m_linkButton->setContentsMargins(0, 0, 0, 0);
  49. m_linkButton->setToolTip("Linked to...");
  50. myLayout->addWidget(m_linkButton);
  51. connect(m_linkButton, &QPushButton::clicked, this, &PropertyLinkedCtrl::MirrorLinkButtonState);
  52. }
  53. bool PropertyLinkedCtrl::LinkIsOptional()
  54. {
  55. return m_linkButton;
  56. }
  57. void PropertyLinkedCtrl::SetOptionalLink(bool linked)
  58. {
  59. m_linkButton->setChecked(linked);
  60. }
  61. void PropertyLinkedCtrl::MirrorToLinkedProperty()
  62. {
  63. if (m_linkEnabled && m_linkedProperty != nullptr)
  64. {
  65. m_linkedProperty->MirrorToLinkedPropertyRecursive(this, m_pLineEdit->text());
  66. }
  67. }
  68. void PropertyLinkedCtrl::MirrorToLinkedPropertyRecursive(PropertyLinkedCtrl* caller, const QString& value)
  69. {
  70. if (caller != this)
  71. {
  72. if (m_linkButton == nullptr || m_linkButton->isChecked())
  73. {
  74. // Stop Property from mirroring again
  75. m_linkEnabled = false;
  76. m_pLineEdit->setText(value);
  77. m_linkEnabled = true;
  78. }
  79. if (m_linkedProperty != nullptr)
  80. {
  81. m_linkedProperty->MirrorToLinkedPropertyRecursive(caller, value);
  82. }
  83. }
  84. }
  85. void PropertyLinkedCtrl::MirrorLinkButtonState(bool checked)
  86. {
  87. if (m_linkedProperty != nullptr)
  88. {
  89. m_linkedProperty->MirrorLinkButtonStateRecursive(this, checked);
  90. // Mirror value of property linked was enabled on to all linked fields
  91. if (checked)
  92. {
  93. MirrorToLinkedProperty();
  94. }
  95. }
  96. }
  97. void PropertyLinkedCtrl::MirrorLinkButtonStateRecursive(PropertyLinkedCtrl* caller, bool state)
  98. {
  99. if (caller != this)
  100. {
  101. if (m_linkButton != nullptr)
  102. {
  103. m_linkButton->setChecked(state);
  104. }
  105. if (m_linkedProperty != nullptr)
  106. {
  107. m_linkedProperty->MirrorLinkButtonStateRecursive(caller, state);
  108. }
  109. }
  110. }
  111. bool PropertyLinkedCtrl::AllLinkedPropertiesEqual()
  112. {
  113. if (m_linkedProperty != nullptr)
  114. {
  115. return m_linkedProperty->AllLinkedPropertiesEqual(this, m_pLineEdit->text());
  116. }
  117. // No linked property so must be equal
  118. else
  119. {
  120. return true;
  121. }
  122. }
  123. bool PropertyLinkedCtrl::AllLinkedPropertiesEqual(PropertyLinkedCtrl* caller, const QString& value)
  124. {
  125. if (caller != this)
  126. {
  127. // Not equal
  128. if (m_pLineEdit->text() != value)
  129. {
  130. return false;
  131. }
  132. if (m_linkedProperty != nullptr)
  133. {
  134. return m_linkedProperty->AllLinkedPropertiesEqual(caller, value);
  135. }
  136. // All checked properties were equal
  137. else
  138. {
  139. return true;
  140. }
  141. }
  142. // All properties were equal
  143. else
  144. {
  145. return true;
  146. }
  147. }
  148. void PropertyLinkedCtrl::SetLinkEnabled(bool enabled)
  149. {
  150. m_linkEnabled = enabled;
  151. }
  152. void PropertyLinkedCtrl::ConsumeAttribute(AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
  153. {
  154. if (attrib == Attributes::LinkOptional && m_linkButton == nullptr)
  155. {
  156. bool optional = false;
  157. if (attrValue->Read<bool>(optional) && optional)
  158. {
  159. MakeLinkButton();
  160. }
  161. }
  162. else
  163. {
  164. PropertyFuncValLineEditCtrl::ConsumeAttribute(attrib, attrValue, debugName);
  165. }
  166. }
  167. // Handler ///////////////////////////////////////////////////////////////////
  168. PropertyLinkedHandler::PropertyLinkedHandler(ValidationHandler* valHdlr)
  169. : AzToolsFramework::PropertyHandler<AZStd::string, PropertyLinkedCtrl>()
  170. , m_validationHandler(valHdlr)
  171. {}
  172. AZ::u32 PropertyLinkedHandler::GetHandlerName(void) const
  173. {
  174. return Handlers::LinkedLineEdit;
  175. }
  176. QWidget* PropertyLinkedHandler::CreateGUI(QWidget* pParent)
  177. {
  178. PropertyLinkedCtrl* ctrl = aznew PropertyLinkedCtrl(pParent);
  179. m_validationHandler->AddValidatorCtrl(ctrl);
  180. return ctrl;
  181. }
  182. void PropertyLinkedHandler::ConsumeAttribute(PropertyLinkedCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
  183. {
  184. if (attrib == Attributes::PropertyIdentfier)
  185. {
  186. AZStd::string ident;
  187. if (attrValue->Read<AZStd::string>(ident))
  188. {
  189. m_identToCtrl.insert(AZStd::pair<AZStd::string, PropertyLinkedCtrl*>(ident, GUI));
  190. auto result = m_ctrlToIdentAndLink.find(GUI);
  191. if (result != m_ctrlToIdentAndLink.end())
  192. {
  193. result->second.identifier = ident;
  194. }
  195. else
  196. {
  197. m_ctrlToIdentAndLink.insert(AZStd::pair<PropertyLinkedCtrl*, IdentAndLink>(GUI, IdentAndLink{ ident, "" }));
  198. m_ctrlInitOrder.push_back(GUI);
  199. }
  200. }
  201. }
  202. else
  203. {
  204. GUI->ConsumeAttribute(attrib, attrValue, debugName);
  205. }
  206. }
  207. void PropertyLinkedHandler::WriteGUIValuesIntoProperty([[maybe_unused]] size_t index, PropertyLinkedCtrl* GUI, property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
  208. {
  209. instance = GUI->GetValue().toUtf8().data();
  210. }
  211. bool PropertyLinkedHandler::ReadValuesIntoGUI([[maybe_unused]] size_t index, PropertyLinkedCtrl* GUI, const property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
  212. {
  213. GUI->SetValue(instance.data());
  214. GUI->ForceValidate();
  215. return true;
  216. }
  217. PropertyLinkedHandler* PropertyLinkedHandler::Register(ValidationHandler* valHdlr)
  218. {
  219. PropertyLinkedHandler* handler = aznew PropertyLinkedHandler(valHdlr);
  220. AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(
  221. &AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Handler::RegisterPropertyType,
  222. handler);
  223. return handler;
  224. }
  225. void PropertyLinkedHandler::LinkAllProperties()
  226. {
  227. // Link all the properties
  228. for (PropertyLinkedCtrl* ctrlPointer : m_ctrlInitOrder)
  229. {
  230. auto property = m_ctrlToIdentAndLink.find(ctrlPointer);
  231. // If it's not linked to another property then continue
  232. if (property->second.linkedIdentifier.empty())
  233. {
  234. continue;
  235. }
  236. auto link = m_identToCtrl.find(property->second.linkedIdentifier);
  237. if (link != m_identToCtrl.end())
  238. {
  239. property->first->SetLinkedProperty(link->second);
  240. //Force mirror non-optional links.
  241. property->first->MirrorToLinkedProperty();
  242. }
  243. else
  244. {
  245. AZ_Assert(false, "Property \"%s\" not found while linking to \"%s\".", property->second.linkedIdentifier.data(), property->second.identifier.data());
  246. }
  247. }
  248. // Enable optional links if all properties in link chain are the same value
  249. EnableOptionalLinksIfAllPropertiesEqual();
  250. }
  251. void PropertyLinkedHandler::EnableOptionalLinksIfAllPropertiesEqual()
  252. {
  253. // Enable optional links if all properties in link chain are the same value
  254. for (const AZStd::pair<PropertyLinkedCtrl*, IdentAndLink>& property : m_ctrlToIdentAndLink)
  255. {
  256. if (property.first->LinkIsOptional())
  257. {
  258. property.first->SetOptionalLink(property.first->AllLinkedPropertiesEqual());
  259. }
  260. }
  261. }
  262. void PropertyLinkedHandler::MirrorAllLinkedProperties()
  263. {
  264. for (PropertyLinkedCtrl* ctrlPointer : m_ctrlInitOrder)
  265. {
  266. ctrlPointer->MirrorToLinkedProperty();
  267. }
  268. }
  269. void PropertyLinkedHandler::DisableAllPropertyLinks()
  270. {
  271. for (PropertyLinkedCtrl* ctrlPointer : m_ctrlInitOrder)
  272. {
  273. ctrlPointer->SetLinkEnabled(false);
  274. }
  275. }
  276. void PropertyLinkedHandler::EnableAllPropertyLinks()
  277. {
  278. for (PropertyLinkedCtrl* ctrlPointer : m_ctrlInitOrder)
  279. {
  280. ctrlPointer->SetLinkEnabled(true);
  281. }
  282. }
  283. } // namespace ProjectSettingsTool
  284. #include <moc_PropertyLinked.cpp>