0.4.1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
DynamicInputPins.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/// @file DynamicInputPins.cpp
10/// @brief Inputs pins which can be added dynamically
11/// @author T. Topp (topp@ins.uni-stuttgart.de)
12/// @date 2023-12-21
13
14#include "DynamicInputPins.hpp"
15
16#include <optional>
17#include <imgui.h>
18
20#include "util/Logger.hpp"
21
23{
24
26 Node* node,
27 std::function<void(Node*)> pinAddCallback,
28 std::function<void(Node*, size_t)> pinDeleteCallback,
29 size_t defaultInputPins)
30 : _firstDynamicPinIdx(firstDynamicPin), _pinAddCallback(std::move(pinAddCallback)), _pinDeleteCallback(std::move(pinDeleteCallback))
31{
32 while (_nDynamicInputPins < defaultInputPins)
33 {
34 _pinAddCallback(node);
36 }
37}
38
39bool DynamicInputPins::ShowGuiWidgets(size_t id, std::vector<InputPin>& inputPins, Node* node, const std::vector<ExtraColumn>& extraColumns)
40{
41 bool changed = false;
42
43 int nExtraColumns = static_cast<int>(extraColumns.size());
44 if (ImGui::BeginTable(fmt::format("Pin Settings##{}", id).c_str(),
45 inputPins.size() > _firstDynamicPinIdx + 1 ? 2 + nExtraColumns : 1 + nExtraColumns,
46 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
47 {
48 ImGui::TableSetupColumn("Pin");
49 for (const auto& column : extraColumns)
50 {
51 ImGui::TableSetupColumn(column.header.c_str());
52 }
53 if (inputPins.size() > _firstDynamicPinIdx + 1)
54 {
55 ImGui::TableSetupColumn(""); // Delete Button column
56 }
57 ImGui::TableHeadersRow();
58
59 // Used to reset the member variabel _dragAndDropPinIndex in case no plot does a drag and drop action
60 bool dragAndDropPinStillInProgress = false;
61
62 auto showDragDropTargetPin = [&](size_t pinIdxTarget) {
63 ImGui::Dummy(ImVec2(-1.F, 2.F));
64
65 bool selectableDummy = true;
66 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5F, 0.5F));
67 ImGui::PushStyleColor(ImGuiCol_Header, IM_COL32(16, 173, 44, 79));
68 ImGui::Selectable(fmt::format("[drop here]").c_str(), &selectableDummy, ImGuiSelectableFlags_None,
69 ImVec2(std::max(ImGui::GetColumnWidth(0), ImGui::CalcTextSize("[drop here]").x), 20.F));
70 ImGui::PopStyleColor();
71 ImGui::PopStyleVar();
72
73 if (ImGui::BeginDragDropTarget())
74 {
75 if (const ImGuiPayload* payloadData = ImGui::AcceptDragDropPayload(fmt::format("DND Pin {}", id).c_str()))
76 {
77 auto pinIdxSource = *static_cast<size_t*>(payloadData->Data);
78
79 if (pinIdxSource < pinIdxTarget)
80 {
81 --pinIdxTarget;
82 }
83
84 move(inputPins, pinIdxSource, pinIdxTarget);
85 changed = true;
86 }
87 ImGui::EndDragDropTarget();
88 }
89 ImGui::Dummy(ImVec2(-1.F, 2.F));
90 };
91
92 std::optional<size_t> deletePinIdx;
93 for (size_t pinIndex = 0; pinIndex < inputPins.size(); pinIndex++)
94 {
95 ImGui::TableNextRow();
96 ImGui::TableNextColumn(); // Pin
97
98 if (pinIndex == _firstDynamicPinIdx && _dragAndDropPinIndex > static_cast<int>(_firstDynamicPinIdx))
99 {
100 showDragDropTargetPin(_firstDynamicPinIdx);
101 }
102
103 bool selectablePinDummy = false;
104 ImGui::Selectable(fmt::format("{}##{}", inputPins.at(pinIndex).name, id).c_str(), &selectablePinDummy);
105 if (pinIndex >= _firstDynamicPinIdx && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
106 {
107 dragAndDropPinStillInProgress = true;
108 _dragAndDropPinIndex = static_cast<int>(pinIndex);
109 // Data is copied into heap inside the drag and drop
110 ImGui::SetDragDropPayload(fmt::format("DND Pin {}", id).c_str(), &pinIndex, sizeof(pinIndex));
111 ImGui::TextUnformatted(inputPins.at(pinIndex).name.c_str());
112 ImGui::EndDragDropSource();
113 }
114 if (_dragAndDropPinIndex >= 0 && pinIndex >= _firstDynamicPinIdx
115 && pinIndex != static_cast<size_t>(_dragAndDropPinIndex - 1)
116 && pinIndex != static_cast<size_t>(_dragAndDropPinIndex))
117 {
118 showDragDropTargetPin(pinIndex + 1);
119 }
120 if (pinIndex >= _firstDynamicPinIdx && ImGui::IsItemHovered())
121 {
122 ImGui::SetTooltip("This item can be dragged to reorder the pins");
123 }
124
125 for (const auto& column : extraColumns)
126 {
127 ImGui::TableNextColumn();
128 changed |= column.content(pinIndex);
129 }
130
131 if (pinIndex >= _firstDynamicPinIdx && inputPins.size() > _firstDynamicPinIdx + 1)
132 {
133 ImGui::TableNextColumn(); // Delete
134 if (ImGui::Button(fmt::format("x##{} - {}", id, pinIndex).c_str()))
135 {
136 deletePinIdx = pinIndex;
137 }
138 if (ImGui::IsItemHovered())
139 {
140 ImGui::SetTooltip("Delete the pin");
141 }
142 }
143 }
144 if (deletePinIdx)
145 {
146 LOG_TRACE("{}: Deleting pin with index {}", id, *deletePinIdx);
147 changed = true;
148 _pinDeleteCallback(node, *deletePinIdx);
150 }
151
152 if (!dragAndDropPinStillInProgress)
153 {
155 }
156
157 ImGui::TableNextRow();
158 ImGui::TableNextColumn(); // Pin
159 if (ImGui::Button(fmt::format("Add Pin##{}", id).c_str()))
160 {
161 LOG_TRACE("{}: Adding a new pin", id);
162 changed = true;
163 _pinAddCallback(node);
165 }
166
167 ImGui::EndTable();
168 }
169
170 return changed;
171}
172
177
179{
180 _pinAddCallback(node);
182}
183
184void to_json(json& j, const DynamicInputPins& obj)
185{
186 j = json{
187 { "nDynamicInputPins", obj._nDynamicInputPins },
188 };
189}
190void from_json(const json& j, DynamicInputPins& obj, Node* node)
191{
192 if (j.contains("nDynamicInputPins"))
193 {
194 size_t nPins = 0;
195 j.at("nDynamicInputPins").get_to(nPins);
196 while (obj._nDynamicInputPins < nPins)
197 {
198 obj._pinAddCallback(node);
199 obj._nDynamicInputPins++;
200 }
201 while (obj._nDynamicInputPins > nPins)
202 {
203 obj._pinDeleteCallback(node, --obj._nDynamicInputPins);
204 }
205 }
206}
207
208} // namespace NAV::gui::widgets
Inputs pins which can be added dynamically.
nlohmann::json json
json namespace
Utility class for logging to console and file.
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Definition Logger.hpp:65
Vector Utility functions.
Abstract parent class for all nodes.
Definition Node.hpp:92
void from_json(const json &j, DynamicInputPins &obj, Node *node)
Converts the provided json object into a node object.
void to_json(json &j, const DynamicInputPins &obj)
Converts the provided object into json.
void move(std::vector< T > &v, size_t sourceIdx, size_t targetIdx)
Moves an element within a vector to a new position.
Definition Vector.hpp:27
std::function< void(Node *, size_t)> _pinDeleteCallback
Function to call to delete a pin. Argument is the pin index.
size_t getNumberOfDynamicPins() const
Get the number Of dynamic pins.
size_t _firstDynamicPinIdx
First pin index which is dynamic.
size_t _nDynamicInputPins
Number of dynamic input pins.
bool ShowGuiWidgets(size_t id, std::vector< InputPin > &inputPins, Node *node, const std::vector< ExtraColumn > &extraColumns={})
Shows the GUI input to select the options.
std::function< void(Node *)> _pinAddCallback
Function to call to add a new pin.
DynamicInputPins(size_t firstDynamicPinIndex, Node *node, std::function< void(Node *)> pinAddCallback, std::function< void(Node *, size_t)> pinDeleteCallback, size_t defaultInputPins=0)
Constructor.
int _dragAndDropPinIndex
Index of the Pin currently being dragged.
void addPin(Node *node)
Adds a pin and call the pinAddCallback.