#include "WindowAppBlockStandardBase.h" #include "WindowAppPouFrame.h" #include "WindowAppItemInterface.h" #include "Pou.h" #include "DialogBlockProperty.h" #include "WindowAppPouScene.h" // bShowOnly 是否仅供展示使用,展示使用的话不提供右键菜单以及其他互动功能 WindowAppBlockStandardBase::WindowAppBlockStandardBase(TOOL* pTool, POU* Pou, bool bShowOnly, QGraphicsObject* parent) : WindowAppBlockBase(pTool, Pou, bShowOnly, parent) { if (!bShowOnly) { setFlag(QGraphicsItem::ItemIsMovable); setFlag(QGraphicsItem::ItemSendsGeometryChanges); } else { setFlag(QGraphicsItem::ItemIsMovable, false); } setFlag(QGraphicsItem::ItemIsSelectable); this->m_toolInfo = pTool; // 创建菜单 createContextMenu(); // 更新矩形区域的尺寸 this->updateRect(); } /////////////////////////////////////////////////////////// //// 返回功能块图形的总体矩形区域 //QRectF WIndowAppBlockStandardBase::boundingRect() const //{ // return blockBoundingRect; //} ///////////////////////////////////////////////////////// //// 显示右键菜单 //void WIndowAppBlockStandardBase::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) //{ // scene()->clearSelection(); // setSelected(true); // // blockMenu->exec(event->screenPos()); //} /// /// 添加接口 /// void WindowAppBlockStandardBase::addItemInterfaces() { // 为本Block添加新的ItemInterface for (_INTERFACE* pInf : qAsConst(m_toolInfo->Interfaces)) { this->addItemInterface(pInf); } // 更新Interface的位置(注意此处坐标系需要转换一下) WindowAppBlockBase::updateInterfacesPostion(); } /// /// 添加单个接口 /// /// WindowAppItemInterface* WindowAppBlockStandardBase::addItemInterface(_INTERFACE* pInfInfo) { WindowAppItemInterface* pNewItemInf = new WindowAppItemInterface ( pInfInfo, m_pPou, this->m_toolInfo, m_bShowOnly, this ); if (!m_bShowOnly) { // Pou中保存此接口信息 m_pPou->registerInterface(pNewItemInf, pInfInfo); } // 保存接口Item信息 m_itemInterfaces.append(pNewItemInf); // 界面中添加此Interface(设置为从属关系之后,都不需要手工添加此Item了,真是方便啊) // scene()->addItem(pNewItemInf); return pNewItemInf; } /// /// 更新Block的相关位置和尺寸 /// void WindowAppBlockStandardBase::updatePosition() { // 更新矩形区域的尺寸 updateRect(); // 更新所有的接口 WindowAppBlockBase::updateInterfacesPostion(); //// 重绘Block this->update(); //// 重绘所有接口 //this->redrawAllInterface(); } /// /// 是否是StandardBase系列的Block,如果增加了新的工具类型,这里也需要补充 /// /// bool WindowAppBlockStandardBase::isStandardBasedBlock() { return (this->type() == ITEM_TYPE_STANDARD || this->type() == ITEM_TYPE_PORT || this->type() == ITEM_TYPE_GOTO || this->type() == ITEM_TYPE_PARALLEL ); } /// /// MoveUp /// void WindowAppBlockStandardBase::onBlockMoveUp() { this->onMenuMoveUp(); } /// /// MoveDown /// void WindowAppBlockStandardBase::onBlockMoveDown() { this->onMenuMoveDown(); } /// /// MoveFirst /// void WindowAppBlockStandardBase::onBlockMoveFirst() { this->onMenuMoveFirst(); } /// /// MoveLast /// void WindowAppBlockStandardBase::onBlockMoveLast() { this->onMenuMoveLast(); } /// /// 2022-9-28,直接给工具设置一个新的Index /// /// void WindowAppBlockStandardBase::setToolIndex(const int& newIndex) { int nCurIndex = m_toolInfo->nIndex; int nFix = newIndex - nCurIndex; // 根据用户的索引号是增加还是减少了,进行数次前移或者后移 if (nFix > 0) { // 后移 for (int i = 0; i < nFix; i++) { this->onBlockMoveDown(); } } else if (nFix < 0) { // 前移 for (int i = 0; i < -nFix; i++) { this->onBlockMoveUp(); } } } /// /// 更新矩形区域的尺寸 /// void WindowAppBlockStandardBase::updateRect() { // 计算高度 int blockHeight = TBD_BASIC_HEIGHT; // 根据接口计算实际需要的高度 int nOutInfCount = 0; int nInInfCount = 0; for (_INTERFACE* pInf : m_toolInfo->Interfaces) { if (!m_bShowOnly && !pInf->bEnable) { continue; } // 仅绘制标准类型的端口 if (pInf->Type == INF_TYPE::INF_TYPE_EVENT || pInf->Type == INF_TYPE::INF_TYPE_CONTROL ) { continue; } // 2021-4-7增加,加入了接口启用与否的判断 if (pInf->Direction == INF_DIRECTION::INF_DIR_OUT) { nOutInfCount++; } else if (pInf->Direction == INF_DIRECTION::INF_DIR_IN) { nInInfCount++; } } // 取更大的值作为整体高度 int nInfCount = nOutInfCount > nInInfCount ? nOutInfCount : nInInfCount; // 2022-5-23,调整并排只有2个接口的情况下的高度 if (nInfCount > 1) { blockHeight = TBD_BASIC_HEIGHT + TBD_INF_SPACING * (nInfCount - 1) - 5; } // 计算宽度 int blockWidth = TBD_BASIC_WIDTH; // TODO : 根据工具名字字符的宽度计算实际需要的宽度 // 主体矩形区域 blockRect.setRect( -blockWidth / 2, -blockHeight / 2, blockWidth, blockHeight ); // 序号矩形区域 blockIndexRect.setRect( blockRect.right() - TBD_INDEX_WIDTH, blockRect.top() - TBD_INDEX_HEIGHT / 2, TBD_INDEX_WIDTH, TBD_INDEX_HEIGHT ); //// 总体矩形边界 //blockBoundingRect.setRect( // blockRect.left() - TBD_INF_LINE, // blockRect.top() - TBD_INDEX_HEIGHT / 2, // blockRect.width() + TBD_INF_LINE + TBD_INF_LINE, // blockRect.height() + TBD_INDEX_HEIGHT + TBD_SHADOW_COUNT * PEN_LINE_WIDTH + 12 //); // 矩形边界(未计算Interface的范围) blockBoundingRect.setRect( blockRect.left(), blockRect.top() - TBD_INDEX_HEIGHT, blockRect.width() + TBD_SHADOW_COUNT * PEN_LINE_WIDTH, blockRect.height() + TBD_INDEX_HEIGHT + TBD_SHADOW_COUNT * PEN_LINE_WIDTH + 12 ); //// 总矩形边界(计算Interface的范围) //blockTotalRect.setRect( // blockRect.left() - TBD_INF_LINE * 2, // blockRect.top() - TBD_INDEX_HEIGHT, // blockRect.width() + TBD_INF_LINE * 4, // // blockRect.height() + TBD_INDEX_HEIGHT + TBD_SHADOW_COUNT * PEN_LINE_WIDTH + 15 //); } /// /// 添加ToolStart、ToolEnd接口,2022-8-21更新,增加了ToolEnd接口支持 /// void WindowAppBlockStandardBase::addItemToolInterfaces() { if (this->m_toolInfo->ToolInterfaces.size() <= 0 ) { qDebug() << "[Error] WindowAppBlockStandardBase::addItemToolInterfaces - ignore."; //return nullptr; } // 添加所有的ToolInterface for (int i = 0; i < this->m_toolInfo->ToolInterfaces.size(); i++) { WindowAppItemInterface* pToolInfItem = this->addItemInterface(this->m_toolInfo->ToolInterfaces[i]); // 更新ToolInterface的位置 QPointF pt = mapToScene(0, 0); QRectF rcBlock = blockRect; rcBlock.translate(pt); pToolInfItem->updateParentRect(rcBlock); // 更新ToolInterface的位置 pToolInfItem->updateToolInterfacePostion(); } //// 添加ToolStart接口 //WindowAppItemInterface* pStartInfItem = this->addItemInterface(this->m_toolInfo->startInterface); //// 更新ToolStart接口的位置 //QPointF pt = mapToScene(0, 0); //QRectF rcBlock = blockRect; //rcBlock.translate(pt); //pTopInfItem->updateParentRect(rcBlock); //// 添加ToolEnd接口 //WindowAppItemInterface* pTopInfItem = this->addItemInterface(this->m_toolInfo->startInterface); //// 更新ToolInterface的位置 //pTopInfItem->updateToolInterfacePostion(); //return pTopInfItem; } ///// ///// 双击弹出设置对话框 ///// ///// //void WindowAppBlockStandardBase::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) //{ // // 只有鼠标左键才响应 // if (event->button() == Qt::LeftButton && !m_bShowOnly) // { // // qDebug() << this->scenePos(); // // m_pPou->ShowToolDialog(this); // } //} /// /// 绘制block /// /// /// /// void WindowAppBlockStandardBase::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { painter->setRenderHint(QPainter::Antialiasing, true); WindowAppBlockBase::paint(painter, option, widget); painter->save(); // 绘制功能块 this->DrawBlock(painter, true); // 绘制序号 this->DrawIndex(painter); painter->restore(); } /// /// 绘制功能块 /// /// void WindowAppBlockStandardBase::DrawBlock(QPainter* painter, bool withToolName /*= true*/) { WindowAppBlockBase::DrawBlock(painter); // 绘制功能块名字 this->DrawBlockTitle(painter, withToolName); // 绘制断点标识 this->DrawBreakPoint(painter); // 绘制程序指针 this->DrawPointer(painter); } /// /// 绘制功能块名字 /// /// /// 是否需要绘制工具基础名称 void WindowAppBlockStandardBase::DrawBlockTitle(QPainter* painter, bool withToolName /*= true*/) { // 实例名文字 painter->setPen(QPen(COLOR_TEXT, PEN_LINE_WIDTH)); painter->setFont(FONT_INSTANCENAME); QRect textRect = QFontMetrics(FONT_INSTANCENAME).boundingRect(m_toolInfo->strInstanceName); int textX = blockRect.left() + (blockRect.width() - textRect.width()) / 2; int textY = blockRect.top() - 4; painter->drawText(textX, textY, m_toolInfo->strInstanceName); // 工具基础名字 if (withToolName) { painter->setFont(FONT_TOOLNAME); textRect = QFontMetrics(FONT_TOOLNAME).boundingRect(m_toolInfo->strName); textX = blockRect.left() + (blockRect.width() - textRect.width()) / 2; textY = blockRect.top() + textRect.height() - 3; painter->drawText(textX, textY, m_toolInfo->strName); } } //////////////////////////////////////////////// // 绘制序号 void WindowAppBlockStandardBase::DrawIndex(QPainter* painter) { painter->setRenderHint(QPainter::Antialiasing); // 边框 if (!this->isSelected()) { painter->setPen(QPen(COLOR_TBD_INDEX_FRAME, PEN_LINE_WIDTH)); } else { painter->setPen(QPen(COLOR_TBD_INDEX_FRAME, PEN_LINE_WIDTH_SEL)); } // 绘制程序执行状态 this->SetExecStatus(painter); // 绘制主体 painter->drawRoundedRect(blockIndexRect, 3, 3); // 序号文字(最多可以容纳0-99) painter->setPen(QPen(COLOR_TBD_INDEX_TEXT, PEN_LINE_WIDTH)); painter->setFont(FONT_INDEX); QString strIndex = QString::number(m_toolInfo->nIndex + 1); QRect textRect = QFontMetrics(FONT_INDEX).boundingRect(strIndex); int textX = blockIndexRect.left() + (blockIndexRect.width() - textRect.width()) / 2; int textY = blockIndexRect.top() + textRect.height() - 1; // 2022-5-6 增加,如果Tool被加入了并行组,则显示一个P,不显示序号了 if (!this->m_toolInfo->isParallelSubTool()) { painter->drawText(textX, textY, strIndex); } else { painter->drawText(textX, textY, TOOL_PARALLEL_LOGO); } } /// /// 绘制断点标识 /// /// void WindowAppBlockStandardBase::DrawBreakPoint(QPainter* painter) { if (m_toolInfo->bEnableBreakPoint) { painter->setPen(QPen(Qt::red, 4, Qt::SolidLine)); painter->drawEllipse(blockRect.left() + 2, blockRect.top() + 2, 4, 4); } } /// /// 绘制程序指针 /// /// void WindowAppBlockStandardBase::DrawPointer(QPainter* painter) { if (m_toolInfo->execParams.nStatus == VPEnum::EXEC_STATUS::Busy) { double x = blockRect.left() - 10.0; double y = blockRect.top() + 4.0; double length = 2.0;//箭头斜着的投影到线上的长度 QVector lines; lines.append(QLineF(x, y, x + 10, y)); lines.append(QLineF(x + 5.0 + length, y + length, x + 10.0, y)); lines.append(QLineF(x + 5.0 + length, y - length, x + 10.0, y)); painter->setPen(QPen(Qt::yellow, 2, Qt::SolidLine)); painter->drawLines(lines); } } /// /// 设置功能块执行状态 /// /// void WindowAppBlockStandardBase::SetExecStatus(QPainter* painter) { // 填充 如果工具执行失败,将标签的背景色设置成红色 switch (m_toolInfo->execParams.nRetValue) { case VPEnum::RETURN_VALUE::Success: painter->setBrush(COLOR_TBD_INDEX_BG); break; case VPEnum::RETURN_VALUE::Error: painter->setBrush(COLOR_TBD_INDEX_BG_ERROR); break; case VPEnum::RETURN_VALUE::Invalid: painter->setBrush(COLOR_TBD_INDEX_BG); break; case VPEnum::RETURN_VALUE::Timeout: painter->setBrush(COLOR_TBD_INDEX_BG); break; case VPEnum::RETURN_VALUE::Goto: painter->setBrush(COLOR_TBD_INDEX_BG); break; case VPEnum::RETURN_VALUE::None: painter->setBrush(COLOR_TBD_INDEX_BG); break; default: painter->setBrush(COLOR_TBD_INDEX_BG); break; } } //================================================================= // // Menu相关 // //================================================================= /// /// 初始化功能块的右键菜单 /// void WindowAppBlockStandardBase::createContextMenu() { WindowAppBlockBase::createContextMenu(); // 硬件组态不显示右键菜单 if (m_pPou->pouName() != GROUP_NAME_HARDWARE) { connect(executeAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuExecute); connect(executeSubAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuExecuteSub); connect(executeAllAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuExecuteAll); connect(executeBreakPoint, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuBreakPoint); connect(moveUpAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuMoveUp); connect(moveDownAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuMoveDown); connect(moveFirstAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuMoveFirst); connect(moveLastAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuMoveLast); } connect(deleteAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuDelete); connect(propertyAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuProperty); connect(copyBlockAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuCopyblock); connect(copyDataAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuCopydata); connect(pasteAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuPaste); contextMenu = new QMenu(); if (m_pPou->pouName() != GROUP_NAME_HARDWARE) { contextMenu->addAction(executeAction); contextMenu->addAction(executeSubAction); contextMenu->addAction(executeAllAction); contextMenu->addSeparator(); contextMenu->addAction(executeBreakPoint); contextMenu->addSeparator(); contextMenu->addAction(moveUpAction); contextMenu->addAction(moveDownAction); contextMenu->addAction(moveFirstAction); contextMenu->addAction(moveLastAction); contextMenu->addSeparator(); } contextMenu->addAction(deleteAction); contextMenu->addSeparator(); contextMenu->addAction(copyBlockAction); contextMenu->addAction(copyDataAction); contextMenu->addAction(pasteAction); contextMenu->addSeparator(); contextMenu->addAction(propertyAction); } /// /// 菜单 - Execute /// void WindowAppBlockStandardBase::onMenuExecute() { QFuture Future = QtConcurrent::run(this, &WindowAppBlockStandardBase::MenuExecute); } /// /// 菜单 - ExecuteSubsequent /// void WindowAppBlockStandardBase::onMenuExecuteSub() { QFuture Future = QtConcurrent::run(this, &WindowAppBlockStandardBase::MenuExecuteSub); } /// /// 菜单 - ExecuteAll /// void WindowAppBlockStandardBase::onMenuExecuteAll() { QFuture Future = QtConcurrent::run(this, &WindowAppBlockStandardBase::MenuExecuteAll); } void WindowAppBlockStandardBase::MenuExecute() { m_pPou->ToolExecutionDispatcher(this->m_toolInfo, TOOL_RUN_MODE::STANDALONE); // m_pPou->ToolExecuteStandard(this->m_toolInfo); } /// /// - ExecuteSubsequent /// void WindowAppBlockStandardBase::MenuExecuteSub() { m_pPou->ToolExecuteSub(this); } /// /// - ExecuteAll /// void WindowAppBlockStandardBase::MenuExecuteAll() { m_pPou->ToolExecuteAll(); } /// /// 菜单 - BreakPoint /// void WindowAppBlockStandardBase::onMenuBreakPoint() { m_pPou->ToolBreakPoint(this); this->update(); } /// /// 菜单 - MoveUp /// void WindowAppBlockStandardBase::onMenuMoveUp() { // 获取当前选中的Block // QGraphicsItem* activeBlock = this->selectedItems().first(); m_pPou->ToolMoveUp(this); update(); } /// /// 菜单 - MoveDown /// void WindowAppBlockStandardBase::onMenuMoveDown() { // 获取当前选中的Block // QGraphicsItem* activeBlock = this->selectedItems().first(); m_pPou->ToolMoveDown(this); update(); } /// /// 菜单 - MoveFirst /// void WindowAppBlockStandardBase::onMenuMoveFirst() { // 获取当前选中的Block //QGraphicsItem* activeBlock = this->selectedItems().first(); m_pPou->ToolMoveFirst(this); update(); } /// /// 菜单 - MoveLast /// void WindowAppBlockStandardBase::onMenuMoveLast() { // 获取当前选中的Block //QGraphicsItem* activeBlock = this->selectedItems().first(); m_pPou->ToolMoveLast(this); update(); } /// /// 菜单 - Delete /// void WindowAppBlockStandardBase::onMenuDelete() { // 2022-10-4,调用基类函数进行删除 WindowAppBlockBase::onDeleteItem(); //// 检查是否可以被删除 //if (!WindowAppBlockBase::couldBeDeleted()) //{ // return; //} //// 2022-3-5增加,如果此工具的Pou被Task选中,需要通知Task删除此工具 //if (m_pPou->isSelByTask()) //{ // WindowAppTaskView* pTaskView = g_pTaskManager->getTaskViewByName(m_pPou->m_pParentTask->strName); // pTaskView->onDelPouTool(m_pPou, this->m_toolInfo); //} //// 逻辑数据删除 //m_pPou->ToolDelete(this); //// 从界面中移除此功能块 //scene()->removeItem(this); } /// /// 菜单 - Property /// void WindowAppBlockStandardBase::onMenuProperty() { // 显示工具属性对话框 DialogBlockProperty dlgProperty(this->m_toolInfo, m_pPou); int res = dlgProperty.exec(); if (res != QDialog::Accepted) { return; } // 保存用户设置 BLOCK_PROPERTY settings = dlgProperty.getBlockSettings(); // 根据用户设置更新工具信息 if (!settings.strNewInstanceName.isEmpty()) { m_pPou->setInstanceName(m_toolInfo, settings.strNewInstanceName, settings.strOldInstanceName); } m_pPou->setToolEnable(m_toolInfo, settings.bToolEnable); m_pPou->setToolInfo(m_toolInfo, settings.strInfo); m_pPou->setToolDelay(m_toolInfo, settings.nInDelay, settings.nOutDelay); for (int i = 0; i < settings.infEnables.size(); i++) { // 2021-4-18 增加了判断,只处理enable发生变化的接口 if (m_toolInfo->Interfaces[i]->bEnable == settings.infEnables[i]) { continue; } // 这里需要检查引用计数,不一定能成功 bool bRet = m_pPou->setInterfaceEnable(m_toolInfo, i, settings.infEnables[i]); if (!bRet) { Utility::VPCriticalMessageBox(QString("Set ") + m_toolInfo->Interfaces[i]->strFullName + " failed!"); } } // 更新用户配置的索引号(如果需要的话) if (this->m_toolInfo->nIndex != settings.nNewIndex && settings.nNewIndex != -1) { this->setToolIndex(settings.nNewIndex); } // 更新本工具(此处会自动完成工具重绘) this->updatePosition(); } /// /// 菜单 - Copy block /// void WindowAppBlockStandardBase::onMenuCopyblock() { m_pPou->ToolCopyBlock(this); } /// /// 菜单 - Copy data /// void WindowAppBlockStandardBase::onMenuCopydata() { m_pPou->ToolCopyData(this); } /// /// 菜单 - Paste /// void WindowAppBlockStandardBase::onMenuPaste() { m_pPou->ToolPaste(this); }