#include "WindowAppItemIsometricLine.h"
WindowAppItemIsometricLine::WindowAppItemIsometricLine(const UI_ISOLINE_INFO& lineInfo) :
m_isoLineInfo(lineInfo)
{
}
///
/// 绘制线条
///
///
///
///
void WindowAppItemIsometricLine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget /*= nullptr*/)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setRenderHint(QPainter::Antialiasing, true);
painter->save();
// 绘制等宽线条
this->drawIsoLines(painter);
painter->restore();
}
///
/// 绘制两个端点
///
///
void WindowAppItemIsometricLine::drawIsoLines(QPainter* painter)
{
// 如果stretchDir参数是None,那么绘制的就是目标控件的等宽线
// 因为目标控件的等宽线永远都只出现在右侧和下侧
if (m_isoLineInfo.stretchDir == STRETCH_DIRECTION::DIR_NONE)
{
// 右侧的等高线
if (m_isoLineInfo.sideDir == SIDE_DIRECTION::SIDE_RIGHT)
{
QLine rightLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_RIGHT);
this->drawIsoLines(painter, rightLine, SIDE_DIRECTION::SIDE_RIGHT);
}
// 下侧的等宽线
else if (m_isoLineInfo.sideDir == SIDE_DIRECTION::SIDE_BOTTOM)
{
QLine bottomLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_BOTTOM);
this->drawIsoLines(painter, bottomLine, SIDE_DIRECTION::SIDE_BOTTOM);
}
// 错误,不应该走到这里
else
{
vDebug() << "[Error] Invalid SideDirection:" << (short) m_isoLineInfo.sideDir;
}
}
// 如果stretchDir参数是有值的,那么绘制的就是源控件的等宽线
// 源控件的等宽线就需要根据拖拽方向来绘制在不同的位置了,需要额外解析一下
else
{
STRETCH_DIRECTION sDir = m_isoLineInfo.stretchDir;
// 如果是等高线
if (m_isoLineInfo.sideDir == SIDE_DIRECTION::SIDE_RIGHT)
{
// 如果拖拽的是上、下、左上、左下,等高线在右侧
if (sDir == STRETCH_DIRECTION::DIR_TOP
|| sDir == STRETCH_DIRECTION::DIR_BOTTOM
|| sDir == STRETCH_DIRECTION::DIR_LEFTTOP
|| sDir == STRETCH_DIRECTION::DIR_LEFTBOTTOM
)
{
// 获取右侧的边,然后在右侧边的右侧绘制等高线
QLine rightLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_RIGHT);
this->drawIsoLines(painter, rightLine, SIDE_DIRECTION::SIDE_RIGHT);
}
// 如果拖拽的是右上、右下,等高线在左侧
else if (sDir == STRETCH_DIRECTION::DIR_RIGHTTOP
|| sDir == STRETCH_DIRECTION::DIR_RIGHTBOTTOM
)
{
// 获取左侧的边,然后在左侧边的左侧绘制等高线
QLine leftLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_LEFT);
this->drawIsoLines(painter, leftLine, SIDE_DIRECTION::SIDE_LEFT);
}
}
// 如果是等宽线
else if (m_isoLineInfo.sideDir == SIDE_DIRECTION::SIDE_BOTTOM)
{
// 如果拖拽的是左、右、左上、右上,等宽线在下侧
if (sDir == STRETCH_DIRECTION::DIR_LEFT
|| sDir == STRETCH_DIRECTION::DIR_RIGHT
|| sDir == STRETCH_DIRECTION::DIR_LEFTTOP
|| sDir == STRETCH_DIRECTION::DIR_RIGHTTOP
)
{
// 获取底部的边,然后在底部边下侧绘制等宽线
QLine bottomLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_BOTTOM);
this->drawIsoLines(painter, bottomLine, SIDE_DIRECTION::SIDE_BOTTOM);
}
// 如果拖拽的是右下、左下,等宽线在上侧
else if (sDir == STRETCH_DIRECTION::DIR_LEFTBOTTOM
|| sDir == STRETCH_DIRECTION::DIR_RIGHTBOTTOM
)
{
// 获取顶部的边,然后在顶部边上侧绘制等宽线
QLine topLine = Utility::getSideLineByID(m_isoLineInfo.pWidget, (short)SIDE_DIRECTION::SIDE_TOP);
this->drawIsoLines(painter, topLine, SIDE_DIRECTION::SIDE_TOP);
}
}
}
}
///
/// 根据指定的位置绘制线条
///
///
///
///
void WindowAppItemIsometricLine::drawIsoLines(QPainter* painter, const QLine& side, SIDE_DIRECTION sideDir)
{
// 设置颜色风格
painter->setPen(QPen(COLOR_REFLINE, PEN_LINE_WIDTH, Qt::SolidLine));
QLine line1, line2;
// 在右侧绘制
if (sideDir == SIDE_DIRECTION::SIDE_RIGHT)
{
// 上侧标尺
line1.setLine(
side.p1().x() + ISOLINE_SPACE,
side.p1().y() - ISOLINE_FIX,
side.p1().x() + ISOLINE_SPACE + ISOLINE_MARK_LEN,
side.p1().y() - ISOLINE_FIX
);
// 下侧标尺
line2.setLine(
side.p2().x() + ISOLINE_SPACE,
side.p2().y() + ISOLINE_FIX,
side.p2().x() + ISOLINE_SPACE + ISOLINE_MARK_LEN,
side.p2().y() + ISOLINE_FIX
);
}
// 在下侧绘制
else if (sideDir == SIDE_DIRECTION::SIDE_BOTTOM)
{
// 左侧标尺
line1.setLine(
side.p1().x() - ISOLINE_FIX,
side.p1().y() + ISOLINE_SPACE,
side.p1().x() - ISOLINE_FIX,
side.p1().y() + ISOLINE_SPACE + ISOLINE_MARK_LEN
);
// 右侧标尺
line2.setLine(
side.p2().x() + ISOLINE_FIX,
side.p2().y() + ISOLINE_SPACE,
side.p2().x() + ISOLINE_FIX,
side.p2().y() + ISOLINE_SPACE + ISOLINE_MARK_LEN
);
}
// 在左侧绘制
else if (sideDir == SIDE_DIRECTION::SIDE_LEFT)
{
// 上侧标尺
line1.setLine(
side.p1().x() - ISOLINE_SPACE - ISOLINE_MARK_LEN,
side.p1().y() - ISOLINE_FIX,
side.p1().x() - ISOLINE_SPACE,
side.p1().y() - ISOLINE_FIX
);
// 下侧标尺
line2.setLine(
side.p2().x() - ISOLINE_SPACE - ISOLINE_MARK_LEN,
side.p2().y() + ISOLINE_FIX,
side.p2().x() - ISOLINE_SPACE,
side.p2().y() + ISOLINE_FIX
);
}
// 在上侧绘制
else if (sideDir == SIDE_DIRECTION::SIDE_TOP)
{
// 左侧标尺
line1.setLine(
side.p1().x() - ISOLINE_FIX,
side.p1().y() - ISOLINE_SPACE - ISOLINE_MARK_LEN,
side.p1().x() - ISOLINE_FIX,
side.p1().y() - ISOLINE_SPACE
);
// 右侧标尺
line2.setLine(
side.p2().x() + ISOLINE_FIX,
side.p2().y() - ISOLINE_SPACE - ISOLINE_MARK_LEN,
side.p2().x() + ISOLINE_FIX,
side.p2().y() - ISOLINE_SPACE
);
}
// 错误,不应该执行到这里
else
{
vDebug() << "[Error] Invalid side direction: " << (int)sideDir;
return;
}
// 绘制标尺线条
painter->drawLine(line1);
painter->drawLine(line2);
// 绘制箭头
this->drawIsoArrowLines(painter, line1, line2, sideDir);
}
///
/// 绘制箭头线条
///
///
void WindowAppItemIsometricLine::drawIsoArrowLines(QPainter* painter, QLine line1, QLine line2, SIDE_DIRECTION sideDir)
{
QLineF arrowLine;
// 如果是左侧边或者右侧边,那么就是纵向的等高线
if (sideDir == SIDE_DIRECTION::SIDE_RIGHT || sideDir == SIDE_DIRECTION::SIDE_LEFT)
{
// 线条
arrowLine.setLine(
line1.x1() + ISOLINE_MARK_LEN / 2,
line1.y1() + ISOLINE_ARROW_SIZE + 1,
line2.x1() + ISOLINE_MARK_LEN / 2,
line2.y1() - ISOLINE_ARROW_SIZE - 1
);
painter->drawLine(arrowLine);
}
// 其他情况就是横向的等宽线
else
{
// 线条
arrowLine.setLine(
line1.x1() + ISOLINE_ARROW_SIZE + 1,
line1.y1() + ISOLINE_MARK_LEN / 2,
line2.x1() - ISOLINE_ARROW_SIZE - 1,
line2.y1() + ISOLINE_MARK_LEN / 2
);
painter->drawLine(arrowLine);
}
// 加上箭头
this->drawIsoArrow(painter, arrowLine);
// 翻转线条,绘制另一侧箭头
arrowLine.setPoints(arrowLine.p2(), arrowLine.p1());
this->drawIsoArrow(painter, arrowLine);
}
///
/// 为指定的线条绘制箭头
///
///
void WindowAppItemIsometricLine::drawIsoArrow(QPainter* painter, QLineF isoLine)
{
// 获取单位向量
QLineF v = isoLine.unitVector();
// 设置箭头长度
v.setLength(ISOLINE_ARROW_SIZE);
v.translate(QPointF(isoLine.dx(), isoLine.dy()));
// 计算法向量
QLineF n = v.normalVector();
// 设置箭头宽度
n.setLength(n.length() * 0.5);
// 计算两次法向量获取反向的法向量
QLineF n2 = n.normalVector().normalVector();
// 三个向量的终点即是三角形的三个顶点
const QPointF points[3] = { v.p2(), n.p2(), n2.p2() };
// 按照三个顶点绘制多边形,然后填充
painter->setBrush(QBrush(COLOR_REFLINE, Qt::SolidPattern));
painter->drawPolygon(points, 3);
}