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.
335 lines
13 KiB
C++
335 lines
13 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 <QLabel>
|
|
#include <QToolButton>
|
|
#include <AzCore/std/bind/bind.h>
|
|
#include <RowWidgets/ui_NodeTreeSelectionWidget.h>
|
|
#include <SceneAPI/SceneCore/Containers/Scene.h>
|
|
#include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
|
|
#include <SceneAPI/SceneCore/DataTypes/ManifestBase/ISceneNodeSelectionList.h>
|
|
#include <SceneAPI/SceneCore/Events/GraphMetaInfoBus.h>
|
|
#include <SceneAPI/SceneCore/Utilities/SceneGraphSelector.h>
|
|
#include <SceneAPI/SceneUI/RowWidgets/NodeTreeSelectionWidget.h>
|
|
#include <SceneAPI/SceneUI/SceneWidgets/ManifestWidget.h>
|
|
#include <SceneAPI/SceneUI/CommonWidgets/OverlayWidget.h>
|
|
|
|
namespace AZ
|
|
{
|
|
namespace SceneAPI
|
|
{
|
|
namespace UI
|
|
{
|
|
AZ_CLASS_ALLOCATOR_IMPL(NodeTreeSelectionWidget, SystemAllocator, 0)
|
|
|
|
NodeTreeSelectionWidget::NodeTreeSelectionWidget(QWidget* parent)
|
|
: QWidget(parent)
|
|
, ui(new Ui::NodeTreeSelectionWidget())
|
|
, m_narrowSelection(false)
|
|
, m_filterName("nodes")
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
ui->m_selectButton->setIcon(QIcon(":/SceneUI/Manifest/TreeIcon.png"));
|
|
connect(ui->m_selectButton, &QToolButton::clicked, this, &NodeTreeSelectionWidget::SelectButtonClicked);
|
|
}
|
|
|
|
NodeTreeSelectionWidget::~NodeTreeSelectionWidget() = default;
|
|
|
|
void NodeTreeSelectionWidget::SetList(const DataTypes::ISceneNodeSelectionList& list)
|
|
{
|
|
m_list = list.Copy();
|
|
}
|
|
|
|
void NodeTreeSelectionWidget::CopyListTo(DataTypes::ISceneNodeSelectionList& target)
|
|
{
|
|
if (m_list)
|
|
{
|
|
m_list->CopyTo(target);
|
|
}
|
|
}
|
|
|
|
void NodeTreeSelectionWidget::SetFilterName(const AZStd::string& name)
|
|
{
|
|
ui->m_selectButton->setToolTip(QString::asprintf("Select %s", name.c_str()));
|
|
m_filterName = name;
|
|
}
|
|
|
|
void NodeTreeSelectionWidget::SetFilterName(AZStd::string&& name)
|
|
{
|
|
ui->m_selectButton->setToolTip(QString::asprintf("Select %s", name.c_str()));
|
|
m_filterName = AZStd::move(name);
|
|
}
|
|
|
|
void NodeTreeSelectionWidget::AddFilterType(const Uuid& idProperty)
|
|
{
|
|
if (m_filterTypes.find(idProperty) == m_filterTypes.end())
|
|
{
|
|
m_filterTypes.insert(idProperty);
|
|
}
|
|
}
|
|
|
|
void NodeTreeSelectionWidget::AddFilterVirtualType(Crc32 name)
|
|
{
|
|
if (m_filterVirtualTypes.find(name) == m_filterVirtualTypes.end())
|
|
{
|
|
m_filterVirtualTypes.insert(name);
|
|
}
|
|
}
|
|
|
|
void NodeTreeSelectionWidget::UseNarrowSelection(bool enable)
|
|
{
|
|
m_narrowSelection = enable;
|
|
}
|
|
|
|
void NodeTreeSelectionWidget::SelectButtonClicked()
|
|
{
|
|
AZ_Assert(!m_treeWidget, "Node tree already active, NodeTreeSelectionWidget button pressed multiple times.");
|
|
AZ_Assert(m_list, "Requested updating of selection list before it was set.");
|
|
ManifestWidget* root = ManifestWidget::FindRoot(this);
|
|
AZ_Assert(root, "NodeTreeSelectionWidget is not a child of a ManifestWidget.");
|
|
if (!m_list || !root)
|
|
{
|
|
return;
|
|
}
|
|
|
|
AZStd::shared_ptr<Containers::Scene> scene = root->GetScene();
|
|
if (!scene)
|
|
{
|
|
return;
|
|
}
|
|
|
|
OverlayWidgetButtonList buttons;
|
|
|
|
OverlayWidgetButton acceptButton;
|
|
acceptButton.m_text = "Select";
|
|
acceptButton.m_callback = AZStd::bind(&NodeTreeSelectionWidget::ListChangesAccepted, this);
|
|
acceptButton.m_triggersPop = true;
|
|
|
|
OverlayWidgetButton cancelButton;
|
|
cancelButton.m_text = "Cancel";
|
|
cancelButton.m_callback = AZStd::bind(&NodeTreeSelectionWidget::ListChangesCanceled, this);
|
|
cancelButton.m_triggersPop = true;
|
|
cancelButton.m_isCloseButton = true;
|
|
|
|
buttons.push_back(&acceptButton);
|
|
buttons.push_back(&cancelButton);
|
|
|
|
ResetNewTreeWidget(*scene);
|
|
|
|
for (const Uuid& filterType : m_filterTypes)
|
|
{
|
|
m_treeWidget->AddFilterType(filterType);
|
|
}
|
|
|
|
for (Crc32 virtualTypeName : m_filterVirtualTypes)
|
|
{
|
|
m_treeWidget->AddVirtualFilterType(virtualTypeName);
|
|
}
|
|
|
|
if (m_narrowSelection)
|
|
{
|
|
m_treeWidget->MakeCheckable(SceneGraphWidget::CheckableOption::OnlyFilterTypesCheckable);
|
|
}
|
|
|
|
m_treeWidget->Build();
|
|
|
|
QLabel* label = new QLabel("Finish selecting nodes to continue editing settings.");
|
|
label->setAlignment(Qt::AlignCenter);
|
|
OverlayWidget::PushLayerToContainingOverlay(this, label, m_treeWidget.get(), "Select nodes", buttons);
|
|
}
|
|
|
|
void NodeTreeSelectionWidget::ResetNewTreeWidget(const Containers::Scene& scene)
|
|
{
|
|
m_treeWidget.reset(aznew SceneGraphWidget(scene, *m_list));
|
|
}
|
|
|
|
void NodeTreeSelectionWidget::ListChangesAccepted()
|
|
{
|
|
m_list = m_treeWidget->ClaimTargetList();
|
|
m_treeWidget.reset();
|
|
|
|
emit valueChanged();
|
|
}
|
|
|
|
void NodeTreeSelectionWidget::ListChangesCanceled()
|
|
{
|
|
m_treeWidget.reset();
|
|
}
|
|
|
|
void NodeTreeSelectionWidget::UpdateSelectionLabel()
|
|
{
|
|
if (m_list)
|
|
{
|
|
size_t selected = CalculateSelectedCount();
|
|
size_t total = CalculateTotalCount();
|
|
AZ_Assert(selected <= total, "Selected count of nodes should not be greater than the total count");
|
|
|
|
if (total == 0)
|
|
{
|
|
ui->m_statusLabel->setText("Default selection");
|
|
}
|
|
else if (selected == total)
|
|
{
|
|
ui->m_statusLabel->setText(QString::asprintf("All %s selected", m_filterName.c_str()));
|
|
}
|
|
else
|
|
{
|
|
ui->m_statusLabel->setText(
|
|
QString("%1 of %2 %3 selected").arg(selected).arg(total).arg(m_filterName.c_str()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ui->m_statusLabel->setText("No list assigned");
|
|
}
|
|
}
|
|
|
|
size_t NodeTreeSelectionWidget::CalculateSelectedCount()
|
|
{
|
|
if (!m_list)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const ManifestWidget* root = ManifestWidget::FindRoot(this);
|
|
AZ_Assert(root, "NodeTreeSelectionWidget is not a child of a ManifestWidget.");
|
|
if (!m_list || !root)
|
|
{
|
|
return 0;
|
|
}
|
|
const Containers::SceneGraph& graph = root->GetScene()->GetGraph();
|
|
|
|
size_t result = 0;
|
|
AZStd::unique_ptr<DataTypes::ISceneNodeSelectionList> tempList(m_list->Copy());
|
|
Utilities::SceneGraphSelector::UpdateNodeSelection(graph, *tempList);
|
|
size_t selectedCount = tempList->GetSelectedNodeCount();
|
|
for (size_t i = 0; i < selectedCount; ++i)
|
|
{
|
|
Containers::SceneGraph::NodeIndex index = graph.Find(tempList->GetSelectedNode(i));
|
|
if (!index.IsValid())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
AZStd::shared_ptr<const DataTypes::IGraphObject> object = graph.GetNodeContent(index);
|
|
if (!object)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (m_filterTypes.empty() && m_filterVirtualTypes.empty())
|
|
{
|
|
result++;
|
|
continue;
|
|
}
|
|
|
|
bool foundType = false;
|
|
for (const Uuid& type : m_filterTypes)
|
|
{
|
|
if (object->RTTI_IsTypeOf(type))
|
|
{
|
|
result++;
|
|
foundType = true;
|
|
break;
|
|
}
|
|
}
|
|
if (foundType)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Check if the object is one of the registered virtual types.
|
|
AZStd::set<Crc32> virtualTypes;
|
|
Events::GraphMetaInfoBus::Broadcast(&Events::GraphMetaInfo::GetVirtualTypes, virtualTypes, *root->GetScene(), index);
|
|
for (Crc32 name : virtualTypes)
|
|
{
|
|
if (m_filterVirtualTypes.find(name) != m_filterVirtualTypes.end())
|
|
{
|
|
result++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
size_t NodeTreeSelectionWidget::CalculateTotalCount()
|
|
{
|
|
const ManifestWidget* root = ManifestWidget::FindRoot(this);
|
|
AZ_Assert(root, "NodeTreeSelectionWidget is not a child of a ManifestWidget.");
|
|
if (!m_list || !root)
|
|
{
|
|
return 0;
|
|
}
|
|
const Containers::SceneGraph& graph = root->GetScene()->GetGraph();
|
|
|
|
size_t total = 0;
|
|
if (m_filterTypes.empty() && m_filterVirtualTypes.empty())
|
|
{
|
|
Containers::SceneGraph::HierarchyStorageConstData view = graph.GetHierarchyStorage();
|
|
if (!graph.GetNodeContent(graph.GetRoot()) && graph.GetNodeName(graph.GetRoot()).GetPathLength() == 0)
|
|
{
|
|
view = Containers::SceneGraph::HierarchyStorageConstData(view.begin() + 1, view.end());
|
|
}
|
|
|
|
for (auto& it : view)
|
|
{
|
|
if (!it.IsEndPoint())
|
|
{
|
|
total++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (auto it = graph.GetContentStorage().begin(); it != graph.GetContentStorage().end(); ++it)
|
|
{
|
|
if (!(*it))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Containers::SceneGraph::NodeIndex index = graph.ConvertToNodeIndex(it);
|
|
|
|
bool foundType = false;
|
|
for (const Uuid& type : m_filterTypes)
|
|
{
|
|
if ((*it)->RTTI_IsTypeOf(type))
|
|
{
|
|
total++;
|
|
foundType = true;
|
|
break;
|
|
}
|
|
}
|
|
if (foundType)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Check if the object is one of the registered virtual types.
|
|
AZStd::set<Crc32> virtualTypes;
|
|
Events::GraphMetaInfoBus::Broadcast(&Events::GraphMetaInfo::GetVirtualTypes, virtualTypes, *root->GetScene(), index);
|
|
for (Crc32 name : virtualTypes)
|
|
{
|
|
if (m_filterVirtualTypes.find(name) != m_filterVirtualTypes.end())
|
|
{
|
|
total++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
} // namespace UI
|
|
} // namespace SceneAPI
|
|
} // namespace AZ
|
|
|
|
#include <RowWidgets/moc_NodeTreeSelectionWidget.cpp>
|