Refactored the implementation of the Workflow_Editor class: now uses shared_ptr and vector for automatic lifecycle management && decoupled nodes and interfaces with abstract base class implementation && implemented an independent unique ID generator && implemented test nodes and interfaces && implemented automatic connection drawing.

This commit is contained in:
LuChiChick 2026-03-13 10:55:28 +08:00
parent b86798db10
commit f6e70335f9
8 changed files with 926 additions and 275 deletions

View File

@ -5,15 +5,15 @@
#include "imgui_impl_win32.h"
#include "imgui_impl_dx11.h"
#include "Workflow_Editor.hpp"
#include "Type_Descriptions.hpp"
extern "C"
{
#include "windows.h"
#include "d3d11.h"
}
#include "Type_Descriptions.hpp"
#include "Workflow-Editor.hpp"
// 主窗体句柄
extern HWND Main_Window_hWnd;
@ -31,6 +31,6 @@ extern Input_File_Node *input_dlt_file_list_head;
extern size_t input_dlt_file_count;
// 节点编辑器
extern Workflow_Editor_Class Workflow_Editor;
extern class Workflow_Editor Workflow_Editor;
#endif

25
Inc/ID_Generator.hpp Normal file
View File

@ -0,0 +1,25 @@
#ifndef __ID_GENERATOR__
#define __ID_GENERATOR__
#include <vector>
// 唯一ID生成器
class Independent_ID_Generator
{
protected:
// 连续ID串
typedef struct
{
int begin;
int end;
} Continuous_ID_Section;
std::vector<Continuous_ID_Section> continuous_id_list;
public:
// 获取ID
int Request_ID(void);
// 释放ID true-> success / false -> fail
bool Release_ID(const int ID);
};
#endif

View File

