#include "Nodes_And_Connectors.hpp" #include "Json_Utilities.hpp" #include "imgui_internal.h" // 客制化圆形带X按钮 bool CircleButtonWithX(const char *id, float radius) { ImGuiWindow *window = ImGui::GetCurrentWindow(); if (window->SkipItems) return false; // 创建ID ImGuiID button_id = window->GetID(id); // 计算按钮位置和大小 ImVec2 pos = window->DC.CursorPos; ImVec2 size(radius * 2, radius * 2); ImRect bb(pos, ImVec2(pos.x + size.x, pos.y + size.y)); // 处理交互 ImGui::ItemSize(bb); if (!ImGui::ItemAdd(bb, button_id)) return false; bool hovered, held; bool pressed = ImGui::ButtonBehavior(bb, button_id, &hovered, &held); // 绘制 ImU32 col = ImGui::GetColorU32( held ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); // 获取绘制列表 ImDrawList *draw_list = ImGui::GetWindowDrawList(); ImVec2 center = ImVec2(pos.x + radius, pos.y + radius); // 绘制圆形 draw_list->AddCircleFilled(center, radius, col, 32); // 绘制边框(可选) draw_list->AddCircle(center, radius, ImGui::GetColorU32(ImGuiCol_Border), 32, 1.0f); // 计算X的线条 float cross_radius = radius * 0.5f; // X的大小 float thickness = radius * 0.15f; // X的粗细 // 绘制X的两条线 draw_list->AddLine( ImVec2(center.x - cross_radius, center.y - cross_radius), ImVec2(center.x + cross_radius, center.y + cross_radius), ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 1.0f, 1.0f)), // 白色X thickness); draw_list->AddLine( ImVec2(center.x + cross_radius, center.y - cross_radius), ImVec2(center.x - cross_radius, center.y + cross_radius), ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 1.0f, 1.0f)), // 白色X thickness); return pressed; } // ================================================================================================= // 必要构造 Abs_Connector::Abs_Connector(Independent_ID_Generator *ID_Generator, Connector_Type_Enum type, const char *socket_str) : ID_Generator(nullptr), id(-1), type(CONNECTOR_TYPE_UNKNOWN), socket_str(nullptr) { // 分配ID this->id = ID_Generator->Request_ID(); if (this->id != -1) { this->ID_Generator = ID_Generator; this->type = type; this->socket_str = socket_str; } // 指针初始化 this->product = nullptr; }; // 析构 Abs_Connector::~Abs_Connector() { // 释放产物 if (this->product != nullptr) free(product); // 断开所有连接 this->Disconnect_All(); // 释放ID this->ID_Generator->Release_ID(this->id); } // 连接到目标连接点 bool Abs_Connector::Connect_To(Abs_Connector *target) { // 判定接口是否匹配 if (strcmp(target->socket_str, this->socket_str) == 0) { // 写连接关系 必须是一收一发 if (((this->type == CONNECTOR_TYPE_OUTPUT) && (target->type == CONNECTOR_TYPE_INPUT)) || ((this->type == CONNECTOR_TYPE_INPUT) && (target->type == CONNECTOR_TYPE_OUTPUT))) { // 向双方写入关联信息 target->related_connector_list.push_back(this); this->related_connector_list.push_back(target); return true; } } return false; } // 断开所有连接 void Abs_Connector::Disconnect_All(void) { for (auto target : this->related_connector_list) { // 删除连接点对自己的记录 for (auto iterator = target->related_connector_list.begin(); iterator != target->related_connector_list.end(); iterator++) if (*iterator == this) { iterator = target->related_connector_list.erase(iterator); break; } } // 清空自身列表 decltype(this->related_connector_list) empty_list; this->related_connector_list.swap(empty_list); } // 与指定的接口断开连接 bool Abs_Connector::Disconnect_To(Abs_Connector *target) { // 查找目标接口 for (auto iterator = this->related_connector_list.begin(); iterator != this->related_connector_list.end(); iterator++) { if (*iterator == target) { // 删除目标连接点对自己的记录 for (auto iterator = target->related_connector_list.begin(); iterator != target->related_connector_list.end(); iterator++) if (*iterator == this) { iterator = target->related_connector_list.erase(iterator); break; } // 自身删除对目标点的记录 iterator = this->related_connector_list.erase(iterator); return true; } } // 未成功查找 return false; } // 注册产物 bool Abs_Connector::Register_Product(void *product, size_t size) { // 非输出类接口 if (this->type != CONNECTOR_TYPE_OUTPUT) return false; // 释放之前的产物 if (this->product != nullptr) free(this->product); // 分配空间 this->product = malloc(size); if (this->product == nullptr) return false; // 复制内容 memcpy(this->product, product, size); return true; } // 获取上级节点 std::vector Abs_Connector::Get_Related_List(void) { return this->related_connector_list; } // 获取产物 void *Abs_Connector::Get_Product(void) { // 输出节点返回直接产物 if (this->type == CONNECTOR_TYPE_OUTPUT) return this->product; // 其它情况返回空值 return nullptr; } // 获取ID int Abs_Connector::Get_ID(void) { return this->id; } // 获取接口类型 Abs_Connector::Connector_Type_Enum Abs_Connector::Get_Type(void) { return this->type; } // ================================================================================================= // 必要构造 Abs_Node::Abs_Node(Independent_ID_Generator *Node_ID_Generator, Independent_ID_Generator *Connector_ID_Generator, Node_Type_Enum type, ImVec2 initial_position) : Node_ID_Generator(nullptr), Connector_ID_Generator(nullptr), id(-1), type(NODE_TYPE_UNKNOWN), initial_position(initial_position) { // 分配ID this->id = Node_ID_Generator->Request_ID(); if (this->id != -1) { this->Node_ID_Generator = Node_ID_Generator; this->Connector_ID_Generator = Connector_ID_Generator; this->type = type; } this->close_flag = false; } // 析构 Abs_Node::~Abs_Node() { // 释放ID this->Node_ID_Generator->Release_ID(this->id); } // 获取ID int Abs_Node::Get_ID(void) { return this->id; } // 获取节点类型 Abs_Node::Node_Type_Enum Abs_Node::Get_Type(void) { return this->type; } // 获取关闭信号 bool Abs_Node::Get_CloseFlag(void) { return this->close_flag; } // 获取接口列表 std::vector> &Abs_Node::Get_Connector_List(void) { return this->Connector_List; } // ================================================================================================= // 必要构造 MSG_InPut_Connector::MSG_InPut_Connector(Independent_ID_Generator *ID_Generator) : Abs_Connector(ID_Generator, CONNECTOR_TYPE_INPUT, "DLT MSG") {} // 绘制接口 void MSG_InPut_Connector::Show(void) { // 输出接口点 ImNodes::BeginInputAttribute(this->id, ImNodesPinShape_CircleFilled); // 填充占位 ImGui::Dummy(ImVec2(0.0f, ImGui::GetTextLineHeight())); ImNodes::EndInputAttribute(); } // 必要构造 MSG_OutPut_Connector::MSG_OutPut_Connector(Independent_ID_Generator *ID_Generator) : Abs_Connector(ID_Generator, CONNECTOR_TYPE_OUTPUT, "DLT MSG") {} // 绘制接口 void MSG_OutPut_Connector::Show(void) { // 输出接口点 ImNodes::BeginOutputAttribute(this->id, ImNodesPinShape_CircleFilled); // 填充占位 ImGui::Dummy(ImVec2(0.0f, ImGui::GetTextLineHeight())); ImNodes::EndOutputAttribute(); } // 必要构造 CSV_Column_Input_Connector::CSV_Column_Input_Connector(Independent_ID_Generator *ID_Generator) : Abs_Connector(ID_Generator, CONNECTOR_TYPE_INPUT, "CSV Column") {} // 绘制接口 void CSV_Column_Input_Connector::Show() { // 输出接口点 ImNodes::BeginInputAttribute(this->id, ImNodesPinShape_TriangleFilled); // 填充占位 ImGui::Dummy(ImVec2(0.0f, ImGui::GetTextLineHeight())); ImNodes::EndInputAttribute(); } // 必要构造 CSV_Column_Output_Connector::CSV_Column_Output_Connector(Independent_ID_Generator *ID_Generator) : Abs_Connector(ID_Generator, CONNECTOR_TYPE_OUTPUT, "CSV Column") {} // 绘制接口 void CSV_Column_Output_Connector::Show() { // 输出接口点 ImNodes::BeginOutputAttribute(this->id, ImNodesPinShape_TriangleFilled); // 填充占位 ImGui::Dummy(ImVec2(0.0f, ImGui::GetTextLineHeight())); ImNodes::EndOutputAttribute(); } // ================================================================================================= // 必要构造 Connector_Test_Node::Connector_Test_Node(Independent_ID_Generator *Node_ID_Generator, Independent_ID_Generator *Connector_ID_Generator, ImVec2 initial_position) : Abs_Node(Node_ID_Generator, Connector_ID_Generator, NODE_TYPE_CONNECTOR_TEST, initial_position) { // 判定是否成功申请ID , 后加载测试用节点列表 if (this->id != -1) { // DLT MSG 相关接口 this->Connector_List.push_back(std::make_shared(Connector_ID_Generator)); // [0] -> MSG this->Connector_List.push_back(std::make_shared(Connector_ID_Generator)); // [1] MSG -> // CSV 相关接口 this->Connector_List.push_back(std::make_shared(Connector_ID_Generator)); // [2] -> Column this->Connector_List.push_back(std::make_shared(Connector_ID_Generator)); // [3] Column -> } } // 绘制节点 void Connector_Test_Node::Show(void) { if (this->close_flag == true) return; // 初始化位置设定 if ((this->initial_position.x != 0) || (this->initial_position.y != 0)) { ImNodes::SetNodeScreenSpacePos(this->id, this->initial_position); this->initial_position = ImVec2(0, 0); } // 全宽适配 bool all_width_fit = true; // 绘制节点 ImNodes::BeginNode(this->id); { // 获取节点当前长宽维度 ImVec2 dimension = ImNodes::GetNodeDimensions(this->id); // 标题部分 ImNodes::BeginNodeTitleBar(); { const char *title_str = u8"接口测试用节点"; ImGui::Text(title_str); ImGui::SameLine(); { ImGui::TextDisabled(u8"(?)"); // 上下边距为调整 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f)); if (ImGui::BeginItemTooltip()) { ImGui::Text("Node ID : %d\n", this->id); ImGui::Separator(); ImGui::Text(u8"注意!仅供接口测试使用!\n该节点不会进行任何处理操作,且不会生成任何产物"); ImGui::EndTooltip(); } ImGui::PopStyleVar(); } ImGui::SameLine(); // 节点宽度调整 auto button_diameter = ImGui::GetTextLineHeight(); auto text_width = ImGui::CalcTextSize(title_str).x + ImGui::CalcTextSize(u8"(?)").x; auto Tittle_Str_Width = text_width + ImNodes::GetStyle().NodePadding.x * 2 + ImGui::GetStyle().ItemSpacing.x * 2; // 宽度判定 if (dimension.x < Tittle_Str_Width + button_diameter + ImGui::GetStyle().ItemSpacing.x) all_width_fit = false; ImGui::Dummy(ImVec2(this->node_width - Tittle_Str_Width - button_diameter - ImGui::GetStyle().ItemSpacing.x, 0.0f)); ImGui::SameLine(); // 绘制关闭按钮 if (CircleButtonWithX("#X", ImGui::GetTextLineHeight() / 2)) this->close_flag = true; } ImNodes::EndNodeTitleBar(); // 节点主体绘制 { ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, ImGui::GetStyle().ItemSpacing.y)); // 绘制DLT相关接口组 { // 宽度判定 auto text_width = ImGui::CalcTextSize("-> DLT-In").x + ImGui::CalcTextSize("DLT-Out ->").x; if (dimension.x < text_width + ImNodes::GetStyle().NodePadding.x * 2) all_width_fit = false; this->Connector_List[0]->Show(); ImGui::SameLine(); ImGui::Text("-> DLT-In"); ImGui::SameLine(); ImGui::Dummy(ImVec2(this->node_width - text_width - ImNodes::GetStyle().NodePadding.x * 2, 0.0f)); ImGui::SameLine(); ImGui::Text("DLT-Out ->"); ImGui::SameLine(); this->Connector_List[1]->Show(); } // 绘制CSV列相关接口组 { // 宽度判定 auto text_width = ImGui::CalcTextSize("-> CSV-Column-In").x + ImGui::CalcTextSize("CSV-Column-Out ->").x; if (dimension.x < text_width + ImNodes::GetStyle().NodePadding.x * 2 + ImGui::CalcTextSize("A").x) all_width_fit = false; if (this->node_width == 0) this->node_width = text_width + ImNodes::GetStyle().NodePadding.x * 2 + ImGui::CalcTextSize("A").x; this->Connector_List[2]->Show(); ImGui::SameLine(); ImGui::Text("-> CSV-Column-In"); ImGui::SameLine(); ImGui::Dummy(ImVec2(this->node_width - text_width - ImNodes::GetStyle().NodePadding.x * 2, 0.0f)); ImGui::SameLine(); ImGui::Text("CSV-Column-Out ->"); ImGui::SameLine(); this->Connector_List[3]->Show(); } ImGui::PopStyleVar(); } // 使用递进的方式自适应宽度 if (all_width_fit == false) this->node_width += 1.0f; } ImNodes::EndNode(); } // 执行处理流程 bool Connector_Test_Node::Execute_Process(void) { return true; } // 必要构造 MSG_Input_Node::MSG_Input_Node(Independent_ID_Generator *Node_ID_Generator, Independent_ID_Generator *Connector_ID_Generator, ImVec2 initial_position) : Abs_Node(Node_ID_Generator, Connector_ID_Generator, NODE_TYPE_MSG_LINE_INPUT, initial_position) { // 判定是否成功申请ID if (this->id != -1) { // 消息输出节点 this->Connector_List.push_back(std::make_shared(Connector_ID_Generator)); } } // 绘制节点 void MSG_Input_Node::Show(void) { if (this->close_flag == true) return; // 初始化位置设定 if ((this->initial_position.x != 0) || (this->initial_position.y != 0)) { ImNodes::SetNodeScreenSpacePos(this->id, this->initial_position); this->initial_position = ImVec2(0, 0); } // 全宽适配 bool all_width_fit = true; // 绘制节点 ImNodes::BeginNode(this->id); { // 标题部分 ImNodes::BeginNodeTitleBar(); { const char *title_str = u8"DLT-信息输入节点"; ImGui::Text(title_str); ImGui::SameLine(); { ImGui::TextDisabled(u8"(?)"); // 上下边距为调整 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f)); if (ImGui::BeginItemTooltip()) { ImGui::Text("Node ID : %d\n", this->id); ImGui::Separator(); ImGui::Text(u8"每个处理流程开始时,输出一条DLT消息;\n每个此类节点输出的消息均会独立遍历所有输入文件;"); ImGui::EndTooltip(); } ImGui::PopStyleVar(); } ImGui::SameLine(); // 节点宽度调整 ImVec2 dimension = ImNodes::GetNodeDimensions(this->id); auto button_diameter = ImGui::GetTextLineHeight(); auto text_width = ImGui::CalcTextSize(title_str).x + ImGui::CalcTextSize(u8"(?)").x; auto Tittle_Str_Width = text_width + ImNodes::GetStyle().NodePadding.x * 2 + ImGui::GetStyle().ItemSpacing.x * 2; if (this->node_width == 0) this->node_width = Tittle_Str_Width + button_diameter + ImGui::GetStyle().ItemSpacing.x; if (dimension.x < Tittle_Str_Width + button_diameter + ImGui::GetStyle().ItemSpacing.x) all_width_fit = false; ImGui::Dummy(ImVec2(this->node_width - Tittle_Str_Width - button_diameter - ImGui::GetStyle().ItemSpacing.x, 0.0f)); ImGui::SameLine(); // 绘制关闭按钮 if (CircleButtonWithX("#X", button_diameter / 2)) this->close_flag = true; } ImNodes::EndNodeTitleBar(); // 节点主体部分 { ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, ImGui::GetStyle().ItemSpacing.y)); // 靠右占位 ImVec2 dimension = ImNodes::GetNodeDimensions(this->id); auto text_width = ImGui::CalcTextSize(u8"DLT-Out ->").x; if (dimension.x < text_width + ImNodes::GetStyle().NodePadding.x * 2) all_width_fit = false; ImGui::Dummy(ImVec2(this->node_width - text_width - ImNodes::GetStyle().NodePadding.x * 2, 0.0f)); ImGui::SameLine(); // 绘制DLT输出接口 ImGui::Text(u8"DLT-Out ->"); ImGui::SameLine(); this->Connector_List[0]->Show(); ImGui::PopStyleVar(); } // 使用递进的方式自适应宽度 if (all_width_fit == false) this->node_width += 1.0f; } ImNodes::EndNode(); } // 执行处理流程 bool MSG_Input_Node::Execute_Process(void) { return true; };