DLT_Splitter/Src/Nodes_And_Connectors.cpp

540 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Nodes_And_Connectors.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;
}
// 获取接口列表
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);
}
// 绘制节点
ImNodes::BeginNode(this->id);
{
// 标题部分
ImNodes::BeginNodeTitleBar();
{
ImGui::Text(u8"接口测试用节点");
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();
// 节点宽度调整
ImGui::Dummy(ImVec2(120.0f, 0.0f));
ImGui::SameLine();
// 绘制关闭按钮
if (CircleButtonWithX("#X", ImGui::GetTextLineHeight() / 2))
this->close_flag = true;
}
ImNodes::EndNodeTitleBar();
// 绘制DLT相关接口组
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, ImGui::GetStyle().ItemSpacing.y));
this->Connector_List[0]->Show();
ImGui::SameLine();
ImGui::Text("-> DLT-In");
ImGui::SameLine();
ImGui::Dummy(ImVec2(ImNodes::GetNodeDimensions(this->id).x - ImGui::CalcTextSize("-> DLT-In").x - ImGui::CalcTextSize("DLT-Out ->").x - (ImNodes::GetStyle().NodePadding.x + ImGui::GetStyle().ItemSpacing.x) * 2, 0.0f));
ImGui::SameLine();
ImGui::Text("DLT-Out ->");
ImGui::SameLine();
this->Connector_List[1]->Show();
ImGui::PopStyleVar();
}
// 绘制CSV列相关接口组
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, ImGui::GetStyle().ItemSpacing.y));
this->Connector_List[2]->Show();
ImGui::SameLine();
ImGui::Text("-> CSV-Column-In");
ImGui::SameLine();
ImGui::Dummy(ImVec2(ImNodes::GetNodeDimensions(this->id).x - ImGui::CalcTextSize("-> CSV-Column-In").x - ImGui::CalcTextSize("CSV-Column-Out ->").x - (ImNodes::GetStyle().NodePadding.x + ImGui::GetStyle().ItemSpacing.x) * 2, 0.0f));
ImGui::SameLine();
ImGui::Text("CSV-Column-Out ->");
ImGui::SameLine();
this->Connector_List[3]->Show();
ImGui::PopStyleVar();
}
}
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));
this->Connector_List.push_back(std::make_shared<MSG_InPut_Connector>(Connector_ID_Generator));
}
}
// 绘制节点
void MSG_Input_Node::Show(void)
{
// auto ImNodesStyle = ImNodes::GetStyle();
// auto ImGuiStyle = ImGui::GetStyle();
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);
}
// 绘制节点
ImNodes::BeginNode(this->id);
{
// 标题部分
ImNodes::BeginNodeTitleBar();
{
ImGui::Text(u8"DLT-信息输入节点");
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();
// ImGui::Dummy(ImVec2(node_width - ImGui::CalcTextSize(u8"DLT-信息输入节点").x - ImGui::GetTextLineHeight(), 0.0f));
// 节点宽度调整
ImGui::Dummy(ImVec2(20.0f, 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));
ImVec2 dimension = ImNodes::GetNodeDimensions(this->id);
ImVec2 text_size = ImGui::CalcTextSize(u8"OUT ->");
if (dimension.x > text_size.x)
{
ImGui::Dummy(ImVec2(dimension.x - text_size.x - (ImNodes::GetStyle().NodePadding.x + ImGui::GetStyle().ItemSpacing.x) * 2, 0.0f));
ImGui::SameLine();
}
ImGui::Text(u8"OUT ->");
ImGui::SameLine();
/**
* @todo 自定义接口绘制
*/
for (auto Connector : this->Connector_List)
{
Connector->Show();
}
ImGui::PopStyleVar();
}
ImNodes::EndNode();
}
// 执行处理流程
bool MSG_Input_Node::Execute_Process(void)
{
return true;
};