0.5.1
Loading...
Searching...
No Matches
FlowManager.cpp
Go to the documentation of this file.
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
10
11#include "util/Json.hpp"
12
13#include <implot.h>
14#include <imgui_node_editor.h>
15namespace ed = ax::NodeEditor;
16
17#include "NodeRegistry.hpp"
18
20#include "internal/Node/Pin.hpp"
23
29
30#include <fstream>
31#include <set>
32#include <iomanip>
33#include <string>
34#include <memory>
35
36#include <iostream>
37
38namespace NAV::flow
39{
40namespace
41{
42
43std::vector<NAV::Node*> m_nodes;
44size_t m_NextId = 1;
45
46bool unsavedChanges = false;
47
48constexpr int loadingFramesToWait = 2;
49
50std::string currentFilename;
51std::filesystem::path programRootPath;
52
53// The current number for the rotated parent folder
54size_t currentRotatedParentFolderNumber;
55
56int loadingFrameCount = 0;
57
58size_t GetNextId()
59{
60 return m_NextId++;
61}
62
63} // namespace
64
65} // namespace NAV::flow
66
67const std::vector<NAV::Node*>& NAV::flow::m_Nodes()
68{
69 return m_nodes;
70}
71
72ax::NodeEditor::NodeId NAV::flow::GetNextNodeId()
73{
74 return { GetNextId() };
75}
76
77ax::NodeEditor::LinkId NAV::flow::GetNextLinkId()
78{
79 return { GetNextId() };
80}
81
82ax::NodeEditor::PinId NAV::flow::GetNextPinId()
83{
84 return { GetNextId() };
85}
86
88{
89 if (!node->id)
90 {
91 node->id = GetNextNodeId();
92 }
93 m_nodes.push_back(node);
94 LOG_DEBUG("Creating node: {}", node->nameId());
95
96 for (auto& pin : node->inputPins)
97 {
98 pin.parentNode = node;
99 }
100 for (auto& pin : node->outputPins)
101 {
102 pin.parentNode = node;
103 }
104
105 m_NextId = std::max(m_NextId, size_t(node->id) + 1);
106 for (const auto& pin : node->inputPins)
107 {
108 m_NextId = std::max(m_NextId, size_t(pin.id) + 1);
109 }
110 for (const auto& pin : node->outputPins)
111 {
112 m_NextId = std::max(m_NextId, size_t(pin.id) + 1);
113 }
114
116}
117
119{
120 LOG_TRACE("called for node: {}", node->nameId());
121 for (auto& pin : node->inputPins)
122 {
123 pin.parentNode = node;
124 }
125 for (auto& pin : node->outputPins)
126 {
127 pin.parentNode = node;
128 }
129
130 for (const auto& pin : node->inputPins)
131 {
132 m_NextId = std::max(m_NextId, size_t(pin.id) + 1);
133 }
134 for (const auto& pin : node->outputPins)
135 {
136 m_NextId = std::max(m_NextId, size_t(pin.id) + 1);
137 }
138}
139
140bool NAV::flow::DeleteNode(ax::NodeEditor::NodeId nodeId)
141{
142 LOG_TRACE("called for node with id {}", size_t(nodeId));
143
144 auto it = std::ranges::find_if(m_nodes, [nodeId](const auto& node) { return node->id == nodeId; });
145 if (it != m_nodes.end())
146 {
147 Node* node = *it;
148 m_nodes.erase(it);
149 LOG_DEBUG("Deleting node: {}", node->nameId());
150
151 if (node->isInitialized())
152 {
153 node->doDeinitialize(true);
154 }
155 for (auto& inputPin : node->inputPins)
156 {
157 if (inputPin.isPinLinked())
158 {
159 inputPin.deleteLink();
160 }
161 }
162 for (auto& outputPin : node->outputPins)
163 {
164 if (outputPin.isPinLinked())
165 {
166 outputPin.deleteLinks();
167 }
168 }
169
170 delete node; // NOLINT(cppcoreguidelines-owning-memory)
171
173
174 return true;
175 }
176
177 return false;
178}
179
181{
182 LOG_TRACE("called");
183
184 while (!m_nodes.empty())
185 {
186 flow::DeleteNode(m_nodes.back()->id);
187 }
188
189 m_NextId = 1;
190
192}
193
194void NAV::flow::AddLink(ax::NodeEditor::LinkId linkId)
195{
196 m_NextId = std::max(m_NextId, size_t(linkId) + 1);
197}
198
199NAV::Node* NAV::flow::FindNode(ax::NodeEditor::NodeId id)
200{
201 for (auto& node : m_nodes)
202 {
203 if (node->id == id)
204 {
205 return node;
206 }
207 }
208
209 return nullptr;
210}
211
212NAV::OutputPin* NAV::flow::FindOutputPin(ax::NodeEditor::PinId id)
213{
214 if (!id) { return nullptr; }
215
216 for (auto& node : m_nodes)
217 {
218 if (!node || node->kind == Node::Kind::GroupBox) { continue; }
219 for (auto& pin : node->outputPins)
220 {
221 if (pin.id == id) { return &pin; }
222 }
223 }
224
225 return nullptr;
226}
227
228NAV::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
245{
246 LOG_TRACE("called");
247 for (auto* node : m_nodes)
248 {
249 if (node && !node->isDisabled() && node->kind != Node::Kind::GroupBox)
250 {
251 node->callbacksEnabled = true;
252 }
253 }
254}
255
257{
258 LOG_TRACE("called");
259 for (auto* node : m_nodes)
260 {
261 node->callbacksEnabled = false;
262 }
263}
264
266{
267 LOG_TRACE("called");
268 for (auto* node : m_nodes)
269 {
270 for (auto& inputPin : node->inputPins)
271 {
272 inputPin.queue.clear();
273 }
274 }
275}
276
278{
279 LOG_TRACE("called");
280 bool nodeCouldNotInitialize = false;
281
283
284 for (auto* node : m_nodes)
285 {
286 if (node && node->kind != Node::Kind::GroupBox && !node->isDisabled() && !node->isInitialized())
287 {
288 if (!node->doInitialize(true))
289 {
290 LOG_ERROR("Node '{}' could not initialize.", node->nameId());
291 nodeCouldNotInitialize = true;
292 }
293 }
294 }
295
296 return !nodeCouldNotInitialize;
297}
298
300{
301 LOG_TRACE("called");
302
303 for (auto* node : m_nodes)
304 {
305 if (node && node->kind != Node::Kind::GroupBox && !node->isDisabled() && !node->isInitialized())
306 {
307 node->doInitialize();
308 }
309 }
310}
311
313{
314 if (currentFilename.empty())
315 {
316 globalAction = GlobalActions::SaveAs;
317 }
318 else
319 {
320 SaveFlowAs(currentFilename);
321 }
322}
323
324void 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 }
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;
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
384bool NAV::flow::LoadFlow(const std::string& filepath)
385{
386 LOG_TRACE("called for path {}", filepath);
387 bool loadSuccessful = true;
388
389 try
390 {
391 std::ifstream filestream(filepath);
392
393 if (!filestream.good())
394 {
395 LOG_ERROR("Load Flow error: Could not open file: {}", filepath);
396 return false;
397 }
398
400
401 json j;
402 filestream >> j;
403
405
406 if (!j.contains("commonLog")) { CommonLog::restore(json{}); }
407 LoadJson(j);
408
409#ifdef TESTING
410 CallPreInitCallback();
411#endif
412
413 if (!ConfigManager::Get<bool>("noinit"))
414 {
415 if (ConfigManager::Get<bool>("nogui"))
416 {
417 if (!InitializeAllNodes())
418 {
419 loadSuccessful = false;
420 }
421 }
422 else
423 {
425 }
426 }
427
428 if (!ConfigManager::Get<bool>("nogui"))
429 {
430 loadingFrameCount = ImGui::GetFrameCount();
431 }
432 unsavedChanges = false;
433 currentFilename = filepath;
434
435 std::string path = filepath;
436 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 LOG_INFO("Loaded flow file: {}", path);
443 }
444 catch (const std::exception& e)
445 {
446 LOG_ERROR("Loading flow file failed with error: {}", e.what());
447 loadSuccessful = false;
448 }
449
450 return loadSuccessful;
451}
452
453bool NAV::flow::LoadJson(const json& j, bool requestNewIds)
454{
455 bool loadSuccessful = true;
456
457 if (j.contains("implot"))
458 {
460
461 if (j.at("implot").contains("prefereFlowOverGlobal"))
462 {
463 j.at("implot").at("prefereFlowOverGlobal").get_to(gui::windows::prefereFlowOverGlobal);
464 }
465
466 std::filesystem::path filepath = flow::GetProgramRootPath();
467 if (std::filesystem::path inputPath{ ConfigManager::Get<std::string>("implot-config") };
468 inputPath.is_relative())
469 {
470 filepath /= inputPath;
471 }
472 else
473 {
474 filepath = inputPath;
475 }
476
477 if (gui::windows::prefereFlowOverGlobal || !std::filesystem::exists(filepath))
478 {
479 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 }
488 else
489 {
491 }
492
493 if (j.contains("colormaps"))
494 {
495 j.at("colormaps").get_to(ColormapsFlow);
496 }
497 else
498 {
499 ColormapsFlow.clear();
500 }
501 if (j.contains("commonLog")) { CommonLog::restore(j.at("commonLog")); }
502
503 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 if (j.contains("nodes"))
542 {
543 for (const auto& nodeJson : j.at("nodes"))
544 {
545 if (!nodeJson.contains("type"))
546 {
547 LOG_ERROR("Node does not contain a type");
548 continue;
549 }
550 Node* node = nullptr;
551 for (const auto& registeredNode : NAV::NodeRegistry::RegisteredNodes())
552 {
553 for (const auto& nodeInfo : registeredNode.second)
554 {
555 if (nodeInfo.type == nodeJson.at("type").get<std::string>())
556 {
557 node = nodeInfo.constructor();
558 break;
559 }
560 }
561 if (node != nullptr)
562 {
563 break;
564 }
565 }
566 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 AddNode(node);
574 auto newNodeId = node->id;
575
576 nodeJson.get_to<Node>(*node);
577 if (nodeJson.contains("data"))
578 {
579 node->restore(nodeJson.at("data"));
580 }
581 // Load second time in case restore changed the amount of pins
582 nodeJson.get_to<Node>(*node);
583
584 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 UpdateNode(node);
598
599 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 std::set<Node*> newlyLinkedNodes;
613
614 if (j.contains("links"))
615 {
616 for (size_t i = 0; i < 2; i++) // Run twice because pins can change type depending on other links
617 {
618 for (const auto& linkJson : j.at("links"))
619 {
620 auto linkId = linkJson.at("id").get<size_t>();
621 auto startPinId = linkJson.at("startPinId").get<size_t>();
622 auto endPinId = linkJson.at("endPinId").get<size_t>();
623
624 InputPin* endPin = nullptr;
625 OutputPin* startPin = nullptr;
626 for (auto* node : m_Nodes())
627 {
628 if (!endPin)
629 {
630 for (auto& inputPin : node->inputPins)
631 {
632 if (endPinId == size_t(inputPin.id)) { endPin = &inputPin; }
633 }
634 }
635 if (!startPin)
636 {
637 for (auto& outputPin : node->outputPins)
638 {
639 if (startPinId == size_t(outputPin.id)) { startPin = &outputPin; }
640 }
641 }
642 if (startPin && endPin) { break; }
643 }
644 if (startPin && endPin)
645 {
646 if (!startPin->createLink(*endPin, linkId))
647 {
648 loadSuccessful = false;
649 continue;
650 }
651 newlyLinkedNodes.insert(startPin->parentNode);
652 newlyLinkedNodes.insert(endPin->parentNode);
653 }
654 }
655 }
656 }
657 if (j.contains("nodes"))
658 {
659 for (auto* node : newlyLinkedNodes)
660 {
661 if (j.at("nodes").contains("node-" + std::to_string(size_t(node->id))))
662 {
663 LOG_DEBUG("Calling restoreAtferLink() for new node '{}'", node->nameId());
664
665 const auto& nodeJson = j.at("nodes").at("node-" + std::to_string(size_t(node->id)));
666 if (nodeJson.contains("data"))
667 {
668 node->restoreAtferLink(nodeJson.at("data"));
669 }
670 }
671 }
672 }
673
674 return loadSuccessful;
675}
676
678{
679 return unsavedChanges;
680}
681
683{
684 // This prevents the newly loaded gui elements from triggering the unsaved changes
685 if (ImGui::GetCurrentContext() && ImGui::GetFrameCount() - loadingFrameCount >= loadingFramesToWait)
686 {
687 unsavedChanges = true;
688 }
689}
690
692{
693 unsavedChanges = false;
694}
695
697{
698 return currentFilename;
699}
700
701void NAV::flow::SetCurrentFilename(const std::string& newFilename)
702{
703 currentFilename = newFilename;
704}
705
706std::filesystem::path NAV::flow::GetProgramRootPath()
707{
708 return programRootPath;
709}
710
711void NAV::flow::SetProgramRootPath(const std::filesystem::path& newRootPath)
712{
713 LOG_DEBUG("Program root path set to {}", newRootPath);
714 programRootPath = newRootPath;
715}
716
717std::filesystem::path NAV::flow::GetOutputPath()
718{
719 std::filesystem::path filepath = flow::GetProgramRootPath();
720
721 if (std::filesystem::path outputPath{ ConfigManager::Get<std::string>("output-path") };
722 outputPath.is_relative())
723 {
724 filepath /= outputPath;
725 }
726 else
727 {
728 filepath = outputPath;
729 }
730
731 if (ConfigManager::Get<bool>("rotate-output"))
732 {
733 filepath /= fmt::format("{:04d}", currentRotatedParentFolderNumber);
734 }
735
736 return filepath;
737}
738
740{
741 currentRotatedParentFolderNumber = 0;
742 for (int i = 10000; i >= 0; --i)
743 {
744 std::filesystem::path outputDir{ programRootPath };
745
746 if (std::filesystem::path outputPath{ ConfigManager::Get<std::string>("output-path") };
747 outputPath.is_relative())
748 {
749 outputDir /= outputPath;
750 }
751 else
752 {
753 outputDir = outputPath;
754 }
755 outputDir /= fmt::format("{:04d}", i);
756 if (std::filesystem::exists(outputDir))
757 {
758 currentRotatedParentFolderNumber = static_cast<size_t>(i + 1); // NOLINT(bugprone-misplaced-widening-cast)
759 break;
760 }
761 }
762 LOG_DEBUG("Output directory set to {}", GetOutputPath());
763}
764
765std::filesystem::path NAV::flow::GetInputPath()
766{
767 std::filesystem::path filepath = flow::GetProgramRootPath();
768
769 if (std::filesystem::path inputPath{ ConfigManager::Get<std::string>("input-path") };
770 inputPath.is_relative())
771 {
772 filepath /= inputPath;
773 }
774 else
775 {
776 filepath = inputPath;
777 }
778
779 return filepath;
780}
781
782std::filesystem::path NAV::flow::GetFlowPath()
783{
784 std::filesystem::path filepath = flow::GetProgramRootPath();
785
786 if (std::filesystem::path inputPath{ ConfigManager::Get<std::string>("flow-path") };
787 inputPath.is_relative())
788 {
789 filepath /= inputPath;
790 }
791 else
792 {
793 filepath = inputPath;
794 }
795
796 return filepath;
797}
798
799std::filesystem::path NAV::flow::GetConfigPath()
800{
801 return flow::GetProgramRootPath() / "config";
802}
803
804#ifdef TESTING
805
806namespace
807{
808std::vector<std::pair<ax::NodeEditor::PinId, NAV::InputPin::WatcherCallback>> watcherPinList;
809std::vector<std::pair<ax::NodeEditor::LinkId, NAV::InputPin::WatcherCallback>> watcherLinkList;
810
811std::function<void()> preInitCallback = nullptr;
812std::function<void()> cleanupCallback = nullptr;
813
814} // namespace
815
816void NAV::flow::RegisterWatcherCallbackToInputPin(ax::NodeEditor::PinId id, const InputPin::WatcherCallback& callback)
817{
818 watcherPinList.emplace_back(id, callback);
819}
820
821void NAV::flow::RegisterWatcherCallbackToLink(ax::NodeEditor::LinkId id, const InputPin::WatcherCallback& callback)
822{
823 watcherLinkList.emplace_back(id, callback);
824}
825
826void NAV::flow::ApplyWatcherCallbacks()
827{
828 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 for (auto& [id, callback] : watcherPinList)
845 {
846 for (auto& node : m_nodes)
847 {
848 for (size_t pinIdx = 0; pinIdx < node->inputPins.size(); pinIdx++)
849 {
850 auto& pin = node->inputPins[pinIdx];
851 if (pin.id == id)
852 {
853 LOG_DEBUG("Adding watcher callback on node '{}' on pin with index {}", pin.parentNode->nameId(), pinIdx);
854 pin.watcherCallbacks.emplace_back(callback);
855 }
856 }
857 }
858 }
859}
860
861void NAV::flow::RegisterPreInitCallback(std::function<void()> callback)
862{
863 preInitCallback = std::move(callback);
864}
865
866void NAV::flow::CallPreInitCallback()
867{
868 if (preInitCallback)
869 {
870 preInitCallback();
871 }
872}
873
874void NAV::flow::RegisterCleanupCallback(std::function<void()> callback)
875{
876 cleanupCallback = std::move(callback);
877}
878void NAV::flow::CallCleanupCallback()
879{
880 if (cleanupCallback)
881 {
882 cleanupCallback();
883 }
884}
885
886void NAV::flow::ClearRegisteredCallbacks()
887{
888 watcherPinList.clear();
889 watcherLinkList.clear();
890 preInitCallback = nullptr;
891 cleanupCallback = nullptr;
892}
893
894#endif
Colormap.
Common logging variables like time into run and local positions.
Config management for the Project.
Flow Executor Thread.
Save/Load the Nodes.
nlohmann::json json
json namespace
GlobalActions
Possible Global Actions to perform in the GUI.
@ SaveAs
Save the flow as filename.
ImPlot style editor window.
Defines how to save certain datatypes to json.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
Definition Logger.hpp:67
#define LOG_ERROR
Error occurred, which stops part of the program to work, but not everything.
Definition Logger.hpp:73
#define LOG_INFO
Info to the user on the state of the program.
Definition Logger.hpp:69
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Definition Logger.hpp:65
Style Editor window.
Utility class which specifies available nodes.
Node Class.
Pin class.
static void restore(const json &j)
Read info from a json object.
Definition CommonLog.cpp:30
static json save()
Returns a json object of the common log.
Definition CommonLog.cpp:21
Input pins of nodes.
Definition Pin.hpp:491
Abstract parent class for all nodes.
Definition Node.hpp:92
bool isInitialized() const
Checks if the node is initialized.
Definition Node.cpp:574
bool doDeinitialize(bool wait=false)
Asks the node worker to deinitialize the node.
Definition Node.cpp:465
virtual void restore(const json &j)
Restores the node from a json object.
Definition Node.cpp:61
const ImVec2 & getSize() const
Get the size of the node.
Definition Node.cpp:328
std::vector< OutputPin > outputPins
List of output pins.
Definition Node.hpp:511
std::vector< InputPin > inputPins
List of input pins.
Definition Node.hpp:509
std::string nameId() const
Node name and id.
Definition Node.cpp:323
ax::NodeEditor::NodeId id
Unique Id of the Node.
Definition Node.hpp:503
Output pins of nodes.
Definition Pin.hpp:338
bool createLink(InputPin &endPin, ax::NodeEditor::LinkId linkId=0)
Creates a link from this pin to another, calling all node specific callbacks.
Definition Pin.cpp:255
Node * parentNode
Reference to the parent node.
Definition Pin.hpp:307
static float bottomViewHeight
Height of the log viewer.
static float leftPaneWidth
Width of the left pane.
static std::vector< ImVec4 > m_colors
Color settings.
static bool hideLeftPane
Hide left pane.
static float rightPaneWidth
Width of the right pane.
static bool hideFPS
Hide FPS counter.
const T & Get(const std::string &key, const T &&defaultValue)
Retrieves the value of a corresponding key from the configuration, if one exists.
bool isRunning() noexcept
Checks if the thread is running.
void stop()
Stops the Thread.
const std::map< std::string, std::vector< NodeInfo > > & RegisteredNodes()
Reference to List of all registered Nodes.
void UpdateNode(Node *node)
Update the provided node object.
InputPin * FindInputPin(ax::NodeEditor::PinId id)
Finds the Pin for the PinId.
ax::NodeEditor::LinkId GetNextLinkId()
Generates a new link id.
const std::vector< Node * > & m_Nodes()
List of all registered Nodes.
Node * FindNode(ax::NodeEditor::NodeId id)
Finds the Node for the NodeId.
void SetProgramRootPath(const std::filesystem::path &newRootPath)
Set the program root path.
bool LoadJson(const json &j, bool requestNewIds=false)
Loads the nodes and links from the specified json object.
void SetCurrentFilename(const std::string &newFilename)
Set the current filename of the open flow.
bool LoadFlow(const std::string &filepath)
Loads the flow from the specified file.
void DisableAllCallbacks()
Disables all Node callbacks.
std::filesystem::path GetConfigPath()
Get the path where config files are searched.
std::filesystem::path GetOutputPath()
Get the path where logs and outputs are stored.
void DeleteAllNodes()
Delete all nodes.
void SaveFlowAs(const std::string &filepath)
Saves the current flow into the specified file.
std::filesystem::path GetInputPath()
Get the path where data files are searched.
void DiscardChanges()
Discards the unsaved changes flag. Does not really discard the changes.
bool DeleteNode(ax::NodeEditor::NodeId nodeId)
Delete the node provided by id.
ax::NodeEditor::PinId GetNextPinId()
Generates a new pin id.
std::string GetCurrentFilename()
Get the current filename of the open flow.
void ApplyChanges()
Signals that there have been changes to the flow.
ax::NodeEditor::NodeId GetNextNodeId()
Generates a new node id.
void AddLink(ax::NodeEditor::LinkId linkId)
Adds the link.
std::filesystem::path GetFlowPath()
Get the path where flow files are searched.
void ClearAllNodeQueues()
Clears all nodes queues.
OutputPin * FindOutputPin(ax::NodeEditor::PinId id)
Finds the Pin for the PinId.
void EnableAllCallbacks()
Enables all Node callbacks.
std::filesystem::path GetProgramRootPath()
Get the program root path.
bool HasUnsavedChanges()
Checks if the currently open flow has unsaved changes.
void SaveFlow(GlobalActions &globalAction)
Saves the current flow into a file.
void SetOutputPath()
Set the path where logs and outputs are stored.
void AddNode(Node *node)
Add the provided node object to the list of nodes.
bool InitializeAllNodes()
Initializes all nodes.
void InitializeAllNodesAsync()
Initializes all nodes in a separate thread.
bool prefereFlowOverGlobal
If true, the ImPlot config from the flow file will be preferred over the global settings file.
bool nodeEditorLightMode
If true, light mode is selected.
void ApplyDarkLightMode(std::vector< ImVec4 > &colors, bool transparentWindows)
bool saveConfigInFlow
If true, the ImPlot config will be saved into the flow file.
std::vector< Colormap > ColormapsFlow
Flow colormaps.
Definition Colormap.cpp:27
@ GroupBox
Group box which can group other nodes and drag them together.
Definition Node.hpp:102