@ -0,0 +1,214 @@
#ifndef __NODES_AND_CONNECTORS__
#define __NODES_AND_CONNECTORS__
#include <vector>
#include <memory>
#include "imgui.h"
#include "imnodes.h"
#include "ID_Generator.hpp"
// =====================================接口抽象======================================================
class Abs_Connector // 抽象接口类
{
protected:
typedef enum
{
CONNECTOR_TYPE_UNKNOWN, // 未知连接点类型
CONNECTOR_TYPE_OUTPUT, // 输出
CONNECTOR_TYPE_INPUT, // 输入
} Connector_Type_Enum; // 接口类型枚举
// ID 分配器
Independent_ID_Generator *ID_Generator;
int id; // ID
Connector_Type_Enum type; // 类型标识
const char *socket_str; // 套接字字符串
Abs_Connector *provider; // 提供者
std::vector<Abs_Connector *> receiver_list; // 接收方
void *product; // 产物
public:
// 显式禁用默认构造
Abs_Connector() = delete;
// 必要构造
Abs_Connector(Independent_ID_Generator *ID_Generator, Connector_Type_Enum type, const char *socket_str);
// 析构
~Abs_Connector();
// 连接到目标连接点
virtual bool Connect_To(Abs_Connector *target);
// 断开连接
virtual void Disconnect(void);
// 注册产物
virtual bool Register_Product(void *product, size_t size);
// 获取上级节点
virtual Abs_Connector *Get_Provider(void);
// 获取产物
virtual void *Get_Product(void);
// 获取ID
virtual int Get_ID(void);
// 绘制连接点
virtual void Show(void) = 0;
};
// =====================================节点抽象======================================================
class Abs_Node // 抽象节点类
{
protected:
typedef enum
{
NODE_TYPE_UNKNOWN, // 未知节点类型
NODE_TYPE_MSG_LINE_INPUT, // 消息输入节点
NODE_TYPE_CSV_EXPORTER, // CSV输出节点
} Node_Type_Enum; // 节点类型枚举
// ID 分配器
Independent_ID_Generator *Node_ID_Generator; // 节点ID生成器
Independent_ID_Generator *Connector_ID_Generator; // 连接点ID生成器
int id; // ID
Node_Type_Enum type; // 类型
ImVec2 initial_position; // 初始位置
bool close_flag; // 关闭标志位
// 接口列表
std::vector<std::shared_ptr<Abs_Connector>> Connector_List;
public:
// 显式禁用默认构造
Abs_Node() = delete;
// 必要构造
Abs_Node(Independent_ID_Generator *Node_ID_Generator,
Independent_ID_Generator *Connector_ID_Generator,
Node_Type_Enum type,
ImVec2 initial_position = ImVec2(0, 0));
// 析构
~Abs_Node();
// 绘制节点
virtual void Show(void) = 0;
// 执行处理流程
virtual bool Execute_Process(void) = 0;
// 获取关闭信号
virtual bool Get_CloseFlag(void);
// 获取接口列表
std::vector<std::shared_ptr<Abs_Connector>> &Get_Connector_List(void);
};
// ====================================接口类声明================================================
// DLT信息输出接口
class MSG_OutPut_Connector : public Abs_Connector
{
public:
// 显式禁用默认构造
MSG_OutPut_Connector() = delete;
// 必要构造
explicit MSG_OutPut_Connector(Independent_ID_Generator *ID_Generator);
// 绘制接口
virtual void Show(void);
};
// DLT信息输入接口
class MSG_InPut_Connector : public Abs_Connector
{
public:
// 显式禁用默认构造
MSG_InPut_Connector() = delete;
// 必要构造
explicit MSG_InPut_Connector(Independent_ID_Generator *ID_Generator);
// 绘制接口
virtual void Show(void);
};
// CSV 列输入接口
class CSV_Column_Input_Connector : public Abs_Connector
{
public:
// 显式禁用默认构造
CSV_Column_Input_Connector() = delete;
// 必要构造
explicit CSV_Column_Input_Connector(Independent_ID_Generator *ID_Generator);
// 绘制接口
virtual void Show(void);
};
// CSV 列输出接口
class CSV_Column_Output_Connector : public Abs_Connector
{
public:
// 显式禁用默认构造
CSV_Column_Output_Connector() = delete;
// 必要构造
explicit CSV_Column_Output_Connector(Independent_ID_Generator *ID_Generator);
// 绘制接口
virtual void Show(void);
};
// ====================================节点类声明================================================
// 接口测试节点
class Connector_Test_Node : public Abs_Node
{
public:
// 显式禁用默认构造
Connector_Test_Node() = delete;
// 必要构造
Connector_Test_Node(Independent_ID_Generator *Node_ID_Generator,
Independent_ID_Generator *Connector_ID_Generator,
ImVec2 initial_position = ImVec2(0, 0));
// 绘制节点
virtual void Show(void);
// 执行处理流程
virtual bool Execute_Process(void);
};
// DLT信息输入类起始点
class MSG_Input_Node : public Abs_Node
{
public:
// 显式禁用默认构造
MSG_Input_Node() = delete;
// 必要构造
MSG_Input_Node(Independent_ID_Generator *Node_ID_Generator,
Independent_ID_Generator *Connector_ID_Generator,
ImVec2 initial_position = ImVec2(0, 0));
// 绘制节点
virtual void Show(void);
// 执行处理流程
virtual bool Execute_Process(void);
};
#endif

View File

