Merge remote-tracking branch 'public/release_candidate' into release
[CRYENGINE.git] / Code / Sandbox / Plugins / EditorParticle / Models / ParticleGraphItems.cpp
blob169db39f1176a5a6ddb025e5b096e16358f00649
1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
4 #include "ParticleGraphItems.h"
6 #include "../Undo.h"
8 #include "Widgets/FeatureGridNodeContentWidget.h"
9 #include "Widgets/NodeIcons.h"
11 #include "ParticleGraphModel.h"
13 #include "QtUtil.h"
15 #include <NodeGraph/NodeWidget.h>
16 #include <NodeGraph/PinWidget.h>
17 #include <NodeGraph/ConnectionWidget.h>
18 #include <NodeGraph/NodeGraphViewStyle.h>
20 #include <QVariant>
22 namespace CryParticleEditor {
24 CNodeItem::CNodeItem(pfx2::IParticleComponent& component, CryGraphEditor::CNodeGraphViewModel& viewModel)
25 : CAbstractNodeItem(*(m_pData = new CryGraphEditor::CNodeEditorData()), viewModel)
26 , m_component(component)
28 SetAcceptsDeactivation(true);
29 SetAcceptsRenaming(true);
31 m_name = component.GetName();
32 m_data.SetPos(Vec2(component.GetNodePosition().x, component.GetNodePosition().y));
34 uint32 featureCount = m_component.GetNumFeatures();
35 m_pins.reserve(featureCount + 1);
37 m_pins.push_back(new CParentPinItem(*this));
38 m_pins.push_back(new CChildPinItem(*this));
40 for (uint32 i = 0; i < featureCount; ++i)
42 pfx2::IParticleFeature* pFeature = m_component.GetFeature(i);
43 if (pFeature)
45 CFeatureItem* pFeatureItem = new CFeatureItem(*pFeature, *this, viewModel);
46 m_features.push_back(pFeatureItem);
47 if (pFeatureItem->HasComponentConnector())
49 m_pins.push_back(pFeatureItem->GetPinItem());
55 CNodeItem::~CNodeItem()
57 for (CryGraphEditor::CAbstractPinItem* pItem : m_pins)
59 CBasePinItem* pPintItem = static_cast<CBasePinItem*>(pItem);
60 if (pPintItem->GetPinType() == EPinType::Parent || pPintItem->GetPinType() == EPinType::Child)
61 delete pPintItem;
64 for (CFeatureItem* pItem : m_features)
66 delete pItem;
69 delete m_pData;
72 void CNodeItem::SetPosition(QPointF position)
74 m_component.SetNodePosition(Vec2(position.x(), position.y()));
75 CAbstractNodeItem::SetPosition(position);
76 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
78 CryGraphEditor::CUndoNodeMove* pUndoObject = new CryGraphEditor::CUndoNodeMove(*this);
79 CUndo::Record(pUndoObject);
83 CryGraphEditor::CNodeWidget* CNodeItem::CreateWidget(CryGraphEditor::CNodeGraphView& view)
85 CryGraphEditor::CNodeWidget* pNode = new CryGraphEditor::CNodeWidget(*this, view);
86 pNode->SetHeaderNameWidth(120);
87 CFeatureGridNodeContentWidget* pContent = new CFeatureGridNodeContentWidget(*pNode, static_cast<CParentPinItem&>(*m_pins[0]), static_cast<CChildPinItem&>(*m_pins[1]), view);
89 pNode->AddHeaderIcon(new CEmitterActiveIcon(*pNode), CryGraphEditor::CHeaderWidget::EIconSlot::Right);
90 pNode->AddHeaderIcon(new CEmitterVisibleIcon(*pNode), CryGraphEditor::CHeaderWidget::EIconSlot::Right);
91 pNode->AddHeaderIcon(new CSoloEmitterModeIcon(*pNode), CryGraphEditor::CHeaderWidget::EIconSlot::Right);
93 pNode->SetContentWidget(pContent);
95 return pNode;
98 QVariant CNodeItem::GetId() const
100 return QVariant::fromValue(QString(m_component.GetName()));
103 bool CNodeItem::HasId(QVariant id) const
105 QString nodeName = m_component.GetName();
106 return (nodeName == id.value<QString>());
109 QVariant CNodeItem::GetTypeId() const
111 // Note: Nodes in particle system don't have a type yet.
112 return QVariant::fromValue(QString());
115 QString CNodeItem::GetName() const
117 return QString(m_component.GetName());
120 void CNodeItem::SetName(const QString& name)
122 const string newName = QtUtil::ToString(name);
123 const string oldName = m_component.GetName();
124 if (oldName != newName)
126 m_component.SetName(newName.c_str());
127 CAbstractNodeItem::SetName(GetName());
128 OnChanged();
130 // TODO: Move this into an CAbstractNodeItem method.
131 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
133 CUndo::Record(new CryGraphEditor::CUndoNodeNameChange(*this, oldName.c_str()));
135 // ~TODO
139 bool CNodeItem::IsDeactivated() const
141 return !m_component.IsEnabled();
144 void CNodeItem::SetDeactivated(bool isDeactivated)
146 if (IsDeactivated() != isDeactivated)
148 m_component.SetEnabled(!isDeactivated);
149 SignalDeactivatedChanged(isDeactivated);
150 OnChanged();
154 void CNodeItem::Serialize(Serialization::IArchive& archive)
156 const string oldName = m_component.GetName();
158 m_component.Serialize(archive);
160 // Note: Update everything.
161 const uint32 numFeatures = m_component.GetNumFeatures();
162 FeatureItemArray features;
163 features.reserve(numFeatures);
164 CryGraphEditor::PinItemArray pins;
165 pins.push_back(m_pins[0]);
166 pins.push_back(m_pins[1]);
168 size_t movedFeatures = 0;
170 for (uint32 i = 0; i < numFeatures; ++i)
172 pfx2::IParticleFeature* pFeatureInterface = m_component.GetFeature(i);
173 auto predicate = [pFeatureInterface](CFeatureItem* pFeatureItem) -> bool
175 return (pFeatureItem && pFeatureInterface == &pFeatureItem->GetFeatureInterface());
178 auto result = std::find_if(m_features.begin(), m_features.end(), predicate);
179 if (result == m_features.end())
181 CFeatureItem* pFeatureItem = new CFeatureItem(*pFeatureInterface, *this, GetViewModel());
182 features.push_back(pFeatureItem);
183 if (pFeatureItem->HasComponentConnector())
185 pins.push_back(pFeatureItem->GetPinItem());
188 SignalFeatureAdded(*pFeatureItem);
190 else
192 CFeatureItem* pFeatureItem = *result;
193 features.push_back(pFeatureItem);
194 if (pFeatureItem->HasComponentConnector())
196 pins.push_back(pFeatureItem->GetPinItem());
199 pFeatureItem->SignalInvalidated();
200 *result = nullptr;
201 ++movedFeatures;
205 for (size_t i = 0; i < m_features.size(); ++i)
207 if (m_features[i] != nullptr)
208 RemoveFeature(i);
211 CRY_ASSERT(m_features.size() == movedFeatures);
213 m_features.swap(features);
214 m_pins.swap(pins);
216 CRY_ASSERT(m_features.size() == numFeatures);
218 SignalInvalidated();
221 CParentPinItem* CNodeItem::GetParentPinItem()
223 return static_cast<CParentPinItem*>(m_pins[0]);
226 CChildPinItem* CNodeItem::GetChildPinItem()
228 return static_cast<CChildPinItem*>(m_pins[1]);
231 uint32 CNodeItem::GetEffectIndex() const
233 CParticleGraphModel& model = static_cast<CParticleGraphModel&>(GetViewModel());
234 const pfx2::IParticleEffect& effect = model.GetEffectInterface();
236 const uint32 numNodes = effect.GetNumComponents();
237 for (uint32 i = 0; i < numNodes; ++i)
239 if (effect.GetComponent(i) == &m_component)
240 return i;
243 return ~0;
246 CFeatureItem* CNodeItem::AddFeature(uint32 index, const pfx2::SParticleFeatureParams& featureParams)
248 m_component.AddFeature(index, featureParams);
250 pfx2::IParticleFeature* pFeature = m_component.GetFeature(index);
251 if (pFeature)
253 CFeatureItem* pFeatureItem = new CFeatureItem(*pFeature, *this, GetViewModel());
254 m_features.insert(m_features.begin() + index, pFeatureItem);
255 if (pFeatureItem->HasComponentConnector())
257 m_pins.push_back(pFeatureItem->GetPinItem());
259 SignalFeatureAdded(*pFeatureItem);
260 OnChanged();
262 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
264 CUndo::Record(new CUndoFeatureCreate(*pFeatureItem));
267 return pFeatureItem;
269 return nullptr;
272 void CNodeItem::RemoveFeature(uint32 index)
274 if (m_features.size() > index)
276 CFeatureItem* pFeatureItem = m_features.at(index);
278 GetViewModel().SignalRemoveCustomItem(*pFeatureItem);
280 m_features.erase(m_features.begin() + index);
282 if (CFeaturePinItem* pFeaturePinItem = pFeatureItem->GetPinItem())
284 if (pFeaturePinItem->IsConnected())
286 CParticleGraphModel& model = static_cast<CParticleGraphModel&>(GetViewModel());
287 for (CryGraphEditor::CAbstractConnectionItem* pConnectionItem : pFeaturePinItem->GetConnectionItems())
289 model.RemoveConnection(*pConnectionItem);
292 auto result = std::find(m_pins.begin(), m_pins.end(), pFeatureItem->GetPinItem());
293 CRY_ASSERT(result != m_pins.end());
294 m_pins.erase(result);
297 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
298 CUndo::Record(new CUndoFeatureRemove(*pFeatureItem));
300 delete pFeatureItem;
301 SignalFeatureRemoved(*pFeatureItem);
304 if (index < m_component.GetNumFeatures())
305 m_component.RemoveFeature(index);
306 OnChanged();
309 bool CNodeItem::MoveFeatureAtIndex(uint32 featureIndex, uint32 destIndex)
311 const uint32 maxIndex = m_features.size() - 1;
312 destIndex = std::min(destIndex, maxIndex);
313 if (featureIndex != destIndex)
315 const size_t numFeatures = m_features.size();
316 std::vector<uint32> ids;
317 ids.reserve(m_features.size());
319 for (size_t i = 0; i < numFeatures; ++i)
320 ids.push_back(i);
322 CFeatureItem* pFeatureItem = m_features[featureIndex];
324 ids.erase(ids.begin() + featureIndex);
325 ids.insert(ids.begin() + destIndex, featureIndex);
327 m_component.SwapFeatures(&ids[0], ids.size());
329 m_features.erase(m_features.begin() + featureIndex);
330 m_features.insert(m_features.begin() + destIndex, pFeatureItem);
332 if (m_component.GetFeature(destIndex) == &pFeatureItem->GetFeatureInterface())
334 SignalFeatureMoved(*pFeatureItem);
335 OnChanged();
336 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
338 CUndo::Record(new CUndoFeatureMove(*pFeatureItem, featureIndex));
339 return true;
343 return false;
346 void CNodeItem::SetVisible(bool isVisible)
348 if (isVisible != m_component.IsVisible())
350 m_component.SetVisible(isVisible);
351 SignalVisibleChanged(isVisible);
352 OnChanged();
356 bool CNodeItem::IsVisible()
358 return m_component.IsVisible();
361 void CNodeItem::OnChanged()
363 static_cast<CParticleGraphModel*>(&GetViewModel())->OnNodeItemChanged(this);
366 CFeaturePinItem::CFeaturePinItem(CFeatureItem& feature)
367 : CBasePinItem(feature.GetNodeItem())
368 , m_featureItem(feature)
372 QString CFeaturePinItem::GetName() const
374 return m_featureItem.GetName();
377 QVariant CFeaturePinItem::GetId() const
379 return QVariant::fromValue(m_featureItem.GetName());
382 bool CFeaturePinItem::HasId(QVariant id) const
384 return (m_featureItem.GetName() == id.value<QString>());
387 bool CFeaturePinItem::CanConnect(const CryGraphEditor::CAbstractPinItem* pOtherPin) const
389 if (pOtherPin)
390 return pOtherPin->IsInputPin() && !pOtherPin->IsConnected();
392 return true;
395 bool CParentPinItem::CanConnect(const CryGraphEditor::CAbstractPinItem* pOtherPin) const
397 if (pOtherPin && pOtherPin->IsOutputPin() && !IsConnected())
399 const auto& otherNodeItem = static_cast<const CNodeItem&>(pOtherPin->GetNodeItem());
400 if (otherNodeItem.GetComponentInterface().CanBeParent(&m_nodeItem.GetComponentInterface()))
401 return true;
403 return false;
406 bool CChildPinItem::CanConnect(const CryGraphEditor::CAbstractPinItem* pOtherPin) const
408 return !pOtherPin || (pOtherPin->IsInputPin() && pOtherPin->CanConnect(this));
411 CFeatureItem::CFeatureItem(pfx2::IParticleFeature& feature, CNodeItem& node, CryGraphEditor::CNodeGraphViewModel& viewModel)
412 : CAbstractNodeGraphViewModelItem(viewModel)
413 , m_featureInterface(feature)
414 , m_node(node)
416 m_pPin = HasComponentConnector() ? new CFeaturePinItem(*this) : nullptr;
418 SetAcceptsDeactivation(true);
419 SetAcceptsHighlightning(true);
420 SetAcceptsSelection(true);
423 CFeatureItem::~CFeatureItem()
425 delete m_pPin;
428 bool CFeatureItem::IsDeactivated() const
430 return m_featureInterface.IsEnabled() == false;
433 void CFeatureItem::SetDeactivated(bool isDeactivated)
435 if (!m_featureInterface.IsEnabled() != isDeactivated)
437 m_featureInterface.SetEnabled(!isDeactivated);
438 m_node.GetComponentInterface().SetChanged();
439 SignalItemDeactivatedChanged(isDeactivated);
441 // Note: Property tree listens only to node properties changed
442 // events. So at least for now we need to invalidate the whole node.
443 m_node.SignalInvalidated();
444 m_node.OnChanged();
448 void CFeatureItem::Serialize(Serialization::IArchive& archive)
450 pfx2::IParticleComponent& component = GetNodeItem().GetComponentInterface();
451 Serialization::SContext context(archive, &component);
452 m_featureInterface.Serialize(archive);
453 if (archive.isInput())
455 component.SetChanged();
456 SignalInvalidated();
460 QString CFeatureItem::GetGroupName() const
462 const pfx2::SParticleFeatureParams& params = m_featureInterface.GetFeatureParams();
463 return QString(params.m_groupName);
466 QString CFeatureItem::GetName() const
468 const pfx2::SParticleFeatureParams& params = m_featureInterface.GetFeatureParams();
469 return QString(params.m_featureName);
472 uint32 CFeatureItem::GetIndex() const
474 pfx2::IParticleComponent& component = m_node.GetComponentInterface();
476 for (uint32 i = 0; i < component.GetNumFeatures(); ++i)
478 if (component.GetFeature(i) == &m_featureInterface)
480 return i;
484 CRY_ASSERT_MESSAGE(0, "Invalid feature item!");
485 return ~0;
488 bool CFeatureItem::HasComponentConnector() const
490 const pfx2::SParticleFeatureParams& params = m_featureInterface.GetFeatureParams();
491 return params.m_hasComponentConnector;
494 QColor CFeatureItem::GetColor() const
496 const pfx2::SParticleFeatureParams& params = m_featureInterface.GetFeatureParams();
497 return QColor(params.m_color.r, params.m_color.g, params.m_color.b);
500 CConnectionItem::CConnectionItem(CBasePinItem& sourcePin, CBasePinItem& targetPin, CryGraphEditor::CNodeGraphViewModel& viewModel)
501 : CryGraphEditor::CAbstractConnectionItem(sourcePin, targetPin, viewModel)
503 sourcePin.AddConnection(*this);
504 targetPin.AddConnection(*this);
506 string sourceNodeName = QtUtil::ToString(sourcePin.GetNodeItem().GetName());
507 string sourceNodePin = QtUtil::ToString(sourcePin.GetName());
508 string targetNodeName = QtUtil::ToString(targetPin.GetNodeItem().GetName());
509 string targetNodePin = QtUtil::ToString(targetPin.GetName());
511 string id;
512 id.Format("%s-%s::%s-%s", sourceNodeName, sourceNodePin, targetNodeName, targetNodePin);
514 m_id = CCrc32::Compute(id.c_str());
517 CryGraphEditor::CConnectionWidget* CConnectionItem::CreateWidget(CryGraphEditor::CNodeGraphView& view)
519 return new CryGraphEditor::CConnectionWidget(this, view);
522 QVariant CConnectionItem::GetId() const
524 return QVariant::fromValue(m_id);
527 bool CConnectionItem::HasId(QVariant id) const
529 return (GetId().value<uint32>() == id.value<uint32>());
532 void CConnectionItem::OnConnectionRemoved()
534 GetSourcePinItem().RemoveConnection(*this);
535 GetTargetPinItem().RemoveConnection(*this);