HierarchyHelpers.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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. #pragma once
  9. #include "EditorWindow.h"
  10. #include "HierarchyWidget.h"
  11. #include "EditorCommon.h"
  12. namespace HierarchyHelpers
  13. {
  14. //-------------------------------------------------------------------------------
  15. void Delete(HierarchyWidget* hierarchy,
  16. SerializeHelpers::SerializedEntryList& entries);
  17. template< typename T >
  18. void AppendAllChildrenToEndOfList(QTreeWidgetItem* rootItem,
  19. T& itemList);
  20. //! Handles whether the given item should be de-selected for control-key multi-selection.
  21. //
  22. //! \return True if the item has been de-selected, false otherwise.
  23. bool HandleDeselect(QTreeWidgetItem* widgetItem,
  24. const bool controlKeyPressed);
  25. //-------------------------------------------------------------------------------
  26. QAction* CreateAddElementAction(HierarchyWidget* hierarchy,
  27. const QTreeWidgetItemRawPtrQList& selectedItems,
  28. bool addAtRoot,
  29. const QPoint* optionalPos);
  30. //-------------------------------------------------------------------------------
  31. void CreateItemsAndElements(HierarchyWidget* widget,
  32. const SerializeHelpers::SerializedEntryList& entryList);
  33. using Creator = std::function<void( HierarchyItem* parent,
  34. LyShine::EntityArray& listOfNewlyCreatedTopLevelElements )>;
  35. LyShine::EntityArray CreateItemsAndElements(HierarchyWidget* widget,
  36. const QTreeWidgetItemRawPtrQList& selectedItems,
  37. bool createAsChildOfSelection,
  38. Creator creator);
  39. //-------------------------------------------------------------------------------
  40. QTreeWidgetItem* ElementToItem(HierarchyWidget* widget, const AZ::Entity* element, bool defaultToInvisibleRootItem);
  41. QTreeWidgetItem* ElementToItem(HierarchyWidget* widget, AZ::EntityId elementId, bool defaultToInvisibleRootItem);
  42. //-------------------------------------------------------------------------------
  43. //! These are helper functions for the templated functions.
  44. //! These AREN'T meant to be used outside of the scope of this file.
  45. QTreeWidgetItem* _GetItem(HierarchyWidget* widget,
  46. QTreeWidgetItem* i);
  47. QTreeWidgetItem* _GetItem(HierarchyWidget* widget,
  48. HierarchyItem* i);
  49. QTreeWidgetItem* _GetItem(HierarchyWidget* widget,
  50. SerializeHelpers::SerializedEntry& e);
  51. QTreeWidgetItem* _GetItem(HierarchyWidget* widget,
  52. AZ::Entity* e);
  53. QTreeWidgetItem* _GetItem(HierarchyWidget* widget,
  54. AZ::EntityId e);
  55. //-------------------------------------------------------------------------------
  56. template< typename T >
  57. bool AllItemExists(HierarchyWidget* widget,
  58. T& listToValidate)
  59. {
  60. QTreeWidgetItem* rootItem = widget->invisibleRootItem();
  61. QTreeWidgetItemRawPtrList allItems;
  62. HierarchyHelpers::AppendAllChildrenToEndOfList(rootItem, allItems);
  63. // IMPORTANT: If the items in each list were sorted, we could use
  64. // std::set_difference() or std::set_intersection() instead.
  65. for (auto && p : listToValidate)
  66. {
  67. QTreeWidgetItem* item = _GetItem(widget, p);
  68. if (item == rootItem)
  69. {
  70. // The invisibleRootItem is valid.
  71. continue;
  72. }
  73. if (std::find(allItems.begin(), allItems.end(), item) == allItems.end())
  74. {
  75. // Not found.
  76. return false;
  77. }
  78. }
  79. return true;
  80. }
  81. //-------------------------------------------------------------------------------
  82. //! Constructs a single-element array for the given element and forwards the request to SetSelectedItems
  83. //
  84. //! If the given element is null, this function is equivalent to calling SetSelectedItems
  85. //! with an empty list (and effectively clears the selection for the given widget).
  86. //
  87. //! \sa SetSelectedItems
  88. void SetSelectedItem(HierarchyWidget* widget,
  89. AZ::Entity* element);
  90. //! Selects all items in the given list and sets the first item in the list as the current item, or clears the current selection if the list is empty.
  91. //
  92. //! This is the list-based counterpart to SetSelectedItem.
  93. //
  94. //! All items in the given list will be selected for the given widget, unless
  95. //! the list is null or empty, in which case the current selection for the
  96. //! widget will be cleared.
  97. //
  98. //! \param widget The HierarchyWidget to operate on
  99. //
  100. //! \param list A list of elements to select
  101. //
  102. //! \sa SetSelectedItem
  103. template< typename T >
  104. void SetSelectedItems(HierarchyWidget* widget,
  105. T* list)
  106. {
  107. // This sets the selected item AND the current item.
  108. // Qt is smart enough to recognize and handle multi-selection
  109. // properly when the Ctrl key or the Shift key is pressed.
  110. // Stop object pick mode when an action explicitly wants to set the hierarchy's selected items
  111. AzToolsFramework::EditorPickModeRequestBus::Broadcast(
  112. &AzToolsFramework::EditorPickModeRequests::StopEntityPickMode);
  113. if ((!list) || list->empty())
  114. {
  115. // Note that calling SetSelectedItems with an empty list should clear
  116. // the selection of the tree widget
  117. widget->clearSelection();
  118. return;
  119. }
  120. AZ_Assert(
  121. widget->selectionMode() == QAbstractItemView::ExtendedSelection,
  122. "If this assert has triggered, then our selection mode assumptions have changed! "
  123. "Changing the selection mode could cause bugs and needs QA verification.");
  124. // The "current item" is like a cursor.
  125. // It's valid to have multiple items selected,
  126. // but you can only have ONE "current item".
  127. for (auto && i : *list)
  128. {
  129. QTreeWidgetItem* item = _GetItem(widget, i);
  130. // item can be null in the case of restoring a selection when switching tabs and an entity in a slice has been deleted
  131. if (item)
  132. {
  133. if (item == _GetItem(widget, list->front()))
  134. {
  135. // Calling setCurrentItem will set the item as current, but won't
  136. // necessarily select the item. If the item is already selected,
  137. // and the control or shift key is pressed, the item will
  138. // actually become de-selected (we explicitly set the selected
  139. // property below to ensure the item becomes selected).
  140. widget->setCurrentItem(item);
  141. }
  142. item->setSelected(true);
  143. }
  144. }
  145. }
  146. //-------------------------------------------------------------------------------
  147. template< typename T >
  148. void ExpandParents(HierarchyWidget* widget,
  149. T& items)
  150. {
  151. for (auto && i : items)
  152. {
  153. QTreeWidgetItem* p = _GetItem(widget, i)->QTreeWidgetItem::parent();
  154. if (p)
  155. {
  156. p->setExpanded(true);
  157. }
  158. }
  159. }
  160. //-------------------------------------------------------------------------------
  161. template< typename T >
  162. void ExpandItemsAndAncestors(HierarchyWidget* widget,
  163. T& items)
  164. {
  165. for (auto && i : items)
  166. {
  167. QTreeWidgetItem* item = _GetItem(widget, i);
  168. // Expand parent first, then child
  169. QTreeWidgetItemRawPtrList itemsToExpand;
  170. while (item)
  171. {
  172. itemsToExpand.push_front(item);
  173. item = item->parent();
  174. }
  175. for (auto itemToExpand : itemsToExpand)
  176. {
  177. itemToExpand->setExpanded(true);
  178. }
  179. }
  180. }
  181. //-------------------------------------------------------------------------------
  182. template< typename T >
  183. void AppendAllChildrenToEndOfList(QTreeWidgetItem* rootItem,
  184. T& itemList)
  185. {
  186. // Seed the list.
  187. int end = rootItem->childCount();
  188. for (int i = 0; i < end; ++i)
  189. {
  190. itemList.push_back(static_cast<typename T::value_type>(rootItem->child(i)));
  191. }
  192. // Note: This is a breadth-first traversal through all items.
  193. for (auto item : itemList)
  194. {
  195. int itemEnd = item->childCount();
  196. for (int i = 0; i < itemEnd; ++i)
  197. {
  198. itemList.push_back(static_cast<typename T::value_type>(item->child(i)));
  199. }
  200. }
  201. }
  202. //-------------------------------------------------------------------------------
  203. //! Important: This function has the side-effect of modifying the input list ("rootList").
  204. template< typename T >
  205. void TraverseListAndAllChildren(T& rootList,
  206. std::function<void(typename T::value_type)> traverser)
  207. {
  208. // Note: This is a breadth-first traversal through all items.
  209. for (auto item : rootList)
  210. {
  211. traverser(item);
  212. int end = item->childCount();
  213. for (int i = 0; i < end; ++i)
  214. {
  215. rootList.push_back(static_cast<typename T::value_type>(item->child(i)));
  216. }
  217. }
  218. }
  219. //! returns true if item1 is before item2 in the element hierarchy
  220. bool CompareOrderInElementHierarchy(HierarchyItem* item1, HierarchyItem* item2);
  221. //! Sort the given list so that the items is in the order that they appear in the element hierarchy
  222. void SortByHierarchyOrder(HierarchyItemRawPtrList &itemsToSerialize);
  223. //-------------------------------------------------------------------------------
  224. } // namespace HierarchyHelpers