250 lines
7.8 KiB
C++
250 lines
7.8 KiB
C++
#include "Workflow-Editor.hpp"
|
||
#include "imgui.h"
|
||
#include "imgui_internal.h"
|
||
#include "imnodes.h"
|
||
#include <algorithm>
|
||
|
||
// 构造函数
|
||
Workflow_Editor_Class::Workflow_Editor_Class() {}
|
||
|
||
// 析构函数
|
||
Workflow_Editor_Class::~Workflow_Editor_Class()
|
||
{
|
||
// 释放资源
|
||
for (auto &pNode : this->Node_List)
|
||
delete pNode;
|
||
}
|
||
|
||
// 客制化圆形带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;
|
||
}
|
||
|
||
// 消息行输入节点绘制函数
|
||
bool MsgLine_Input_Node_Class::show_and_get_state()
|
||
{
|
||
// 节点宽度
|
||
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++)
|
||
{
|
||
if ((*iterator)->show_and_get_state())
|
||
{
|
||
delete *iterator;
|
||
|
||
// 迭代器删除后会返回下一个位置的迭代器
|
||
iterator = this->Node_List.erase(iterator);
|
||
iterator--;
|
||
}
|
||
}
|
||
|
||
// 右键菜单
|
||
{
|
||
const bool open_popup = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
|
||
ImNodes::IsEditorHovered() &&
|
||
ImGui::IsMouseReleased(ImGuiMouseButton_Right);
|
||
|
||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f));
|
||
if (!ImGui::IsAnyItemHovered() && open_popup)
|
||
{
|
||
ImGui::OpenPopup("RightClick_Popup");
|
||
}
|
||
|
||
if (ImGui::BeginPopup("RightClick_Popup"))
|
||
{
|
||
ImVec2 click_pos = ImGui::GetMousePosOnOpeningCurrentPopup();
|
||
// 节点添加菜单
|
||
if (ImGui::BeginMenu("Add Nodes"))
|
||
{
|
||
if (ImGui::MenuItem("Msg input node."))
|
||
this->Add_Node(NODE_TYPE_MSG_LINE_INPUT, click_pos);
|
||
ImGui::EndMenu();
|
||
}
|
||
|
||
ImGui::EndPopup();
|
||
}
|
||
}
|
||
|
||
{
|
||
// ImNodes::BeginNode(1);
|
||
// ImNodes::BeginNodeTitleBar();
|
||
|
||
// // 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();
|
||
}
|
||
|
||
// 添加指定类型节点
|
||
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:
|
||
break;
|
||
}
|
||
|
||
// 重新排序确保后续ID分配正常
|
||
std::sort(this->Node_List.begin(),
|
||
this->Node_List.end(),
|
||
[](Node_Class *a, Node_Class *b) -> bool
|
||
{ return a->getID() < b->getID(); });
|
||
} |