ReflectedPropertyItem.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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 "EditorDefs.h"
  9. #include "ReflectedPropertyItem.h"
  10. // AzToolsFramework
  11. #include <AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx>
  12. // Editor
  13. #include "ReflectedVarWrapper.h"
  14. #include "ReflectedPropertyCtrl.h"
  15. #include "Undo/UndoVariableChange.h"
  16. // default number of increments to cover the range of a property - determined experimentally by feel
  17. const float ReflectedPropertyItem::s_DefaultNumStepIncrements = 500.0f;
  18. //A ReflectedVarAdapter for holding IVariableContainers
  19. //The extra ReflectedVarAdapter is the extra case of a container (has children) but also has a value itself.
  20. //An example is an IVariable array whose type is forced to IVariable::DT_TEXTURE. The base Ivariable has a texture,
  21. //but it also has children that are parameters of the texture. The ReflectedPropertyEditor does not support this case
  22. //so we work around by adding the base property to the list of children and showing the value of the base property
  23. //in the container value space instead of "X Elements"
  24. static ColorF StringToColor(const QString &value)
  25. {
  26. ColorF color;
  27. float r, g, b, a;
  28. int res = azsscanf(value.toUtf8().data(), "%f,%f,%f,%f", &r, &g, &b, &a);
  29. if (res == 4)
  30. {
  31. color.Set(r, g, b, a);
  32. }
  33. else if (res == 3)
  34. {
  35. color.Set(r, g, b);
  36. }
  37. else
  38. {
  39. unsigned abgr;
  40. azsscanf(value.toUtf8().data(), "%u", &abgr);
  41. color = ColorF(abgr);
  42. }
  43. return color;
  44. }
  45. class ReflectedVarContainerAdapter : public ReflectedVarAdapter
  46. {
  47. public:
  48. ReflectedVarContainerAdapter(ReflectedPropertyItem *item, ReflectedPropertyControl *control, ReflectedVarAdapter *variableAdapter = nullptr)
  49. : m_extraVariableAdapter(variableAdapter)
  50. , m_item(item)
  51. , m_propertyCtrl(control)
  52. , m_containerVar(new CPropertyContainer(AZStd::string()))
  53. {
  54. m_containerVar->SetAutoExpand(false);
  55. }
  56. void SetVariable(IVariable *pVariable) override
  57. {
  58. if (m_extraVariableAdapter)
  59. m_extraVariableAdapter->SetVariable(pVariable);
  60. //Check whether the parent container has autoExpand flag set, and if so, the autoexpand flag for this item
  61. //We need to do this because the default IVariable flags has the item expanded, so most items are expanded,
  62. //but the ReflectedPropertyEditor expands all ancestors if any item is expanded.
  63. //This is not what we want -- the old property editor did not expand ancestors. In case of Material editor,
  64. //this expansion can be really expensive!
  65. const bool parentIsAutoExpand = m_item->GetParent() == nullptr || m_item->GetParent()->GetContainer() == nullptr || m_item->GetParent()->GetContainer()->m_containerVar->AutoExpand();
  66. const bool bDefaultExpand = (pVariable->GetFlags() & IVariable::UI_COLLAPSED) == 0 || (pVariable->GetFlags() & IVariable::UI_AUTO_EXPAND);
  67. m_containerVar->SetAutoExpand(parentIsAutoExpand && bDefaultExpand);
  68. UpdateCommon(pVariable, pVariable);
  69. }
  70. //helps implement ReflectedPropertyControl::ReplaceVarBlock
  71. void ReplaceVarBlock(CVarBlock *varBlock) override
  72. {
  73. m_containerVar->Clear();
  74. UpdateCommon(m_item->GetVariable(), varBlock);
  75. }
  76. void SyncReflectedVarToIVar(IVariable *pVariable) override
  77. {
  78. if (m_extraVariableAdapter)
  79. {
  80. m_extraVariableAdapter->SyncReflectedVarToIVar(pVariable);
  81. //update text on parent container. Do not have control update attributes since this will happen anyway as part of updating ReflectedVar
  82. updateContainerText(pVariable, false);
  83. }
  84. };
  85. void SyncIVarToReflectedVar(IVariable *pVariable) override
  86. {
  87. if (m_extraVariableAdapter)
  88. {
  89. m_extraVariableAdapter->SyncIVarToReflectedVar(pVariable);
  90. //update text on parent container. Force control to update attributes since this doesn't normally happen when updating an IVar from ReflectedVar
  91. updateContainerText(pVariable, true);
  92. }
  93. };
  94. CReflectedVar *GetReflectedVar() override { return m_containerVar.data(); }
  95. bool Contains(CReflectedVar *var) override { return var == m_containerVar.data() || (m_extraVariableAdapter && m_extraVariableAdapter->GetReflectedVar() == var); }
  96. private:
  97. void UpdateCommon(IVariable *nameVariable, IVariableContainer *childContainer)
  98. {
  99. m_containerVar->m_varName = nameVariable->GetHumanName().toUtf8().data();
  100. m_containerVar->m_description = nameVariable->GetDescription().toUtf8().data();
  101. if (m_extraVariableAdapter)
  102. {
  103. m_containerVar->AddProperty(m_extraVariableAdapter->GetReflectedVar());
  104. }
  105. //Handle adding empty varblock
  106. if (!childContainer)
  107. return;
  108. for (int i = 0; i < childContainer->GetNumVariables(); i++)
  109. {
  110. AddChild(childContainer->GetVariable(i));
  111. }
  112. }
  113. void AddChild(IVariable *var)
  114. {
  115. if (var->GetFlags() & IVariable::UI_INVISIBLE)
  116. return;
  117. ReflectedPropertyItemPtr item = new ReflectedPropertyItem(m_propertyCtrl, m_item);
  118. item->SetVariable(var);
  119. m_containerVar->AddProperty(item->GetReflectedVar());
  120. }
  121. void updateContainerText(IVariable *pVariable, bool updateAttributes)
  122. {
  123. //set text of the container to the value of the main variable. If it's empty, use space, otherwise ReflectedPropertyEditor doesn't update it!
  124. m_containerVar->SetValueText(pVariable->GetDisplayValue().isEmpty() ? AZStd::string(" ") : AZStd::string(pVariable->GetDisplayValue().toUtf8().data()));
  125. if (updateAttributes)
  126. m_propertyCtrl->InvalidateCtrl();
  127. }
  128. private:
  129. //optional adapter for case where this item contains a variable in addition to a container of variables.
  130. ReflectedVarAdapter *m_extraVariableAdapter;
  131. QScopedPointer<CPropertyContainer> m_containerVar;
  132. ReflectedPropertyItem *m_item;
  133. ReflectedPropertyControl *m_propertyCtrl;
  134. };
  135. ReflectedPropertyItem::ReflectedPropertyItem(ReflectedPropertyControl *control, ReflectedPropertyItem *parent)
  136. : m_pVariable(nullptr)
  137. , m_reflectedVarAdapter(nullptr)
  138. , m_reflectedVarContainerAdapter(nullptr)
  139. , m_parent(parent)
  140. , m_propertyCtrl(control)
  141. , m_syncingIVar(false)
  142. , m_strNoScriptDefault("<<undefined>>")
  143. , m_strScriptDefault(m_strNoScriptDefault)
  144. {
  145. m_type = ePropertyInvalid;
  146. m_modified = false;
  147. if (parent)
  148. parent->AddChild(this);
  149. m_onSetCallback = AZStd::bind(&ReflectedPropertyItem::OnVariableChange, this, AZStd::placeholders::_1);
  150. m_onSetEnumCallback = AZStd::bind(&ReflectedPropertyItem::OnVariableEnumChange, this, AZStd::placeholders::_1);
  151. }
  152. ReflectedPropertyItem::~ReflectedPropertyItem()
  153. {
  154. // just to make sure we dont double (or infinitely recurse...) delete
  155. AddRef();
  156. if (m_pVariable)
  157. ReleaseVariable();
  158. RemoveAllChildren();
  159. }
  160. void ReflectedPropertyItem::SetVariable(IVariable *var)
  161. {
  162. if (var == m_pVariable)
  163. {
  164. // Early exit optimization if setting the same var as the current var.
  165. // A common use case, in Track View for example, is to re-use the save var for a property when switching to a new
  166. // instance of the same variable. The visible display of the value is often handled by invalidating the property,
  167. // but the non-visible attributes, i.e. the range values, are usually set using this method. Thus we reset the ranges
  168. // explicitly here when the Ivariable var is the same
  169. if (m_reflectedVarAdapter)
  170. m_reflectedVarAdapter->UpdateRangeLimits(var);
  171. return;
  172. }
  173. _smart_ptr<IVariable> pInputVar = var;
  174. // Release previous variable.
  175. if (m_pVariable)
  176. ReleaseVariable();
  177. m_pVariable = pInputVar;
  178. assert(m_pVariable != nullptr);
  179. m_pVariable->AddOnSetCallback(&m_onSetCallback);
  180. m_pVariable->AddOnSetEnumCallback(&m_onSetEnumCallback);
  181. // Fetch base parameter description
  182. Prop::Description desc(m_pVariable);
  183. m_type = desc.m_type;
  184. switch (m_type)
  185. {
  186. case ePropertyVector2:
  187. m_reflectedVarAdapter = new ReflectedVarVector2Adapter;
  188. break;
  189. case ePropertyVector:
  190. m_reflectedVarAdapter = new ReflectedVarVector3Adapter;
  191. break;
  192. case ePropertyVector4:
  193. m_reflectedVarAdapter = new ReflectedVarVector4Adapter;
  194. break;
  195. case ePropertyFloat:
  196. case ePropertyAngle:
  197. //if the Description has a valid global enumDB lookup, edit as an enum, otherwise use normal float editor
  198. if (desc.m_pEnumDBItem)
  199. m_reflectedVarAdapter = new ReflectedVarDBEnumAdapter;
  200. else
  201. m_reflectedVarAdapter = new ReflectedVarFloatAdapter;
  202. break;
  203. case ePropertyInt:
  204. //if the Description has a valid global enumDB lookup, edit as an enum, otherwise use normal int editor
  205. if (desc.m_pEnumDBItem)
  206. m_reflectedVarAdapter = new ReflectedVarDBEnumAdapter;
  207. else
  208. m_reflectedVarAdapter = new ReflectedVarIntAdapter;
  209. break;
  210. case ePropertyBool:
  211. m_reflectedVarAdapter = new ReflectedVarBoolAdapter;
  212. break;
  213. case ePropertyString:
  214. //if the Description has a valid global enumDB lookup, edit as an enum, otherwise use normal string editor
  215. if (desc.m_pEnumDBItem)
  216. m_reflectedVarAdapter = new ReflectedVarDBEnumAdapter;
  217. else
  218. m_reflectedVarAdapter = new ReflectedVarStringAdapter;
  219. break;
  220. case ePropertySelection:
  221. m_reflectedVarAdapter = new ReflectedVarEnumAdapter;
  222. break;
  223. case ePropertyAnimation:
  224. m_reflectedVarAdapter = new ReflectedVarAnimationAdapter;
  225. break;
  226. case ePropertyColor:
  227. m_reflectedVarAdapter = new ReflectedVarColorAdapter;
  228. break;
  229. case ePropertyUser:
  230. m_reflectedVarAdapter = new ReflectedVarUserAdapter;
  231. break;
  232. case ePropertyEquip:
  233. case ePropertyReverbPreset:
  234. case ePropertyGameToken:
  235. case ePropertyMissionObj:
  236. case ePropertySequence:
  237. case ePropertySequenceId:
  238. case ePropertyLocalString:
  239. case ePropertyLightAnimation:
  240. case ePropertyParticleName:
  241. m_reflectedVarAdapter = new ReflectedVarGenericPropertyAdapter(desc.m_type);
  242. break;
  243. case ePropertyTexture:
  244. case ePropertyModel:
  245. case ePropertyGeomCache:
  246. case ePropertyAudioTrigger:
  247. case ePropertyAudioSwitch:
  248. case ePropertyAudioSwitchState:
  249. case ePropertyAudioRTPC:
  250. case ePropertyAudioEnvironment:
  251. case ePropertyAudioPreloadRequest:
  252. case ePropertyFile:
  253. m_reflectedVarAdapter = new ReflectedVarResourceAdapter;
  254. break;
  255. case ePropertyFloatCurve:
  256. case ePropertyColorCurve:
  257. m_reflectedVarAdapter = new ReflectedVarSplineAdapter(this, m_type);
  258. break;
  259. case ePropertyMotion:
  260. m_reflectedVarAdapter = new ReflectedVarMotionAdapter;
  261. break;
  262. default:
  263. break;
  264. }
  265. const bool hasChildren = (m_pVariable->GetNumVariables() > 0 || desc.m_type == ePropertyTable || m_pVariable->GetType() == IVariable::ARRAY);
  266. //const bool isNotContainerType = (m_pVariable->GetType() != IVariable::ARRAY && desc.m_type != ePropertyTable && desc.m_type != ePropertyInvalid);
  267. if (hasChildren )
  268. {
  269. m_reflectedVarContainerAdapter = new ReflectedVarContainerAdapter(this, m_propertyCtrl, m_reflectedVarAdapter);
  270. m_reflectedVarAdapter = m_reflectedVarContainerAdapter;
  271. }
  272. if (m_reflectedVarAdapter)
  273. {
  274. m_reflectedVarAdapter->SetVariable(m_pVariable);
  275. m_reflectedVarAdapter->SyncReflectedVarToIVar(m_pVariable);
  276. }
  277. m_modified = false;
  278. }
  279. void ReflectedPropertyItem::ReplaceVarBlock(CVarBlock *varBlock)
  280. {
  281. RemoveAllChildren();
  282. if (m_reflectedVarAdapter)
  283. m_reflectedVarAdapter->ReplaceVarBlock(varBlock);
  284. }
  285. void ReflectedPropertyItem::AddChild(ReflectedPropertyItem *item)
  286. {
  287. assert(item);
  288. m_childs.push_back(item);
  289. }
  290. void ReflectedPropertyItem::RemoveAllChildren()
  291. {
  292. for (int i = 0; i < m_childs.size(); i++)
  293. {
  294. m_childs[i]->m_parent = nullptr;
  295. }
  296. m_childs.clear();
  297. }
  298. void ReflectedPropertyItem::RemoveChild(ReflectedPropertyItem* item)
  299. {
  300. for (int i = 0; i < m_childs.size(); i++)
  301. {
  302. if (m_childs[i] == item)
  303. {
  304. item->m_parent = nullptr;
  305. m_childs.erase(m_childs.begin() + i);
  306. return;
  307. }
  308. }
  309. }
  310. CReflectedVar * ReflectedPropertyItem::GetReflectedVar() const
  311. {
  312. return m_reflectedVarAdapter ? m_reflectedVarAdapter->GetReflectedVar() : nullptr;
  313. }
  314. ReflectedPropertyItem * ReflectedPropertyItem::findItem(CReflectedVar *var)
  315. {
  316. if (m_reflectedVarAdapter && m_reflectedVarAdapter->Contains(var) )
  317. return this;
  318. for (auto child : m_childs)
  319. {
  320. ReflectedPropertyItem *result = child->findItem(var);
  321. if (result)
  322. return result;
  323. }
  324. return nullptr;
  325. }
  326. ReflectedPropertyItem * ReflectedPropertyItem::findItem(IVariable *var)
  327. {
  328. if (m_pVariable == var)
  329. return this;
  330. for (auto child : m_childs)
  331. {
  332. ReflectedPropertyItem *result = child->findItem(var);
  333. if (result)
  334. return result;
  335. }
  336. return nullptr;
  337. }
  338. ReflectedPropertyItem* ReflectedPropertyItem::findItem(const QString &name)
  339. {
  340. if (m_pVariable && m_pVariable->GetHumanName() == name)
  341. return this;
  342. for (auto child : m_childs)
  343. {
  344. ReflectedPropertyItem *result = child->findItem(name);
  345. if (result)
  346. return result;
  347. }
  348. return nullptr;
  349. }
  350. ReflectedPropertyItem * ReflectedPropertyItem::FindItemByFullName(const QString& fullName)
  351. {
  352. if (GetFullName() == fullName)
  353. {
  354. return this;
  355. }
  356. for (int i = 0; i < m_childs.size(); ++i)
  357. {
  358. auto pFound = m_childs[i]->FindItemByFullName(fullName);
  359. if (pFound)
  360. {
  361. return pFound;
  362. }
  363. }
  364. return nullptr;
  365. }
  366. QString ReflectedPropertyItem::GetName() const
  367. {
  368. return m_pVariable ? m_pVariable->GetHumanName() : QString();
  369. }
  370. QString ReflectedPropertyItem::GetFullName() const
  371. {
  372. if (m_parent && m_pVariable)
  373. {
  374. return m_parent->GetFullName() + "::" + m_pVariable->GetName();
  375. }
  376. else if (m_pVariable)
  377. {
  378. return m_pVariable->GetName();
  379. }
  380. else
  381. {
  382. return {};
  383. }
  384. }
  385. void ReflectedPropertyItem::OnReflectedVarChanged()
  386. {
  387. m_syncingIVar = true;
  388. if (m_reflectedVarAdapter)
  389. {
  390. std::unique_ptr<CUndo> undo;
  391. if (!CUndo::IsRecording())
  392. {
  393. if (!m_propertyCtrl->CallUndoFunc(this))
  394. undo.reset(new CUndo((m_pVariable->GetHumanName() + " Modified").toUtf8().data()));
  395. }
  396. m_reflectedVarAdapter->SyncIVarToReflectedVar(m_pVariable);
  397. if (m_propertyCtrl->IsStoreUndoByItems() && CUndo::IsRecording())
  398. CUndo::Record(new CUndoVariableChange(m_pVariable, "PropertyChange"));
  399. m_modified = true;
  400. }
  401. m_syncingIVar = false;
  402. }
  403. void ReflectedPropertyItem::SyncReflectedVarToIVar()
  404. {
  405. if (m_reflectedVarAdapter)
  406. {
  407. m_reflectedVarAdapter->SyncReflectedVarToIVar(m_pVariable);
  408. }
  409. }
  410. void ReflectedPropertyItem::ReleaseVariable()
  411. {
  412. if (m_pVariable)
  413. {
  414. // Unwire all from variable.
  415. m_pVariable->RemoveOnSetCallback(&m_onSetCallback);
  416. m_pVariable->RemoveOnSetEnumCallback(&m_onSetEnumCallback);
  417. }
  418. m_pVariable = nullptr;
  419. delete m_reflectedVarAdapter;
  420. m_reflectedVarAdapter = nullptr;
  421. }
  422. void ReflectedPropertyItem::OnVariableChange(IVariable* pVar)
  423. {
  424. assert(pVar != 0 && pVar == m_pVariable);
  425. if (m_syncingIVar)
  426. return;
  427. // When variable changes, invalidate UI.
  428. m_modified = true;
  429. if (m_reflectedVarAdapter)
  430. {
  431. m_reflectedVarAdapter->OnVariableChange(pVar);
  432. }
  433. SyncReflectedVarToIVar();
  434. m_propertyCtrl->InvalidateCtrl();
  435. }
  436. void ReflectedPropertyItem::OnVariableEnumChange([[maybe_unused]] IVariable* pVar)
  437. {
  438. if (m_reflectedVarAdapter && m_reflectedVarAdapter->UpdateReflectedVarEnums())
  439. {
  440. m_propertyCtrl->InvalidateCtrl(true);
  441. }
  442. }
  443. void ReflectedPropertyItem::ReloadValues()
  444. {
  445. m_modified = false;
  446. if (m_pVariable)
  447. SetVariable(m_pVariable);
  448. for (int i = 0; i < GetChildCount(); i++)
  449. {
  450. GetChild(i)->ReloadValues();
  451. }
  452. SyncReflectedVarToIVar();
  453. }
  454. /** Changes value of item.
  455. */
  456. void ReflectedPropertyItem::SetValue(const QString& sValue, bool bRecordUndo, bool bForceModified)
  457. {
  458. if (!m_pVariable)
  459. {
  460. return;
  461. }
  462. _smart_ptr<ReflectedPropertyItem> holder = this; // Make sure we are not released during this function.
  463. QString value = sValue;
  464. switch (m_type)
  465. {
  466. case ePropertyBool:
  467. if (QString::compare(value, "true", Qt::CaseInsensitive) == 0 || value.toInt() != 0)
  468. {
  469. value = "1";
  470. }
  471. else
  472. {
  473. value = "0";
  474. }
  475. break;
  476. case ePropertyVector2:
  477. if (!value.contains(','))
  478. {
  479. value = value + ", " + value;
  480. }
  481. break;
  482. case ePropertyVector4:
  483. if (!value.contains(','))
  484. {
  485. value = value + ", " + value + ", " + value + ", " + value;
  486. }
  487. break;
  488. case ePropertyVector:
  489. if (!value.contains(','))
  490. {
  491. value = value + ", " + value + ", " + value;
  492. }
  493. break;
  494. case ePropertyTexture:
  495. case ePropertyModel:
  496. value.replace('\\', '/');
  497. break;
  498. }
  499. // correct the length of value
  500. switch (m_type)
  501. {
  502. case ePropertyTexture:
  503. case ePropertyModel:
  504. case ePropertyFile:
  505. if (value.length() >= MAX_PATH)
  506. {
  507. value = value.left(MAX_PATH);
  508. }
  509. break;
  510. }
  511. bool bModified = bForceModified || m_pVariable->GetDisplayValue() != value;
  512. bool bStoreUndo = (m_pVariable->GetDisplayValue() != value || bForceModified) && bRecordUndo;
  513. std::unique_ptr<CUndo> undo;
  514. if (bStoreUndo && !CUndo::IsRecording())
  515. {
  516. if (!m_propertyCtrl->CallUndoFunc(this))
  517. {
  518. undo.reset(new CUndo((GetName() + " Modified").toUtf8().data()));
  519. }
  520. }
  521. if (m_pVariable)
  522. {
  523. if (bModified)
  524. {
  525. if (m_propertyCtrl->IsStoreUndoByItems() && bStoreUndo && CUndo::IsRecording())
  526. {
  527. CUndo::Record(new CUndoVariableChange(m_pVariable, "PropertyChange"));
  528. }
  529. if (bForceModified)
  530. {
  531. m_pVariable->SetForceModified(true);
  532. }
  533. switch (m_type)
  534. {
  535. case ePropertyColor:
  536. {
  537. ColorF color = StringToColor(value);
  538. if (m_pVariable->GetType() == IVariable::VECTOR)
  539. {
  540. m_pVariable->Set(color.toVec3());
  541. }
  542. else
  543. {
  544. m_pVariable->Set(static_cast<int>(color.pack_abgr8888()));
  545. }
  546. break;
  547. }
  548. case ePropertyInvalid:
  549. break;
  550. default:
  551. m_pVariable->SetDisplayValue(value);
  552. break;
  553. }
  554. }
  555. }
  556. else
  557. {
  558. if (bModified)
  559. {
  560. m_modified = true;
  561. // If Value changed mark document modified.
  562. // Notify parent that this Item have been modified.
  563. m_propertyCtrl->OnItemChange(this);
  564. }
  565. }
  566. }
  567. void ReflectedPropertyItem::SendOnItemChange()
  568. {
  569. m_propertyCtrl->OnItemChange(this);
  570. }
  571. void ReflectedPropertyItem::ExpandAllChildren(bool recursive)
  572. {
  573. Expand(true);
  574. for (auto child : m_childs)
  575. {
  576. if (recursive)
  577. {
  578. child->ExpandAllChildren(recursive);
  579. }
  580. else
  581. {
  582. child->Expand(true);
  583. }
  584. }
  585. }
  586. void ReflectedPropertyItem::Expand(bool expand)
  587. {
  588. AzToolsFramework::PropertyRowWidget *widget = m_propertyCtrl->FindPropertyRowWidget(this);
  589. if (widget)
  590. {
  591. widget->SetExpanded(expand);
  592. }
  593. }
  594. QString ReflectedPropertyItem::GetPropertyName() const
  595. {
  596. return m_pVariable ? m_pVariable->GetHumanName() : QString();
  597. }