#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;
}
}