592 lines
19 KiB
C++
592 lines
19 KiB
C++
#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 *> 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;
|
||
}
|
||
|
||
// 获取节点配置参数
|
||
Json_Arry Abs_Node::Get_Arguments(void)
|
||
{
|
||
return Json_Arry();
|
||
}
|
||
|
||
// 应用配置参数
|
||
bool Abs_Node::Apply_Arguments(Json_Arry Arg_Arry)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
// 获取接口列表
|
||
std::vector<std::shared_ptr<Abs_Connector>> &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<MSG_InPut_Connector>(Connector_ID_Generator)); // [0] -> MSG
|
||
this->Connector_List.push_back(std::make_shared<MSG_OutPut_Connector>(Connector_ID_Generator)); // [1] MSG ->
|
||
|
||
// CSV 相关接口
|
||
this->Connector_List.push_back(std::make_shared<CSV_Column_Input_Connector>(Connector_ID_Generator)); // [2] -> Column
|
||
this->Connector_List.push_back(std::make_shared<CSV_Column_Output_Connector>(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<MSG_OutPut_Connector>(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;
|
||
}; |