Une petite extension d'éditeur de nœuds sans dépendance pour cher imgui.
Imnodes vise à fournir une interface simple en mode immédiat pour créer un éditeur de nœuds dans une fenêtre ImGui. Imnodes fournit des blocs de construction simples et personnalisables dont un utilisateur a besoin pour créer son éditeur de nœuds.
Caractéristiques:
imnodes.h
, imnodes_internal.h
et imnodes.cpp
dans votre projet aux côtés d'ImGui. Ce référentiel comprend quelques exemples de fichiers, sous example/
. Ils sont destinés à être des exemples simples vous donnant une idée de ce que vous pouvez construire avec imnodes.
Si vous devez créer les exemples, vous pouvez utiliser le script CMake fourni pour le faire.
# Initialize the vcpkg submodule
$ git submodule update --init
# Run the generation step and build
$ cmake -B build-release/ -S . -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake
$ cmake --build build-release -- -j
Notez que cela n’a pas été testé sous Linux et risque d’échouer sur la plate-forme.
Voici un petit aperçu de la façon dont l’extension est utilisée. Pour plus d’informations sur des exemples d’utilisation, faites défiler vers le bas du README.
Avant que quoi que ce soit puisse être fait, la bibliothèque doit être initialisée. Cela peut être fait en même temps que l'initialisation dear imgui
.
ImGui::CreateContext ();
ImNodes::CreateContext ();
// elsewhere in the code...
ImNodes::DestroyContext ();
ImGui::DestroyContext ();
L'éditeur de nœuds est un espace de travail qui contient des nœuds. L'éditeur de nœuds doit être instancié dans une fenêtre, comme tout autre élément de l'interface utilisateur.
ImGui::Begin ( " node editor " );
ImNodes::BeginNodeEditor ();
ImNodes::EndNodeEditor ();
ImGui::End ();
Vous devriez maintenant avoir un espace de travail avec une grille visible dans la fenêtre. Un nœud vide peut désormais être instancié :
const int hardcoded_node_id = 1 ;
ImNodes::BeginNodeEditor ();
ImNodes::BeginNode (hardcoded_node_id);
ImGui::Dummy (ImVec2( 80 . 0f , 45 . 0f ));
ImNodes::EndNode ();
ImNodes::EndNodeEditor ();
Les nœuds, comme les fenêtres dans dear imgui
doivent être identifiés de manière unique. Mais nous ne pouvons pas utiliser les titres des nœuds pour l'identification, car il devrait être possible d'avoir plusieurs nœuds du même nom dans l'espace de travail. Au lieu de cela, vous utilisez simplement des nombres entiers pour l'identification.
Les attributs sont le contenu de l'interface utilisateur du nœud. Un attribut aura une épingle (le petit cercle) de chaque côté du nœud. Il existe deux types d'attributs : les attributs d'entrée et les attributs de sortie. Les broches d'attribut d'entrée se trouvent sur le côté gauche du nœud et les broches d'attribut de sortie sont sur la droite. Comme les nœuds, les broches doivent être identifiées de manière unique.
ImNodes::BeginNode (hardcoded_node_id);
const int output_attr_id = 2 ;
ImNodes::BeginOutputAttribute (output_attr_id);
// in between Begin|EndAttribute calls, you can call ImGui
// UI functions
ImGui::Text ( " output pin " );
ImNodes::EndOutputAttribute ();
ImNodes::EndNode ();
L'extension ne se soucie pas vraiment de ce qu'il y a dans l'attribut. Il restitue simplement la broche de l'attribut et permet à l'utilisateur de créer des liens entre les broches.
Une barre de titre peut être ajoutée au nœud à l'aide de BeginNodeTitleBar
et EndNodeTitleBar
. Comme pour les attributs, vous placez le contenu de votre barre de titre entre les appels de fonction. Notez que ces fonctions doivent être appelées avant d'ajouter des attributs ou d'autres éléments d'interface utilisateur dear imgui
au nœud, car la disposition du nœud est construite dans l'ordre, de haut en bas.
ImNodes::BeginNode (hardcoded_node_id);
ImNodes::BeginNodeTitleBar ();
ImGui::TextUnformatted ( " output node " );
ImNodes::EndNodeTitleBar ();
// pins and other node UI content omitted...
ImNodes::EndNode ();
L'utilisateur doit également restituer ses propres liens entre les nœuds. Un lien est une courbe qui relie deux attributs. Un lien n’est qu’une paire d’identifiants d’attribut. Et comme les nœuds et les attributs, les liens doivent également être identifiés par des valeurs entières uniques :
std::vector<std::pair< int , int >> links;
// elsewhere in the code...
for ( int i = 0 ; i < links.size(); ++i)
{
const std::pair< int , int > p = links[i];
// in this case, we just use the array index of the link
// as the unique identifier
ImNodes::Link (i, p. first , p. second );
}
Après l'appel EndNodeEditor
, vous pouvez vérifier si un lien a été créé pendant la trame avec l'appel de fonction IsLinkCreated
:
int start_attr, end_attr;
if (ImNodes::IsLinkCreated(&start_attr, &end_attr))
{
links. push_back ( std::make_pair (start_attr, end_attr));
}
En plus de rechercher de nouveaux liens, vous pouvez également vérifier si les éléments de l'interface utilisateur sont survolés par le curseur de la souris :
int node_id;
if (ImNodes::IsNodeHovered(&node_id))
{
node_hovered = node_id;
}
Vous pouvez également vérifier si un nœud a été sélectionné. Les nœuds peuvent être cliqués ou sélectionnés en cliquant et en faisant glisser le sélecteur de case dessus.
// Note that since many nodes can be selected at once, we first need to query the number of
// selected nodes before getting them.
const int num_selected_nodes = ImNodes::NumSelectedNodes();
if (num_selected_nodes > 0 )
{
std::vector< int > selected_nodes;
selected_nodes. resize (num_selected_nodes);
ImNodes::GetSelectedNodes (selected_nodes. data ());
}
Voir imnodes.h
pour plus de fonctions liées aux événements de l'interface utilisateur.
Comme dear imgui
, le style de l'interface utilisateur peut être modifié. Vous pouvez définir le style de couleur des nœuds, des broches et des liens individuels au milieu du cadre en appelant ImNodes::PushColorStyle
et ImNodes::PopColorStyle
.
// set the titlebar color of an individual node
ImNodes::PushColorStyle (
ImNodesCol_TitleBar, IM_COL32( 11 , 109 , 191 , 255 ));
ImNodes::PushColorStyle (
ImNodesCol_TitleBarSelected, IM_COL32( 81 , 148 , 204 , 255 ));
ImNodes::BeginNode (hardcoded_node_id);
// node internals here...
ImNodes::EndNode ();
ImNodes::PopColorStyle ();
ImNodes::PopColorStyle ();
Si le style n'est pas défini au milieu de l'image, ImNodes::GetStyle
peut être appelé à la place et les valeurs peuvent être définies directement dans le tableau de style.
// set the titlebar color for all nodes
ImNodesStyle& style = ImNodes::GetStyle();
style.colors[ImNodesCol_TitleBar] = IM_COL32( 232 , 27 , 86 , 255 );
style.colors[ImNodesCol_TitleBarSelected] = IM_COL32( 241 , 108 , 146 , 255 );
Pour gérer une navigation plus rapide dans de grands graphiques, vous pouvez utiliser une superposition de mini-carte interactive. La mini-carte peut être zoomée et défilée. Les nœuds de l'éditeur suivront le panoramique de la mini-carte en conséquence.
ImGui::Begin ( " node editor " );
ImNodes::BeginNodeEditor ();
// add nodes...
// must be called right before EndNodeEditor
ImNodes::MiniMap ();
ImNodes::EndNodeEditor ();
ImGui::End ();
La taille relative et l'emplacement des coins de la mini-carte dans l'espace de l'éditeur peuvent être spécifiés comme suit :
// MiniMap is a square region with a side length that is 20% the largest editor canvas dimension
// See ImNodesMiniMapLocation_ for other corner locations
ImNodes::MiniMap ( 0 . 2f , ImNodesMiniMapLocation_TopRight);
La mini-carte prend également en charge une personnalisation limitée du survol des nœuds via un rappel défini par l'utilisateur.
// User callback
void mini_map_node_hovering_callback ( int node_id, void * user_data)
{
ImGui::SetTooltip ( " This is node %d " , node_id);
}
// Later on...
ImNodes::MiniMap ( 0 . 2f , ImNodesMiniMapLocation_TopRight, mini_map_node_hovering_callback, custom_user_data);
// 'custom_user_data' can be used to supply extra information needed for drawing within the callback
ImNodes peut être personnalisé en fournissant un en-tête imnodes_config.h
et en spécifiant la définition de IMNODES_USER_CONFIG=imnodes_config.h
lors de la compilation.
Il est actuellement possible de remplacer le type de la fonction de rappel de survol de la mini-carte. Ceci est utile lors de la génération de liaisons pour une autre langue.
Voici un exemple imnodes_config.h, qui génère un wrapper pybind pour le rappel.
# pragma once
# include < pybind11/functional.h >
namespace pybind11 {
inline bool PyWrapper_Check (PyObject *o) { return true ; }
class wrapper : public object {
public:
PYBIND11_OBJECT_DEFAULT (wrapper, object, PyWrapper_Check)
wrapper ( void * x) { m_ptr = (PyObject*)x; }
explicit operator bool () const { return m_ptr != nullptr && m_ptr != Py_None; }
};
} // namespace pybind11
namespace py = pybind11;
# define ImNodesMiniMapNodeHoveringCallback py::wrapper
# define ImNodesMiniMapNodeHoveringCallbackUserData py::wrapper
ImGui::Separator()
s'étend sur la durée de la fenêtre actuelle. Par conséquent, l’utilisation d’un séparateur à l’intérieur d’un nœud entraînera le débordement du séparateur hors du nœud dans la grille de l’éditeur de nœuds. Voir le répertoire examples/
pour voir l'utilisation de la bibliothèque plus en détail.