ملحق محرر عقدة صغير وخالي من التبعية لـ imgui العزيز.
يهدف Imnodes إلى توفير واجهة بسيطة ذات وضع فوري لإنشاء محرر عقدة داخل نافذة ImGui. يوفر Imnodes كتل بناء بسيطة وقابلة للتخصيص يحتاجها المستخدم لإنشاء محرر العقدة الخاص به.
سمات:
imnodes.h
و imnodes_internal.h
و imnodes.cpp
في مشروعك جنبًا إلى جنب مع ImGui. يتضمن هذا المستودع بعض الأمثلة على الملفات، ضمن example/
. الغرض منها هو أن تكون بمثابة أمثلة بسيطة تعطيك فكرة عما يمكنك بناءه باستخدام imnodes.
إذا كنت بحاجة إلى إنشاء الأمثلة، فيمكنك استخدام البرنامج النصي CMake المتوفر للقيام بذلك.
# 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
لاحظ أن هذا لم يتم اختباره على Linux ومن المحتمل أن يفشل على النظام الأساسي.
فيما يلي نظرة عامة صغيرة على كيفية استخدام الامتداد. لمزيد من المعلومات حول مثال الاستخدام، قم بالتمرير إلى أسفل الملف التمهيدي (README).
قبل القيام بأي شيء، يجب تهيئة المكتبة. يمكن القيام بذلك في نفس وقت تهيئة dear imgui
.
ImGui::CreateContext ();
ImNodes::CreateContext ();
// elsewhere in the code...
ImNodes::DestroyContext ();
ImGui::DestroyContext ();
محرر العقدة هو مساحة عمل تحتوي على العقد. يجب إنشاء محرر العقدة داخل النافذة، مثل أي عنصر آخر في واجهة المستخدم.
ImGui::Begin ( " node editor " );
ImNodes::BeginNodeEditor ();
ImNodes::EndNodeEditor ();
ImGui::End ();
الآن يجب أن يكون لديك مساحة عمل بها شبكة مرئية في النافذة. يمكن الآن إنشاء عقدة فارغة:
const int hardcoded_node_id = 1 ;
ImNodes::BeginNodeEditor ();
ImNodes::BeginNode (hardcoded_node_id);
ImGui::Dummy (ImVec2( 80 . 0f , 45 . 0f ));
ImNodes::EndNode ();
ImNodes::EndNodeEditor ();
يجب تحديد العقد، مثل النوافذ في dear imgui
بشكل فريد. لكن لا يمكننا استخدام عناوين العقد لتحديد الهوية، لأنه من الممكن أن يكون لديك العديد من العقد التي تحمل الاسم نفسه في مساحة العمل. بدلاً من ذلك، يمكنك فقط استخدام الأعداد الصحيحة لتحديد الهوية.
السمات هي محتوى واجهة المستخدم للعقدة. سيكون للسمة دبوس (الدائرة الصغيرة) على جانبي العقدة. هناك نوعان من السمات: سمات الإدخال، وسمات الإخراج. توجد دبابيس سمات الإدخال على الجانب الأيسر من العقدة، ودبابيس سمات الإخراج على اليمين. مثل العقد، يجب تحديد الدبابيس بشكل فريد.
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 ();
لا يهتم الامتداد حقًا بما هو موجود في السمة. فهو يعرض فقط الدبوس للسمة، ويسمح للمستخدم بإنشاء روابط بين المسامير.
يمكن إضافة شريط عنوان إلى العقدة باستخدام BeginNodeTitleBar
و EndNodeTitleBar
. كما هو الحال مع السمات، يمكنك وضع محتوى شريط العنوان الخاص بك بين استدعاءات الوظائف. لاحظ أنه يجب استدعاء هذه الوظائف قبل إضافة سمات أو عناصر واجهة مستخدم dear imgui
الأخرى إلى العقدة، نظرًا لأن تخطيط العقدة مبني بالترتيب، من الأعلى إلى الأسفل.
ImNodes::BeginNode (hardcoded_node_id);
ImNodes::BeginNodeTitleBar ();
ImGui::TextUnformatted ( " output node " );
ImNodes::EndNodeTitleBar ();
// pins and other node UI content omitted...
ImNodes::EndNode ();
يتعين على المستخدم تقديم الروابط الخاصة به بين العقد أيضًا. الارتباط هو منحنى يربط بين سمتين. الارتباط هو مجرد زوج من معرفات السمات. وكما هو الحال مع العقد والسمات، يجب أيضًا تحديد الروابط من خلال قيم عددية فريدة:
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 );
}
بعد استدعاء EndNodeEditor
، يمكنك التحقق مما إذا تم إنشاء رابط أثناء الإطار باستخدام استدعاء الوظيفة IsLinkCreated
:
int start_attr, end_attr;
if (ImNodes::IsLinkCreated(&start_attr, &end_attr))
{
links. push_back ( std::make_pair (start_attr, end_attr));
}
بالإضافة إلى التحقق من الروابط الجديدة، يمكنك أيضًا التحقق مما إذا كان يتم تمرير مؤشر الماوس فوق عناصر واجهة المستخدم:
int node_id;
if (ImNodes::IsNodeHovered(&node_id))
{
node_hovered = node_id;
}
يمكنك أيضًا التحقق لمعرفة ما إذا تم تحديد أي عقدة. يمكن النقر فوق العقد، أو يمكن تحديدها عن طريق النقر فوق مربع التحديد وسحبه فوقها.
// 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 ());
}
راجع imnodes.h
لمزيد من الوظائف المتعلقة بحدث واجهة المستخدم.
مثل dear imgui
، يمكن تغيير نمط واجهة المستخدم. يمكنك ضبط نمط الألوان للعقد الفردية والدبابيس والروابط في منتصف الإطار عن طريق استدعاء ImNodes::PushColorStyle
و 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 ();
إذا لم يتم تعيين النمط في منتصف الإطار، فيمكن استدعاء ImNodes::GetStyle
بدلاً من ذلك، ويمكن تعيين القيم في مصفوفة النمط مباشرةً.
// 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 );
للتعامل بشكل أسرع مع الرسوم البيانية الكبيرة، يمكنك استخدام تراكب الخريطة المصغرة التفاعلية. يمكن تكبير الخريطة المصغرة وتمريرها. ستقوم عقد المحرر بتتبع تحريك الخريطة المصغرة وفقًا لذلك.
ImGui::Begin ( " node editor " );
ImNodes::BeginNodeEditor ();
// add nodes...
// must be called right before EndNodeEditor
ImNodes::MiniMap ();
ImNodes::EndNodeEditor ();
ImGui::End ();
يمكن تحديد الحجم النسبي وموقع الزاوية للخريطة المصغرة في مساحة المحرر على النحو التالي:
// 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);
تدعم الخريطة المصغرة أيضًا التخصيص المحدود للعقدة من خلال رد اتصال محدد من قبل المستخدم.
// 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 من خلال توفير رأس imnodes_config.h
وتحديد تعريف IMNODES_USER_CONFIG=imnodes_config.h
عند التحويل البرمجي.
من الممكن حاليًا تجاوز نوع وظيفة رد الاتصال التي تحوم على الخريطة المصغرة. يعد هذا مفيدًا عند إنشاء روابط للغة أخرى.
فيما يلي مثال على imnodes_config.h، الذي يقوم بإنشاء غلاف pybind لرد الاتصال.
# 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()
على امتداد النافذة الحالية. ونتيجة لذلك، فإن استخدام فاصل داخل العقدة سيؤدي إلى تسرب الفاصل من العقدة إلى شبكة محرر العقدة. راجع examples/
الدليل لمعرفة استخدام المكتبة بمزيد من التفصيل.