HierarchyHelpers.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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 <QMessageBox>
  10. //-------------------------------------------------------------------------------
  11. namespace
  12. {
  13. void CreateItems(HierarchyWidget* widget,
  14. LyShine::EntityArray& completeListOfNewlyCreatedTopLevelElements)
  15. {
  16. // Create items for all new elements.
  17. widget->CreateItems(completeListOfNewlyCreatedTopLevelElements);
  18. // IMPORTANT: The CTRL key is down when we paste items.
  19. // This has the side effect of ADDING to the selection,
  20. // instead of replacing it. The solution is to explicitely
  21. // UNSELECT the previously selected items BEFORE selecting
  22. // the newly created items.
  23. widget->clearSelection();
  24. // Expand and select.
  25. {
  26. HierarchyHelpers::ExpandParents(widget, completeListOfNewlyCreatedTopLevelElements);
  27. HierarchyHelpers::SetSelectedItems(widget, &completeListOfNewlyCreatedTopLevelElements);
  28. }
  29. }
  30. } // anonymous namespace.
  31. //-------------------------------------------------------------------------------
  32. namespace HierarchyHelpers
  33. {
  34. //-------------------------------------------------------------------------------
  35. void Delete(HierarchyWidget* hierarchy,
  36. SerializeHelpers::SerializedEntryList& entries)
  37. {
  38. hierarchy->SetIsDeleting(true);
  39. {
  40. for (auto& e : entries)
  41. {
  42. // IMPORTANT: It's SAFE to delete a HierarchyItem. Its
  43. // destructor will take care of removing the item from
  44. // the parent container, AND deleting all child items.
  45. // There's no risk of leaking memory. We just have to
  46. // make sure we don't have any dangling pointers.
  47. delete HierarchyHelpers::ElementToItem(hierarchy, e.m_id, false);
  48. }
  49. }
  50. hierarchy->SetIsDeleting(false);
  51. hierarchy->SignalUserSelectionHasChanged(hierarchy->selectedItems());
  52. hierarchy->GetEditorWindow()->EntitiesAddedOrRemoved();
  53. }
  54. bool HandleDeselect(QTreeWidgetItem* widgetItem, const bool controlKeyPressed)
  55. {
  56. if (widgetItem && widgetItem->isSelected())
  57. {
  58. // Ctrl+clicking a selected element should de-select it
  59. if (controlKeyPressed)
  60. {
  61. widgetItem->setSelected(false);
  62. return true;
  63. }
  64. }
  65. return false;
  66. }
  67. //-------------------------------------------------------------------------------
  68. QAction* CreateAddElementAction(HierarchyWidget* hierarchy,
  69. const QTreeWidgetItemRawPtrQList& selectedItems,
  70. bool addAtRoot,
  71. const QPoint* optionalPos)
  72. {
  73. QAction* action = new QAction(QIcon(":/Icons/Eye_Open.png"),
  74. QString("&Empty element%1").arg(!addAtRoot && selectedItems.size() > 1 ? "s" : ""),
  75. hierarchy);
  76. QObject::connect(action,
  77. &QAction::triggered,
  78. hierarchy,
  79. [hierarchy, addAtRoot, optionalPos]([[maybe_unused]] bool checked)
  80. {
  81. if (addAtRoot)
  82. {
  83. hierarchy->clearSelection();
  84. }
  85. hierarchy->AddElement(hierarchy->selectedItems(), optionalPos);
  86. });
  87. return action;
  88. }
  89. //-------------------------------------------------------------------------------
  90. void CreateItemsAndElements(HierarchyWidget* widget,
  91. const SerializeHelpers::SerializedEntryList& entryList)
  92. {
  93. LyShine::EntityArray completeListOfNewlyCreatedTopLevelElements;
  94. // Create elements
  95. {
  96. // Because the entries use m_insertAboveThisId to correctly insert elements
  97. // in the right place and two siblings can be in the list of entries, the later
  98. // sibling has to be inserted first so that the earlier one can find the element
  99. // it should be before. We know that the SerializedEntryList is created in the order
  100. // that elements are in the element hierarchy. So we iterate in reverse order over the
  101. // SerializedEntryList while inserting the elements.
  102. for (auto iter = entryList.rbegin(); iter != entryList.rend(); ++iter)
  103. {
  104. auto& e = *iter;
  105. SerializeHelpers::RestoreSerializedElements(widget->GetEditorWindow()->GetCanvas(),
  106. EntityHelpers::GetEntity(e.m_parentId),
  107. EntityHelpers::GetEntity(e.m_insertAboveThisId),
  108. widget->GetEditorWindow()->GetEntityContext(),
  109. e.m_undoXml.c_str(),
  110. false,
  111. &completeListOfNewlyCreatedTopLevelElements);
  112. }
  113. }
  114. // because we iterated backward above the completeListOfNewlyCreatedTopLevelElements is now
  115. // in the reverse order of what the items should be in the HierarchyWidget. CreateItems
  116. // relies on them being in the correct order so we reverse the list.
  117. std::reverse(completeListOfNewlyCreatedTopLevelElements.begin(), completeListOfNewlyCreatedTopLevelElements.end());
  118. // Now create the items in the QTreeWidget
  119. CreateItems(widget, completeListOfNewlyCreatedTopLevelElements);
  120. widget->GetEditorWindow()->EntitiesAddedOrRemoved();
  121. }
  122. //-------------------------------------------------------------------------------
  123. LyShine::EntityArray CreateItemsAndElements(HierarchyWidget* widget,
  124. const QTreeWidgetItemRawPtrQList& selectedItems,
  125. bool createAsChildOfSelection,
  126. Creator creator)
  127. {
  128. LyShine::EntityArray completeListOfNewlyCreatedTopLevelElements;
  129. // Create elements
  130. {
  131. HierarchyItem* parent = nullptr;
  132. {
  133. HierarchyItem* selectedItem = nullptr;
  134. {
  135. HierarchyItemRawPtrList items;
  136. SelectionHelpers::GetListOfTopLevelSelectedItems(widget,
  137. selectedItems,
  138. widget->invisibleRootItem(),
  139. items);
  140. selectedItem = (items.empty() ? nullptr : items.front());
  141. }
  142. // It's ok for parent to be nullptr.
  143. if (createAsChildOfSelection)
  144. {
  145. // Create as a child of the selectedItem.
  146. parent = selectedItem;
  147. }
  148. else
  149. {
  150. // Create as a sibling of the selectedItem.
  151. parent = selectedItem ? selectedItem->Parent() : nullptr;
  152. }
  153. }
  154. // Create.
  155. {
  156. LyShine::EntityArray listOfNewlyCreatedTopLevelElements;
  157. creator(parent, listOfNewlyCreatedTopLevelElements);
  158. if (listOfNewlyCreatedTopLevelElements.empty())
  159. {
  160. // This happens when the serialization version numbers DON'T match.
  161. QMessageBox(
  162. QMessageBox::Critical, "Error", QString("Failed to load elements. The serialization format is incompatible."), QMessageBox::Ok,
  163. widget->GetEditorWindow())
  164. .exec();
  165. // Nothing more to do.
  166. return LyShine::EntityArray();
  167. }
  168. completeListOfNewlyCreatedTopLevelElements.insert(
  169. completeListOfNewlyCreatedTopLevelElements.end(),
  170. listOfNewlyCreatedTopLevelElements.begin(),
  171. listOfNewlyCreatedTopLevelElements.end()
  172. );
  173. }
  174. }
  175. // Create the items to go along the elements created above.
  176. CreateItems(widget, completeListOfNewlyCreatedTopLevelElements);
  177. widget->GetEditorWindow()->EntitiesAddedOrRemoved();
  178. return completeListOfNewlyCreatedTopLevelElements;
  179. }
  180. //-------------------------------------------------------------------------------
  181. QTreeWidgetItem* ElementToItem(HierarchyWidget* widget, const AZ::Entity* element, bool defaultToInvisibleRootItem)
  182. {
  183. if (!element)
  184. {
  185. return (defaultToInvisibleRootItem ? widget->invisibleRootItem() : nullptr);
  186. }
  187. return ElementToItem(widget, element->GetId(), defaultToInvisibleRootItem);
  188. }
  189. QTreeWidgetItem* ElementToItem(HierarchyWidget* widget, AZ::EntityId elementId, bool defaultToInvisibleRootItem)
  190. {
  191. if (!elementId.IsValid())
  192. {
  193. return (defaultToInvisibleRootItem ? widget->invisibleRootItem() : nullptr);
  194. }
  195. auto i = widget->GetEntityItemMap().find(elementId);
  196. if (i == widget->GetEntityItemMap().end())
  197. {
  198. // Not found.
  199. return (defaultToInvisibleRootItem ? widget->invisibleRootItem() : nullptr);
  200. }
  201. else
  202. {
  203. // Found.
  204. return i->second;
  205. }
  206. }
  207. //-------------------------------------------------------------------------------
  208. QTreeWidgetItem* _GetItem([[maybe_unused]] HierarchyWidget* widget,
  209. QTreeWidgetItem* i)
  210. {
  211. return i;
  212. }
  213. QTreeWidgetItem* _GetItem([[maybe_unused]] HierarchyWidget* widget,
  214. HierarchyItem* i)
  215. {
  216. return i;
  217. }
  218. QTreeWidgetItem* _GetItem(HierarchyWidget* widget,
  219. SerializeHelpers::SerializedEntry& e)
  220. {
  221. return HierarchyHelpers::ElementToItem(widget, e.m_id, false);
  222. }
  223. QTreeWidgetItem* _GetItem(HierarchyWidget* widget,
  224. AZ::Entity* e)
  225. {
  226. return HierarchyHelpers::ElementToItem(widget, e, false);
  227. }
  228. QTreeWidgetItem* _GetItem(HierarchyWidget* widget,
  229. AZ::EntityId e)
  230. {
  231. return HierarchyHelpers::ElementToItem(widget, e, false);
  232. }
  233. //-------------------------------------------------------------------------------
  234. void SetSelectedItem(HierarchyWidget* widget,
  235. AZ::Entity* element)
  236. {
  237. LyShine::EntityArray elementUnderCursor;
  238. if (element)
  239. {
  240. elementUnderCursor.push_back(element);
  241. }
  242. SetSelectedItems(widget, &elementUnderCursor);
  243. }
  244. bool CompareOrderInElementHierarchy(HierarchyItem* item1, HierarchyItem* item2)
  245. {
  246. AZ::Entity* entity1 = item1->GetElement();
  247. AZ::Entity* entity2 = item2->GetElement();
  248. return EntityHelpers::CompareOrderInElementHierarchy(entity1, entity2);
  249. }
  250. void SortByHierarchyOrder(HierarchyItemRawPtrList &itemList)
  251. {
  252. itemList.sort(CompareOrderInElementHierarchy);
  253. }
  254. //-------------------------------------------------------------------------------
  255. } // namespace HierarchyHelpers