/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include #include #include #include #include #include #include #include #include #include #include #include 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(); if (m_list->GetSelectedNodeCount() == 0 && m_list->GetUnselectedNodeCount() == 0) { if (const auto* root = ManifestWidget::FindRoot(this)) { Utilities::SceneGraphSelector::UnselectAll(root->GetScene()->GetGraph(), *m_list); } } } 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 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 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 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 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 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