CommandHierarchyItemReparent.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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 <AzCore/std/sort.h>
  10. CommandHierarchyItemReparent::CommandHierarchyItemReparent(UndoStack* stack,
  11. HierarchyWidget* hierarchy,
  12. const HierarchyItemRawPtrList& items)
  13. : QUndoCommand()
  14. , m_stack(stack)
  15. , m_hierarchy(hierarchy)
  16. , m_listToValidate()
  17. , m_isFirstExecution(true)
  18. , m_sourceChildrenSorted(false)
  19. , m_destinationChildrenSorted(false)
  20. {
  21. for (auto item : items)
  22. {
  23. // Add source child info
  24. ChildItem sourceChildItem;
  25. sourceChildItem.m_id = item->GetEntityId();
  26. sourceChildItem.m_parentId = item->GetPreMoveParentId();
  27. sourceChildItem.m_row = item->GetPreMoveChildRow();
  28. m_sourceChildren.push_back(sourceChildItem);
  29. // Add destination child info
  30. ChildItem destChildItem;
  31. destChildItem.m_id = sourceChildItem.m_id;
  32. QTreeWidgetItem* itemParent = item->QTreeWidgetItem::parent();
  33. if (!itemParent)
  34. {
  35. itemParent = m_hierarchy->invisibleRootItem();
  36. }
  37. HierarchyItem* postMoveParent = HierarchyItem::RttiCast(itemParent);
  38. destChildItem.m_parentId = (postMoveParent ? postMoveParent->GetEntityId() : AZ::EntityId());
  39. destChildItem.m_row = itemParent->indexOfChild(item);
  40. m_destinationChildren.push_back(destChildItem);
  41. // Add items to validate
  42. if (sourceChildItem.m_id.IsValid())
  43. {
  44. m_listToValidate.push_back(sourceChildItem.m_id);
  45. }
  46. if (sourceChildItem.m_parentId.IsValid())
  47. {
  48. m_listToValidate.push_back(sourceChildItem.m_parentId);
  49. }
  50. if (destChildItem.m_parentId.IsValid())
  51. {
  52. m_listToValidate.push_back(destChildItem.m_parentId);
  53. }
  54. }
  55. if (items.size() == 1)
  56. {
  57. setText(QString("move \"%1\"").arg(items.front()->GetElement()->GetName().c_str()));
  58. }
  59. else
  60. {
  61. setText(QString("move elements"));
  62. }
  63. }
  64. void CommandHierarchyItemReparent::undo()
  65. {
  66. UndoStackExecutionScope s(m_stack);
  67. Reparent(m_destinationChildren, m_sourceChildren, m_sourceChildrenSorted);
  68. }
  69. void CommandHierarchyItemReparent::redo()
  70. {
  71. UndoStackExecutionScope s(m_stack);
  72. Reparent(m_sourceChildren, m_destinationChildren, m_destinationChildrenSorted);
  73. }
  74. void CommandHierarchyItemReparent::Reparent(ChildItemList& sourceChildren, ChildItemList& destChildren, bool& childrenSorted)
  75. {
  76. if (!HierarchyHelpers::AllItemExists(m_hierarchy, m_listToValidate))
  77. {
  78. // At least one item is missing.
  79. // Nothing to do.
  80. return;
  81. }
  82. if (!childrenSorted)
  83. {
  84. // Sort children by destination index to be inserted in that order
  85. destChildren.sort([](const ChildItem& i1, const ChildItem& i2) { return i1.m_row < i2.m_row; });
  86. childrenSorted = true;
  87. }
  88. if (m_isFirstExecution)
  89. {
  90. m_isFirstExecution = false;
  91. }
  92. else
  93. {
  94. // Editor-side.
  95. //
  96. // IMPORTANT: The editor-side MUST be done BEFORE the runtime-side.
  97. // First remove all items
  98. for (auto child : sourceChildren)
  99. {
  100. HierarchyItem* item = HierarchyItem::RttiCast(HierarchyHelpers::ElementToItem(m_hierarchy, child.m_id, false));
  101. QTreeWidgetItem* sourceParentItem = HierarchyHelpers::ElementToItem(m_hierarchy, child.m_parentId, true);
  102. sourceParentItem->removeChild(item);
  103. }
  104. // Add items to new parents
  105. for (auto child : destChildren)
  106. {
  107. HierarchyItem* item = HierarchyItem::RttiCast(HierarchyHelpers::ElementToItem(m_hierarchy, child.m_id, false));
  108. QTreeWidgetItem* destinationParentItem = HierarchyHelpers::ElementToItem(m_hierarchy, child.m_parentId, true);
  109. destinationParentItem->insertChild(child.m_row, item);
  110. }
  111. }
  112. // Runtime-side.
  113. //
  114. // IMPORTANT: The runtime-side depends on the editor-side being done FIRST.
  115. // First remove all elements
  116. for (auto child : sourceChildren)
  117. {
  118. UiElementBus::Event(child.m_id, &UiElementBus::Events::RemoveFromParent);
  119. }
  120. // Add elements to new parents
  121. LyShine::EntityArray selectedElements;
  122. for (auto child : destChildren)
  123. {
  124. QTreeWidgetItem* destinationParentItem = HierarchyHelpers::ElementToItem(m_hierarchy, child.m_parentId, true);
  125. HierarchyItem* destinationParent = HierarchyItem::RttiCast(destinationParentItem);
  126. AZ::Entity* parentElement = (destinationParent ? destinationParent->GetElement() : nullptr);
  127. // Add the element to its new parent
  128. UiElementBus::Event(child.m_id, &UiElementBus::Events::AddToParentAtIndex, parentElement, child.m_row);
  129. // Add item to selected item list
  130. HierarchyItem* item = HierarchyItem::RttiCast(HierarchyHelpers::ElementToItem(m_hierarchy, child.m_id, false));
  131. selectedElements.push_back(item->GetElement());
  132. }
  133. // Set the focus to the currently manipulated items
  134. HierarchyHelpers::SetSelectedItems(m_hierarchy, &selectedElements);
  135. }
  136. void CommandHierarchyItemReparent::Push(UndoStack* stack,
  137. HierarchyWidget* hierarchy,
  138. const HierarchyItemRawPtrList& items,
  139. [[maybe_unused]] const QTreeWidgetItemRawPtrList& itemParents)
  140. {
  141. stack->push(new CommandHierarchyItemReparent(stack,
  142. hierarchy,
  143. items));
  144. }