0.5.1
Loading...
Searching...
No Matches
GlobalActions.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
9#include "GlobalActions.hpp"
10
12
14
15#include <imgui_node_editor.h>
16#include <imgui_node_editor_internal.h>
17namespace ed = ax::NodeEditor;
18
19#include <nlohmann/json.hpp>
20using json = nlohmann::json; ///< json namespace
21#include "util/Json.hpp"
22
24
25#include <vector>
26#include <deque>
27#include <limits>
28#include <iterator>
29
30namespace NAV::gui
31{
32namespace
33{
34/// @brief Specifies if the elements in the clipboard are cutted or copied
35bool elementsCutted = false;
36/// @brief Clipboard storage
37json clipboard;
38
39} // namespace
40} // namespace NAV::gui
41
43{
44 return static_cast<bool>(ed::GetSelectedNodes(nullptr, ed::GetSelectedObjectCount()));
45}
46
48{
49 return !clipboard.empty();
50}
51
53{
54 std::vector<ax::NodeEditor::NodeId> selectedNodeIds;
55 selectedNodeIds.resize(static_cast<size_t>(ed::GetSelectedObjectCount()));
56
57 auto selectedNodesCount = ed::GetSelectedNodes(selectedNodeIds.data(), ed::GetSelectedObjectCount());
58 selectedNodeIds.resize(static_cast<size_t>(selectedNodesCount));
59
60 clipboard.clear();
61
62 for (const auto& nodeId : selectedNodeIds)
63 {
64 const NAV::Node* node = flow::FindNode(nodeId);
65
66 clipboard["nodes"]["node-" + std::to_string(size_t(node->id))] = *node;
67 clipboard["nodes"]["node-" + std::to_string(size_t(node->id))]["data"] = node->save();
68
69 for (const auto& outputPin : node->outputPins)
70 {
71 for (const auto& link : outputPin.links)
72 {
73 auto& j = clipboard["links"]["link-" + std::to_string(size_t(link.linkId))];
74 j["id"] = size_t(link.linkId);
75 j["startPinId"] = size_t(outputPin.id);
76 j["endPinId"] = size_t(link.connectedPinId);
77 }
78 }
79
80 flow::DeleteNode(nodeId);
81 }
82
83 elementsCutted = true;
84}
85
87{
88 std::vector<ax::NodeEditor::NodeId> selectedNodeIds;
89 selectedNodeIds.resize(static_cast<size_t>(ed::GetSelectedObjectCount()));
90
91 auto selectedNodesCount = ed::GetSelectedNodes(selectedNodeIds.data(), ed::GetSelectedObjectCount());
92 selectedNodeIds.resize(static_cast<size_t>(selectedNodesCount));
93
94 clipboard.clear();
95
96 for (const auto& nodeId : selectedNodeIds)
97 {
98 const NAV::Node* node = flow::FindNode(nodeId);
99
100 clipboard["nodes"]["node-" + std::to_string(size_t(node->id))] = *node;
101 clipboard["nodes"]["node-" + std::to_string(size_t(node->id))]["data"] = node->save();
102
103 for (const auto& outputPin : node->outputPins)
104 {
105 for (const auto& link : outputPin.links)
106 {
107 auto& j = clipboard["links"]["link-" + std::to_string(size_t(link.linkId))];
108 j["id"] = size_t(link.linkId);
109 j["startPinId"] = size_t(outputPin.id);
110 j["endPinId"] = size_t(link.connectedPinId);
111 }
112 }
113 }
114
115 elementsCutted = false;
116}
117
119{
120 // Store the node count to later iterate over the new nodes
121 auto nodeCountBeforeLoad = flow::m_Nodes().size();
122
123 LOG_DEBUG("Pasting clipboard {}", clipboard.dump(4));
124
125 flow::LoadJson(clipboard, !elementsCutted);
126
127 // Find Top Left Position of all new nodes to move them to the mouse cursor
128 ImVec2 leftTopMostPos{ std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() };
129 if (clipboard.contains("nodes"))
130 {
131 for (const auto& nodeJson : clipboard.at("nodes"))
132 {
133 ImVec2 pos;
134 if (nodeJson.contains("pos"))
135 {
136 nodeJson.at("pos").get_to(pos);
137
138 leftTopMostPos.x = std::min(pos.x, leftTopMostPos.x);
139 leftTopMostPos.y = std::min(pos.y, leftTopMostPos.y);
140 }
141 }
142 }
143
144 // Get Mouse Position in editor coordinates
145 auto viewRect = reinterpret_cast<ax::NodeEditor::Detail::EditorContext*>(ed::GetCurrentEditor())->GetViewRect();
146 ImVec2 mousePos = ImGui::GetMousePos();
149 mousePos *= ed::GetCurrentZoom();
150 mousePos += viewRect.GetTL();
151
152 // Move the Nodes relative to the current mouse position
153 for (size_t i = nodeCountBeforeLoad; i < flow::m_Nodes().size(); i++)
154 {
155 auto* node = flow::m_Nodes().at(i);
156 ed::SetNodePosition(node->id, mousePos + (ed::GetNodePosition(node->id) - leftTopMostPos));
157 }
158
159 // Collect the node ids which get new links to call the restoreAfterLinks function on them
160 std::map<size_t, ed::NodeId> newlyLinkedNodes;
161
162 // Recreate links
163 if (clipboard.contains("links"))
164 {
165 for (const auto& linkJson : clipboard.at("links"))
166 {
167 auto startPinId = linkJson.at("startPinId").get<size_t>();
168 auto endPinId = linkJson.at("endPinId").get<size_t>();
169
170 size_t startPinOldParentNodeId = 0;
171 size_t startPinParentNodeIndex = 0;
172 size_t startPinIndex = 0;
173 Pin::Kind startPinKind = Pin::Kind::None;
174
175 size_t endPinOldParentNodeId = 0;
176 size_t endPinParentNodeIndex = 0;
177 size_t endPinIndex = 0;
178 Pin::Kind endPinKind = Pin::Kind::None;
179
180 // Search for the nodes and pins which where connected by the old link
181 if (clipboard.contains("nodes"))
182 {
183 size_t nodeIndex = 0;
184 for (const auto& nodeJson : clipboard.at("nodes"))
185 {
186 if (nodeJson.contains("inputPins"))
187 {
188 size_t pinIndex = 0;
189 for (const auto& pinJson : nodeJson.at("inputPins"))
190 {
191 if (pinJson.at("id").get<size_t>() == startPinId)
192 {
193 startPinOldParentNodeId = nodeJson.at("id");
194 startPinParentNodeIndex = nodeCountBeforeLoad + nodeIndex;
195 startPinIndex = pinIndex;
196 startPinKind = Pin::Kind::Input;
197 }
198 if (pinJson.at("id").get<size_t>() == endPinId)
199 {
200 endPinOldParentNodeId = nodeJson.at("id");
201 endPinParentNodeIndex = nodeCountBeforeLoad + nodeIndex;
202 endPinIndex = pinIndex;
203 endPinKind = Pin::Kind::Input;
204 }
205 pinIndex++;
206 }
207 }
208 if (nodeJson.contains("outputPins"))
209 {
210 size_t pinIndex = 0;
211 for (const auto& pinJson : nodeJson.at("outputPins"))
212 {
213 if (pinJson.at("id").get<size_t>() == startPinId)
214 {
215 startPinOldParentNodeId = nodeJson.at("id");
216 startPinParentNodeIndex = nodeCountBeforeLoad + nodeIndex;
217 startPinIndex = pinIndex;
218 startPinKind = Pin::Kind::Output;
219 }
220 if (pinJson.at("id").get<size_t>() == endPinId)
221 {
222 endPinOldParentNodeId = nodeJson.at("id");
223 endPinParentNodeIndex = nodeCountBeforeLoad + nodeIndex;
224 endPinIndex = pinIndex;
225 endPinKind = Pin::Kind::Output;
226 }
227 pinIndex++;
228 }
229 }
230 nodeIndex++;
231 }
232 }
233
234 if (startPinKind != Pin::Kind::None && endPinKind != Pin::Kind::None)
235 {
236 if (startPinKind == Pin::Kind::Output && endPinKind == Pin::Kind::Input)
237 {
238 auto& startPin = flow::m_Nodes().at(startPinParentNodeIndex)->outputPins.at(startPinIndex);
239 auto& endPin = flow::m_Nodes().at(endPinParentNodeIndex)->inputPins.at(endPinIndex);
240
241 if (!endPin.isPinLinked())
242 {
243 startPin.createLink(endPin);
244 }
245 }
246
247 newlyLinkedNodes[startPinOldParentNodeId] = flow::m_Nodes().at(startPinParentNodeIndex)->id;
248 newlyLinkedNodes[endPinOldParentNodeId] = flow::m_Nodes().at(endPinParentNodeIndex)->id;
249 }
250 }
251 }
252 if (clipboard.contains("nodes"))
253 {
254 for (auto [oldId, newId] : newlyLinkedNodes)
255 {
256 auto* node = flow::FindNode(newId);
257
258 if (clipboard.at("nodes").contains("node-" + std::to_string(oldId)))
259 {
260 [[maybe_unused]] auto* oldNode = flow::FindNode(oldId);
261
262 LOG_DEBUG("Calling restoreAtferLink() for new node '{}', which was copied from node '{}'", node->nameId(), oldNode->nameId());
263
264 const auto& nodeJson = clipboard.at("nodes").at("node-" + std::to_string(oldId));
265 if (nodeJson.contains("data"))
266 {
267 node->restoreAtferLink(nodeJson.at("data"));
268 }
269 }
270 }
271 }
272
273 elementsCutted = false;
274}
Config management for the Project.
Save/Load the Nodes.
nlohmann::json json
json namespace
Global Gui Actions.
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
Abstract parent class for all nodes.
Definition Node.hpp:92
std::vector< OutputPin > outputPins
List of output pins.
Definition Node.hpp:511
virtual json save() const
Saves the node into a json object.
Definition Node.cpp:59
ax::NodeEditor::NodeId id
Unique Id of the Node.
Definition Node.hpp:503
static float leftPaneWidth
Width of the left pane.
static constexpr float SPLITTER_THICKNESS
Thickness of the splitter between left and right pane.
static float menuBarHeight
Height of the menu bar on top.
const std::vector< Node * > & m_Nodes()
List of all registered Nodes.
Node * FindNode(ax::NodeEditor::NodeId id)
Finds the Node for the NodeId.
bool LoadJson(const json &j, bool requestNewIds=false)
Loads the nodes and links from the specified json object.
bool DeleteNode(ax::NodeEditor::NodeId nodeId)
Delete the node provided by id.
bool canPasteFlowElements()
Checks if elements can be pasted.
void copyFlowElements()
Copies the currently selected elements.
bool canCutOrCopyFlowElements()
Checks if elements can be cutted/copied.
void pasteFlowElements()
Pastes the copied/cutted elements.
void cutFlowElements()
Cuts the currently selected elements.
Kind of the Pin (Input/Output)
Definition Pin.hpp:165
@ Input
Input Pin.
Definition Pin.hpp:171
@ Output
Output Pin.
Definition Pin.hpp:170
@ None
None.
Definition Pin.hpp:169