You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmSubWxs/nmWxLayerGeometryPreview.cpp

81 lines
4.5 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "nmWxLayerGeometryPreview.h"
#include <QPainter>
nmWxLayerGeometryPreview::nmWxLayerGeometryPreview(QWidget* parent)
: QWidget(parent), m_nSelectedRow(-1)
{
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
}
QSize nmWxLayerGeometryPreview::sizeHint() const
{
// 仅给布局一个随字体变化的推荐尺寸;实际宽高由父布局分配,不固定窗口像素大小。
return QSize(fontMetrics().width("Layer 0000") + 24, fontMetrics().height() * 12);
}
void nmWxLayerGeometryPreview::setGeometryData(const nmLayerGeometry& geometry, int selectedRow)
{
// 值复制使绘图不依赖外部对象地址;update() 由事件循环合并重绘请求。
m_oGeometry = geometry;
m_nSelectedRow = selectedRow;
update();
}
QRectF nmWxLayerGeometryPreview::layerRect(int nRow) const
{
const QRectF oArea = QRectF(rect()).adjusted(6, 6, -6, -6); // 与预览边框保持一致的逻辑像素绘图区。
if (oArea.width() <= 0.0 || oArea.height() <= 0.0) return QRectF();
const double dFirstTop = m_oGeometry.m_vecLayers.first().m_dTopDepth; // 米制深度原点。
const double dSpan = m_oGeometry.m_vecLayers.last().m_dBottomDepth - dFirstTop; // 包含历史间隙的米制跨度。
const nmLayerGeometryRow& oLayer = m_oGeometry.m_vecLayers.at(nRow); // 借用待绘制/命中的层快照。
// 两个坐标均为逻辑像素;只用于图形定位,不反向写入米制几何。
const double dTopPixel = oArea.top() + (oLayer.m_dTopDepth - dFirstTop) / dSpan * oArea.height();
const double dBottomPixel = oArea.top() + (oLayer.m_dBottomDepth - dFirstTop) / dSpan * oArea.height();
return QRectF(oArea.left(), dTopPixel, oArea.width(), dBottomPixel - dTopPixel);
}
int nmWxLayerGeometryPreview::layerAtPoint(const QPoint& pos) const
{
if (!m_oGeometry.isValid()) return -1;
const QPointF oPosition(pos); // 鼠标位置与色带矩形共用控件局部逻辑像素坐标。
for (int nRow = 0; nRow < m_oGeometry.m_vecLayers.size(); ++nRow) {
const QRectF oBand = layerRect(nRow); // 复用绘制矩形,不按总厚度另外推算点击层。
// 共用边界归下方层,最后一层包含其底边;间隙内没有任何矩形可命中。
if (!oBand.isEmpty() && oBand.contains(oPosition)
&& (oPosition.y() < oBand.bottom() || nRow == m_oGeometry.m_vecLayers.size() - 1))
return nRow;
}
return -1;
}
void nmWxLayerGeometryPreview::paintEvent(QPaintEvent*)
{
QPainter painter(this); // 本次绘制事件的画笔,坐标采用控件的逻辑像素空间。
painter.fillRect(rect(), palette().base());
painter.setPen(palette().mid().color());
painter.drawRect(rect().adjusted(0, 0, -1, -1));
// 输入处于待修正状态时,窗口会传入空快照;保留背景,不继续显示上一次的旧剖面。
if (!m_oGeometry.isValid()) return;
const QRectF area = QRectF(rect()).adjusted(6, 6, -6, -6); // 留出边框内边距后的有效绘图区,单位为逻辑像素。
if (area.width() <= 0.0 || area.height() <= 0.0) return;
for (int i = 0; i < m_oGeometry.m_vecLayers.size(); ++i) {
const nmLayerGeometryRow& row = m_oGeometry.m_vecLayers.at(i); // 只读层快照,几何数值仍为米。
const QRectF band = layerRect(i); // 绘制与鼠标命中共用同一色带矩形,间隙不填充。
const QColor color = row.m_clrLayer.isValid() ? row.m_clrLayer : palette().midlight().color(); // 缺失颜色时采用主题色。
painter.fillRect(band, color);
painter.setPen(QPen(i == m_nSelectedRow ? palette().highlight().color()
: palette().mid().color(), i == m_nSelectedRow ? 2 : 1));
painter.drawRect(band);
// 过薄层只保留色带;文字放不下时不跨层绘制,长层名则用省略号避免挤出边界。
// 根据填充色明暗选择文字颜色,使深浅色层均能辨认名称。
if (band.height() >= fontMetrics().height() + 4) {
painter.setPen(qGray(color.rgb()) < 128 ? Qt::white : Qt::black);
// 仅用于色带显示的名称,旧数据无名时使用默认值,不反向修改快照。
const QString name = row.m_sName.isEmpty() ? QString("Layer%1").arg(i + 1) : row.m_sName;
painter.drawText(band.adjusted(3, 0, -3, 0), Qt::AlignCenter,
fontMetrics().elidedText(name, Qt::ElideRight, qMax(0, int(band.width()) - 6)));
}
}
}