1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "ParticleGraphItems.h"
8 #include "Widgets/FeatureGridNodeContentWidget.h"
9 #include "Widgets/NodeIcons.h"
11 #include "ParticleGraphModel.h"
15 #include <NodeGraph/NodeWidget.h>
16 #include <NodeGraph/PinWidget.h>
17 #include <NodeGraph/ConnectionWidget.h>
18 #include <NodeGraph/NodeGraphViewStyle.h>
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
);
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
)
64 for (CFeatureItem
* pItem
: m_features
)
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
);
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());
129 // TODO: Move this into an CAbstractNodeItem method.
130 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
132 CUndo::Record(new CryGraphEditor::CUndoNodeNameChange(*this, oldName
.c_str()));
138 bool CNodeItem::IsDeactivated() const
140 return !m_component
.IsEnabled();
143 void CNodeItem::SetDeactivated(bool isDeactivated
)
145 if (IsDeactivated() != isDeactivated
)
147 m_component
.SetEnabled(!isDeactivated
);
148 SignalDeactivatedChanged(isDeactivated
);
149 static_cast<CParticleGraphModel
*>(&GetViewModel())->OnNodeItemChanged(this);
153 void CNodeItem::Serialize(Serialization::IArchive
& archive
)
155 const string oldName
= m_component
.GetName();
157 m_component
.Serialize(archive
);
159 // Note: Update everything.
160 const uint32 numFeatures
= m_component
.GetNumFeatures();
161 FeatureItemArray features
;
162 features
.reserve(numFeatures
);
163 CryGraphEditor::PinItemArray pins
;
164 pins
.push_back(m_pins
[0]);
165 pins
.push_back(m_pins
[1]);
167 size_t movedFeatures
= 0;
169 for (uint32 i
= 0; i
< numFeatures
; ++i
)
171 pfx2::IParticleFeature
* pFeatureInterface
= m_component
.GetFeature(i
);
172 auto predicate
= [pFeatureInterface
](CFeatureItem
* pFeatureItem
) -> bool
174 return (pFeatureItem
&& pFeatureInterface
== &pFeatureItem
->GetFeatureInterface());
177 auto result
= std::find_if(m_features
.begin(), m_features
.end(), predicate
);
178 if (result
== m_features
.end())
180 CFeatureItem
* pFeatureItem
= new CFeatureItem(*pFeatureInterface
, *this, GetViewModel());
181 features
.push_back(pFeatureItem
);
182 if (pFeatureItem
->HasComponentConnector())
184 pins
.push_back(pFeatureItem
->GetPinItem());
187 SignalFeatureAdded(*pFeatureItem
);
191 CFeatureItem
* pFeatureItem
= *result
;
192 features
.push_back(pFeatureItem
);
193 if (pFeatureItem
->HasComponentConnector())
195 pins
.push_back(pFeatureItem
->GetPinItem());
198 pFeatureItem
->SignalInvalidated();
204 for (size_t i
= 0; i
< m_features
.size(); ++i
)
206 if (m_features
[i
] != nullptr)
210 CRY_ASSERT(m_features
.size() == movedFeatures
);
212 m_features
.swap(features
);
215 CRY_ASSERT(m_features
.size() == numFeatures
);
220 CParentPinItem
* CNodeItem::GetParentPinItem()
222 return static_cast<CParentPinItem
*>(m_pins
[0]);
225 CChildPinItem
* CNodeItem::GetChildPinItem()
227 return static_cast<CChildPinItem
*>(m_pins
[1]);
230 uint32
CNodeItem::GetIndex() const
232 CParticleGraphModel
& model
= static_cast<CParticleGraphModel
&>(GetViewModel());
233 const pfx2::IParticleEffectPfx2
& effect
= model
.GetEffectInterface();
235 const uint32 numNodes
= effect
.GetNumComponents();
236 for (uint32 i
= 0; i
< numNodes
; ++i
)
238 if (effect
.GetComponent(i
) == &m_component
)
245 CFeatureItem
* CNodeItem::AddFeature(uint32 index
, const pfx2::SParticleFeatureParams
& featureParams
)
247 m_component
.AddFeature(index
, featureParams
);
249 pfx2::IParticleFeature
* pFeature
= m_component
.GetFeature(index
);
252 CFeatureItem
* pFeatureItem
= new CFeatureItem(*pFeature
, *this, GetViewModel());
253 m_features
.insert(m_features
.begin() + index
, pFeatureItem
);
254 if (pFeatureItem
->HasComponentConnector())
256 m_pins
.push_back(pFeatureItem
->GetPinItem());
258 SignalFeatureAdded(*pFeatureItem
);
260 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
262 CUndo::Record(new CUndoFeatureCreate(*pFeatureItem
));
270 void CNodeItem::RemoveFeature(uint32 index
)
272 if (m_features
.size() > index
)
274 CFeatureItem
* pFeatureItem
= m_features
.at(index
);
276 GetViewModel().SignalRemoveCustomItem(*pFeatureItem
);
277 SignalFeatureRemoved(*pFeatureItem
);
279 m_features
.erase(m_features
.begin() + index
);
281 if (CFeaturePinItem
* pFeaturePinItem
= pFeatureItem
->GetPinItem())
283 if (pFeaturePinItem
->IsConnected())
285 CParticleGraphModel
& model
= static_cast<CParticleGraphModel
&>(GetViewModel());
286 for (CryGraphEditor::CAbstractConnectionItem
* pConnectionItem
: pFeaturePinItem
->GetConnectionItems())
288 model
.RemoveConnection(*pConnectionItem
);
291 auto result
= std::find(m_pins
.begin(), m_pins
.end(), pFeatureItem
->GetPinItem());
292 CRY_ASSERT(result
!= m_pins
.end());
293 m_pins
.erase(result
);
296 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
297 CUndo::Record(new CUndoFeatureRemove(*pFeatureItem
));
302 if (index
< m_component
.GetNumFeatures())
303 m_component
.RemoveFeature(index
);
306 bool CNodeItem::MoveFeatureAtIndex(uint32 featureIndex
, uint32 destIndex
)
308 const uint32 maxIndex
= m_features
.size() - 1;
309 destIndex
= std::min(destIndex
, maxIndex
);
310 if (featureIndex
!= destIndex
)
312 const size_t numFeatures
= m_features
.size();
313 std::vector
<uint32
> ids
;
314 ids
.reserve(m_features
.size());
316 for (size_t i
= 0; i
< numFeatures
; ++i
)
319 CFeatureItem
* pFeatureItem
= m_features
[featureIndex
];
321 ids
.erase(ids
.begin() + featureIndex
);
322 ids
.insert(ids
.begin() + destIndex
, featureIndex
);
324 m_component
.SwapFeatures(&ids
[0], ids
.size());
326 m_features
.erase(m_features
.begin() + featureIndex
);
327 m_features
.insert(m_features
.begin() + destIndex
, pFeatureItem
);
329 if (m_component
.GetFeature(destIndex
) == &pFeatureItem
->GetFeatureInterface())
331 SignalFeatureMoved(*pFeatureItem
);
332 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
334 CUndo::Record(new CUndoFeatureMove(*pFeatureItem
, featureIndex
));
342 void CNodeItem::SetVisible(bool isVisible
)
344 if (isVisible
!= m_component
.IsVisible())
346 m_component
.SetVisible(isVisible
);
347 SignalVisibleChanged(isVisible
);
348 static_cast<CParticleGraphModel
*>(&GetViewModel())->OnNodeItemChanged(this);
352 bool CNodeItem::IsVisible()
354 return m_component
.IsVisible();
357 CFeaturePinItem::CFeaturePinItem(CFeatureItem
& feature
)
358 : CBasePinItem(feature
.GetNodeItem())
359 , m_featureItem(feature
)
363 QString
CFeaturePinItem::GetName() const
365 return m_featureItem
.GetName();
368 QVariant
CFeaturePinItem::GetId() const
370 return QVariant::fromValue(m_featureItem
.GetName());
373 bool CFeaturePinItem::HasId(QVariant id
) const
375 return (m_featureItem
.GetName() == id
.value
<QString
>());
378 bool CFeaturePinItem::CanConnect(const CryGraphEditor::CAbstractPinItem
* pOtherPin
) const
381 return pOtherPin
->IsInputPin() && !pOtherPin
->IsConnected();
386 CFeatureItem::CFeatureItem(pfx2::IParticleFeature
& feature
, CNodeItem
& node
, CryGraphEditor::CNodeGraphViewModel
& viewModel
)
387 : CAbstractNodeGraphViewModelItem(viewModel
)
388 , m_featureInterface(feature
)
391 m_pPin
= HasComponentConnector() ? new CFeaturePinItem(*this) : nullptr;
393 SetAcceptsDeactivation(true);
394 SetAcceptsHighlightning(true);
395 SetAcceptsSelection(true);
398 CFeatureItem::~CFeatureItem()
403 bool CFeatureItem::IsDeactivated() const
405 return m_featureInterface
.IsEnabled() == false;
408 void CFeatureItem::SetDeactivated(bool isDeactivated
)
410 if (!m_featureInterface
.IsEnabled() != isDeactivated
)
412 m_featureInterface
.SetEnabled(!isDeactivated
);
413 m_node
.GetComponentInterface().SetChanged();
414 SignalItemDeactivatedChanged(isDeactivated
);
416 // Note: Property tree listens only to node properties changed
417 // events. So at least for now we need to invalidate the whole node.
418 m_node
.SignalInvalidated();
419 static_cast<CParticleGraphModel
*>(&GetViewModel())->OnNodeItemChanged(&m_node
);
423 void CFeatureItem::Serialize(Serialization::IArchive
& archive
)
425 pfx2::IParticleComponent
& component
= GetNodeItem().GetComponentInterface();
426 Serialization::SContext
context(archive
, &component
);
427 m_featureInterface
.Serialize(archive
);
428 if (archive
.isInput())
430 component
.SetChanged();
435 QString
CFeatureItem::GetGroupName() const
437 const pfx2::SParticleFeatureParams
& params
= m_featureInterface
.GetFeatureParams();
438 return QString(params
.m_groupName
);
441 QString
CFeatureItem::GetName() const
443 const pfx2::SParticleFeatureParams
& params
= m_featureInterface
.GetFeatureParams();
444 return QString(params
.m_featureName
);
447 uint32
CFeatureItem::GetIndex() const
449 pfx2::IParticleComponent
& component
= m_node
.GetComponentInterface();
451 for (uint32 i
= 0; i
< component
.GetNumFeatures(); ++i
)
453 if (component
.GetFeature(i
) == &m_featureInterface
)
459 CRY_ASSERT_MESSAGE(0, "Invalid feature item!");
463 bool CFeatureItem::HasComponentConnector() const
465 const pfx2::SParticleFeatureParams
& params
= m_featureInterface
.GetFeatureParams();
466 return params
.m_hasComponentConnector
;
469 QColor
CFeatureItem::GetColor() const
471 const pfx2::SParticleFeatureParams
& params
= m_featureInterface
.GetFeatureParams();
472 return QColor(params
.m_color
.r
, params
.m_color
.g
, params
.m_color
.b
);
475 CConnectionItem::CConnectionItem(CBasePinItem
& sourcePin
, CBasePinItem
& targetPin
, CryGraphEditor::CNodeGraphViewModel
& viewModel
)
476 : CryGraphEditor::CAbstractConnectionItem(viewModel
)
477 , m_sourcePin(sourcePin
)
478 , m_targetPin(targetPin
)
480 m_sourcePin
.AddConnection(*this);
481 m_targetPin
.AddConnection(*this);
483 string sourceNodeName
= QtUtil::ToString(m_sourcePin
.GetNodeItem().GetName());
484 string sourceNodePin
= QtUtil::ToString(m_sourcePin
.GetName());
485 string targetNodeName
= QtUtil::ToString(m_targetPin
.GetNodeItem().GetName());
486 string targetNodePin
= QtUtil::ToString(m_targetPin
.GetName());
489 id
.Format("%s-%s::%s-%s", sourceNodeName
, sourceNodePin
, targetNodeName
, targetNodePin
);
491 m_id
= CCrc32::Compute(id
.c_str());
494 CConnectionItem::~CConnectionItem()
499 CryGraphEditor::CConnectionWidget
* CConnectionItem::CreateWidget(CryGraphEditor::CNodeGraphView
& view
)
501 return new CryGraphEditor::CConnectionWidget(this, view
);
504 QVariant
CConnectionItem::GetId() const
506 return QVariant::fromValue(m_id
);
509 bool CConnectionItem::HasId(QVariant id
) const
511 return (GetId().value
<uint32
>() == id
.value
<uint32
>());
514 void CConnectionItem::OnConnectionRemoved()
516 m_sourcePin
.RemoveConnection(*this);
517 m_targetPin
.RemoveConnection(*this);