@ -1,89 +1,58 @@
#ifndef __WORKFLOW_EDITOR_HPP__
#define __WORKFLOW_EDITOR_HPP__
#include "imgui.h"
extern "C"
{
#include "stdint.h"
}
#include <vector>
// // 并行工作链
// class Parallel_Working_List
// {
// private:
// // 节点计数
// size_t node_count;
// // 内部迭代器
// class iterator
// {
// };
// public:
// iterator begin() { return iterator(arr); }
// iterator end() { return iterator(arr + SIZE); }
// };
// 节点类型枚举
typedef enum
{
NODE_TYPE_MSG_LINE_INPUT, // 消息输入节点
NODE_TYPE_CSV_EXPORTER, // CSV输出节点
} NodeType;
// 节点基类
class Node_Class
{
protected:
int id; // 节点ID
bool initial_state; // 初始状态
ImVec2 initial_position; // 初始位置
public:
// 初始化列表构造
explicit Node_Class(int id, ImVec2 initial_position = ImVec2(0, 0)) : id(id), initial_state(true), initial_position(initial_position) {}
int getID() { return this->id; }
/**
*
* @param null
* @return 0 -> normal : 1-> close
*/
virtual bool show_and_get_state(void) = 0;
virtual ~Node_Class() = default; // 抽象基类必须有虚析构函数
};
// 消息输出节点
class MsgLine_Input_Node_Class : public Node_Class
{
public:
explicit MsgLine_Input_Node_Class(int id, ImVec2 initial_position = ImVec2(0, 0)) : Node_Class(id, initial_position) {};
bool show_and_get_state(void) override;
};
#include <memory>
#include "imgui.h"
#include "imnodes.h"
#include "ID_Generator.hpp"
#include "Nodes_And_Connectors.hpp"
// 节点编辑器类
class Workflow_Editor_Class
class Workflow_Editor
{
protected:
// 节点列表
std::vector<Node_Class *> Node_List;
typedef enum
{
NODE_TYPE_UNKNOWN, // 未知节点类型
NODE_TYPE_MSG_LINE_INPUT, // 消息输入节点
NODE_TYPE_CSV_EXPORTER, // CSV输出节点
} Node_Type_Enum; // 节点类型枚举
// ID 分配器
Independent_ID_Generator Connector_ID_Generator; // 连接点ID生成器
Independent_ID_Generator Node_ID_Generator; // 节点ID生成器
Independent_ID_Generator Edge_ID_Generator; // 边ID生成器
// 边定义
typedef struct
{
int id = -1; // 边ID
int source_connector_id = -1; // 源连接点
int target_connector_id = -1; // 目标连接点
} Edge;
// 数据池
std::vector<std::shared_ptr<Abs_Connector>> Connector_Pool; // 连接点池
std::vector<std::shared_ptr<Abs_Node>> Node_Pool; // 节点池
std::vector<Edge> Edge_Pool; // 边池
/**
* N个元素即N个处理流程
*
*
*
*/
std::vector<std::vector<std::vector<std::shared_ptr<Abs_Node>>>> Process_Route; // 工作层级路由
std::vector<std::shared_ptr<Abs_Node>> Separate_Node_List; // 散点列表
// =====================================函数声明=================================================
// 新增节点 true -> success / false -> failed
bool Add_Node(Node_Type_Enum type, ImVec2 initial_position = ImVec2(0, 0));
public:
// 构造函数
Workflow_Editor_Class();
// 析构函数
~Workflow_Editor_Class();
// 显示工作流节点编辑器
// 绘制节点编辑器
void Show(void);
// 新增节点
void Add_Node(NodeType type, ImVec2 initial_position = ImVec2(0, 0));
};
#endif

View File

@ -17,4 +17,4 @@ Input_File_Node *input_dlt_file_list_head;
size_t input_dlt_file_count;
// 节点编辑器
Workflow_Editor_Class Workflow_Editor;
class Workflow_Editor Workflow_Editor;

98
Src/ID_Generator.cpp Normal file
View File

