Skip to content

georgiitonchev/nodes_graph

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ImGui Node Graph Editor

An ImGui-based framework for creating custom node graph editors, supporting use cases such as dialogue systems, quest systems, and behaviour trees.

example-app

The screenshot is from the example app.

Table of Contents

Features

  • Nodes: Supports basic and group nodes.
  • Slots: Slots can act as inputs, outputs, or both.
  • Connections: Connections may store extra data, such as type (color) or a value.
  • Serialization/Deserialization: Graphs are saved and loaded in JSON format.
  • Undo/Redo: Command-pattern–based undo/redo system.
  • Copy/Paste: Nodes can be duplicated with customizable clone implementations.
  • Context Menus: Extendable context menu options for nodes.
  • Validation: Nodes can define and enforce their own validation rules.
  • Canvas: Interactive canvas with scrolling and zooming support.
  • Scaling: Basic support for different resolutions and DPI scales.

Dependencies

Dependencies for the example app

  • SDL3: Simple DirectMedia Layer (SDL for short) is a cross-platform library designed to make it easy to write multi-media software, such as games and emulators.

Examples

An example, work in progress, SDL3 app for Windows and macOS can be seen in the examples folder.

Usage

Nodes

Nodes are created by implementing the base Node class. Each node defines its own Initialization, Drawing, Serialization, Deserialization, Validation, and Cloning implementations.

Here's the full implementation of the Speech node from the example app:

// speech_node.h

#pragma once
#include "node.h"
#include "../input.h"

class SpeechNode : public Node
{
private:
  // Fields holding the node's data
  std::string _target;
  std::string _text;

  // Initialization
  void _Init() override
  {
    // Optional custom outline color of the node
    _colorOutline = IM_COL32(55, 149, 189, 255);
  
    // All four slots are defined as both input and output by the last two arguments.
    AddSlot(SlotPosition::Left, true, true);
    AddSlot(SlotPosition::Top, true, true);
    AddSlot(SlotPosition::Right, true, true);
    AddSlot(SlotPosition::Bottom, true, true);
  }

  // Drawing
  void _Draw(ImDrawList* drawList) override
  {
    // Input::Text is a simple wrapper around ImGui::InputText, handling dpi scaling and undo/redo functionalities.
    Input::Text("Target", &_target);
    Input::Text("Text", &_text);
  }

  // Serialization
  void _ToJson(nlohmann::json& j) override
  {
    j["target"] = _target;
    j["text"] = _text;
  }

  // Deserialization
  void _FromJson(const nlohmann::json& j) override
  {
    j.at("target").get_to(_target);
    j.at("text").get_to(_text);
  }

  // Validation
  bool _Validate() override
  {
    if (_target.empty())
    {
      SetValidationMessage("Target cannot be empty.");
      return false;
    }
  
    if (_text.empty())
    {
      SetValidationMessage("Text cannot be empty.");
      return false;
    }
  
    return true;
  }

  // Cloning
  Node* _Clone() override
  {
    auto node = new SpeechNode();
    node->_target = _target;
    node->_text = _text;
    return node;
  }
};

For nodes to appear as a create option when right-clicking the canvas, they need to be registered at app startup with NodesGraph::RegisterNode as seen in the example app here:

// main.cpp

static void RegisterNodes()
{
  // Register the node with the "Speech" label.
  // This will show up in the nodes creation context menu.
  NodesGraph::RegisterNode<SpeechNode>("Speech");
}

Group Nodes

Group nodes are created by implementing the GroupNode class. Group nodes must specify the type of child node.

Here’s the full implementation of the Responses group node (with its child ResponseNode) from the example app.

// responses_node.h

#pragma once
#include "node.h"
#include "../input.h"

// Define the child node
class ResponseNode : public Node {
private:
  std::string _text;
  
  void _Init() override
  {
    AddSlot(SlotPosition::Left, false, true);
    AddSlot(SlotPosition::Right, false, true);
  }
  
  void _Draw(ImDrawList* drawList) override
  {
    Input::Text("Text", &_text);
  }
  
  void _ToJson(nlohmann::json& j) override
  {
    j["text"] = _text;
  }
  
  void _FromJson(const nlohmann::json& j) override
  {
    j.at("text").get_to(_text);
  }
  
  bool _Validate() override
  {
    if (_text.empty())
    {
      SetValidationMessage("Text cannot be empty.");
      return false;
    }
    return true;
  }
  
  Node* _Clone() override
  {
    auto clone = new ResponseNode();
    clone->_text = _text;
    return clone;
  }
};

// Define the group node
class ResponsesNode : public GroupNode<ResponseNode> {
private:
  void _Init() override
  {
    _colorOutline = IM_COL32(255, 157, 35, 255);
    AddSlot(SlotPosition::Left, true, false);
    AddSlot(SlotPosition::Top, true, false);
    AddSlot(SlotPosition::Right, true, false);
    AddSlot(SlotPosition::Bottom, true, false);
  }
  
  void _Draw(ImDrawList* drawList) override
  {
  }
  
  void _ToJson(nlohmann::json& j) override
  {
  }
  
  void _FromJson(const nlohmann::json& j) override
  {
  }
  
  Node* _Clone() override
  {
    return new ResponsesNode();
  }
};

For a more complete usage example, see the example project.

Building / Installing

The core framework source files are in the /src folder and can be easily copied into your project.

The example project uses CMake and can be built on both Windows and macOS.

# Clone the repository with its submodules
git clone --recurse-submodules https://github.com/georgiitonchev/nodes_graph.git

# Navigate to the example project
cd nodes_graph/examples/app_sdl3

# Create a folder to contain build files
mkdir build
cd build

# Configure the project
cmake ..

# Build the project
cmake --build .

# Run the app
./Debug/app_sdl3

Disclaimers, Issues, and Limitations

  • This is just a personal project and a work in progress, not a finished or commercial tool, so it’s not perfect and may contain bugs.
  • Due to how zooming is implemented, some ImGui widgets will not render properly.
    • ImGui::InputTextMultiline
  • Support for ImGui style colors not yet implemented. ImGui::StyleColorsDark, ImGui::StyleColorsClassic, ImGui::StyleColorsLight

About

An ImGui-based framework for creating custom node graph editors.

Topics

Resources

Stars

Watchers

Forks

Contributors