1 // Copyright 2001-2019 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());
130 // TODO: Move this into an CAbstractNodeItem method.
131 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
133 CUndo::Record(new CryGraphEditor::CUndoNodeNameChange(*this, oldName
.c_str()));
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
);
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
);
192 CFeatureItem
* pFeatureItem
= *result
;
193 features
.push_back(pFeatureItem
);
194 if (pFeatureItem
->HasComponentConnector())
196 pins
.push_back(pFeatureItem
->GetPinItem());
199 pFeatureItem
->SignalInvalidated();
205 for (size_t i
= 0; i
< m_features
.size(); ++i
)
207 if (m_features
[i
] != nullptr)
211 CRY_ASSERT(m_features
.size() == movedFeatures
);
213 m_features
.swap(features
);
216 CRY_ASSERT(m_features
.size() == numFeatures
);
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
)
246 CFeatureItem
* CNodeItem::AddFeature(uint32 index
, const pfx2::SParticleFeatureParams
& featureParams
)
248 m_component
.AddFeature(index
, featureParams
);
250 pfx2::IParticleFeature
* pFeature
= m_component
.GetFeature(index
);
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
);
262 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
264 CUndo::Record(new CUndoFeatureCreate(*pFeatureItem
));
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
));
301 SignalFeatureRemoved(*pFeatureItem
);
304 if (index
< m_component
.GetNumFeatures())
305 m_component
.RemoveFeature(index
);
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
)
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
);
336 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
338 CUndo::Record(new CUndoFeatureMove(*pFeatureItem
, featureIndex
));
346 void CNodeItem::SetVisible(bool isVisible
)
348 if (isVisible
!= m_component
.IsVisible())
350 m_component
.SetVisible(isVisible
);
351 SignalVisibleChanged(isVisible
);
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
390 return pOtherPin
->IsInputPin() && !pOtherPin
->IsConnected();
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()))
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
)
416 m_pPin
= HasComponentConnector() ? new CFeaturePinItem(*this) : nullptr;
418 SetAcceptsDeactivation(true);
419 SetAcceptsHighlightning(true);
420 SetAcceptsSelection(true);
423 CFeatureItem::~CFeatureItem()
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();
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();
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
)
484 CRY_ASSERT_MESSAGE(0, "Invalid feature item!");
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());
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);