INSTINCT Code Coverage Report


Directory: src/
File: internal/FlowManager.cpp
Date: 2025-11-25 23:34:18
Exec Total Coverage
Lines: 276 401 68.8%
Functions: 34 43 79.1%
Branches: 335 952 35.2%

Line Branch Exec Source
1 // This file is part of INSTINCT, the INS Toolkit for Integrated
2 // Navigation Concepts and Training by the Institute of Navigation of
3 // the University of Stuttgart, Germany.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9 #include "internal/FlowManager.hpp"
10
11 #include "util/Json.hpp"
12
13 #include <implot.h>
14 #include <imgui_node_editor.h>
15 namespace ed = ax::NodeEditor;
16
17 #include "NodeRegistry.hpp"
18
19 #include "internal/Node/Node.hpp"
20 #include "internal/Node/Pin.hpp"
21 #include "internal/ConfigManager.hpp"
22 #include "internal/FlowExecutor.hpp"
23
24 #include "internal/gui/windows/ImPlotStyleEditor.hpp"
25 #include "internal/gui/NodeEditorApplication.hpp"
26 #include "internal/gui/windows/NodeEditorStyleEditor.hpp"
27 #include "util/Plot/Colormap.hpp"
28 #include "util/Logger/CommonLog.hpp"
29
30 #include <fstream>
31 #include <set>
32 #include <iomanip>
33 #include <string>
34 #include <memory>
35
36 #include <iostream>
37
38 namespace NAV::flow
39 {
40 namespace
41 {
42
43 std::vector<NAV::Node*> m_nodes;
44 size_t m_NextId = 1;
45
46 bool unsavedChanges = false;
47
48 constexpr int loadingFramesToWait = 2;
49
50 std::string currentFilename;
51 std::filesystem::path programRootPath;
52
53 // The current number for the rotated parent folder
54 size_t currentRotatedParentFolderNumber;
55
56 int loadingFrameCount = 0;
57
58 12594 size_t GetNextId()
59 {
60 12594 return m_NextId++;
61 }
62
63 } // namespace
64
65 } // namespace NAV::flow
66
67 1371 const std::vector<NAV::Node*>& NAV::flow::m_Nodes()
68 {
69 1371 return m_nodes;
70 }
71
72 357 ax::NodeEditor::NodeId NAV::flow::GetNextNodeId()
73 {
74
1/2
✓ Branch 2 taken 357 times.
✗ Branch 3 not taken.
357 return { GetNextId() };
75 }
76
77 3 ax::NodeEditor::LinkId NAV::flow::GetNextLinkId()
78 {
79
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 return { GetNextId() };
80 }
81
82 12234 ax::NodeEditor::PinId NAV::flow::GetNextPinId()
83 {
84
1/2
✓ Branch 2 taken 12234 times.
✗ Branch 3 not taken.
12234 return { GetNextId() };
85 }
86
87 357 void NAV::flow::AddNode(NAV::Node* node)
88 {
89
1/2
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
357 if (!node->id)
90 {
91 357 node->id = GetNextNodeId();
92 }
93 357 m_nodes.push_back(node);
94
2/4
✓ Branch 2 taken 357 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 357 times.
✗ Branch 7 not taken.
357 LOG_DEBUG("Creating node: {}", node->nameId());
95
96
2/2
✓ Branch 4 taken 216 times.
✓ Branch 5 taken 357 times.
573 for (auto& pin : node->inputPins)
97 {
98 216 pin.parentNode = node;
99 }
100
2/2
✓ Branch 4 taken 273 times.
✓ Branch 5 taken 357 times.
630 for (auto& pin : node->outputPins)
101 {
102 273 pin.parentNode = node;
103 }
104
105
1/2
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
357 m_NextId = std::max(m_NextId, size_t(node->id) + 1);
106
2/2
✓ Branch 4 taken 216 times.
✓ Branch 5 taken 357 times.
573 for (const auto& pin : node->inputPins)
107 {
108
1/2
✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
216 m_NextId = std::max(m_NextId, size_t(pin.id) + 1);
109 }
110
2/2
✓ Branch 4 taken 273 times.
✓ Branch 5 taken 357 times.
630 for (const auto& pin : node->outputPins)
111 {
112
1/2
✓ Branch 1 taken 273 times.
✗ Branch 2 not taken.
273 m_NextId = std::max(m_NextId, size_t(pin.id) + 1);
113 }
114
115 357 flow::ApplyChanges();
116 357 }
117
118 357 void NAV::flow::UpdateNode(Node* node)
119 {
120 LOG_TRACE("called for node: {}", node->nameId());
121
2/2
✓ Branch 4 taken 302 times.
✓ Branch 5 taken 357 times.
659 for (auto& pin : node->inputPins)
122 {
123 302 pin.parentNode = node;
124 }
125
2/2
✓ Branch 4 taken 294 times.
✓ Branch 5 taken 357 times.
651 for (auto& pin : node->outputPins)
126 {
127 294 pin.parentNode = node;
128 }
129
130
2/2
✓ Branch 4 taken 302 times.
✓ Branch 5 taken 357 times.
659 for (const auto& pin : node->inputPins)
131 {
132
1/2
✓ Branch 1 taken 302 times.
✗ Branch 2 not taken.
302 m_NextId = std::max(m_NextId, size_t(pin.id) + 1);
133 }
134
2/2
✓ Branch 4 taken 294 times.
✓ Branch 5 taken 357 times.
651 for (const auto& pin : node->outputPins)
135 {
136
1/2
✓ Branch 1 taken 294 times.
✗ Branch 2 not taken.
294 m_NextId = std::max(m_NextId, size_t(pin.id) + 1);
137 }
138 357 }
139
140 355 bool NAV::flow::DeleteNode(ax::NodeEditor::NodeId nodeId)
141 {
142 LOG_TRACE("called for node with id {}", size_t(nodeId));
143
144
1/2
✓ Branch 1 taken 355 times.
✗ Branch 2 not taken.
1474 auto it = std::ranges::find_if(m_nodes, [nodeId](const auto& node) { return node->id == nodeId; });
145
1/2
✓ Branch 2 taken 355 times.
✗ Branch 3 not taken.
355 if (it != m_nodes.end())
146 {
147 355 Node* node = *it;
148
1/2
✓ Branch 2 taken 355 times.
✗ Branch 3 not taken.
355 m_nodes.erase(it);
149
3/6
✓ Branch 1 taken 355 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 355 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 355 times.
✗ Branch 9 not taken.
355 LOG_DEBUG("Deleting node: {}", node->nameId());
150
151
3/4
✓ Branch 1 taken 355 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 347 times.
✓ Branch 4 taken 8 times.
355 if (node->isInitialized())
152 {
153
1/2
✓ Branch 1 taken 347 times.
✗ Branch 2 not taken.
347 node->doDeinitialize(true);
154 }
155
2/2
✓ Branch 5 taken 301 times.
✓ Branch 6 taken 355 times.
656 for (auto& inputPin : node->inputPins)
156 {
157
3/4
✓ Branch 1 taken 301 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 188 times.
✓ Branch 4 taken 113 times.
301 if (inputPin.isPinLinked())
158 {
159
1/2
✓ Branch 1 taken 188 times.
✗ Branch 2 not taken.
188 inputPin.deleteLink();
160 }
161 }
162
2/2
✓ Branch 5 taken 293 times.
✓ Branch 6 taken 355 times.
648 for (auto& outputPin : node->outputPins)
163 {
164
3/4
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 75 times.
✓ Branch 4 taken 218 times.
293 if (outputPin.isPinLinked())
165 {
166
1/2
✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
75 outputPin.deleteLinks();
167 }
168 }
169
170
1/2
✓ Branch 0 taken 355 times.
✗ Branch 1 not taken.
355 delete node; // NOLINT(cppcoreguidelines-owning-memory)
171
172
1/2
✓ Branch 1 taken 355 times.
✗ Branch 2 not taken.
355 flow::ApplyChanges();
173
174 355 return true;
175 }
176
177 return false;
178 }
179
180 227 void NAV::flow::DeleteAllNodes()
181 {
182 LOG_TRACE("called");
183
184
2/2
✓ Branch 1 taken 355 times.
✓ Branch 2 taken 227 times.
582 while (!m_nodes.empty())
185 {
186 355 flow::DeleteNode(m_nodes.back()->id);
187 }
188
189 227 m_NextId = 1;
190
191 227 flow::ApplyChanges();
192 227 }
193
194 293 void NAV::flow::AddLink(ax::NodeEditor::LinkId linkId)
195 {
196
1/2
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
293 m_NextId = std::max(m_NextId, size_t(linkId) + 1);
197 293 }
198
199 222 NAV::Node* NAV::flow::FindNode(ax::NodeEditor::NodeId id)
200 {
201
1/2
✓ Branch 5 taken 330 times.
✗ Branch 6 not taken.
330 for (auto& node : m_nodes)
202 {
203
3/4
✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 222 times.
✓ Branch 4 taken 108 times.
330 if (node->id == id)
204 {
205 222 return node;
206 }
207 }
208
209 return nullptr;
210 }
211
212 39 NAV::OutputPin* NAV::flow::FindOutputPin(ax::NodeEditor::PinId id)
213 {
214
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 if (!id) { return nullptr; }
215
216
1/2
✓ Branch 5 taken 42 times.
✗ Branch 6 not taken.
42 for (auto& node : m_nodes)
217 {
218
3/6
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
42 if (!node || node->kind == Node::Kind::GroupBox) { continue; }
219
2/2
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 3 times.
45 for (auto& pin : node->outputPins)
220 {
221
3/4
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
✓ Branch 4 taken 3 times.
42 if (pin.id == id) { return &pin; }
222 }
223 }
224
225 return nullptr;
226 }
227
228 NAV::InputPin* NAV::flow::FindInputPin(ax::NodeEditor::PinId id)
229 {
230 if (!id) { return nullptr; }
231
232 for (auto& node : m_nodes)
233 {
234 if (!node || node->kind == Node::Kind::GroupBox) { continue; }
235 for (auto& pin : node->inputPins)
236 {
237 if (pin.id == id) { return &pin; }
238 }
239 }
240
241 return nullptr;
242 }
243
244 113 void NAV::flow::EnableAllCallbacks()
245 {
246 LOG_TRACE("called");
247
2/2
✓ Branch 5 taken 355 times.
✓ Branch 6 taken 113 times.
468 for (auto* node : m_nodes)
248 {
249
8/10
✓ Branch 0 taken 355 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 355 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 354 times.
✓ Branch 6 taken 1 times.
✓ Branch 8 taken 350 times.
✓ Branch 9 taken 4 times.
✓ Branch 10 taken 350 times.
✓ Branch 11 taken 5 times.
355 if (node && !node->isDisabled() && node->kind != Node::Kind::GroupBox)
250 {
251 350 node->callbacksEnabled = true;
252 }
253 }
254 113 }
255
256 226 void NAV::flow::DisableAllCallbacks()
257 {
258 LOG_TRACE("called");
259
2/2
✓ Branch 4 taken 710 times.
✓ Branch 5 taken 226 times.
936 for (auto* node : m_nodes)
260 {
261 710 node->callbacksEnabled = false;
262 }
263 226 }
264
265 113 void NAV::flow::ClearAllNodeQueues()
266 {
267 LOG_TRACE("called");
268
2/2
✓ Branch 5 taken 355 times.
✓ Branch 6 taken 113 times.
468 for (auto* node : m_nodes)
269 {
270
2/2
✓ Branch 5 taken 301 times.
✓ Branch 6 taken 355 times.
656 for (auto& inputPin : node->inputPins)
271 {
272 301 inputPin.queue.clear();
273 }
274 }
275 113 }
276
277 227 bool NAV::flow::InitializeAllNodes()
278 {
279 LOG_TRACE("called");
280 227 bool nodeCouldNotInitialize = false;
281
282 227 InitializeAllNodesAsync();
283
284
2/2
✓ Branch 5 taken 712 times.
✓ Branch 6 taken 227 times.
939 for (auto* node : m_nodes)
285 {
286
11/14
✓ Branch 0 taken 712 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 704 times.
✓ Branch 4 taken 8 times.
✓ Branch 6 taken 704 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 702 times.
✓ Branch 9 taken 2 times.
✓ Branch 11 taken 702 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 157 times.
✓ Branch 14 taken 545 times.
✓ Branch 15 taken 157 times.
✓ Branch 16 taken 555 times.
712 if (node && node->kind != Node::Kind::GroupBox && !node->isDisabled() && !node->isInitialized())
287 {
288
3/4
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 156 times.
157 if (!node->doInitialize(true))
289 {
290
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 LOG_ERROR("Node '{}' could not initialize.", node->nameId());
291 1 nodeCouldNotInitialize = true;
292 }
293 }
294 }
295
296 227 return !nodeCouldNotInitialize;
297 }
298
299 227 void NAV::flow::InitializeAllNodesAsync()
300 {
301 LOG_TRACE("called");
302
303
2/2
✓ Branch 5 taken 712 times.
✓ Branch 6 taken 227 times.
939 for (auto* node : m_nodes)
304 {
305
11/14
✓ Branch 0 taken 712 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 704 times.
✓ Branch 4 taken 8 times.
✓ Branch 6 taken 704 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 702 times.
✓ Branch 9 taken 2 times.
✓ Branch 11 taken 702 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 352 times.
✓ Branch 14 taken 350 times.
✓ Branch 15 taken 352 times.
✓ Branch 16 taken 360 times.
712 if (node && node->kind != Node::Kind::GroupBox && !node->isDisabled() && !node->isInitialized())
306 {
307
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
352 node->doInitialize();
308 }
309 }
310 227 }
311
312 void NAV::flow::SaveFlow(GlobalActions& globalAction)
313 {
314 if (currentFilename.empty())
315 {
316 globalAction = GlobalActions::SaveAs;
317 }
318 else
319 {
320 SaveFlowAs(currentFilename);
321 }
322 }
323
324 void NAV::flow::SaveFlowAs(const std::string& filepath)
325 {
326 std::ofstream filestream(filepath);
327
328 if (!filestream.good())
329 {
330 std::cerr << "Save Flow error: Could not open file: " << filepath;
331 return;
332 }
333
334 json j;
335 for (const auto& node : m_Nodes())
336 {
337 j["nodes"]["node-" + std::to_string(size_t(node->id))] = *node;
338 j["nodes"]["node-" + std::to_string(size_t(node->id))]["data"] = node->save();
339
340 for (const auto& outputPin : node->outputPins)
341 {
342 for (const auto& link : outputPin.links)
343 {
344 auto& jLink = j["links"]["link-" + std::to_string(size_t(link.linkId))];
345 jLink["id"] = size_t(link.linkId);
346 jLink["startPinId"] = size_t(outputPin.id);
347 jLink["endPinId"] = size_t(link.connectedPinId);
348 }
349 }
350 }
351 if (gui::windows::saveConfigInFlow)
352 {
353 j["implot"]["style"] = ImPlot::GetStyle();
354 j["implot"]["prefereFlowOverGlobal"] = gui::windows::prefereFlowOverGlobal;
355 }
356
357 j["fonts"]["useBigDefaultFont"] = gui::NodeEditorApplication::isUsingBigDefaultFont();
358 j["fonts"]["useBigWindowFont"] = gui::NodeEditorApplication::isUsingBigWindowFont();
359 j["fonts"]["useBigPanelFont"] = gui::NodeEditorApplication::isUsingBigPanelFont();
360 j["fonts"]["useBigMonoFont"] = gui::NodeEditorApplication::isUsingBigMonoFont();
361 j["leftPane"]["hide"] = gui::NodeEditorApplication::hideLeftPane;
362 j["leftPane"]["leftWidth"] = gui::NodeEditorApplication::leftPaneWidth;
363 j["leftPane"]["rightWidth"] = gui::NodeEditorApplication::rightPaneWidth;
364 j["bottomViewHeight"] = gui::NodeEditorApplication::bottomViewHeight;
365 j["hideFPS"] = gui::NodeEditorApplication::hideFPS;
366 j["lightMode"] = gui::windows::nodeEditorLightMode;
367 j["gridLinesEnabled"] = ed::GetStyle().Colors[ed::StyleColor_Grid].w;
368 j["transparentWindows"] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w;
369
370 // if (ImGui::Checkbox("Light mode", &nodeEditorLightMode))
371 // {
372 // ApplyDarkLightMode(NodeEditorApplication::m_colors);
373 // flow::ApplyChanges();
374 // }
375
376 j["colormaps"] = ColormapsFlow;
377 j["commonLog"] = CommonLog::save();
378
379 filestream << std::setw(4) << j << std::endl; // NOLINT(performance-avoid-endl)
380
381 unsavedChanges = false;
382 }
383
384 114 bool NAV::flow::LoadFlow(const std::string& filepath)
385 {
386 LOG_TRACE("called for path {}", filepath);
387 114 bool loadSuccessful = true;
388
389 try
390 {
391
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 std::ifstream filestream(filepath);
392
393
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 114 times.
114 if (!filestream.good())
394 {
395 LOG_ERROR("Load Flow error: Could not open file: {}", filepath);
396 return false;
397 }
398
399
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 114 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
114 if (FlowExecutor::isRunning()) { FlowExecutor::stop(); }
400
401 114 json j;
402
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 filestream >> j;
403
404
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 DeleteAllNodes();
405
406
4/6
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 93 times.
✓ Branch 4 taken 21 times.
✓ Branch 7 taken 93 times.
✗ Branch 8 not taken.
114 if (!j.contains("commonLog")) { CommonLog::restore(json{}); }
407
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 LoadJson(j);
408
409 #ifdef TESTING
410
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 CallPreInitCallback();
411 #endif
412
413
3/6
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 114 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 114 times.
✗ Branch 8 not taken.
228 if (!ConfigManager::Get<bool>("noinit"))
414 {
415
3/6
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 114 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 114 times.
✗ Branch 8 not taken.
228 if (ConfigManager::Get<bool>("nogui"))
416 {
417
3/4
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 113 times.
114 if (!InitializeAllNodes())
418 {
419 1 loadSuccessful = false;
420 }
421 }
422 else
423 {
424 InitializeAllNodesAsync();
425 }
426 }
427
428
3/6
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 114 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 114 times.
228 if (!ConfigManager::Get<bool>("nogui"))
429 {
430 loadingFrameCount = ImGui::GetFrameCount();
431 }
432 114 unsavedChanges = false;
433
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 currentFilename = filepath;
434
435
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 std::string path = filepath;
436
3/6
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 114 times.
✗ Branch 5 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 114 times.
114 if (path.find(GetProgramRootPath().string()) != std::string::npos)
437 {
438 path = path.substr(GetProgramRootPath().string().size());
439 if (path.starts_with('\\') || path.starts_with('/')) { path = path.substr(1); }
440 }
441
442
2/4
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 114 times.
✗ Branch 6 not taken.
114 LOG_INFO("Loaded flow file: {}", path);
443 114 }
444 catch (const std::exception& e)
445 {
446 LOG_ERROR("Loading flow file failed with error: {}", e.what());
447 loadSuccessful = false;
448 }
449
450 114 return loadSuccessful;
451 }
452
453 114 bool NAV::flow::LoadJson(const json& j, bool requestNewIds)
454 {
455 114 bool loadSuccessful = true;
456
457
3/4
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 113 times.
114 if (j.contains("implot"))
458 {
459 1 gui::windows::saveConfigInFlow = true;
460
461
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 if (j.at("implot").contains("prefereFlowOverGlobal"))
462 {
463
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
1 j.at("implot").at("prefereFlowOverGlobal").get_to(gui::windows::prefereFlowOverGlobal);
464 }
465
466
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 std::filesystem::path filepath = flow::GetProgramRootPath();
467
4/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
2 if (std::filesystem::path inputPath{ ConfigManager::Get<std::string>("implot-config") };
468 1 inputPath.is_relative())
469 {
470
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 filepath /= inputPath;
471 }
472 else
473 {
474 filepath = inputPath;
475 1 }
476
477
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
1 if (gui::windows::prefereFlowOverGlobal || !std::filesystem::exists(filepath))
478 {
479
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
2 if (!ConfigManager::Get<bool>("nogui"))
480 {
481 if (j.at("implot").contains("style"))
482 {
483 j.at("implot").at("style").get_to(ImPlot::GetStyle());
484 }
485 }
486 }
487 1 }
488 else
489 {
490 113 gui::windows::saveConfigInFlow = false;
491 }
492
493
3/4
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 70 times.
✓ Branch 4 taken 44 times.
114 if (j.contains("colormaps"))
494 {
495
2/4
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 70 times.
✗ Branch 5 not taken.
70 j.at("colormaps").get_to(ColormapsFlow);
496 }
497 else
498 {
499 44 ColormapsFlow.clear();
500 }
501
5/8
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 93 times.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 21 times.
✗ Branch 10 not taken.
114 if (j.contains("commonLog")) { CommonLog::restore(j.at("commonLog")); }
502
503
3/6
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 114 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 114 times.
228 if (!ConfigManager::Get<bool>("nogui"))
504 {
505 if (j.contains("fonts"))
506 {
507 if (j.at("fonts").contains("useBigDefaultFont"))
508 {
509 gui::NodeEditorApplication::swapDefaultFont(j.at("fonts").at("useBigDefaultFont").get<bool>());
510 }
511 if (j.at("fonts").contains("useBigWindowFont"))
512 {
513 gui::NodeEditorApplication::swapWindowFont(j.at("fonts").at("useBigWindowFont").get<bool>());
514 }
515 if (j.at("fonts").contains("useBigPanelFont"))
516 {
517 gui::NodeEditorApplication::swapPanelFont(j.at("fonts").at("useBigPanelFont").get<bool>());
518 }
519 if (j.at("fonts").contains("useBigMonoFont"))
520 {
521 gui::NodeEditorApplication::swapMonoFont(j.at("fonts").at("useBigMonoFont").get<bool>());
522 }
523 }
524 if (j.contains("leftPane"))
525 {
526 j.at("leftPane").at("hide").get_to(gui::NodeEditorApplication::hideLeftPane);
527 j.at("leftPane").at("leftWidth").get_to(gui::NodeEditorApplication::leftPaneWidth);
528 j.at("leftPane").at("rightWidth").get_to(gui::NodeEditorApplication::rightPaneWidth);
529 }
530 if (j.contains("bottomViewHeight")) { j.at("bottomViewHeight").get_to(gui::NodeEditorApplication::bottomViewHeight); }
531 if (j.contains("hideFPS")) { j.at("hideFPS").get_to(gui::NodeEditorApplication::hideFPS); }
532 if (j.contains("lightMode"))
533 {
534 j.at("lightMode").get_to(gui::windows::nodeEditorLightMode);
535 gui::windows::ApplyDarkLightMode(gui::NodeEditorApplication::m_colors, ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w != 1.0F);
536 }
537 if (j.contains("gridLinesEnabled")) { j.at("gridLinesEnabled").get_to(ed::GetStyle().Colors[ed::StyleColor_Grid].w); }
538 if (j.contains("transparentWindows")) { j.at("transparentWindows").get_to(ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w); }
539 }
540
541
2/4
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 114 times.
✗ Branch 4 not taken.
114 if (j.contains("nodes"))
542 {
543
6/10
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 357 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 357 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 471 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 357 times.
✓ Branch 15 taken 114 times.
471 for (const auto& nodeJson : j.at("nodes"))
544 {
545
2/4
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 357 times.
357 if (!nodeJson.contains("type"))
546 {
547 LOG_ERROR("Node does not contain a type");
548 continue;
549 }
550 357 Node* node = nullptr;
551
2/4
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 1918 times.
✗ Branch 9 not taken.
1918 for (const auto& registeredNode : NAV::NodeRegistry::RegisteredNodes())
552 {
553
2/2
✓ Branch 5 taken 21000 times.
✓ Branch 6 taken 1561 times.
22561 for (const auto& nodeInfo : registeredNode.second)
554 {
555
4/6
✓ Branch 1 taken 21000 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21000 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 357 times.
✓ Branch 9 taken 20643 times.
21000 if (nodeInfo.type == nodeJson.at("type").get<std::string>())
556 {
557
1/2
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
357 node = nodeInfo.constructor();
558 357 break;
559 }
560 }
561
2/2
✓ Branch 0 taken 357 times.
✓ Branch 1 taken 1561 times.
1918 if (node != nullptr)
562 {
563 357 break;
564 }
565 }
566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 357 times.
357 if (node == nullptr)
567 {
568 LOG_ERROR("Node type ({}) is not a valid type.", nodeJson.at("type").get<std::string>());
569 loadSuccessful = false;
570 continue;
571 }
572
573
1/2
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
357 AddNode(node);
574 357 auto newNodeId = node->id;
575
576
1/2
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
357 nodeJson.get_to<Node>(*node);
577
2/4
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 357 times.
✗ Branch 4 not taken.
357 if (nodeJson.contains("data"))
578 {
579
2/4
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 357 times.
✗ Branch 5 not taken.
357 node->restore(nodeJson.at("data"));
580 }
581 // Load second time in case restore changed the amount of pins
582
1/2
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
357 nodeJson.get_to<Node>(*node);
583
584
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 357 times.
357 if (requestNewIds)
585 {
586 node->id = newNodeId;
587 for (auto& pin : node->inputPins)
588 {
589 pin.id = GetNextPinId();
590 }
591 for (auto& pin : node->outputPins)
592 {
593 pin.id = GetNextPinId();
594 }
595 }
596
597
1/2
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
357 UpdateNode(node);
598
599
3/6
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 357 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 357 times.
714 if (!ConfigManager::Get<bool>("nogui"))
600 {
601 ed::SetNodePosition(node->id, nodeJson.at("pos").get<ImVec2>());
602
603 if (node->getSize().x > 0 && node->getSize().y > 0)
604 {
605 ed::SetGroupSize(node->id, node->getSize());
606 }
607 }
608 }
609 }
610
611 // Collect the node ids which get new links to call the restoreAfterLinks function on them
612 114 std::set<Node*> newlyLinkedNodes;
613
614
3/4
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 77 times.
✓ Branch 4 taken 37 times.
114 if (j.contains("links"))
615 {
616
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 77 times.
231 for (size_t i = 0; i < 2; i++) // Run twice because pins can change type depending on other links
617 {
618
6/10
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 580 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 580 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 734 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 580 times.
✓ Branch 15 taken 154 times.
734 for (const auto& linkJson : j.at("links"))
619 {
620
2/4
✓ Branch 1 taken 580 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 580 times.
✗ Branch 5 not taken.
580 auto linkId = linkJson.at("id").get<size_t>();
621
2/4
✓ Branch 1 taken 580 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 580 times.
✗ Branch 5 not taken.
580 auto startPinId = linkJson.at("startPinId").get<size_t>();
622
2/4
✓ Branch 1 taken 580 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 580 times.
✗ Branch 5 not taken.
580 auto endPinId = linkJson.at("endPinId").get<size_t>();
623
624 580 InputPin* endPin = nullptr;
625 580 OutputPin* startPin = nullptr;
626
1/2
✓ Branch 6 taken 2776 times.
✗ Branch 7 not taken.
2776 for (auto* node : m_Nodes())
627 {
628
2/2
✓ Branch 0 taken 2150 times.
✓ Branch 1 taken 626 times.
2776 if (!endPin)
629 {
630
2/2
✓ Branch 5 taken 3124 times.
✓ Branch 6 taken 2150 times.
5274 for (auto& inputPin : node->inputPins)
631 {
632
3/4
✓ Branch 1 taken 3124 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 580 times.
✓ Branch 4 taken 2544 times.
3124 if (endPinId == size_t(inputPin.id)) { endPin = &inputPin; }
633 }
634 }
635
2/2
✓ Branch 0 taken 1934 times.
✓ Branch 1 taken 842 times.
2776 if (!startPin)
636 {
637
2/2
✓ Branch 5 taken 2208 times.
✓ Branch 6 taken 1934 times.
4142 for (auto& outputPin : node->outputPins)
638 {
639
3/4
✓ Branch 1 taken 2208 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 580 times.
✓ Branch 4 taken 1628 times.
2208 if (startPinId == size_t(outputPin.id)) { startPin = &outputPin; }
640 }
641 }
642
4/4
✓ Branch 0 taken 1422 times.
✓ Branch 1 taken 1354 times.
✓ Branch 2 taken 580 times.
✓ Branch 3 taken 842 times.
2776 if (startPin && endPin) { break; }
643 }
644
2/4
✓ Branch 0 taken 580 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 580 times.
✗ Branch 3 not taken.
580 if (startPin && endPin)
645 {
646
4/6
✓ Branch 1 taken 580 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 580 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 578 times.
580 if (!startPin->createLink(*endPin, linkId))
647 {
648 2 loadSuccessful = false;
649 2 continue;
650 }
651
1/2
✓ Branch 1 taken 578 times.
✗ Branch 2 not taken.
578 newlyLinkedNodes.insert(startPin->parentNode);
652
1/2
✓ Branch 1 taken 578 times.
✗ Branch 2 not taken.
578 newlyLinkedNodes.insert(endPin->parentNode);
653 }
654 }
655 }
656 }
657
2/4
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 114 times.
✗ Branch 4 not taken.
114 if (j.contains("nodes"))
658 {
659
2/2
✓ Branch 5 taken 315 times.
✓ Branch 6 taken 114 times.
429 for (auto* node : newlyLinkedNodes)
660 {
661
6/12
✓ Branch 1 taken 315 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 315 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 315 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 315 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 315 times.
✗ Branch 14 not taken.
✓ Branch 17 taken 315 times.
✗ Branch 18 not taken.
315 if (j.at("nodes").contains("node-" + std::to_string(size_t(node->id))))
662 {
663
3/6
✓ Branch 1 taken 315 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 315 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 315 times.
✗ Branch 9 not taken.
315 LOG_DEBUG("Calling restoreAtferLink() for new node '{}'", node->nameId());
664
665
5/10
✓ Branch 1 taken 315 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 315 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 315 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 315 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 315 times.
✗ Branch 14 not taken.
315 const auto& nodeJson = j.at("nodes").at("node-" + std::to_string(size_t(node->id)));
666
2/4
✓ Branch 1 taken 315 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 315 times.
✗ Branch 4 not taken.
315 if (nodeJson.contains("data"))
667 {
668
2/4
✓ Branch 1 taken 315 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 315 times.
✗ Branch 5 not taken.
315 node->restoreAtferLink(nodeJson.at("data"));
669 }
670 }
671 }
672 }
673
674 114 return loadSuccessful;
675 114 }
676
677 bool NAV::flow::HasUnsavedChanges()
678 {
679 return unsavedChanges;
680 }
681
682 13758 void NAV::flow::ApplyChanges()
683 {
684 // This prevents the newly loaded gui elements from triggering the unsaved changes
685
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 13758 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 13758 times.
13758 if (ImGui::GetCurrentContext() && ImGui::GetFrameCount() - loadingFrameCount >= loadingFramesToWait)
686 {
687 unsavedChanges = true;
688 }
689 13758 }
690
691 void NAV::flow::DiscardChanges()
692 {
693 unsavedChanges = false;
694 }
695
696 std::string NAV::flow::GetCurrentFilename()
697 {
698 return currentFilename;
699 }
700
701 void NAV::flow::SetCurrentFilename(const std::string& newFilename)
702 {
703 currentFilename = newFilename;
704 }
705
706 827 std::filesystem::path NAV::flow::GetProgramRootPath()
707 {
708 827 return programRootPath;
709 }
710
711 118 void NAV::flow::SetProgramRootPath(const std::filesystem::path& newRootPath)
712 {
713
1/2
✓ Branch 3 taken 118 times.
✗ Branch 4 not taken.
118 LOG_DEBUG("Program root path set to {}", newRootPath);
714 118 programRootPath = newRootPath;
715 118 }
716
717 262 std::filesystem::path NAV::flow::GetOutputPath()
718 {
719 262 std::filesystem::path filepath = flow::GetProgramRootPath();
720
721
4/8
✓ Branch 1 taken 262 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 262 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 262 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 262 times.
✗ Branch 11 not taken.
524 if (std::filesystem::path outputPath{ ConfigManager::Get<std::string>("output-path") };
722 262 outputPath.is_relative())
723 {
724
1/2
✓ Branch 1 taken 262 times.
✗ Branch 2 not taken.
262 filepath /= outputPath;
725 }
726 else
727 {
728 filepath = outputPath;
729 262 }
730
731
4/6
✓ Branch 1 taken 262 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 262 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 30 times.
✓ Branch 8 taken 232 times.
524 if (ConfigManager::Get<bool>("rotate-output"))
732 {
733
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
60 filepath /= fmt::format("{:04d}", currentRotatedParentFolderNumber);
734 }
735
736 262 return filepath;
737 }
738
739 127 void NAV::flow::SetOutputPath()
740 {
741 127 currentRotatedParentFolderNumber = 0;
742
2/2
✓ Branch 0 taken 1270091 times.
✓ Branch 1 taken 118 times.
1270209 for (int i = 10000; i >= 0; --i)
743 {
744
1/2
✓ Branch 1 taken 1270091 times.
✗ Branch 2 not taken.
1270091 std::filesystem::path outputDir{ programRootPath };
745
746
4/8
✓ Branch 1 taken 1270091 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1270091 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1270091 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1270091 times.
✗ Branch 11 not taken.
2540182 if (std::filesystem::path outputPath{ ConfigManager::Get<std::string>("output-path") };
747 1270091 outputPath.is_relative())
748 {
749
1/2
✓ Branch 1 taken 1270091 times.
✗ Branch 2 not taken.
1270091 outputDir /= outputPath;
750 }
751 else
752 {
753 outputDir = outputPath;
754 1270091 }
755
1/2
✓ Branch 1 taken 1270091 times.
✗ Branch 2 not taken.
2540182 outputDir /= fmt::format("{:04d}", i);
756
3/4
✓ Branch 1 taken 1270091 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 1270082 times.
1270091 if (std::filesystem::exists(outputDir))
757 {
758 9 currentRotatedParentFolderNumber = static_cast<size_t>(i + 1); // NOLINT(bugprone-misplaced-widening-cast)
759 9 break;
760 }
761 1270091 }
762
2/4
✓ Branch 2 taken 127 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 127 times.
✗ Branch 7 not taken.
127 LOG_DEBUG("Output directory set to {}", GetOutputPath());
763 127 }
764
765 331 std::filesystem::path NAV::flow::GetInputPath()
766 {
767 331 std::filesystem::path filepath = flow::GetProgramRootPath();
768
769
4/8
✓ Branch 1 taken 331 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 330 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 330 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 331 times.
✗ Branch 11 not taken.
662 if (std::filesystem::path inputPath{ ConfigManager::Get<std::string>("input-path") };
770 329 inputPath.is_relative())
771 {
772
1/2
✓ Branch 1 taken 332 times.
✗ Branch 2 not taken.
331 filepath /= inputPath;
773 }
774 else
775 {
776 filepath = inputPath;
777 332 }
778
779 331 return filepath;
780 }
781
782 3 std::filesystem::path NAV::flow::GetFlowPath()
783 {
784 3 std::filesystem::path filepath = flow::GetProgramRootPath();
785
786
4/8
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
6 if (std::filesystem::path inputPath{ ConfigManager::Get<std::string>("flow-path") };
787 3 inputPath.is_relative())
788 {
789
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 filepath /= inputPath;
790 }
791 else
792 {
793 filepath = inputPath;
794 3 }
795
796 3 return filepath;
797 }
798
799 std::filesystem::path NAV::flow::GetConfigPath()
800 {
801 return flow::GetProgramRootPath() / "config";
802 }
803
804 #ifdef TESTING
805
806 namespace
807 {
808 std::vector<std::pair<ax::NodeEditor::PinId, NAV::InputPin::WatcherCallback>> watcherPinList;
809 std::vector<std::pair<ax::NodeEditor::LinkId, NAV::InputPin::WatcherCallback>> watcherLinkList;
810
811 std::function<void()> preInitCallback = nullptr;
812 std::function<void()> cleanupCallback = nullptr;
813
814 } // namespace
815
816 144 void NAV::flow::RegisterWatcherCallbackToInputPin(ax::NodeEditor::PinId id, const InputPin::WatcherCallback& callback)
817 {
818 144 watcherPinList.emplace_back(id, callback);
819 144 }
820
821 void NAV::flow::RegisterWatcherCallbackToLink(ax::NodeEditor::LinkId id, const InputPin::WatcherCallback& callback)
822 {
823 watcherLinkList.emplace_back(id, callback);
824 }
825
826 113 void NAV::flow::ApplyWatcherCallbacks()
827 {
828
1/2
✗ Branch 7 not taken.
✓ Branch 8 taken 113 times.
113 for (auto& [linkId, callback] : watcherLinkList)
829 {
830 for (auto& node : m_nodes)
831 {
832 for (size_t pinIdx = 0; pinIdx < node->inputPins.size(); pinIdx++)
833 {
834 auto& pin = node->inputPins[pinIdx];
835 if (pin.isPinLinked() && pin.link.linkId == linkId)
836 {
837 LOG_DEBUG("Adding watcher callback on node '{}' on pin with index {}", pin.parentNode->nameId(), pinIdx);
838 pin.watcherCallbacks.emplace_back(callback);
839 }
840 }
841 }
842 }
843
844
2/2
✓ Branch 7 taken 144 times.
✓ Branch 8 taken 113 times.
257 for (auto& [id, callback] : watcherPinList)
845 {
846
2/2
✓ Branch 5 taken 742 times.
✓ Branch 6 taken 144 times.
886 for (auto& node : m_nodes)
847 {
848
2/2
✓ Branch 1 taken 726 times.
✓ Branch 2 taken 742 times.
1468 for (size_t pinIdx = 0; pinIdx < node->inputPins.size(); pinIdx++)
849 {
850 726 auto& pin = node->inputPins[pinIdx];
851
3/4
✓ Branch 1 taken 726 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 144 times.
✓ Branch 4 taken 582 times.
726 if (pin.id == id)
852 {
853
3/6
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 144 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 144 times.
✗ Branch 9 not taken.
144 LOG_DEBUG("Adding watcher callback on node '{}' on pin with index {}", pin.parentNode->nameId(), pinIdx);
854
1/2
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
144 pin.watcherCallbacks.emplace_back(callback);
855 }
856 }
857 }
858 }
859 113 }
860
861 104 void NAV::flow::RegisterPreInitCallback(std::function<void()> callback)
862 {
863 104 preInitCallback = std::move(callback);
864 104 }
865
866 114 void NAV::flow::CallPreInitCallback()
867 {
868
2/2
✓ Branch 1 taken 104 times.
✓ Branch 2 taken 10 times.
114 if (preInitCallback)
869 {
870 104 preInitCallback();
871 }
872 114 }
873
874 38 void NAV::flow::RegisterCleanupCallback(std::function<void()> callback)
875 {
876 38 cleanupCallback = std::move(callback);
877 38 }
878 113 void NAV::flow::CallCleanupCallback()
879 {
880
2/2
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 75 times.
113 if (cleanupCallback)
881 {
882 38 cleanupCallback();
883 }
884 113 }
885
886 114 void NAV::flow::ClearRegisteredCallbacks()
887 {
888 114 watcherPinList.clear();
889 114 watcherLinkList.clear();
890 114 preInitCallback = nullptr;
891 114 cleanupCallback = nullptr;
892 114 }
893
894 #endif
895