DLT_Splitter/Src/Workflow_Editor.cpp

470 lines
16 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 "Workflow_Editor.hpp"
#include "imgui_internal.h"
#include "Global_Variables.hpp"
extern "C"
{
#include "windows.h"
}
// 绘制节点编辑器
void Workflow_Editor::Show(void)
{
// 选区信息
bool bounding_box_delete_flag = false;
int bounding_box_link_nums = ImNodes::NumSelectedLinks();
int bounding_box_node_nums = ImNodes::NumSelectedNodes();
// 浅色主题节点编辑器窗体
ImNodes::StyleColorsLight();
ImNodes::BeginNodeEditor();
{
// 显示所有节点
for (auto iterator = this->Node_Pool.begin(); iterator != this->Node_Pool.end(); iterator++)
{
if ((*iterator)->Get_CloseFlag() == true)
{
// 处理节点删除
iterator = this->Del_Node(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 (open_popup)
{
ImGui::OpenPopup("RightClick_Popup");
}
if (ImGui::BeginPopup("RightClick_Popup"))
{
ImVec2 click_pos = ImGui::GetMousePosOnOpeningCurrentPopup();
// 节点添加菜单
if (ImGui::BeginMenu(u8"创建节点"))
{
if (ImGui::MenuItem(u8"接口测试节点"))
this->Add_Node(Abs_Node::NODE_TYPE_CONNECTOR_TEST, click_pos);
if (ImGui::MenuItem(u8"DLT信息输入节点"))
this->Add_Node(Abs_Node::NODE_TYPE_MSG_LINE_INPUT, click_pos);
ImGui::EndMenu();
}
// 删除框选内容
if (ImGui::MenuItem(u8"删除所选内容", nullptr, nullptr, (bounding_box_link_nums > 0) || (bounding_box_node_nums > 0)))
bounding_box_delete_flag = true;
ImGui::EndPopup();
}
ImGui::PopStyleVar();
}
// 显示所有的连线
for (auto Edge : this->Edge_Pool)
ImNodes::Link(Edge.id, Edge.source_connector_id, Edge.target_connector_id);
// 缩略图
ImNodes::MiniMap(0.2f, ImNodesMiniMapLocation_TopRight);
}
ImNodes::EndNodeEditor();
// 处理连线
{
int source_id = -1, target_id = -1;
if (ImNodes::IsLinkCreated(&source_id, &target_id))
this->Add_Link(source_id, target_id);
}
// 处理键盘事件
{
// Ctrl + A 全选
if (ImGui::IsKeyChordPressed(ImGuiMod_Ctrl | ImGuiKey_A) == true)
{
for (auto Link : this->Edge_Pool)
if (ImNodes::IsLinkSelected(Link.id) == false)
ImNodes::SelectLink(Link.id);
for (auto pNode : this->Node_Pool)
if (ImNodes::IsNodeSelected(pNode->Get_ID()) == false)
ImNodes::SelectNode(pNode->Get_ID());
}
// Ctrl + X 剪切
if (ImGui::IsKeyChordPressed(ImGuiMod_Ctrl | ImGuiKey_X) == true)
{
bounding_box_delete_flag = true;
/**
* @todo
* 剪切板实现
*/
}
// Delete 按键释放 或有删除请求
if (ImGui::IsKeyReleased(ImGuiKey_Delete) || bounding_box_delete_flag)
{
// 释放所有选中的边
{
std::vector<int> target_edge_id_list;
target_edge_id_list.resize(ImNodes::NumSelectedLinks());
if (target_edge_id_list.size() > 0)
{
ImNodes::GetSelectedLinks(&target_edge_id_list[0]);
for (auto edge_iterator = this->Edge_Pool.begin(); edge_iterator != this->Edge_Pool.end(); edge_iterator++)
{
if (target_edge_id_list.size() > 0)
for (auto target_id_iterator = target_edge_id_list.begin(); target_id_iterator != target_edge_id_list.end(); target_id_iterator++)
{
if (*target_id_iterator == edge_iterator->id)
{
target_edge_id_list.erase(target_id_iterator);
edge_iterator = this->Del_Link(edge_iterator) - 1;
break;
}
}
else
break;
}
}
}
// 释放所有选中的节点
{
std::vector<int> target_id_list;
target_id_list.resize(ImNodes::NumSelectedNodes());
if (target_id_list.size() > 0)
ImNodes::GetSelectedNodes(&target_id_list[0]);
for (auto target_id : target_id_list)
this->Del_Node(target_id);
}
}
}
}
// 新增节点 true -> success / false -> failed
bool Workflow_Editor::Add_Node(Abs_Node::Node_Type_Enum type, ImVec2 initial_position)
{
// 新节点
std::shared_ptr<Abs_Node> p_New_Node;
// 记录节点
switch (type)
{
case Abs_Node::NODE_TYPE_CONNECTOR_TEST: // 接口测试节点
p_New_Node = std::make_shared<Connector_Test_Node>(&this->Node_ID_Generator,
&this->Connector_ID_Generator,
initial_position);
break;
case Abs_Node::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;
case Abs_Node::NODE_TYPE_CSV_EXPORTER: // CSV输出器
break;
default:
return false;
}
// 成功分配时
if (p_New_Node.get() != nullptr)
{
// 将新增的节点记录到接口池及散点池
this->Node_Pool.push_back(p_New_Node);
this->Separate_Node_List.push_back(p_New_Node);
/**
* @todo
* 考量接口列表是否有必要存在,遍历时可以通过遍历节点所含的接口列表来定位
* 如果有节点需要动态扩充接口,此时接口列表遍历方式存在问题
*/
// 记录节点内含的接口列表
for (auto p_Connector : p_New_Node->Get_Connector_List())
this->Connector_Pool.push_back(p_Connector);
// 记录到散点池
return true;
}
return false;
}
// 删除节点 返回迭代器指定位置的下一个位置的迭代器,仅限内部使用
std::vector<std::shared_ptr<Abs_Node>>::iterator Workflow_Editor::Del_Node(std::vector<std::shared_ptr<Abs_Node>>::iterator iterator)
{
// 散点删除
int node_id = (*iterator)->Get_ID();
for (auto iterator = this->Separate_Node_List.begin(); iterator != this->Separate_Node_List.end(); iterator++)
if ((*iterator)->Get_ID() == node_id)
{
iterator = this->Separate_Node_List.erase(iterator);
break;
}
// 获取接口列表
auto Connector_List = (*iterator)->Get_Connector_List();
// 删除列表中所有与该节点接口相关的边并从接口池中删除
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) - 1;
}
}
// 从接口池中移除
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);
return iterator;
}
// 删除节点 true -> success / false -> failed
bool Workflow_Editor::Del_Node(int target_node_id)
{
// 查找ID
for (auto iterator = this->Node_Pool.begin(); iterator != this->Node_Pool.end(); iterator++)
{
// 从节点池删除对应的节点
if ((*iterator)->Get_ID() == target_node_id)
{
this->Del_Node(iterator);
return true;
}
}
// 未成功查找
return false;
}
// 新增连接 true -> success / false -> failed
bool Workflow_Editor::Add_Link(int source_connector_id, int target_connector_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_connector_id)
p_source_connector = pConnector;
if (pConnector->Get_ID() == target_connector_id)
p_target_connector = pConnector;
if ((p_source_connector.get() != nullptr) && (p_target_connector.get() != nullptr))
{
find = true;
break;
}
}
if (find)
break;
}
// 判定查找结果
if (find)
{
// 检查下一步的连接是否会出现回环
{
// 工具Lambda表达式查找接口id的所属节点
auto Lambda_Find_Owner = [&](int connector_id) -> Abs_Node *
{
for (auto pNode : this->Node_Pool)
{
for (auto pConnector : pNode->Get_Connector_List())
{
if (pConnector->Get_ID() == connector_id)
return pNode.get();
}
}
return nullptr;
};
// 关联关系查找递归Lambda
auto Lambda_Find_Related = [&](auto self, Abs_Node *pSource, Abs_Node *pTarget) -> bool
{
std::vector<Abs_Node *> Sub_Node_List;
for (auto pConnector : pSource->Get_Connector_List())
{
// 检索所有OutPut类型的接口的下位节点
if (pConnector->Get_Type() == Abs_Connector::CONNECTOR_TYPE_OUTPUT)
{
for (auto pSubConnector : pConnector->Get_Related_List())
{
auto pSubNode = Lambda_Find_Owner(pSubConnector->Get_ID());
bool duplicated = false;
// 查重并加入子节点列表
for (auto pNode : Sub_Node_List)
{
if (pNode == pSubNode)
{
duplicated = true;
break;
}
}
if (!duplicated)
Sub_Node_List.push_back(pSubNode);
}
}
}
// 递归出口 无子节点时直接返回
if (Sub_Node_List.size() == 0)
return false;
// 检索所有的下位节点
for (auto pNode : Sub_Node_List)
{
if (pNode == pTarget)
return true;
else if (self(self, pNode, pTarget) == true)
return true;
}
return false;
};
// 检查连接关系
if (Lambda_Find_Related(Lambda_Find_Related, Lambda_Find_Owner(target_connector_id), Lambda_Find_Owner(source_connector_id)))
{
MessageBoxW(Main_Window_hWnd, L"存在回环连线!!!", L"", MB_OK | MB_ICONERROR);
return false;
}
}
// 先尝试连接,成功后再进行边池操作
if (p_source_connector->Connect_To(p_target_connector.get()) == true)
{
// 记录到边池
this->Edge_Pool.push_back({this->Edge_ID_Generator.Request_ID(), source_connector_id, target_connector_id});
/**
* @todo 调整工作路由层级
*/
}
return true;
}
return false;
}
// 删除边 返回迭代器指定位置的下一个位置的迭代器,仅限内部使用
std::vector<Workflow_Editor::Edge>::iterator Workflow_Editor::Del_Link(std::vector<Edge>::iterator iterator)
{
// 查找接口
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() == iterator->source_connector_id)
p_source_connector = pConnector;
if (pConnector->Get_ID() == iterator->target_connector_id)
p_target_connector = pConnector;
if ((p_source_connector.get() != nullptr) && (p_target_connector.get() != nullptr))
{
find = true;
break;
}
}
if (find)
break;
}
// 判定查找结果
if (find)
{
// 成功删除连接关系
if (p_source_connector->Disconnect_To(p_target_connector.get()) == true)
{
/**
* @todo 调整工作路由层级
*/
// 释放ID并销毁容器
this->Edge_ID_Generator.Release_ID(iterator->id);
return this->Edge_Pool.erase(iterator);
}
}
return iterator--;
}
// 删除连接 true -> success / false -> failed
bool Workflow_Editor::Del_Link(int source_connector_id, int target_connector_id)
{
// 遍历边池,删除对应的边
for (auto iterator = this->Edge_Pool.begin(); iterator != this->Edge_Pool.end(); iterator++)
if ((iterator->source_connector_id == source_connector_id) && (iterator->target_connector_id == target_connector_id))
{
this->Del_Link(iterator);
return true;
}
return false;
}
// 创建工作路由 true -> success / false -> failed
bool Workflow_Editor::Build_Process_Route(void)
{
// 找出所有的头节点
std::vector<std::shared_ptr<Abs_Node>> Head_List;
for (auto pNode : this->Node_Pool)
{
if (pNode->Get_Type() == Abs_Node::NODE_TYPE_MSG_LINE_INPUT)
Head_List.push_back(pNode);
}
return true;
}
// 清除工作路由 true -> success / false -> failed
bool Workflow_Editor::Clear_Process_Route(void)
{
decltype(this->Process_Route) empty_route;
this->Process_Route.swap(empty_route);
return true;
}