综合平台编程器项目的远程存储
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

207 line
8.2 KiB

  1. /**
  2. * @file logic_editor_widget.h
  3. * @brief 定义结构化梯形图编辑和运行轨迹画布
  4. * @version 1.0.0
  5. * @author suyu
  6. * @date 2026-08-22
  7. */
  8. #pragma once
  9. #include "domain/control_logic_model.h"
  10. #include "services/logic_command_service.h"
  11. #include "services/logic_editor_service.h"
  12. #include "services/software_logic_executor.h"
  13. #include <QGraphicsView>
  14. #include <string>
  15. #include <utility>
  16. #include <vector>
  17. class QGraphicsScene;
  18. class QCompleter;
  19. class QEvent;
  20. class QLineEdit;
  21. class QMouseEvent;
  22. class QRubberBand;
  23. class QResizeEvent;
  24. /** 将结构化梯形图表达式投影成网格图元;不保存自由线段,编辑通过服务提交 */
  25. class LogicEditorWidget final : public QGraphicsView
  26. {
  27. Q_OBJECT
  28. public:
  29. /** 梯形图中的条件、输出、横线和辅助选择图元类型 */
  30. class NodeItem;
  31. class WireItem;
  32. class WireCellItem;
  33. class GapCellItem;
  34. class VerticalConnectorItem;
  35. class RungItem;
  36. class EmptySlotItem;
  37. class OutputSlotItem;
  38. /** 创建梯形图画布并绑定编辑服务 */
  39. explicit LogicEditorWidget(
  40. LogicEditorService &editor_service,
  41. QWidget *parent = nullptr);
  42. /** 切换当前显示的控制逻辑;不存在时显示空场景 */
  43. void setLogicId(const std::string &logic_id);
  44. /** 设置是否允许编辑梯形图 */
  45. void setEditingEnabled(bool enabled);
  46. /** 设置离线运行轨迹;真机模式应传入空轨迹,避免显示本地伪轨迹 */
  47. void setRuntimeTrace(
  48. const LogicTraceSnapshot &trace,
  49. const std::string &fault_node_id = {});
  50. /** 清除当前运行轨迹和故障节点标记 */
  51. void clearRuntimeTrace();
  52. /** 返回当前是否正在显示运行轨迹 */
  53. bool runtimeTraceEnabled() const;
  54. /** 根据当前逻辑模型重建梯形图场景 */
  55. void reloadLogic();
  56. /** 选中指定节点并滚动到可见区域 */
  57. void selectNode(const std::string &node_id);
  58. /** 返回当前选中的单个节点标识 */
  59. std::string selectedNodeId() const;
  60. /** 返回当前选中的多个节点标识 */
  61. std::vector<std::string> selectedNodeIds() const;
  62. /** 返回当前选中的网络标识 */
  63. std::string selectedRungId() const;
  64. /** 新增一个空的梯形图网络 */
  65. LogicEditorResult addRung();
  66. /** 将当前选择转换为服务调用并新增串联条件 */
  67. LogicEditorResult addCondition(const LogicNodeConfig &config);
  68. /** 将当前选择转换为服务调用并新增并联支路 */
  69. LogicEditorResult addParallelBranch(const LogicNodeConfig &config);
  70. /** 在当前选择位置新增横线 */
  71. LogicEditorResult addHorizontalWire();
  72. /** 在当前选择位置新增竖线 */
  73. LogicEditorResult addVerticalWire();
  74. /** 删除当前选择位置的横线 */
  75. LogicEditorResult deleteHorizontalWire();
  76. /** 删除当前选择位置的竖线 */
  77. LogicEditorResult deleteVerticalWire();
  78. /** 设置当前网络的输出线圈 */
  79. LogicEditorResult setOutput(
  80. const LogicNodeConfig &config, bool configured = false);
  81. /** 按当前画布选择位置粘贴一组连续条件 */
  82. LogicEditorResult pasteConditionNodes(const std::vector<LogicNode> &nodes);
  83. /** 删除当前选中的节点、线段或网络 */
  84. LogicEditorResult deleteSelected();
  85. signals:
  86. /** 当前选中的节点发生变化时发出 */
  87. void nodeSelected(const QString &node_id);
  88. /** 梯形图模型成功发生变化时发出 */
  89. void graphChanged();
  90. /** 编辑服务操作失败时发出可显示的错误信息 */
  91. void editorError(const QString &message);
  92. protected:
  93. /** 在任意网络区域开始鼠标框选 */
  94. void mousePressEvent(QMouseEvent *event) override;
  95. /** 更新鼠标框选区域 */
  96. void mouseMoveEvent(QMouseEvent *event) override;
  97. /** 完成鼠标框选并提交场景选择 */
  98. void mouseReleaseEvent(QMouseEvent *event) override;
  99. /** 在条件网格或输出槽双击时打开命令输入框 */
  100. void mouseDoubleClickEvent(QMouseEvent *event) override;
  101. /** 在窗口大小变化后重新布局梯形图场景 */
  102. void resizeEvent(QResizeEvent *event) override;
  103. /** 滚动画布时同步命令输入框位置 */
  104. void scrollContentsBy(int dx, int dy) override;
  105. /** 处理命令输入框的回车、取消和按键事件 */
  106. bool eventFilter(QObject *watched, QEvent *event) override;
  107. private:
  108. /** 处理图形场景选择变化 */
  109. void handleSelectionChanged();
  110. /** 把编辑服务结果转换为错误信号 */
  111. void reportFailure(const LogicEditorResult &result);
  112. /** 返回当前选中的网络标识 */
  113. std::string currentRungId() const;
  114. /** 选中指定表达式图元 */
  115. void selectExpression(const std::string &expression_id);
  116. /** 选中指定横线图元 */
  117. void selectWire(const std::string &wire_id);
  118. /** 收集当前选中的表达式标识 */
  119. std::vector<std::string> selectedExpressionIds() const;
  120. /** 收集当前选中的横线标识 */
  121. std::vector<std::string> selectedWireIds() const;
  122. /** 收集当前选中的并联支路标识 */
  123. std::vector<std::string> selectedBranchIds() const;
  124. /** 收集当前选中的空网格位置 */
  125. std::vector<std::pair<std::string, int>> selectedEmptySlots() const;
  126. /** 收集当前选中的横线网格位置 */
  127. std::vector<std::pair<std::string, int>> selectedWireCells() const;
  128. /** 收集当前选中的显式断路网格位置 */
  129. std::vector<std::pair<std::string, int>> selectedGapCells() const;
  130. /** 判断当前是否选中了网络内的图元 */
  131. bool hasSelectedRungItem() const;
  132. /** 收集当前明确选中的网络图元 */
  133. std::vector<std::string> selectedRungItemIds() const;
  134. /** 打开指定目标位置的命令输入框 */
  135. void beginCommandInput(
  136. const LogicCommandTarget &target,
  137. const QPointF &scene_center);
  138. /** 提交当前命令输入;失败时保留输入框并标红 */
  139. void commitCommandInput();
  140. /** 关闭命令输入框并清理临时状态 */
  141. void cancelCommandInput();
  142. /** 根据网络、列和支路标识查找下一输入位置 */
  143. bool beginNextCommandInput();
  144. /** 按目标定位输入框的屏幕矩形 */
  145. void positionCommandInput(const QPointF &scene_center);
  146. /** 返回当前场景目标的中心位置 */
  147. bool findCommandTargetCenter(
  148. const LogicCommandTarget &target,
  149. QPointF *scene_center) const;
  150. /** 将成功命令选中并刷新属性面板 */
  151. void selectCommandResult(const LogicCommandResult &result);
  152. /** 梯形图编辑服务,不由控件拥有 */
  153. LogicEditorService &editor_service_;
  154. /** 命令语解析和结构化编辑适配服务 */
  155. LogicCommandService command_service_;
  156. /** 承载梯形图图元的场景 */
  157. QGraphicsScene *scene_ = nullptr;
  158. /** 当前显示的控制逻辑标识 */
  159. std::string logic_id_;
  160. /** 当前选中的网络标识 */
  161. std::string current_rung_id_;
  162. /** 最近一次收到的运行轨迹 */
  163. LogicTraceSnapshot trace_;
  164. /** 最近一次运行故障节点标识 */
  165. std::string fault_node_id_;
  166. /** 是否显示运行轨迹 */
  167. bool runtime_trace_enabled_ = false;
  168. /** 是否允许编辑梯形图 */
  169. bool editing_enabled_ = true;
  170. /** 鼠标框选覆盖层 */
  171. QRubberBand *selection_band_ = nullptr;
  172. /** 框选起点(视口坐标) */
  173. QPoint selection_origin_;
  174. /** 框选时是否已超过拖拽阈值 */
  175. bool selection_dragging_ = false;
  176. /** 框选起始时的键盘修饰键 */
  177. Qt::KeyboardModifiers selection_modifiers_ = Qt::NoModifier;
  178. /** 命令输入框,仅在编辑态临时创建 */
  179. QLineEdit *command_editor_ = nullptr;
  180. /** 命令输入补全器 */
  181. QCompleter *command_completer_ = nullptr;
  182. /** 当前命令输入目标 */
  183. LogicCommandTarget command_target_;
  184. /** 是否沿当前命令序列继续输入 */
  185. bool command_continuing_ = false;
  186. /** OR/ORI 只增加支路,不推进主表达式列 */
  187. bool command_keep_column_ = false;
  188. /** 连续输入对应的当前网络 */
  189. std::string command_current_rung_id_;
  190. /** 编辑已有网络 OR 时保留的选择范围 */
  191. std::vector<std::string> command_parallel_node_ids_;
  192. };