@ -0,0 +1,98 @@
#include "ID_Generator.hpp"
// 请求ID
int Independent_ID_Generator::Request_ID()
{
// 没有元素时
if (this->continuous_id_list.size() == 0)
{
this->continuous_id_list.push_back({0, 0});
// 判定分配情况
if (this->continuous_id_list.size() == 0)
return -1;
else
return 0;
}
// 第一段未从最小 ID 开启
auto first_iterator = this->continuous_id_list.begin();
if (first_iterator->begin != 0)
{
if (first_iterator->begin == 1)
first_iterator->begin--;
else
{
// 划分新段
size_t pre_size = this->continuous_id_list.size();
first_iterator = this->continuous_id_list.insert(first_iterator, {0, 0});
if (!(this->continuous_id_list.size() > pre_size))
return -1;
}
return 0;
}
// 仅第一段时
if (this->continuous_id_list.size() == 1)
{
first_iterator->end++;
return first_iterator->end;
}
// 有两段及以上时,判断是否出现合并
auto second_iterator = first_iterator + 1;
if (first_iterator->end + 2 == second_iterator->begin)
{
int target_id = first_iterator->end + 1;
first_iterator->end = second_iterator->end;
this->continuous_id_list.erase(second_iterator);
return target_id;
}
else
{
first_iterator->end++;
return first_iterator->end;
}
return -1;
}
// 释放ID true-> success / false -> fail
bool Independent_ID_Generator::Release_ID(const int ID)
{
// 遍历查找所属片
for (auto iterator = this->continuous_id_list.begin(); iterator != this->continuous_id_list.end(); iterator++)
{
// 找到对应的ID所属片
if (ID >= iterator->begin && ID <= iterator->end)
{
// 散点删除
if (iterator->begin == iterator->end)
this->continuous_id_list.erase(iterator);
else if (ID == iterator->begin) // 前端点
iterator->begin++;
else if (ID == iterator->end) // 后端点
iterator->end--;
else // 中间段
{
// 插入后返回新的迭代器
size_t pre_size = this->continuous_id_list.size();
iterator = this->continuous_id_list.insert(iterator, {iterator->begin, ID - 1});
// 判定分配是否成功
if (!(this->continuous_id_list.size() > pre_size))
return false;
// 记录ID
iterator++;
iterator->begin = ID + 1;
}
// 完成并退出
return true;
}
}
// 没有找到所属片
return false;
}

View File

@ -0,0 +1,378 @@
#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;
this->provider = nullptr;
};
// 析构
Abs_Connector::~Abs_Connector()
{
// 释放产物
if (this->product != nullptr)
free(product);
// 断开连接
this->Disconnect();
// 释放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))
{
target->provider = this;
this->receiver_list.push_back(target);
return true;
}
if ((this->type == CONNECTOR_TYPE_INPUT) && (target->type == CONNECTOR_TYPE_OUTPUT))
{
target->receiver_list.push_back(this);
this->provider = target;
return true;
}
}
return false;
}
// 断开连接
void Abs_Connector::Disconnect(void)
{
// 受点断开供方连接
if (this->type == CONNECTOR_TYPE_INPUT)
{
// 断开供方对自身的记录
for (auto iterator = this->provider->receiver_list.begin(); iterator != this->provider->receiver_list.end(); iterator++)
{
// 供方断开自身列表记录
if ((*iterator) == this)
{
this->provider->receiver_list.erase(iterator);
break;
}
}
// 断开自身对供方的记录
this->provider = nullptr;
}
// 供方断开所有受点的供方记录
if (this->type == CONNECTOR_TYPE_OUTPUT)
{
// 断开受点的供方记录
for (auto receiver : this->receiver_list)
receiver->provider = nullptr;
// 清空受点列表
decltype(this->receiver_list) empty_list;
this->receiver_list.swap(empty_list);
}
}
// 注册产物
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;
}
// 获取上级节点
Abs_Connector *Abs_Connector::Get_Provider(void)
{
return this->provider;
}
// 获取产物
void *Abs_Connector::Get_Product(void)
{
// 输出节点返回直接产物
if (this->type == CONNECTOR_TYPE_OUTPUT)
return this->product;
// 输入节点返回间接产物(提供者方产物)
if (this->type == CONNECTOR_TYPE_INPUT)
{
if (this->provider == nullptr)
return nullptr;
return this->provider->product;
}
// 未知类型
return nullptr;
}
// 获取ID
int Abs_Connector::Get_ID(void)
{
return this->id;
}
// =================================================================================================
// 必要构造
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);
}
// 获取关闭信号
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_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, 1);
ImNodes::EndOutputAttribute();
}
// 必要构造
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, 1);
ImNodes::EndInputAttribute();
}
// =================================================================================================
// 必要构造
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;
};

