ส่วนขยายตัวแก้ไขโหนดขนาดเล็กที่ไม่ต้องพึ่งพาสำหรับ imgui ที่รัก
Imnodes มุ่งหวังที่จะจัดเตรียมอินเทอร์เฟซโหมดทันทีที่เรียบง่ายสำหรับการสร้างตัวแก้ไขโหนดภายในหน้าต่าง ImGui Imnodes จัดเตรียม Building Block ที่เรียบง่ายและปรับแต่งได้ ซึ่งผู้ใช้จำเป็นต้องสร้างโปรแกรมแก้ไขโหนดของตน
คุณสมบัติ:
imnodes.h
, imnodes_internal.h
และ imnodes.cpp
ลงในโปรเจ็กต์ของคุณควบคู่ไปกับ ImGui พื้นที่เก็บข้อมูลนี้มีไฟล์ตัวอย่างบางส่วน ภายใต้ example/
สิ่งเหล่านี้มีไว้เป็นตัวอย่างง่ายๆ เพื่อให้คุณเข้าใจว่าคุณสามารถสร้างอะไรด้วยอิมโหนดได้
หากคุณต้องการสร้างตัวอย่าง คุณสามารถใช้สคริปต์ 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 ();
ตัวแก้ไขโหนดเป็นพื้นที่ทำงานที่มีโหนด ตัวแก้ไขโหนดจะต้องสร้างอินสแตนซ์ภายในหน้าต่าง เช่นเดียวกับองค์ประกอบ UI อื่นๆ
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
จะต้องถูกระบุโดยไม่ซ้ำกัน แต่เราไม่สามารถใช้ชื่อโหนดเพื่อระบุตัวตนได้ เนื่องจากควรเป็นไปได้ที่จะมีหลายโหนดที่มีชื่อเดียวกันในพื้นที่ทำงาน คุณเพียงแค่ใช้จำนวนเต็มเพื่อระบุตัวตนแทน
คุณสมบัติคือเนื้อหา UI ของโหนด คุณลักษณะจะมีหมุด (วงกลมเล็กๆ) อยู่ที่ด้านใดด้านหนึ่งของโหนด แอ็ตทริบิวต์มีสองประเภท: แอ็ตทริบิวต์อินพุตและเอาต์พุต พินแอททริบิวต์อินพุตอยู่ที่ด้านซ้ายของโหนด และพินแอททริบิวต์เอาต์พุตอยู่ทางด้านขวา เช่นเดียวกับโหนด พินต้องได้รับการระบุโดยไม่ซ้ำกัน
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));
}
นอกเหนือจากการตรวจสอบลิงก์ใหม่แล้ว คุณยังสามารถตรวจสอบได้ว่าเคอร์เซอร์เมาส์วางองค์ประกอบ UI ไว้เหนือหรือไม่:
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
สำหรับฟังก์ชันที่เกี่ยวข้องกับเหตุการณ์ UI เพิ่มเติม
เช่นเดียวกับ dear imgui
รูปแบบของ UI สามารถเปลี่ยนแปลงได้ คุณสามารถตั้งค่ารูปแบบสีของแต่ละโหนด พิน และลิงก์มิดเฟรมได้โดยการเรียก 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 wrapper สำหรับการโทรกลับ
# 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/
ไดเร็กทอรีเพื่อดูการใช้ไลบรารีโดยละเอียดยิ่งขึ้น