#include "WindowAppBlockBase.h" #include "WindowAppItemInterface.h" #include "VPCommand.h" #include "Pou.h" #include "WindowAppPouScene.h" // extern WindowAppPouManager pouManager; WindowAppBlockBase::WindowAppBlockBase( TOOL* pTool, POU* Pou, bool bShowOnly, QGraphicsObject* parent ) : QGraphicsObject(parent) , m_toolInfo(pTool) , m_pPou(Pou) , m_bShowOnly(bShowOnly) , contextMenu(nullptr) , m_oldPos(0, 0) { // 创建右键菜单 createContextMenu(); } /// /// 绘制图形 /// /// /// /// void WindowAppBlockBase::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { Q_UNUSED(painter); Q_UNUSED(widget); Q_UNUSED(option); } /// /// 返回矩形区域 /// /// QRectF WindowAppBlockBase::boundingRect() const { return blockBoundingRect; } ////////////////////////////////////////////////////////// // 绘制功能块 void WindowAppBlockBase::DrawBlock(QPainter* painter) { // 边框 if (!this->isSelected()) { painter->setPen(QPen(COLOR_TBD_FRAME1, PEN_LINE_WIDTH)); } else { painter->setPen(QPen(COLOR_TBD_FRAME1, PEN_LINE_WIDTH_SEL)); } // 填充 painter->setBrush(COLOR_TBD_BG); // 绘制主体 painter->drawRect(blockRect); } /////////////////////////////////////////////////// // 绘制功能块阴影 void WindowAppBlockBase::DrawBlockShadow(QPainter* painter) { // 三重阴影的颜色 QColor colorShadow[TBD_SHADOW_COUNT]; colorShadow[0] = COLOR_TBD_SHADOW1; colorShadow[1] = COLOR_TBD_SHADOW2; colorShadow[2] = COLOR_TBD_SHADOW3; for (int i = 1; i <= TBD_SHADOW_COUNT; i++) { // 偏移 int offset = i * PEN_LINE_WIDTH; painter->setPen(QPen(colorShadow[i - 1], PEN_LINE_WIDTH)); painter->drawLine( QPoint( blockRect.right() + offset, blockRect.y() + offset ), QPoint( blockRect.right() + offset, blockRect.bottom() + offset ) ); painter->drawLine( QPoint( blockRect.x() + offset, blockRect.bottom() + offset ), QPoint( blockRect.right() + offset, blockRect.bottom() + offset ) ); } // 三重阴影的顶点颜色 QColor colorCorner[TBD_SHADOW_COUNT]; colorCorner[0] = COLOR_TBD_SHADOW_CORNER1; colorCorner[1] = COLOR_TBD_SHADOW_CORNER2; colorCorner[2] = COLOR_TBD_SHADOW_CORNER3; for (int i = 1; i <= TBD_SHADOW_COUNT; i++) { // 偏移 int offset = i * PEN_LINE_WIDTH; painter->setPen(QPen(colorCorner[i - 1], PEN_LINE_WIDTH)); painter->drawPoint( QPoint( blockRect.right() + offset, blockRect.bottom() + offset ) ); } } /// /// 更新ItemInterface的位置 /// /// void WindowAppBlockBase::updateInterfacesPostion() { // (注意此处坐标系需要转换一下) QPointF pt = mapToScene(0, 0); QRectF rcBlock = blockRect; rcBlock.translate(pt); // 根据矩形区域计算对应的Interface的位置 int outCount = 0, inCount = 0; for (WindowAppItemInterface* pItemInf : qAsConst(m_itemInterfaces)) { if (!m_bShowOnly && !pItemInf->m_infInfo->bEnable) { continue; } // 2022-5-23, 跳过ToolStart接口 if (pItemInf->m_infInfo->isToolStart() || pItemInf->m_infInfo->isToolEnd()) { continue; } // 为接口更新最新的父功能块区域尺寸 pItemInf->updateParentRect(rcBlock); // 输出接口 if (pItemInf->m_infInfo->Direction == INF_DIRECTION::INF_DIR_OUT) { pItemInf->updatePostion(outCount); outCount++; } else if (pItemInf->m_infInfo->Direction == INF_DIRECTION::INF_DIR_IN) { pItemInf->updatePostion(inCount); inCount++; } } } ///// ///// 更新单个Interface的位置 ///// ///// //void WindowAppBlockBase::updateInterfacePostion(WindowAppItemInterface* pInfItem) //{ // //} /// /// 重绘所有的Interface /// void WindowAppBlockBase::redrawAllInterface() { for (WindowAppItemInterface* pItemInf : qAsConst(m_itemInterfaces)) { pItemInf->update(); } } /// /// 显示右键菜单 /// /// void WindowAppBlockBase::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) { if (!isSelected()) { scene()->clearSelection(); setSelected(true); } // 如果不是仅供展示用时,才弹出右键菜单 if (!m_bShowOnly) { if (contextMenu != nullptr) { contextMenu->exec(event->screenPos()); } } } /// /// 功能块有变动时 /// /// /// /// QVariant WindowAppBlockBase::itemChange(GraphicsItemChange change, const QVariant& value) { if (change == QGraphicsItem::ItemPositionChange && scene()) { // 更新Interface的位置(此处Qt自动处理了,不需要额外处理) // WindowAppBlockBase::updateAllInterfacesPostion(blockRect); // qDebug() << "WindowAppBlockTool::itemChange"; //// 功能块移动时,通知对应的Interface以及Interface的link同步移动 //emit blockMoveSignal(this); } // 移动完毕之后,执行位置检测 else if (change == QGraphicsItem::ItemPositionHasChanged && scene()) { // 功能块移动完毕后,通知对应的Interface以及Interface的link同步移动 emit blockMoveSignal(this); // 位置检测 WindowAppBlockBase::checkPosition(value); } else if (change == QGraphicsItem::ItemSelectedChange) { // 如果选中状态变更的话,就重绘所有的Interface WindowAppBlockBase::redrawAllInterface(); } return QGraphicsItem::itemChange(change, value); } /// /// 初始化功能块的右键菜单Action /// void WindowAppBlockBase::createContextMenu() { // 硬件组态不显示右键菜单 if (m_pPou->pouName() != GROUP_NAME_HARDWARE) { executeAction = new QAction(QIcon(":/image/Execute.png"), ("&Execute"), this); executeAction->setShortcut(QStringLiteral("Ctrl+F5")); executeAction->setStatusTip(("Execute this tool")); executeSubAction = new QAction(("&Execute Subsequent"), this); executeSubAction->setStatusTip(("Execute from this tool")); executeAllAction = new QAction(("&Execute All"), this); executeAllAction->setStatusTip(("Execute all tools")); executeBreakPoint = new QAction(("&BreakPoint"), this); executeBreakPoint->setStatusTip(("BreakPoint")); moveUpAction = new QAction(QIcon(":/image/MoveUp.png"), ("Move Up"), this); moveUpAction->setStatusTip(("Move up tool from diagram")); moveDownAction = new QAction(QIcon(":/image/MoveDown.png"), ("Move Down"), this); moveDownAction->setStatusTip(("Move down tool from diagram")); moveFirstAction = new QAction(QIcon(":/image/MoveFirst.png"), ("Move First"), this); moveFirstAction->setStatusTip(("Move first tool from diagram")); moveLastAction = new QAction(QIcon(":/image/MoveLast.png"), ("MoveLast"), this); moveLastAction->setStatusTip(("Move last tool from diagram")); } deleteAction = new QAction(QIcon(":/image/Delete.png"), ("&Delete"), this); deleteAction->setStatusTip(("Delete item from diagram")); propertyAction = new QAction(("&Property"), this); propertyAction->setStatusTip(("Property of this item")); copyBlockAction = new QAction(("Copy block"), this); copyDataAction = new QAction(("Copy data"), this); pasteAction = new QAction(("Paste"), this); } /// /// 返回本功能块的引用计数(所有接口引用计数之和) /// /// int WindowAppBlockBase::getRefCount() { int nRefCount = 0; for (WindowAppItemInterface* pItemInf : qAsConst(m_itemInterfaces)) { nRefCount += pItemInf->m_infInfo->nRefCount; } return nRefCount; } /// /// // 是否可以被删除(引用计数=0,且没有被Task使用) /// /// bool WindowAppBlockBase::couldBeDeleted() { // 首先需要查询一下引用计数 int nRefCount = this->getRefCount(); if (nRefCount > 0) { Utility::VPCriticalMessageBox("Can't delete this block for reference count is " + QString::number(nRefCount)); return false; } // 2021-8-12增加,还需要检查本Pou是否被Task选用,如果选用则不允许删除 if (this->m_pPou->isRunningInTask()) { Utility::VPCriticalMessageBox("Can't delete this block : this block is running in task[" + m_pPou->m_pParentTask->strName + "]"); return false; } return true; } /// /// 2021-8-17 检查功能块位置(碰撞检测,限制移动范围) /// /// /// QVariant WindowAppBlockBase::checkPosition(const QVariant& value) { // 最新中心点位置 QPointF curPos = value.toPointF(); // 碰撞检测 bool bFix = checkCollision(); bFix = false; //暂时屏蔽碰撞 if (bFix) { // 恢复上次的位置 this->setPos(m_fixPos); return value; } // 碰撞检测如果没有变更功能块位置,然后继续做边界检测 bFix = restrictBlockPos(curPos); bFix = false; // 暂时屏蔽边界检测 if (bFix) { // 恢复上次的位置 this->setPos(m_fixPos); } else { // 如果不需要调整,则保存最新的位置 m_fixPos = value.toPointF(); } return value; } /// /// 2021-8-17 处理碰撞判断 /// /// /// 返回是否做出了变更 bool WindowAppBlockBase::checkCollision() { // 整个场景区域 QRectF rcScene = scene()->sceneRect(); // 获取界面中和本功能块产生碰撞的物体 QList listCollision = scene()->collidingItems(this); // 需要排除自身的interface,因为Interface和功能块本身存在碰撞 for (QGraphicsItem* pItem : listCollision) { if (pItem->type() != ITEM_TYPE_STANDARD && pItem->type() != ITEM_TYPE_PORT) { listCollision.removeOne(pItem); } } // 判断是否还有碰撞 if (!listCollision.isEmpty()) { return true; } return false; } /// /// 2021-8-17 限制功能块在场景内 /// /// /// 返回是否做出了变更 bool WindowAppBlockBase::restrictBlockPos(QPointF curPos) { // 整个场景区域 QRectF rcScene = scene()->sceneRect(); // 重新计算最新的功能块矩形区域(含Interface) QRectF blockTotalRect; if (this->type() == ITEM_TYPE_STANDARD) { blockTotalRect.setRect( (double)curPos.x() - (double)(blockRect.width() / 2.0) - (double)TBD_INF_LINE - 8.0, (double)curPos.y() - (double)(blockRect.height() / 2.0) - (double)TBD_INDEX_HEIGHT, (double)blockRect.width() + (double)(TBD_INF_LINE * 3.0) + 5.0, (double)blockRect.height() + (double)TBD_INDEX_HEIGHT + (double)(TBD_SHADOW_COUNT * PEN_LINE_WIDTH) + 15.0 ); } else if (this->type() == ITEM_TYPE_PORT) { blockTotalRect.setRect( (double)curPos.x() - (double)(blockRect.width() / 2.0) - TBD_INF_LINE - 8, (double)curPos.y() - (double)blockRect.height() - 5.0, (double)blockRect.width() + (double)(TBD_INF_LINE * 3.0), (double)blockRect.height() + (double)TBD_INDEX_HEIGHT ); } else { return false; } // 判断场景是否包含此矩形区域 if (rcScene.contains(blockTotalRect)) { //// 如果不需要调整,则保存最新的位置 //m_fixPos = value.toPointF(); // qDebug() << blockTotalRect << " pass last:" << m_fixPos;; return false; } else { // qDebug() << blockTotalRect << " restrict resotre to " << m_fixPos; //if (m_fixPos == QPointF(0.0, 0.0)) //{ // return false; //} //// 恢复上次的位置 //this->setPos(m_fixPos); return true; } } /// /// 2022-10-4,删除当前功能块(统一功能块的删除入口) /// void WindowAppBlockBase::onDeleteItem() { //// 2022-10-2,为了整合进Undo架构,改为由Scene统一删除 //m_pPou->parentScene()->delToolItem(this); // 生成删除指令,调用Undo体系进行删除 PouToolDelCommand* toolDelCommand = new PouToolDelCommand( (WindowAppPouScene*)this->scene(), this->m_toolInfo, this->scenePos() ); ((WindowAppPouScene*)scene())->m_CommandManager.executeCommand(toolDelCommand); } /// /// 鼠标左键按下 /// /// void WindowAppBlockBase::mousePressEvent(QGraphicsSceneMouseEvent* event) { //设置鼠标形状 // TODO: 2022-4-22为了方便功能块调试,临时屏蔽 // setCursor(Qt::ClosedHandCursor); // 图元多选 系统默认Ctrl + 鼠标左键可实现多选 if (event->button() == Qt::LeftButton) { // 2022-10-2,按下时记录功能块当前位置,用于比较鼠标抬起后是否移动 m_oldPos = event->scenePos(); //设置shift+鼠标左键单选 if (event->modifiers() == Qt::ShiftModifier) { setSelected(true); } else { QGraphicsItem::mousePressEvent(event); } } } /// /// 鼠标右键抬起 /// /// void WindowAppBlockBase::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { if (event->button() == Qt::LeftButton) { // 2022-10-2,抬起时记录功能块当前位置,用于比较鼠标抬起后是否移动 QPointF curPos = event->scenePos(); // 如果移动了,则记录这次动作,用于执行Redo if (curPos != m_oldPos) { PouToolMoveCommand* toolMoveCommand = new PouToolMoveCommand( this->m_pPou, this->m_toolInfo->strInstanceName, m_oldPos, curPos ); ((WindowAppPouScene*)scene())->m_CommandManager.executeCommand(toolMoveCommand, true); m_oldPos = curPos; } } QGraphicsItem::mouseReleaseEvent(event); } /// /// 2022-6-22 查找某个InferfaceItem是否在本Block内 /// /// /// bool WindowAppBlockBase::isInBlock(WindowAppItemInterface* infItem) { int nIndex = m_itemInterfaces.indexOf(infItem); if (nIndex >= 0) { return true; } else { return false; } }