View File

@ -1,171 +1,130 @@
#include "Workflow-Editor.hpp"
#include "imgui.h"
#include "Workflow_Editor.hpp"
#include "imgui_internal.h"
#include "imnodes.h"
#include <algorithm>
// 构造函数
Workflow_Editor_Class::Workflow_Editor_Class() {}
// 析构函数
Workflow_Editor_Class::~Workflow_Editor_Class()
// 新增节点
bool Workflow_Editor::Add_Node(Node_Type_Enum type, ImVec2 initial_position)
{
// 释放资源
for (auto &pNode : this->Node_List)
delete pNode;
}
// 新节点
std::shared_ptr<Abs_Node> p_New_Node;
// 客制化圆形带X按钮
bool CircleButtonWithX(const char *id, float radius)
// 记录节点
switch (type)
{
ImGuiWindow *window = ImGui::GetCurrentWindow();
if (window->SkipItems)
case NODE_TYPE_MSG_LINE_INPUT: // 消息行输入 (头节点)
// 创建节点
p_New_Node = std::make_shared<MSG_Input_Node>(&this->Node_ID_Generator,
&this->Connector_ID_Generator,
initial_position);
break;
// // 记录到节点池和接口池
// this->Node_Pool.push_back(p_New_Node);
// for (auto p_Connector : p_New_Node->Get_Connector_List())
// this->Connector_Pool.push_back(p_Connector);
// // 编辑工作路由
// {
// // 起始层级只有起始节点
// std::vector<std::shared_ptr<Abs_Node>> Begin_Layer;
// Begin_Layer.push_back(p_New_Node);
// // 层级列表仅有起始层级
// std::vector<std::vector<std::shared_ptr<Abs_Node>>> Layer_List;
// Layer_List.push_back(Begin_Layer);
// // 插入工作路由表
// this->Process_Route.push_back(Layer_List);
// }
// return true;
case NODE_TYPE_CSV_EXPORTER: // CSV输出器
break;
default:
return false;
}
// 创建ID
ImGuiID button_id = window->GetID(id);
if (p_New_Node.get() != nullptr)
{
// 将新增的节点及其接口记录到对应的池
this->Node_Pool.push_back(p_New_Node);
for (auto p_Connector : p_New_Node->Get_Connector_List())
this->Connector_Pool.push_back(p_Connector);
// 计算按钮位置和大小
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))
// 记录到散点池
this->Separate_Node_List.push_back(p_New_Node);
return true;
}
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;
}
// 消息行输入节点绘制函数
bool MsgLine_Input_Node_Class::show_and_get_state()
// 绘制节点编辑器
void Workflow_Editor::Show(void)
{
// 节点宽度
const float node_width = 200.0f;
bool delete_flag = false;
// 初始化位置设定
if (this->initial_state)
{
ImNodes::SetNodeScreenSpacePos(this->id, this->initial_position);
this->initial_state = false;
}
// 绘制节点
ImNodes::BeginNode(this->id);
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, ImGui::GetStyle().ItemSpacing.y));
// 标题部分
ImNodes::BeginNodeTitleBar();
{
ImGui::TextUnformatted(u8"DLT-信息输入节点");
ImGui::SameLine();
ImGui::Dummy(ImVec2(node_width - ImGui::CalcTextSize(u8"DLT-信息输入节点").x - ImGui::GetTextLineHeight(), 0.0f));
ImGui::SameLine();
// 绘制关闭按钮
if (CircleButtonWithX("#X", ImGui::GetTextLineHeight() / 2))
delete_flag = true;
}
ImNodes::EndNodeTitleBar();
// // 正文部分
// ImGui::Text(u8"DLT消息输入流\n每次输出一条消息");
// ImGui::Text(u8"(节点ID : %d)", this->id);
// 链接点
ImNodes::BeginOutputAttribute(0, 1);
// const float label_width = ImGui::CalcTextSize(u8"DLT消息行->").x;
// ImGui::Indent(label_width);
ImGui::Dummy(ImVec2(node_width - ImGui::CalcTextSize("(?) DLT MSG ->").x, 0.0f));
ImGui::SameLine();
// Help Mark
{
ImGui::TextDisabled("(?) ");
if (ImGui::BeginItemTooltip())
{
ImGui::TextUnformatted(u8"每个处理流程开始时输出一条DLT消息\n每个此类节点输出的消息均会独立遍历所有输入文件;");
ImGui::EndTooltip();
}
}
ImGui::SameLine();
ImGui::TextUnformatted("DLT MSG ->");
ImNodes::EndOutputAttribute();
ImGui::PopStyleVar();
}
ImNodes::EndNode();
// 返回节点状态
return delete_flag;
}
// 显示工作流节点编辑器
void Workflow_Editor_Class::Show(void)
{
// 浅色主题
// 浅色主题节点编辑器窗体
ImNodes::StyleColorsLight();
ImNodes::BeginNodeEditor();
ImGui::PopStyleVar();
{
// 显示所有节点
for (auto iterator = this->Node_List.begin(); iterator != this->Node_List.end(); iterator++)
for (auto iterator = this->Node_Pool.begin(); iterator != this->Node_Pool.end(); iterator++)
{
if ((*iterator)->show_and_get_state())
auto Connector_List = (*iterator)->Get_Connector_List();
if ((*iterator)->Get_CloseFlag() == true)
{
delete *iterator;
// 迭代器删除后会返回下一个位置的迭代器
iterator = this->Node_List.erase(iterator);
// 删除列表中所有与该节点接口相关的边并从接口池中删除
for (auto pConnector : Connector_List)
{
int connector_id = pConnector->Get_ID();
// 遍历边池
for (auto iterator = this->Edge_Pool.begin(); iterator != this->Edge_Pool.end(); iterator++)
{
if ((iterator->source_connector_id == connector_id) || (iterator->target_connector_id == connector_id))
{
// 注销边ID
this->Edge_ID_Generator.Release_ID(connector_id);
// 注销边记录,迭代器删除后会返回下一个位置的迭代器
iterator = this->Edge_Pool.erase(iterator);
iterator--;
}
}
// 从接口池中移除
for (auto iterator = this->Connector_Pool.begin(); iterator != this->Connector_Pool.end(); iterator++)
{
if (*iterator == pConnector)
{
// 注销节点记录
iterator = this->Connector_Pool.erase(iterator);
break;
}
}
}
/**
* @todo
* @todo
*/
// 从节点池中删除该节点,迭代器删除后会返回下一个位置的迭代器
iterator = this->Node_Pool.erase(iterator);
iterator--;
}
else
// 绘制节点
(*iterator)->Show();
}
// 右键菜单
{
const bool open_popup = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
ImNodes::IsEditorHovered() &&
ImGui::IsMouseReleased(ImGuiMouseButton_Right);
// 设置弹窗周边Padding
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f));
if (!ImGui::IsAnyItemHovered() && open_popup)
// if (!ImGui::IsAnyItemHovered() && open_popup)
if (open_popup)
{
ImGui::OpenPopup("RightClick_Popup");
}
@ -174,77 +133,85 @@ void Workflow_Editor_Class::Show(void)
{
ImVec2 click_pos = ImGui::GetMousePosOnOpeningCurrentPopup();
// 节点添加菜单
if (ImGui::BeginMenu("Add Nodes"))
if (ImGui::BeginMenu(u8"创建节点"))
{
if (ImGui::MenuItem("Msg input node."))
if (ImGui::MenuItem(u8"DLT信息输入节点"))
this->Add_Node(NODE_TYPE_MSG_LINE_INPUT, click_pos);
ImGui::EndMenu();
}
ImGui::EndPopup();
}
ImGui::PopStyleVar();
}
{
// ImNodes::BeginNode(1);
// ImNodes::BeginNodeTitleBar();
// 显示所有的连线
for (auto Edge : this->Edge_Pool)
ImNodes::Link(Edge.id, Edge.source_connector_id, Edge.target_connector_id);
// // ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 10.0f); // 绘制风格栈压入窗口圆角为0
// // ImGui::Button("X");
// // ImGui::PopStyleVar();
// if (CircleButtonWithX("#X", ImGui::GetTextLineHeight() / 2))
// {
// };
// ImGui::SameLine();
// ImGui::TextUnformatted("Output Node");
// ImNodes::EndNodeTitleBar();
// ImGui::Text("Test Format %%d :%d", 123);
// ImGui::Button("Click");
// ImGui::SameLine();
// static bool check = false;
// ImGui::Checkbox("", &check);
// ImNodes::EndNode();
}
}
// 缩略图
ImNodes::MiniMap(0.2f, ImNodesMiniMapLocation_TopRight);
}
ImNodes::EndNodeEditor();
// 处理连线
{
int source_id = -1, target_id = -1;
if (ImNodes::IsLinkCreated(&source_id, &target_id))
{
// 查找接口
bool find = false;
std::shared_ptr<Abs_Connector> p_source_connector;
std::shared_ptr<Abs_Connector> p_target_connector;
for (auto pNode : this->Node_Pool)
{
for (auto pConnector : pNode->Get_Connector_List())
{
if (pConnector->Get_ID() == source_id)
p_source_connector = pConnector;
if (pConnector->Get_ID() == target_id)
p_target_connector = pConnector;
if ((p_source_connector.get() != nullptr) && (p_target_connector.get() != nullptr))
{
find = true;
break;
}
}
// 添加指定类型节点
void Workflow_Editor_Class::Add_Node(NodeType type, ImVec2 initial_position)
{
// 获取可用ID
auto get_id = [&]() -> int
{
int target_id = 0;
for (auto &pNode : this->Node_List)
if (target_id == pNode->getID())
target_id++;
else
break;
return target_id;
};
// 记录节点
switch (type)
{
case NODE_TYPE_MSG_LINE_INPUT: // 消息行输入
this->Node_List.push_back(new MsgLine_Input_Node_Class(get_id(), initial_position));
break;
case NODE_TYPE_CSV_EXPORTER: // CSV输出器
default:
if (find)
break;
}
// 重新排序确保后续ID分配正常
std::sort(this->Node_List.begin(),
this->Node_List.end(),
[](Node_Class *a, Node_Class *b) -> bool
{ return a->getID() < b->getID(); });
// 判定查找结果
if (find)
{
// 输入类型节点只允许一个父接口,输出类型节点可以有多个子接口
if (p_target_connector->Get_Provider() != nullptr)
{
int origin_source_id = p_target_connector->Get_Provider()->Get_ID();
for (auto iterator = this->Edge_Pool.begin(); iterator != this->Edge_Pool.end(); iterator++)
{
if (iterator->source_connector_id == origin_source_id && iterator->target_connector_id == target_id)
{
this->Edge_ID_Generator.Release_ID(iterator->id);
this->Edge_Pool.erase(iterator);
break;
}
}
}
// 尝试连接
if (p_source_connector->Connect_To(p_target_connector.get()) == true)
{
// 记录到边池
this->Edge_Pool.push_back({this->Edge_ID_Generator.Request_ID(), source_id, target_id});
/**
* @todo
*/
}
}
}
}
}