You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/LyShine/Code/Editor/SelectionHelpers.cpp

299 lines
8.6 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorCommon.h"
namespace SelectionHelpers
{
//-------------------------------------------------------------------------------
void UnmarkAllAndAllTheirChildren(QTreeWidgetItem* baseRootItem)
{
// Seed the list.
HierarchyItemRawPtrList itemList;
HierarchyHelpers::AppendAllChildrenToEndOfList(baseRootItem, itemList);
// Traverse the list.
HierarchyHelpers::TraverseListAndAllChildren(itemList,
[](HierarchyItem* childItem)
{
childItem->SetMark(false);
});
}
void MarkOnlyDirectChildrenOf(const QTreeWidgetItemRawPtrQList& parentItems)
{
for (auto j : parentItems)
{
int end = j->childCount();
for (int i = 0; i < end; ++i)
{
HierarchyItem* item = HierarchyItem::RttiCast(j->child(i));
item->SetMark(true);
}
}
}
bool A_IsParentOf_B(QTreeWidgetItem* A,
QTreeWidgetItem* B)
{
// We MUST have an "A", and "A" and "B" MUST be different.
// Otherwise, early-out. We don't need to test "B" here,
// by itself, because we'll do so in the "while" loop below.
if (!(A && (A != B)))
{
// Nothing to do.
return false;
}
while (B)
{
// Walk up the hierarchy.
B = B->parent();
// If A is the parent of B,
// A will eventually equal B.
if (A == B)
{
return true;
}
}
return false;
}
bool IsMarkedOrParentIsMarked(HierarchyItem* item)
{
if (!item)
{
// Nothing to do.
return false;
}
do
{
if (item->GetMark())
{
return true;
}
// Walk up the hierarchy.
item = item->Parent();
}
while (item);
return false;
}
void FindUnmarked(HierarchyItemRawPtrList& results,
const QTreeWidgetItemRawPtrQList& parentItems)
{
for (auto j : parentItems)
{
HierarchyItem* item = HierarchyItem::RttiCast(j);
AZ_Assert(item, "There's an item in the Hierarchy that isn't a HierarchyItem.");
if (!IsMarkedOrParentIsMarked(item))
{
results.push_back(item);
}
}
}
//-------------------------------------------------------------------------------
AZ::Entity* GetTopLevelParentOfElement(const LyShine::EntityArray& elements, AZ::Entity* elementToFind)
{
do
{
for (auto e : elements)
{
if (e == elementToFind)
{
return e;
}
}
elementToFind = EntityHelpers::GetParentElement(elementToFind);
} while (elementToFind);
return nullptr;
}
void RemoveEntityFromArray(LyShine::EntityArray& listToTrim, const AZ::Entity* entityToRemove)
{
for (auto e = listToTrim.begin(); e != listToTrim.end(); ++e)
{
if (*e == entityToRemove)
{
listToTrim.erase(e);
return;
}
}
}
//-------------------------------------------------------------------------------
void GetListOfTopLevelSelectedItems([[maybe_unused]] const HierarchyWidget* widget,
const QTreeWidgetItemRawPtrQList& selectedItems,
QTreeWidgetItemRawPtrQList& results)
{
AZ_Assert(&selectedItems != &results, "Input and output cannot be the same");
results = selectedItems;
// Remove all non-top-parent nodes.
// IMPORTANT: This algorithm's time complexity is O(n^2),
// and space complexity is O(n).
for (auto i : selectedItems)
{
for (auto j : selectedItems)
{
if ((i != j) &&
A_IsParentOf_B(i, j))
{
results.removeOne(j);
}
}
}
}
void GetListOfTopLevelSelectedItems([[maybe_unused]] const HierarchyWidget* widget,
const QTreeWidgetItemRawPtrQList& selectedItems,
QTreeWidgetItem* invisibleRootItem,
HierarchyItemRawPtrList& results)
{
UnmarkAllAndAllTheirChildren(invisibleRootItem);
// Note: The mark is used as a pruning flag.
// All items with a mark, or under a marked item, will be culled.
MarkOnlyDirectChildrenOf(selectedItems);
FindUnmarked(results, selectedItems);
}
//-------------------------------------------------------------------------------
HierarchyItemRawPtrList GetSelectedHierarchyItems([[maybe_unused]] const HierarchyWidget* widget,
const QTreeWidgetItemRawPtrQList& selectedItems)
{
HierarchyItemRawPtrList items;
// selectedItems -> HierarchyItemRawPtrList.
for (auto i : selectedItems)
{
HierarchyItem* item = HierarchyItem::RttiCast(i);
if (item)
{
items.push_back(item);
}
else
{
AZ_Assert(0, "This should NEVER happen. Because we should ONLY be able to select HierarchyItem in the widget.");
}
}
return items;
}
LyShine::EntityArray GetSelectedElements([[maybe_unused]] const HierarchyWidget* widget,
const QTreeWidgetItemRawPtrQList& selectedItems)
{
auto count = selectedItems.count();
LyShine::EntityArray elements(count);
{
for (int i = 0; i < count; ++i)
{
HierarchyItem* item = HierarchyItem::RttiCast(selectedItems[i]);
if (item)
{
elements[i] = item->GetElement();
}
else
{
AZ_Assert(0, "This should NEVER happen, because every item in the hierarchy should represent an element.");
}
}
}
return elements;
}
EntityHelpers::EntityIdList GetSelectedElementIds([[maybe_unused]] const HierarchyWidget* widget,
const QTreeWidgetItemRawPtrQList& selectedItems,
bool addInvalidIdIfEmpty)
{
EntityHelpers::EntityIdList ids;
{
auto count = selectedItems.count();
for (int i = 0; i < count; ++i)
{
HierarchyItem* item = HierarchyItem::RttiCast(selectedItems[i]);
if (item)
{
ids.push_back(item->GetEntityId());
}
else
{
AZ_Assert(0, "This should NEVER happen, because every item in the hierarchy should represent an element.");
}
}
if (addInvalidIdIfEmpty && ids.empty())
{
ids.push_back(AZ::EntityId());
}
}
return ids;
}
LyShine::EntityArray GetTopLevelSelectedElements(const HierarchyWidget* widget,
const QTreeWidgetItemRawPtrQList& selectedItems)
{
HierarchyItemRawPtrList topLevelSelectedItems;
GetListOfTopLevelSelectedItems(widget,
selectedItems,
widget->invisibleRootItem(),
topLevelSelectedItems);
// HierarchyItemRawPtrList -> EntityArray.
LyShine::EntityArray elements;
for (auto item : topLevelSelectedItems)
{
elements.push_back(item->GetElement());
}
return elements;
}
LyShine::EntityArray GetTopLevelSelectedElementsNotControlledByParent(const HierarchyWidget* widget,
const QTreeWidgetItemRawPtrQList& selectedItems)
{
HierarchyItemRawPtrList topLevelSelectedItems;
GetListOfTopLevelSelectedItems(widget,
selectedItems,
widget->invisibleRootItem(),
topLevelSelectedItems);
// HierarchyItemRawPtrList -> EntityArray.
LyShine::EntityArray elements;
for (auto item : topLevelSelectedItems)
{
if (!ViewportHelpers::IsControlledByLayout(item->GetElement()))
{
elements.push_back(item->GetElement());
}
}
return elements;
}
//-------------------------------------------------------------------------------
} // namespace SelectionHelpers