Loading [MathJax]/extensions/TeX/AMSsymbols.js
Radium Engine  1.5.28
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
EntityTreeModel.cpp
1#include <Core/CoreMacros.hpp>
2#include <Engine/Rendering/RenderObject.hpp>
3#include <Engine/Rendering/RenderObjectManager.hpp>
4#include <Engine/Scene/Component.hpp>
5#include <Engine/Scene/Entity.hpp>
6#include <Engine/Scene/EntityManager.hpp>
7#include <Gui/TreeModel/EntityTreeModel.hpp>
9#include <algorithm>
10#include <memory>
11#include <stack>
12#include <vector>
13
15
16namespace Ra {
17namespace Gui {
18
20 m_rootItem.reset( new EngineTreeItem );
21 m_rootItem->m_parent = nullptr;
22
23 auto roManager = m_engine->getRenderObjectManager();
24 for ( const auto& ent : m_engine->getEntityManager()->getEntities() ) {
25 EngineTreeItem* entityItem = new EngineTreeItem;
26 entityItem->m_entry = ItemEntry( ent );
27 entityItem->m_parent = m_rootItem.get();
28 for ( const auto& comp : ent->getComponents() ) {
29 if ( comp ) {
30 EngineTreeItem* componentItem = new EngineTreeItem;
31 componentItem->m_entry = ItemEntry( ent, comp.get() );
32 componentItem->m_parent = entityItem;
33 for ( const auto& roIdx : comp->m_renderObjects ) {
34 EngineTreeItem* roItem = new EngineTreeItem;
35 roItem->m_entry = ItemEntry( ent, comp.get(), roIdx );
36 roItem->m_parent = componentItem;
37 roItem->setChecked( roManager->getRenderObject( roIdx )->isVisible() );
38 componentItem->m_children.emplace_back( roItem );
39 }
40 entityItem->m_children.emplace_back( componentItem );
41 }
42 }
43 m_rootItem->m_children.emplace_back( entityItem );
44 }
45}
46
47const ItemEntry& ItemModel::getEntry( const QModelIndex& index ) const {
48 return static_cast<EngineTreeItem*>( getItem( index ) )->m_entry;
49}
50
51QModelIndex ItemModel::findEntryIndex( const ItemEntry& entry ) const {
52 if ( entry.isValid() ) {
54 stack.push( m_rootItem.get() );
55 while ( !stack.empty() ) {
56 EngineTreeItem* item = static_cast<EngineTreeItem*>( stack.top() );
57 stack.pop();
58 // Found item, so build the index corresponding to it.
59 if ( item->m_entry == entry ) {
60 return createIndex( item->getIndexInParent(), 0, item );
61 }
62
63 // Add children to the stack
64 for ( const auto& child : item->m_children ) {
65 stack.push( child.get() );
66 }
67 }
68 }
69
70 return QModelIndex();
71}
72
73void ItemModel::addItem( const Engine::Scene::ItemEntry& ent ) {
74 CORE_ASSERT( ent.isValid(), "Inserting invalid entry" );
75 CORE_ASSERT( !findEntryIndex( ent ).isValid(), "Entry already in model" );
76 auto roManager = m_engine->getRenderObjectManager();
77
78 if ( !findEntryIndex( ent ).isValid() ) {
79 TreeItem* parentItem;
80 QModelIndex parentIdx;
81 if ( ent.isEntityNode() ) { parentItem = m_rootItem.get(); }
82 else {
83 ItemEntry parentEntry;
84 if ( ent.isRoNode() ) { parentEntry = ItemEntry( ent.m_entity, ent.m_component ); }
85 else if ( ent.isComponentNode() ) { parentEntry = ItemEntry( ent.m_entity ); }
86 parentIdx = findEntryIndex( parentEntry );
87 CORE_ASSERT( parentIdx.isValid(), "Parent does not exist" );
88 parentItem = getItem( parentIdx );
89 }
90
91 CORE_ASSERT( getItem( parentIdx ) == parentItem, "Model inconsistency" );
92
93 EngineTreeItem* childItem = new EngineTreeItem;
94 childItem->m_entry = ent;
95 childItem->m_parent = parentItem;
96 if ( ent.isRoNode() ) {
97 childItem->setChecked( roManager->getRenderObject( ent.m_roIndex )->isVisible() );
98 // update parent checkbox if every ro aren't visible
99 bool checked = roManager->getRenderObject( ent.m_roIndex )->isVisible();
100 auto pent = static_cast<EngineTreeItem*>( parentItem )->m_entry.m_component;
101 for ( const auto& roIdx : pent->getRenderObjects() ) {
102 checked = checked || roManager->getRenderObject( roIdx )->isVisible();
103 }
104
105 parentItem->setChecked( checked );
106 }
107 else if ( ent.isComponentNode() ) {
108 //
109 bool checked = false;
110 for ( const auto& roIdx : ent.m_component->getRenderObjects() ) {
111 checked = checked || roManager->getRenderObject( roIdx )->isVisible();
112 }
113 childItem->setChecked( checked );
114 }
115
116 int row = int( parentItem->m_children.size() );
117 beginInsertRows( parentIdx, row, row );
118 parentItem->m_children.emplace_back( childItem );
119 endInsertRows();
120 }
121}
122
123void ItemModel::removeItem( const Engine::Scene::ItemEntry& ent ) {
124 QModelIndex entryIndex = findEntryIndex( ent );
125 CORE_ASSERT( ent.isValid(), "Removing invalid entry" );
126 CORE_ASSERT( entryIndex.isValid(), "Entry not in model" );
127 if ( entryIndex.isValid() ) {
128 EngineTreeItem* toRemove = static_cast<EngineTreeItem*>( getItem( entryIndex ) );
129 TreeItem* parentItem = toRemove->m_parent;
130 auto& childList = parentItem->m_children;
131 const auto childPos =
132 std::find_if( childList.begin(), childList.end(), [toRemove]( const auto& ptr ) {
133 return ptr.get() == toRemove;
134 } );
135
136 CORE_ASSERT( childPos != childList.end(), "Child not in parent's list" );
137 int row = toRemove->getIndexInParent();
138 CORE_ASSERT( childPos - childList.begin() == row, "Iterator consistency error" );
139 beginRemoveRows( parent( entryIndex ), row, row );
140 parentItem->m_children.erase( childPos );
141 endRemoveRows();
142 }
143}
144
145void ItemModel::onDataChanged( const QModelIndex& topLeft,
146 const QModelIndex& bottomRight,
147 const QVector<int>& roles ) {
148 if ( topLeft == bottomRight && roles.size() == 1 && roles.first() == Qt::CheckStateRole ) {
149 auto index = topLeft;
150 if ( index.isValid() ) {
151 bool visible = getItem( index )->isChecked();
152 auto ent = getEntry( index );
153
154 if ( ent.isValid() && ent.isRoNode() ) {
155 emit visibilityROChanged( ent.m_roIndex, visible );
156 }
157 }
158 }
159}
160
162 CORE_ASSERT( m_parent, "Looking for the root item's index." );
163 for ( uint i = 0; i < m_parent->m_children.size(); ++i ) {
164 if ( m_parent->m_children[i].get() == this ) { return i; }
165 }
166 // If we reached here, it means that the item
167 // was not found in its parent's child list.
168 // indicating the tree is corrupted.
169 CORE_ASSERT( false, " Did not find child in parent" );
170 return -1;
171}
172
173} // namespace Gui
174} // namespace Ra
Scene::EntityManager * getEntityManager() const
Rendering::RenderObjectManager * getRenderObjectManager() const
Manager getters.
void buildModel() override
Internal function to build the tree.
QModelIndex findEntryIndex(const Engine::Scene::ItemEntry &entry) const
const Engine::Scene::ItemEntry & getEntry(const QModelIndex &index) const
const Engine::RadiumEngine * m_engine
Engine instance.
Base class for element of the tree representation.
Definition TreeModel.hpp:31
int getIndexInParent() const
std::vector< std::unique_ptr< TreeItem > > m_children
Children of item in the tree.
Definition TreeModel.hpp:70
TreeItem * getItem(const QModelIndex &index) const
Get the tree item corresponding to the given index.
Definition TreeModel.cpp:24
QModelIndex parent(const QModelIndex &child) const override
Definition TreeModel.cpp:79
std::unique_ptr< TreeItem > m_rootItem
Root of the tree.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Definition TreeModel.cpp:67
T empty(T... args)
T find_if(T... args)
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:4
T pop(T... args)
T push(T... args)
Ra::Core::Utils::Index m_roIndex
RO index of the represented object.
Definition ItemEntry.hpp:66
bool isValid() const
Returns true if the item represents any valid object.
Definition ItemEntry.cpp:43
bool isComponentNode() const
Returns true if the item represents a component.
Definition ItemEntry.hpp:84
Entity * m_entity
The entity represented by the item, or owning the object represented.
Definition ItemEntry.hpp:59
bool isEntityNode() const
Returns true if the item represents an entity.
Definition ItemEntry.hpp:79
bool isRoNode() const
Returns true if the item represents a render object.
Definition ItemEntry.hpp:89
T top(T... args)