#ifndef CNODESELECTION_H #define CNODESELECTION_H #include #include #include #include #include class CNodeSelection : public QObject { Q_OBJECT FNodeFlags mAllowedNodes{ENodeType::All}; QList mSelectedNodes; mutable CAABox mCachedBounds; mutable bool mBoundsDirty = true; public: CNodeSelection() = default; ~CNodeSelection() override { for (CSceneNode *pNode : mSelectedNodes) pNode->SetSelected(false); } void SelectNode(CSceneNode *pNode) { if (IsAllowedType(pNode->NodeType()) && !pNode->IsSelected()) { pNode->SetSelected(true); mSelectedNodes << pNode; mCachedBounds.ExpandBounds(pNode->AABox()); emit Modified(); } } void DeselectNode(CSceneNode *pNode) { if (pNode->IsSelected()) { pNode->SetSelected(false); mSelectedNodes.removeOne(pNode); mBoundsDirty = true; emit Modified(); } } void Clear() { for (CSceneNode *pNode : mSelectedNodes) pNode->SetSelected(false); mSelectedNodes.clear(); mBoundsDirty = true; emit Modified(); } void ClearAndSelectNode(CSceneNode *pNode) { // Block signals for Clear so that Modified only emits once. blockSignals(true); Clear(); blockSignals(false); SelectNode(pNode); } void SetSelectedNodes(const QList& rkList) { blockSignals(true); Clear(); for (CSceneNode *pNode : rkList) SelectNode(pNode); blockSignals(false); mBoundsDirty = true; emit Modified(); } CAABox Bounds() const { if (mBoundsDirty) { mCachedBounds = CAABox::Infinite(); for (CSceneNode *pNode : mSelectedNodes) { mCachedBounds.ExpandBounds(pNode->AABox()); if (pNode->NodeType() == ENodeType::Script) { CScriptNode *pScript = static_cast(pNode); if (pScript->HasPreviewVolume()) mCachedBounds.ExpandBounds(pScript->PreviewVolumeAABox()); } } mBoundsDirty = false; } return mCachedBounds; } uint32 Size() const { return mSelectedNodes.size(); } bool IsEmpty() const { return Size() == 0; } CSceneNode* At(uint32 Index) const { return mSelectedNodes[Index]; } CSceneNode* Front() const { return mSelectedNodes.front(); } CSceneNode* Back() const { return mSelectedNodes.back(); } CSceneNode* operator[](uint32 Index) const { return mSelectedNodes[Index]; } void UpdateBounds() { mBoundsDirty = true; } void SetAllowedNodeTypes(FNodeFlags Types) { mAllowedNodes = Types; } bool IsAllowedType(ENodeType Type) const { return (mAllowedNodes & Type) != 0; } bool IsAllowedType(CSceneNode *pNode) const { return (mAllowedNodes & pNode->NodeType()) != 0; } QList SelectedNodeList() const { return mSelectedNodes; } signals: void Modified(); }; #endif // CNODESELECTION_H