!I (1670414, 1670415, 1670416, 1670424, 1670431):
[CRYENGINE.git] / Code / Sandbox / Plugins / EditorSchematyc / GraphNodeItem.cpp
blobfbb314b8176b371be66ae1361ed7d1065830baf6
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
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>
15 #include <QString>
17 namespace CrySchematycEditor {
19 CNodeItem::CNodeItem(Schematyc::IScriptGraphNode& scriptNode, CryGraphEditor::CNodeGraphViewModel& model)
20 : CAbstractNodeItem(model)
21 , m_scriptNode(scriptNode)
22 , m_isDirty(false)
24 SetAcceptsRenaming(false);
25 SetAcceptsDeactivation(false);
27 LoadFromScriptElement();
30 CNodeItem::~CNodeItem()
32 for (CryGraphEditor::CAbstractPinItem* pItem : m_pins)
33 delete pItem;
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
42 return pNodeWidget;
45 void CNodeItem::Serialize(Serialization::IArchive& archive)
47 Schematyc::ESerializationPass serPass;
48 if (archive.isEdit())
50 serPass = Schematyc::ESerializationPass::Edit;
52 else
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())
70 Refresh(true);
72 // TODO: This should happen in Serialize(...) function not here.
73 gEnv->pSchematyc->GetScriptRegistry().ElementModified(m_scriptNode.GetGraph().GetElement());
74 // ~TODO
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())
85 Refresh(true);
87 // TODO: This should happen in Serialize(...) function not here.
88 gEnv->pSchematyc->GetScriptRegistry().ElementModified(m_scriptNode.GetGraph().GetElement());
89 // ~TODO
92 Validate();
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
138 if (id.IsInput())
140 for (CryGraphEditor::CAbstractPinItem* pAbstractPinItem : m_pins)
142 CPinItem* pPinItem = static_cast<CPinItem*>(pAbstractPinItem);
143 if (pPinItem->IsInputPin() && pPinItem->GetPortId() == id.GetPortId())
145 return pPinItem;
149 else
151 for (CryGraphEditor::CAbstractPinItem* pAbstractPinItem : m_pins)
153 CPinItem* pPinItem = static_cast<CPinItem*>(pAbstractPinItem);
154 if (pPinItem->IsOutputPin() && pPinItem->GetPortId() == id.GetPortId())
156 return pPinItem;
161 return nullptr;
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);
188 // ~TODO
190 if (m_isDirty || forceRefresh)
192 m_isDirty = false;
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));
196 // ~TODO
198 RefreshName();
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);
224 else
226 CPinItem* pPinItem = static_cast<CPinItem*>(*result);
227 pins.push_back(pPinItem);
229 *result = nullptr;
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);
251 else
253 CPinItem* pPinItem = static_cast<CPinItem*>(*result);
254 pins.push_back(pPinItem);
256 *result = nullptr;
260 m_pins.swap(pins);
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();
271 // ~TODO
273 SignalPinRemoved(*pPinItem);
274 delete pPinItem;
278 size_t inputIdx = 0;
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++);
285 else
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).
298 // ~TODO
300 RefreshName();
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());
325 Validate();
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)
342 switch (messageType)
344 case Schematyc::EValidatorMessageType::Warning:
346 ++warningCount;
347 break;
349 case Schematyc::EValidatorMessageType::Error:
351 ++errorCount;
352 break;
356 m_scriptNode.Validate(validateScriptNode);
358 CAbstractNodeItem::SetWarnings(warningCount > 0);
359 CAbstractNodeItem::SetErrors(errorCount > 0);
361 SignalValidated(*this);