Commit 69e02c7f authored by Gauthier Quesnel's avatar Gauthier Quesnel
Browse files

gui: create mapping between core and gui

parent b4d884bc
...@@ -9,11 +9,13 @@ namespace irt { ...@@ -9,11 +9,13 @@ namespace irt {
void void
node_editor_initialize(); node_editor_initialize();
void void
node_editor_show(); node_editor_show();
void void
node_editor_shutdown(); node_editor_shutdown();
} // namespace irt } // namespace irt
#endif #endif
\ No newline at end of file
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "gui.hpp" #include "gui.hpp"
#include <fmt/format.h>
#include <irritator/core.hpp> #include <irritator/core.hpp>
namespace irt { namespace irt {
...@@ -64,10 +66,40 @@ run_simulation(simulation& sim, ...@@ -64,10 +66,40 @@ run_simulation(simulation& sim,
st = simulation_status::success; st = simulation_status::success;
} }
struct g_model
{
g_model() = default;
ImVec2 position{ 0.f, 0.f };
int index{ -1 };
};
struct editor struct editor
{ {
imnodes::EditorContext* context = nullptr; imnodes::EditorContext* context = nullptr;
array<int> g_input_ports;
array<int> g_output_ports;
array<g_model> g_models;
int current_model_id = 0;
int current_port_id = 0;
bool initialized = false;
int get_model(const model_id id) const noexcept
{
return g_models[get_index(id)].index;
}
int get_in(const input_port_id id) const noexcept
{
return g_input_ports[get_index(id)];
}
int get_out(const output_port_id id) const noexcept
{
return g_output_ports[get_index(id)];
}
simulation sim; simulation sim;
double simulation_begin = 0.0; double simulation_begin = 0.0;
double simulation_end = 10.0; double simulation_end = 10.0;
...@@ -83,15 +115,47 @@ struct editor ...@@ -83,15 +115,47 @@ struct editor
std::vector<float> obs_a; std::vector<float> obs_a;
std::vector<float> obs_b; std::vector<float> obs_b;
bool initialize() bool initialize() noexcept
{ {
if (!is_success(sim.init(1024u, 32768u))) if (!is_success(sim.init(1024u, 32768u)))
return false; return false;
if (!is_success(g_models.init(sim.models.capacity())))
return false;
if (!is_success(g_input_ports.init(sim.input_ports.capacity())))
return false;
if (!is_success(g_output_ports.init(sim.output_ports.capacity())))
return false;
initialized = true;
return true; return true;
} }
status initialize_lotka_volterra() template<typename Dynamics>
status alloc(Dynamics& dynamics, dynamics_id dyn_id,
const char* name = nullptr) noexcept
{
irt_return_if_bad(sim.alloc(dynamics, dyn_id, name));
g_models[get_index(dynamics.id)].index = current_model_id++;
if constexpr (is_detected_v<has_input_port_t, Dynamics>)
for (size_t i = 0, e = std::size(dynamics.x); i != e; ++i)
g_input_ports[get_index(dynamics.x[i])] = current_port_id++;
if constexpr (is_detected_v<has_output_port_t, Dynamics>)
for (size_t i = 0, e = std::size(dynamics.y); i != e; ++i)
g_output_ports[get_index(dynamics.y[i])] = current_port_id++;
printf("mdl %d port %d\n", current_model_id, current_port_id);
return status::success;
}
status initialize_lotka_volterra() noexcept
{ {
if (!sim.adder_2_models.can_alloc(2) || if (!sim.adder_2_models.can_alloc(2) ||
!sim.mult_2_models.can_alloc(2) || !sim.mult_2_models.can_alloc(2) ||
...@@ -128,20 +192,13 @@ struct editor ...@@ -128,20 +192,13 @@ struct editor
sum_b.default_input_coeffs[0] = -1.0; sum_b.default_input_coeffs[0] = -1.0;
sum_b.default_input_coeffs[1] = 0.1; sum_b.default_input_coeffs[1] = 0.1;
irt_return_if_bad( irt_return_if_bad(alloc(sum_a, sim.adder_2_models.get_id(sum_a), "sum_a"));
sim.alloc(sum_a, sim.adder_2_models.get_id(sum_a), "sum_a")); irt_return_if_bad(alloc(sum_b, sim.adder_2_models.get_id(sum_b), "sum_b"));
irt_return_if_bad( irt_return_if_bad(alloc(product, sim.mult_2_models.get_id(product), "prod"));
sim.alloc(sum_b, sim.adder_2_models.get_id(sum_b), "sum_b")); irt_return_if_bad(alloc(integrator_a, sim.integrator_models.get_id(integrator_a), "int_a"));
irt_return_if_bad( irt_return_if_bad(alloc(integrator_b, sim.integrator_models.get_id(integrator_b), "int_b"));
sim.alloc(product, sim.mult_2_models.get_id(product), "prod")); irt_return_if_bad(alloc(quantifier_a, sim.quantifier_models.get_id(quantifier_a), "qua_a"));
irt_return_if_bad(sim.alloc( irt_return_if_bad(alloc(quantifier_b, sim.quantifier_models.get_id(quantifier_b), "qua_b"));
integrator_a, sim.integrator_models.get_id(integrator_a), "int_a"));
irt_return_if_bad(sim.alloc(
integrator_b, sim.integrator_models.get_id(integrator_b), "int_b"));
irt_return_if_bad(sim.alloc(
quantifier_a, sim.quantifier_models.get_id(quantifier_a), "qua_a"));
irt_return_if_bad(sim.alloc(
quantifier_b, sim.quantifier_models.get_id(quantifier_b), "qua_b"));
irt_return_if_bad(sim.connect(sum_a.y[0], integrator_a.x[1])); irt_return_if_bad(sim.connect(sum_a.y[0], integrator_a.x[1]));
irt_return_if_bad(sim.connect(sum_b.y[0], integrator_b.x[1])); irt_return_if_bad(sim.connect(sum_b.y[0], integrator_b.x[1]));
...@@ -167,106 +224,41 @@ struct editor ...@@ -167,106 +224,41 @@ struct editor
} }
}; };
int
to_int(u32 value) noexcept
{
assert((u64)value < (u64)std::numeric_limits<int>::max());
return static_cast<int>(value);
}
int
get_model(model_id id)
{
return to_int(get_key(id));
}
int
get_model(const data_array<model, model_id>& array, const model& mdl)
{
return get_model(array.get_id(mdl));
}
int
get_model(const data_array<model, model_id>& array, const model* mdl)
{
assert(mdl);
return get_model(array.get_id(*mdl));
}
int
get_out(output_port_id id)
{
return to_int(get_key(id)) << 16;
}
int
get_out(const data_array<output_port, output_port_id>& array,
const output_port& out)
{
return get_out(array.get_id(out));
}
int
get_out(const data_array<output_port, output_port_id>& array,
const output_port* out)
{
assert(out);
return get_out(array.get_id(*out));
}
int
get_in(input_port_id id)
{
return to_int(get_key(id));
}
int
get_in(const data_array<input_port, input_port_id>& array, const input_port& in)
{
return get_in(array.get_id(in));
}
int
get_in(const data_array<input_port, input_port_id>& array, const input_port* in)
{
assert(in);
return get_in(array.get_id(*in));
}
static void static void
show_connections(simulation& sim) noexcept show_connections(editor& ed) noexcept
{ {
int number = 1; int number = 1;
irt::output_port* output_port = nullptr; irt::output_port* output_port = nullptr;
while (sim.output_ports.next(output_port)) { while (ed.sim.output_ports.next(output_port)) {
int src = get_out(sim.output_ports, output_port); output_port_id src = ed.sim.output_ports.get_id(output_port);
for (const input_port_id id_dst : output_port->connections) { for (const input_port_id id_dst : output_port->connections) {
if (auto* input_port = sim.input_ports.try_to_get(id_dst); if (auto* input_port = ed.sim.input_ports.try_to_get(id_dst);
input_port) { input_port) {
int dst = get_in(id_dst);
++number; ++number;
imnodes::Link(number, src, dst); imnodes::Link(number, ed.get_out(src), ed.get_in(id_dst));
} }
} }
} }
} }
static void static void
show_model_dynamics(simulation& sim, model& mdl) show_model_dynamics(editor& ed, model& mdl)
{ {
switch (mdl.type) { switch (mdl.type) {
case dynamics_type::none: /* none does not have input port. */ case dynamics_type::none: /* none does not have input port. */
case dynamics_type::cross:
case dynamics_type::time_func:
break; break;
case dynamics_type::integrator: { case dynamics_type::integrator: {
auto& dyn = sim.integrator_models.get(mdl.id); auto& dyn = ed.sim.integrator_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[0]));
ImGui::TextUnformatted("quanta"); ImGui::TextUnformatted("quanta");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[1])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[1]));
ImGui::TextUnformatted("x_dot"); ImGui::TextUnformatted("x_dot");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[2])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[2]));
ImGui::TextUnformatted("reset"); ImGui::TextUnformatted("reset");
imnodes::EndAttribute(); imnodes::EndAttribute();
...@@ -275,15 +267,15 @@ show_model_dynamics(simulation& sim, model& mdl) ...@@ -275,15 +267,15 @@ show_model_dynamics(simulation& sim, model& mdl)
ImGui::InputDouble("reset", &dyn.default_reset_value); ImGui::InputDouble("reset", &dyn.default_reset_value);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
imnodes::BeginOutputAttribute(get_out(dyn.y[0])); imnodes::BeginOutputAttribute(ed.get_out(dyn.y[0]));
const float text_width = ImGui::CalcTextSize("x").x; const float text_width = ImGui::CalcTextSize("x").x;
ImGui::Indent(120.f + ImGui::CalcTextSize("quanta").x - text_width); ImGui::Indent(120.f + ImGui::CalcTextSize("quanta").x - text_width);
ImGui::TextUnformatted("x"); ImGui::TextUnformatted("x");
imnodes::EndAttribute(); imnodes::EndAttribute();
} break; } break;
case dynamics_type::quantifier: { case dynamics_type::quantifier: {
auto& dyn = sim.quantifier_models.get(mdl.id); auto& dyn = ed.sim.quantifier_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[0]));
ImGui::TextUnformatted("x_dot"); ImGui::TextUnformatted("x_dot");
imnodes::EndAttribute(); imnodes::EndAttribute();
...@@ -292,16 +284,16 @@ show_model_dynamics(simulation& sim, model& mdl) ...@@ -292,16 +284,16 @@ show_model_dynamics(simulation& sim, model& mdl)
ImGui::SliderInt("archive length", &dyn.default_past_length, 3, 100); ImGui::SliderInt("archive length", &dyn.default_past_length, 3, 100);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
imnodes::BeginOutputAttribute(get_out(dyn.y[0])); imnodes::BeginOutputAttribute(ed.get_out(dyn.y[0]));
ImGui::TextUnformatted("quanta"); ImGui::TextUnformatted("quanta");
imnodes::EndAttribute(); imnodes::EndAttribute();
} break; } break;
case dynamics_type::adder_2: { case dynamics_type::adder_2: {
auto& dyn = sim.adder_2_models.get(mdl.id); auto& dyn = ed.sim.adder_2_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[0]));
ImGui::TextUnformatted("x0"); ImGui::TextUnformatted("x0");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[1])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[1]));
ImGui::TextUnformatted("x1"); ImGui::TextUnformatted("x1");
imnodes::EndAttribute(); imnodes::EndAttribute();
...@@ -310,21 +302,21 @@ show_model_dynamics(simulation& sim, model& mdl) ...@@ -310,21 +302,21 @@ show_model_dynamics(simulation& sim, model& mdl)
ImGui::InputDouble("coeff-1", &dyn.default_input_coeffs[1]); ImGui::InputDouble("coeff-1", &dyn.default_input_coeffs[1]);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
imnodes::BeginOutputAttribute(get_out(dyn.y[0])); imnodes::BeginOutputAttribute(ed.get_out(dyn.y[0]));
const float text_width = ImGui::CalcTextSize("sum").x; const float text_width = ImGui::CalcTextSize("sum").x;
ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x - text_width); ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x - text_width);
ImGui::TextUnformatted("sum"); ImGui::TextUnformatted("sum");
imnodes::EndAttribute(); imnodes::EndAttribute();
} break; } break;
case dynamics_type::adder_3: { case dynamics_type::adder_3: {
auto& dyn = sim.adder_3_models.get(mdl.id); auto& dyn = ed.sim.adder_3_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[0]));
ImGui::TextUnformatted("x0"); ImGui::TextUnformatted("x0");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[1])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[1]));
ImGui::TextUnformatted("x1"); ImGui::TextUnformatted("x1");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[2])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[2]));
ImGui::TextUnformatted("x2"); ImGui::TextUnformatted("x2");
imnodes::EndAttribute(); imnodes::EndAttribute();
...@@ -334,24 +326,24 @@ show_model_dynamics(simulation& sim, model& mdl) ...@@ -334,24 +326,24 @@ show_model_dynamics(simulation& sim, model& mdl)
ImGui::InputDouble("coeff-2", &dyn.default_input_coeffs[2]); ImGui::InputDouble("coeff-2", &dyn.default_input_coeffs[2]);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
imnodes::BeginOutputAttribute(get_out(dyn.y[0])); imnodes::BeginOutputAttribute(ed.get_out(dyn.y[0]));
const float text_width = ImGui::CalcTextSize("sum").x; const float text_width = ImGui::CalcTextSize("sum").x;
ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x - text_width); ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x - text_width);
ImGui::TextUnformatted("sum"); ImGui::TextUnformatted("sum");
imnodes::EndAttribute(); imnodes::EndAttribute();
} break; } break;
case dynamics_type::adder_4: { case dynamics_type::adder_4: {
auto& dyn = sim.adder_4_models.get(mdl.id); auto& dyn = ed.sim.adder_4_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[0]));
ImGui::TextUnformatted("x0"); ImGui::TextUnformatted("x0");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[1])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[1]));
ImGui::TextUnformatted("x1"); ImGui::TextUnformatted("x1");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[2])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[2]));
ImGui::TextUnformatted("x2"); ImGui::TextUnformatted("x2");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[3])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[3]));
ImGui::TextUnformatted("x3"); ImGui::TextUnformatted("x3");
imnodes::EndAttribute(); imnodes::EndAttribute();
...@@ -362,18 +354,18 @@ show_model_dynamics(simulation& sim, model& mdl) ...@@ -362,18 +354,18 @@ show_model_dynamics(simulation& sim, model& mdl)
ImGui::InputDouble("coeff-2", &dyn.default_input_coeffs[3]); ImGui::InputDouble("coeff-2", &dyn.default_input_coeffs[3]);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
imnodes::BeginOutputAttribute(get_out(dyn.y[0])); imnodes::BeginOutputAttribute(ed.get_out(dyn.y[0]));
const float text_width = ImGui::CalcTextSize("sum").x; const float text_width = ImGui::CalcTextSize("sum").x;
ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x - text_width); ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x - text_width);
ImGui::TextUnformatted("sum"); ImGui::TextUnformatted("sum");
imnodes::EndAttribute(); imnodes::EndAttribute();
} break; } break;
case dynamics_type::mult_2: { case dynamics_type::mult_2: {
auto& dyn = sim.mult_2_models.get(mdl.id); auto& dyn = ed.sim.mult_2_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[0]));
ImGui::TextUnformatted("x0"); ImGui::TextUnformatted("x0");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[1])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[1]));
ImGui::TextUnformatted("x1"); ImGui::TextUnformatted("x1");
imnodes::EndAttribute(); imnodes::EndAttribute();
...@@ -382,21 +374,21 @@ show_model_dynamics(simulation& sim, model& mdl) ...@@ -382,21 +374,21 @@ show_model_dynamics(simulation& sim, model& mdl)
ImGui::InputDouble("coeff-1", &dyn.default_input_coeffs[1]); ImGui::InputDouble("coeff-1", &dyn.default_input_coeffs[1]);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
imnodes::BeginOutputAttribute(get_out(dyn.y[0])); imnodes::BeginOutputAttribute(ed.get_out(dyn.y[0]));
const float text_width = ImGui::CalcTextSize("prod").x; const float text_width = ImGui::CalcTextSize("prod").x;
ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x - text_width); ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x - text_width);
ImGui::TextUnformatted("prod"); ImGui::TextUnformatted("prod");
imnodes::EndAttribute(); imnodes::EndAttribute();
} break; } break;
case dynamics_type::mult_3: { case dynamics_type::mult_3: {
auto& dyn = sim.mult_3_models.get(mdl.id); auto& dyn = ed.sim.mult_3_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[0]));
ImGui::TextUnformatted("x0"); ImGui::TextUnformatted("x0");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[1])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[1]));
ImGui::TextUnformatted("x1"); ImGui::TextUnformatted("x1");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[2])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[2]));
ImGui::TextUnformatted("x2"); ImGui::TextUnformatted("x2");
imnodes::EndAttribute(); imnodes::EndAttribute();
...@@ -406,24 +398,24 @@ show_model_dynamics(simulation& sim, model& mdl) ...@@ -406,24 +398,24 @@ show_model_dynamics(simulation& sim, model& mdl)
ImGui::InputDouble("coeff-2", &dyn.default_input_coeffs[2]); ImGui::InputDouble("coeff-2", &dyn.default_input_coeffs[2]);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
imnodes::BeginOutputAttribute(get_out(dyn.y[0])); imnodes::BeginOutputAttribute(ed.get_out(dyn.y[0]));
const float text_width = ImGui::CalcTextSize("prod").x; const float text_width = ImGui::CalcTextSize("prod").x;
ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x - text_width); ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x - text_width);
ImGui::TextUnformatted("prod"); ImGui::TextUnformatted("prod");
imnodes::EndAttribute(); imnodes::EndAttribute();
} break; } break;
case dynamics_type::mult_4: { case dynamics_type::mult_4: {
auto& dyn = sim.mult_4_models.get(mdl.id); auto& dyn = ed.sim.mult_4_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[0]));
ImGui::TextUnformatted("x0"); ImGui::TextUnformatted("x0");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[1])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[1]));
ImGui::TextUnformatted("x1"); ImGui::TextUnformatted("x1");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[2])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[2]));
ImGui::TextUnformatted("x2"); ImGui::TextUnformatted("x2");
imnodes::EndAttribute(); imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[3])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[3]));
ImGui::TextUnformatted("x3"); ImGui::TextUnformatted("x3");
imnodes::EndAttribute(); imnodes::EndAttribute();
...@@ -434,32 +426,32 @@ show_model_dynamics(simulation& sim, model& mdl) ...@@ -434,32 +426,32 @@ show_model_dynamics(simulation& sim, model& mdl)
ImGui::InputDouble("coeff-3", &dyn.default_input_coeffs[3]); ImGui::InputDouble("coeff-3", &dyn.default_input_coeffs[3]);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
imnodes::BeginOutputAttribute(get_out(dyn.y[0])); imnodes::BeginOutputAttribute(ed.get_out(dyn.y[0]));
const float text_width = ImGui::CalcTextSize("prod").x; const float text_width = ImGui::CalcTextSize("prod").x;
ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x - text_width); ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x - text_width);
ImGui::TextUnformatted("prod"); ImGui::TextUnformatted("prod");
imnodes::EndAttribute(); imnodes::EndAttribute();
} break; } break;
case dynamics_type::counter: { case dynamics_type::counter: {
auto& dyn = sim.counter_models.get(mdl.id); auto& dyn = ed.sim.counter_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0])); imnodes::BeginInputAttribute(ed.get_in(dyn.x[0]));
ImGui::TextUnformatted("in"); ImGui::TextUnformatted("in");
imnodes::EndAttribute(); imnodes::EndAttribute();
} break;