Adjusted UI layout && Tested dynamic window expansion effects && Added node editor area (experimental, currently only one simple test node available with no practical functionality)
This commit is contained in:
parent
cfb1be0efd
commit
0f2f2720fc
@ -12,6 +12,7 @@ extern "C"
|
||||
}
|
||||
|
||||
#include "Type_Descriptions.hpp"
|
||||
#include "Workflow-Editor.hpp"
|
||||
|
||||
// 主窗体句柄
|
||||
extern HWND Main_Window_hWnd;
|
||||
@ -29,4 +30,7 @@ extern ID3D11RenderTargetView *g_mainRenderTargetView; // D3D11 渲染目标
|
||||
extern Input_File_Node *input_dlt_file_list_head;
|
||||
extern size_t input_dlt_file_count;
|
||||
|
||||
// 节点编辑器
|
||||
extern Workflow_Editor_Class Workflow_Editor;
|
||||
|
||||
#endif
|
||||
89
Inc/Workflow-Editor.hpp
Normal file
89
Inc/Workflow-Editor.hpp
Normal file
@ -0,0 +1,89 @@
|
||||
#ifndef __WORKFLOW_NODES_HPP__
|
||||
#define __WORKFLOW_NODES_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;
|
||||
};
|
||||
|
||||
// 节点编辑器类
|
||||
class Workflow_Editor_Class
|
||||
{
|
||||
protected:
|
||||
// 节点列表
|
||||
std::vector<Node_Class *> Node_List;
|
||||
|
||||
public:
|
||||
// 构造函数
|
||||
Workflow_Editor_Class();
|
||||
|
||||
// 析构函数
|
||||
~Workflow_Editor_Class();
|
||||
|
||||
// 显示工作流节点编辑器
|
||||
void Show(void);
|
||||
|
||||
// 新增节点
|
||||
void Add_Node(NodeType type, ImVec2 initial_position = ImVec2(0, 0));
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -15,3 +15,6 @@ ID3D11RenderTargetView *g_mainRenderTargetView = nullptr; // D3D11 渲染目标
|
||||
// 文件输入相关
|
||||
Input_File_Node *input_dlt_file_list_head;
|
||||
size_t input_dlt_file_count;
|
||||
|
||||
// 节点编辑器
|
||||
Workflow_Editor_Class Workflow_Editor;
|
||||
@ -36,24 +36,62 @@ void UI_Layout()
|
||||
// 设置窗体相关属性,不允许停靠
|
||||
window_flags |= ImGuiWindowFlags_NoDocking;
|
||||
|
||||
// 临时设置一下窗体大小,动态扩张窗体
|
||||
{
|
||||
static size_t Width = MAIN_FRAME_SIZE_WIDTH_MIN;
|
||||
static size_t Height = MAIN_FRAME_SIZE_HEIGHT_MIN;
|
||||
if (!(Width >= 1400 && Height >= 700))
|
||||
{
|
||||
SetWindowPos(
|
||||
Main_Window_hWnd,
|
||||
NULL,
|
||||
(GetSystemMetrics(SM_CXSCREEN) - (Width)) / 2,
|
||||
(GetSystemMetrics(SM_CYSCREEN) - (Height)) / 2,
|
||||
Width,
|
||||
Height,
|
||||
SWP_NOZORDER);
|
||||
|
||||
if (Height < 700)
|
||||
Height += 5;
|
||||
if (Width < 1400)
|
||||
Width += 20;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Begin("Main Panel", NULL, window_flags); // 创建主面板
|
||||
ImGui::PopStyleVar(2); // 退出绘制风格栈中的设置项
|
||||
{
|
||||
const ImGuiStyle &style = ImGui::GetStyle();
|
||||
float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(MonitorFromPoint(POINT{0, 0}, MONITOR_DEFAULTTOPRIMARY));
|
||||
|
||||
// 拖拽输入区域
|
||||
Widgets::Drag_Input_Area(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().x / 2 > MAIN_FRAME_SIZE_WIDTH_MIN / 2 ? MAIN_FRAME_SIZE_WIDTH_MIN / 2 : ImGui::GetContentRegionAvail().x / 2));
|
||||
// 左半部分
|
||||
ImGui::BeginChild("Left Part", ImVec2(MAIN_FRAME_SIZE_WIDTH_MIN, ImGui::GetContentRegionAvail().y));
|
||||
{
|
||||
|
||||
// 文件列表组件
|
||||
Widgets::File_List_Area(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - (ImGui::GetTextLineHeightWithSpacing() + 20 * main_scale + style.ItemSpacing.y)));
|
||||
// 拖拽输入区域
|
||||
Widgets::Drag_Input_Area(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().x / 2 > MAIN_FRAME_SIZE_WIDTH_MIN * main_scale / 2 ? MAIN_FRAME_SIZE_WIDTH_MIN * main_scale / 2 : ImGui::GetContentRegionAvail().x / 2));
|
||||
|
||||
// 导出文件
|
||||
Widgets::Control_Panel(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetTextLineHeightWithSpacing() + 20 * main_scale));
|
||||
// 文件列表组件
|
||||
Widgets::File_List_Area(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - (ImGui::GetTextLineHeightWithSpacing() + 20 * main_scale + style.ItemSpacing.y)));
|
||||
|
||||
// 导出文件
|
||||
Widgets::Control_Panel(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetTextLineHeightWithSpacing() + 20 * main_scale));
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
// 右半部分
|
||||
ImGui::BeginChild("Right Part", ImVec2(0, 0));
|
||||
{
|
||||
// 工作流节点编辑器
|
||||
Workflow_Editor.Show();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
// ImGui::ShowDemoWindow(nullptr);
|
||||
ImGui::ShowDemoWindow(nullptr);
|
||||
}
|
||||
|
||||
void Widgets::Drag_Input_Area(const ImVec2 &size)
|
||||
|
||||
250
Src/Workflow-Editor.cpp
Normal file
250
Src/Workflow-Editor.cpp
Normal file
@ -0,0 +1,250 @@
|
||||
#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(); });
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user