1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
5 #include "GraphNodeItem.h"
6 #include "GraphPinItem.h"
7 #include "GraphViewModel.h"
9 #include <CrySchematyc/Script/IScriptGraph.h>
11 #include <NodeGraph/NodeWidget.h>
12 #include <NodeGraph/PinGridNodeContentWidget.h>
13 #include <NodeGraph/NodeGraphUndo.h>
17 namespace CrySchematycEditor
{
19 CNodeItem::CNodeItem(Schematyc::IScriptGraphNode
& scriptNode
, CryGraphEditor::CNodeGraphViewModel
& model
)
20 : CAbstractNodeItem(model
)
21 , m_scriptNode(scriptNode
)
24 SetAcceptsRenaming(false);
25 SetAcceptsDeactivation(false);
27 LoadFromScriptElement();
30 CNodeItem::~CNodeItem()
32 for (CryGraphEditor::CAbstractPinItem
* pItem
: m_pins
)
36 CryGraphEditor::CNodeWidget
* CNodeItem::CreateWidget(CryGraphEditor::CNodeGraphView
& view
)
38 CryGraphEditor::CNodeWidget
* pNodeWidget
= new CryGraphEditor::CNodeWidget(*this, view
);
39 CryGraphEditor::CPinGridNodeContentWidget
* pContent
= new CryGraphEditor::CPinGridNodeContentWidget(*pNodeWidget
, view
);
41 // cppcheck-suppress memleak
45 void CNodeItem::Serialize(Serialization::IArchive
& archive
)
47 Schematyc::ESerializationPass serPass
;
50 serPass
= Schematyc::ESerializationPass::Edit
;
54 serPass
= archive
.isInput() ? Schematyc::ESerializationPass::Load
: Schematyc::ESerializationPass::Save
;
57 if (serPass
== Schematyc::ESerializationPass::Load
)
59 Schematyc::SSerializationContextParams
serializationContextParams(archive
, Schematyc::ESerializationPass::LoadDependencies
);
60 Schematyc::ISerializationContextPtr pSerializationContext
= gEnv
->pSchematyc
->CreateSerializationContext(serializationContextParams
);
62 m_scriptNode
.Serialize(archive
);
65 Schematyc::SSerializationContextParams
serializationContextParams(archive
, serPass
);
66 Schematyc::ISerializationContextPtr pSerializationContext
= gEnv
->pSchematyc
->CreateSerializationContext(serializationContextParams
);
68 if (archive
.isOutput() && archive
.isEdit())
72 // TODO: This should happen in Serialize(...) function not here.
73 gEnv
->pSchematyc
->GetScriptRegistry().ElementModified(m_scriptNode
.GetGraph().GetElement());
77 m_scriptNode
.Serialize(archive
);
79 if (archive
.isInput())
81 // We only want to do an immediate refresh if the change doesn't come from
82 // the editor. Otherwise we wait for the output serialization pass.
83 if (!archive
.isEdit())
87 // TODO: This should happen in Serialize(...) function not here.
88 gEnv
->pSchematyc
->GetScriptRegistry().ElementModified(m_scriptNode
.GetGraph().GetElement());
96 QPointF
CNodeItem::GetPosition() const
98 Vec2 pos
= m_scriptNode
.GetPos();
99 return QPointF(pos
.x
, pos
.y
);
102 void CNodeItem::SetPosition(QPointF position
)
104 Vec2
pos(position
.x(), position
.y());
105 m_scriptNode
.SetPos(pos
);
107 CAbstractNodeItem::SetPosition(position
);
108 if (GetIEditor()->GetIUndoManager()->IsUndoRecording())
110 CryGraphEditor::CUndoNodeMove
* pUndoObject
= new CryGraphEditor::CUndoNodeMove(*this);
111 CUndo::Record(pUndoObject
);
115 QVariant
CNodeItem::GetId() const
117 return QVariant::fromValue(m_scriptNode
.GetGUID());
120 bool CNodeItem::HasId(QVariant id
) const
122 return (id
.value
<CryGUID
>() == m_scriptNode
.GetGUID());
125 QVariant
CNodeItem::GetTypeId() const
127 return QVariant::fromValue(m_scriptNode
.GetTypeGUID());
130 CryGraphEditor::CAbstractPinItem
* CNodeItem::GetPinItemById(QVariant id
) const
132 const CPinId pinId
= id
.value
<CPinId
>();
133 return GetPinItemById(pinId
);
136 CPinItem
* CNodeItem::GetPinItemById(CPinId id
) const
140 for (CryGraphEditor::CAbstractPinItem
* pAbstractPinItem
: m_pins
)
142 CPinItem
* pPinItem
= static_cast<CPinItem
*>(pAbstractPinItem
);
143 if (pPinItem
->IsInputPin() && pPinItem
->GetPortId() == id
.GetPortId())
151 for (CryGraphEditor::CAbstractPinItem
* pAbstractPinItem
: m_pins
)
153 CPinItem
* pPinItem
= static_cast<CPinItem
*>(pAbstractPinItem
);
154 if (pPinItem
->IsOutputPin() && pPinItem
->GetPortId() == id
.GetPortId())
164 CryGUID
CNodeItem::GetGUID() const
166 return m_scriptNode
.GetGUID();
169 const char* CNodeItem::GetStyleId() const
171 return m_scriptNode
.GetStyleId();
174 bool CNodeItem::IsRemovable() const
176 return !m_scriptNode
.GetFlags().Check(Schematyc::EScriptGraphNodeFlags::NotRemovable
);
179 bool CNodeItem::IsPasteAllowed() const
181 return !m_scriptNode
.GetFlags().Check(Schematyc::EScriptGraphNodeFlags::NotCopyable
);
184 void CNodeItem::Refresh(bool forceRefresh
)
186 // TODO: This is a workaround for broken mappings after undo.
187 m_scriptNode
.GetGraph().FixMapping(m_scriptNode
);
190 if (m_isDirty
|| forceRefresh
)
194 // TODO: We shouldn't have to do this here but it's the only way to refresh the whole node for now!
195 m_scriptNode
.ProcessEvent(Schematyc::SScriptEvent(Schematyc::EScriptEventId::EditorPaste
));
200 // We iterate through all pins and check what was removed/added.
201 const uint32 numPins
= m_scriptNode
.GetInputCount() + m_scriptNode
.GetOutputCount();
203 CryGraphEditor::PinItemArray pins
;
204 pins
.reserve(numPins
);
206 const uint32 numInputPins
= m_scriptNode
.GetInputCount();
207 for (uint32 i
= 0; i
< numInputPins
; ++i
)
209 CPinId
pinId(m_scriptNode
.GetInputId(i
), CPinId::EType::Input
);
210 auto predicate
= [pinId
](CryGraphEditor::CAbstractPinItem
* pAbstractPinItem
) -> bool
212 CPinItem
* pPinItem
= static_cast<CPinItem
*>(pAbstractPinItem
);
213 return (pPinItem
&& pinId
== pPinItem
->GetPinId());
216 auto result
= std::find_if(m_pins
.begin(), m_pins
.end(), predicate
);
217 if (result
== m_pins
.end())
219 CPinItem
* pPinItem
= new CPinItem(i
, EPinFlag::Input
, *this, GetViewModel());
220 pins
.push_back(pPinItem
);
222 SignalPinAdded(*pPinItem
);
226 CPinItem
* pPinItem
= static_cast<CPinItem
*>(*result
);
227 pins
.push_back(pPinItem
);
233 const uint32 numOutputPins
= m_scriptNode
.GetOutputCount();
234 for (uint32 i
= 0; i
< numOutputPins
; ++i
)
236 CPinId
pinId(m_scriptNode
.GetOutputId(i
), CPinId::EType::Output
);
237 auto predicate
= [pinId
](CryGraphEditor::CAbstractPinItem
* pAbstractPinItem
) -> bool
239 CPinItem
* pPinItem
= static_cast<CPinItem
*>(pAbstractPinItem
);
240 return (pPinItem
&& pinId
== pPinItem
->GetPinId());
243 auto result
= std::find_if(m_pins
.begin(), m_pins
.end(), predicate
);
244 if (result
== m_pins
.end())
246 CPinItem
* pPinItem
= new CPinItem(i
, EPinFlag::Output
, *this, GetViewModel());
247 pins
.push_back(pPinItem
);
249 SignalPinAdded(*pPinItem
);
253 CPinItem
* pPinItem
= static_cast<CPinItem
*>(*result
);
254 pins
.push_back(pPinItem
);
261 CRY_ASSERT(m_pins
.size() == numPins
);
263 for (CryGraphEditor::CAbstractPinItem
* pPinItem
: pins
)
265 if (pPinItem
!= nullptr)
267 // TODO: We need to destroy the connections since Schematyc backend did so already without
268 // notifying the editor. Remove that as soon as we have proper communication between
269 // editor and backend.
270 pPinItem
->Disconnect();
273 SignalPinRemoved(*pPinItem
);
279 size_t outputIdx
= 0;
280 for (uint32 i
= 0; i
< m_pins
.size(); ++i
)
282 CPinItem
* pPinItem
= static_cast<CPinItem
*>(m_pins
.at(i
));
283 if (pPinItem
->IsInputPin())
284 pPinItem
->UpdateWithNewIndex(inputIdx
++);
286 pPinItem
->UpdateWithNewIndex(outputIdx
++);
288 pPinItem
->SignalInvalidated();
293 void CNodeItem::LoadFromScriptElement()
295 // TODO: Just call RefreshLayout(...) here?!
296 m_scriptNode
.ProcessEvent(Schematyc::SScriptEvent(Schematyc::EScriptEventId::EditorRefresh
));
297 // N.B. After the release of 5.3 we should figure out whether it's really necessary to refresh elements upon initial selection (as opposed to only refreshing when changes are made).
302 const Vec2 pos
= m_scriptNode
.GetPos();
303 SetPosition(QPoint(pos
.x
, pos
.y
));
305 const QString
styleId(GetStyleId());
307 const uint32 numInputs
= m_scriptNode
.GetInputCount();
308 for (uint32 i
= 0; i
< numInputs
; ++i
)
310 CryGraphEditor::CAbstractPinItem
* pPinItem
= new CPinItem(i
, EPinFlag::Input
, *this, GetViewModel());
311 m_pins
.push_back(pPinItem
);
314 const uint32 numOutputs
= m_scriptNode
.GetOutputCount();
315 for (uint32 i
= 0; i
< numOutputs
; ++i
)
317 CryGraphEditor::CAbstractPinItem
* pPinItem
= new CPinItem(i
, EPinFlag::Output
, *this, GetViewModel());
318 m_pins
.push_back(pPinItem
);
321 SetAcceptsDeletion(IsRemovable());
322 SetAcceptsCopy(IsCopyAllowed());
323 SetAcceptsPaste(IsPasteAllowed());
328 void CNodeItem::RefreshName()
330 m_shortName
= m_scriptNode
.GetName();
332 CNodeItem::SignalNameChanged();
335 void CNodeItem::Validate()
337 uint32 warningCount
= 0;
338 uint32 errorCount
= 0;
340 auto validateScriptNode
= [&warningCount
, &errorCount
](Schematyc::EValidatorMessageType messageType
, const char* szMessage
)
344 case Schematyc::EValidatorMessageType::Warning
:
349 case Schematyc::EValidatorMessageType::Error
:
356 m_scriptNode
.Validate(validateScriptNode
);
358 CAbstractNodeItem::SetWarnings(warningCount
> 0);
359 CAbstractNodeItem::SetErrors(errorCount
> 0);
361 SignalValidated(*this);