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