# include # include # include namespace ed = ax::NodeEditor; struct Example: public Application { // Struct to hold basic information about connection between // pins. Note that connection (aka. link) has its own ID. // This is useful later with dealing with selections, deletion // or other operations. struct LinkInfo { ed::LinkId Id; ed::PinId InputId; ed::PinId OutputId; }; using Application::Application; void OnStart() override { ed::Config config; config.SettingsFile = "BasicInteraction.json"; m_Context = ed::CreateEditor(&config); } void OnStop() override { ed::DestroyEditor(m_Context); } void ImGuiEx_BeginColumn() { ImGui::BeginGroup(); } void ImGuiEx_NextColumn() { ImGui::EndGroup(); ImGui::SameLine(); ImGui::BeginGroup(); } void ImGuiEx_EndColumn() { ImGui::EndGroup(); } void OnFrame(float deltaTime) override { auto& io = ImGui::GetIO(); ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f); ImGui::Separator(); ed::SetCurrentEditor(m_Context); // Start interaction with editor. ed::Begin("My Editor", ImVec2(0.0, 0.0f)); int uniqueId = 1; // // 1) Commit known data to editor // // Submit Node A ed::NodeId nodeA_Id = uniqueId++; ed::PinId nodeA_InputPinId = uniqueId++; ed::PinId nodeA_OutputPinId = uniqueId++; if (m_FirstFrame) ed::SetNodePosition(nodeA_Id, ImVec2(10, 10)); ed::BeginNode(nodeA_Id); ImGui::Text("Node A"); ed::BeginPin(nodeA_InputPinId, ed::PinKind::Input); ImGui::Text("-> In"); ed::EndPin(); ImGui::SameLine(); ed::BeginPin(nodeA_OutputPinId, ed::PinKind::Output); ImGui::Text("Out ->"); ed::EndPin(); ed::EndNode(); // Submit Node B ed::NodeId nodeB_Id = uniqueId++; ed::PinId nodeB_InputPinId1 = uniqueId++; ed::PinId nodeB_InputPinId2 = uniqueId++; ed::PinId nodeB_OutputPinId = uniqueId++; if (m_FirstFrame) ed::SetNodePosition(nodeB_Id, ImVec2(210, 60)); ed::BeginNode(nodeB_Id); ImGui::Text("Node B"); ImGuiEx_BeginColumn(); ed::BeginPin(nodeB_InputPinId1, ed::PinKind::Input); ImGui::Text("-> In1"); ed::EndPin(); ed::BeginPin(nodeB_InputPinId2, ed::PinKind::Input); ImGui::Text("-> In2"); ed::EndPin(); ImGuiEx_NextColumn(); ed::BeginPin(nodeB_OutputPinId, ed::PinKind::Output); ImGui::Text("Out ->"); ed::EndPin(); ImGuiEx_EndColumn(); ed::EndNode(); // Submit Links for (auto& linkInfo : m_Links) ed::Link(linkInfo.Id, linkInfo.InputId, linkInfo.OutputId); // // 2) Handle interactions // // Handle creation action, returns true if editor want to create new object (node or link) if (ed::BeginCreate()) { ed::PinId inputPinId, outputPinId; if (ed::QueryNewLink(&inputPinId, &outputPinId)) { // QueryNewLink returns true if editor want to create new link between pins. // // Link can be created only for two valid pins, it is up to you to // validate if connection make sense. Editor is happy to make any. // // Link always goes from input to output. User may choose to drag // link from output pin or input pin. This determine which pin ids // are valid and which are not: // * input valid, output invalid - user started to drag new ling from input pin // * input invalid, output valid - user started to drag new ling from output pin // * input valid, output valid - user dragged link over other pin, can be validated if (inputPinId && outputPinId) // both are valid, let's accept link { // ed::AcceptNewItem() return true when user release mouse button. if (ed::AcceptNewItem()) { // Since we accepted new link, lets add one to our list of links. m_Links.push_back({ ed::LinkId(m_NextLinkId++), inputPinId, outputPinId }); // Draw new link. ed::Link(m_Links.back().Id, m_Links.back().InputId, m_Links.back().OutputId); } // You may choose to reject connection between these nodes // by calling ed::RejectNewItem(). This will allow editor to give // visual feedback by changing link thickness and color. } } } ed::EndCreate(); // Wraps up object creation action handling. // Handle deletion action if (ed::BeginDelete()) { // There may be many links marked for deletion, let's loop over them. ed::LinkId deletedLinkId; while (ed::QueryDeletedLink(&deletedLinkId)) { // If you agree that link can be deleted, accept deletion. if (ed::AcceptDeletedItem()) { // Then remove link from your data. for (auto& link : m_Links) { if (link.Id == deletedLinkId) { m_Links.erase(&link); break; } } } // You may reject link deletion by calling: // ed::RejectDeletedItem(); } } ed::EndDelete(); // Wrap up deletion action // End of interaction with editor. ed::End(); if (m_FirstFrame) ed::NavigateToContent(0.0f); ed::SetCurrentEditor(nullptr); m_FirstFrame = false; // ImGui::ShowMetricsWindow(); } ed::EditorContext* m_Context = nullptr; // Editor context, required to trace a editor state. bool m_FirstFrame = true; // Flag set for first frame only, some action need to be executed once. ImVector m_Links; // List of live links. It is dynamic unless you want to create read-only view over nodes. int m_NextLinkId = 100; // Counter to help generate link ids. In real application this will probably based on pointer to user data structure. }; int Main(int argc, char** argv) { Example exampe("Basic Interaction", argc, argv); if (exampe.Create()) return exampe.Run(); return 0; }