Adds a minimal node editor implementation
Implements a basic node editor using ImGui for creating and manipulating nodes and links. Introduces node creation, deletion, selection, dragging, zooming, panning, and linking functionalities. Adds basic pin typing for color and compatibility, including Any, Float, Vector, Texture, and Exec types. Also includes saving and loading node graphs to/from strings.
This commit is contained in:
Binary file not shown.
@@ -32,3 +32,8 @@
|
||||
62 3579 7822428527763633 CMakeFiles/ImNodeEditor.dir/src/ImNodeEditor.cpp.obj 966712c70001063c
|
||||
3581 4167 7822428562950218 libImNodeEditor.a 456ddb6c40baee90
|
||||
4168 4647 7822428568807417 example.exe 24050db2cb3fbf91
|
||||
25 2053 7822433126382984 CMakeFiles/example.dir/examples/example_main.cpp.obj c467c4ef9fc3e04b
|
||||
15 3089 7822433126235298 CMakeFiles/ImNodeEditor.dir/src/ImNodeEditor.cpp.obj 966712c70001063c
|
||||
3090 3339 7822433156978395 libImNodeEditor.a 456ddb6c40baee90
|
||||
78 2061 7822433307832734 CMakeFiles/example.dir/examples/example_main.cpp.obj c467c4ef9fc3e04b
|
||||
2063 2448 7822433327670595 example.exe 24050db2cb3fbf91
|
||||
|
||||
@@ -30,16 +30,16 @@ int main() {
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
// ---- GLEW init (must be after context creation) ----
|
||||
// ---- GLEW init ----
|
||||
glewExperimental = GL_TRUE;
|
||||
GLenum err = glewInit();
|
||||
if (err != GLEW_OK) {
|
||||
std::fprintf(stderr, "GLEW init error: %s\n", glewGetErrorString(err));
|
||||
return 3;
|
||||
}
|
||||
glGetError(); // clear benign error
|
||||
glGetError();
|
||||
|
||||
// ---- ImGui ----
|
||||
// ImGui
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
@@ -49,23 +49,30 @@ int main() {
|
||||
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||
ImGui_ImplOpenGL3_Init("#version 330 core");
|
||||
|
||||
ImNodeEditor::Editor editor;
|
||||
using namespace ImNodeEditor;
|
||||
|
||||
// Seed example nodes/links
|
||||
const int n1 = editor.AddNode("Texture", ImVec2(100, 120));
|
||||
const int n1_out = editor.AddPin(n1, ImNodeEditor::PinKind::Output);
|
||||
Editor editor;
|
||||
|
||||
// Seed example nodes/links with types
|
||||
const int n1 = editor.AddNode("Number", ImVec2(100, 120));
|
||||
const int n1_out = editor.AddPin(n1, PinKind::Output, PinType::Float);
|
||||
|
||||
const int n2 = editor.AddNode("Multiply", ImVec2(380, 160));
|
||||
const int n2_inA = editor.AddPin(n2, ImNodeEditor::PinKind::Input);
|
||||
const int n2_inB = editor.AddPin(n2, ImNodeEditor::PinKind::Input);
|
||||
const int n2_out = editor.AddPin(n2, ImNodeEditor::PinKind::Output);
|
||||
const int n2_inA = editor.AddPin(n2, PinKind::Input, PinType::Float);
|
||||
const int n2_inB = editor.AddPin(n2, PinKind::Input, PinType::Float);
|
||||
const int n2_out = editor.AddPin(n2, PinKind::Output, PinType::Float);
|
||||
|
||||
const int n3 = editor.AddNode("Output", ImVec2(700, 200));
|
||||
const int n3_in = editor.AddPin(n3, ImNodeEditor::PinKind::Input);
|
||||
const int n3_in = editor.AddPin(n3, PinKind::Input, PinType::Float);
|
||||
|
||||
// Texture node to showcase color/type (not connected by default)
|
||||
const int n4 = editor.AddNode("Texture", ImVec2(120, 300));
|
||||
const int n4_out = editor.AddPin(n4, PinKind::Output, PinType::Texture);
|
||||
|
||||
editor.AddLink(n1_out, n2_inA);
|
||||
editor.AddLink(n2_out, n3_in);
|
||||
|
||||
bool show_demo_window = false;
|
||||
bool show_editor_window = true;
|
||||
|
||||
while (!glfwWindowShouldClose(window)) {
|
||||
@@ -104,21 +111,25 @@ int main() {
|
||||
const char* text =
|
||||
"NODE 1 100 100 A\n"
|
||||
"NODE 2 300 160 B\n"
|
||||
"PIN 1 1 1 0\n"
|
||||
"PIN 2 2 0 0\n"
|
||||
"PIN 1 1 1 0 1\n"
|
||||
"PIN 2 2 0 0 1\n"
|
||||
"LINK 1 1 2\n";
|
||||
editor.LoadFromString(text);
|
||||
}
|
||||
if (ImGui::MenuItem("Quit")) glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("View")) {
|
||||
ImGui::MenuItem("Show ImGui Demo", nullptr, &show_demo_window);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (show_editor_window) {
|
||||
ImGui::Begin("Node Editor", &show_editor_window, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar);
|
||||
ImGui::Begin("Node Editor", nullptr, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar);
|
||||
ImVec2 avail = ImGui::GetContentRegionAvail();
|
||||
editor.Draw("MainCanvas", avail);
|
||||
ImGui::End();
|
||||
|
||||
1263
src/ImNodeEditor.cpp
1263
src/ImNodeEditor.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,6 @@
|
||||
// ImNodeEditor.h
|
||||
// Minimal, standalone node editor for Dear ImGui.
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -17,6 +19,10 @@ namespace ImNodeEditor {
|
||||
|
||||
enum class PinKind : int { Input = 0, Output = 1 };
|
||||
|
||||
// Basic pin typing for color + compatibility.
|
||||
// Any = wild-card (connects to anything).
|
||||
enum class PinType : int { Any = 0, Float = 1, Vector = 2, Texture = 3, Exec = 4 };
|
||||
|
||||
struct ColorTheme {
|
||||
ImU32 gridMinor = IM_COL32(50, 50, 50, 255);
|
||||
ImU32 gridMajor = IM_COL32(70, 70, 70, 255);
|
||||
@@ -24,13 +30,19 @@ struct ColorTheme {
|
||||
ImU32 nodeHeader= IM_COL32(60, 60, 80, 255);
|
||||
ImU32 nodeBorder= IM_COL32(110,110,140,255);
|
||||
ImU32 nodeSelected = IM_COL32(180,180,220,255);
|
||||
ImU32 pinFill = IM_COL32(180,180,200,255);
|
||||
ImU32 pinFill = IM_COL32(180,180,200,255); // used for Any
|
||||
ImU32 pinHover = IM_COL32(255,220,150,255);
|
||||
ImU32 link = IM_COL32(180,180,200,255);
|
||||
ImU32 linkHover = IM_COL32(255,240,170,255);
|
||||
ImU32 linkSel = IM_COL32(200,200,255,255);
|
||||
ImU32 selectionRect = IM_COL32(80,140,255,60);
|
||||
ImU32 selectionRectBorder = IM_COL32(80,140,255,180);
|
||||
|
||||
// Pin type colors (override defaults)
|
||||
ImU32 typeFloat = IM_COL32(90, 200, 100, 255);
|
||||
ImU32 typeVector = IM_COL32(90, 180, 240, 255);
|
||||
ImU32 typeTexture = IM_COL32(240, 180, 80, 255);
|
||||
ImU32 typeExec = IM_COL32(220, 80, 80, 255);
|
||||
};
|
||||
|
||||
struct EditorConfig {
|
||||
@@ -56,6 +68,7 @@ struct Pin {
|
||||
int node = 0;
|
||||
PinKind kind = PinKind::Input;
|
||||
int order = 0;
|
||||
PinType type = PinType::Any;
|
||||
ImVec2 localPos{};
|
||||
ImRect rect{};
|
||||
};
|
||||
@@ -72,8 +85,8 @@ struct Node {
|
||||
|
||||
struct Link {
|
||||
int id = 0;
|
||||
int aPin = 0;
|
||||
int bPin = 0;
|
||||
int aPin = 0; // output
|
||||
int bPin = 0; // input
|
||||
bool selected = false;
|
||||
};
|
||||
|
||||
@@ -91,19 +104,19 @@ public:
|
||||
|
||||
// Creation API
|
||||
int AddNode(const std::string& title, ImVec2 canvasPos);
|
||||
int AddPin(int nodeId, PinKind kind, int order = -1);
|
||||
int AddPin(int nodeId, PinKind kind, int order = -1); // legacy: Any type
|
||||
int AddPin(int nodeId, PinKind kind, PinType type, int order = -1); // typed
|
||||
int AddLink(int pinA, int pinB);
|
||||
void RemoveNode(int nodeId);
|
||||
void RemoveLink(int linkId);
|
||||
|
||||
// Access
|
||||
Node* GetNode(int nodeId);
|
||||
Pin* GetPin(int pinId);
|
||||
Link* GetLink(int linkId);
|
||||
|
||||
Node* GetNode(int nodeId);
|
||||
Pin* GetPin(int pinId);
|
||||
Link* GetLink(int linkId);
|
||||
const Node* GetNode(int nodeId) const;
|
||||
const Pin* GetPin(int pinId) const;
|
||||
const Link* GetLink(int linkId) const;
|
||||
const Pin* GetPin(int pinId) const;
|
||||
const Link* GetLink(int linkId) const;
|
||||
|
||||
// Frame draw
|
||||
void Draw(const char* label, ImVec2 size = ImVec2(0,0));
|
||||
@@ -137,7 +150,6 @@ private:
|
||||
void UpdatePinRects(Node& n);
|
||||
HoverInfo HitTest(const ImVec2& mouseCanvas) const;
|
||||
bool LinkDistanceToPoint(const Link& L, const ImVec2& P, float& outMin) const;
|
||||
ImVec2 PinScreenPos(const Pin& p) const;
|
||||
|
||||
// Interaction
|
||||
void HandleCanvasInput(const ImRect& canvas);
|
||||
@@ -146,8 +158,9 @@ private:
|
||||
void HandleKeyboard();
|
||||
|
||||
// Utilities
|
||||
static float CubicBezierYForX(float x);
|
||||
ImVec2 EvalLinkTangent(const ImVec2& a, const ImVec2& b) const;
|
||||
static float CubicBezierYForX(float x);
|
||||
ImU32 PinTypeColor(PinType t) const;
|
||||
|
||||
private:
|
||||
EditorConfig m_cfg{};
|
||||
|
||||
Reference in New Issue
Block a user