Panel circle for visual feedback
This commit is contained in:
106
PanelsPanel.cpp
Normal file
106
PanelsPanel.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "PanelsPanel.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtMath>
|
||||
|
||||
PanelsPanel::PanelsPanel(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(4, 4, 4, 4);
|
||||
|
||||
m_statusLabel = new QLabel("Connect to load panels...", this);
|
||||
m_statusLabel->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
|
||||
m_statusLabel->setStyleSheet("color: #888; font-style: italic;");
|
||||
layout->addWidget(m_statusLabel);
|
||||
layout->addStretch(1);
|
||||
|
||||
setMinimumSize(200, 200);
|
||||
}
|
||||
|
||||
void PanelsPanel::setRnpCount(int count)
|
||||
{
|
||||
m_count = count;
|
||||
m_colors.clear();
|
||||
m_statusLabel->setText(count > 0
|
||||
? QString("%1 panel%2").arg(count).arg(count == 1 ? "" : "s")
|
||||
: "No panels reported");
|
||||
update();
|
||||
}
|
||||
|
||||
void PanelsPanel::setPanelColor(int index, const QColor &color)
|
||||
{
|
||||
m_colors[index] = color;
|
||||
update();
|
||||
}
|
||||
|
||||
void PanelsPanel::reset()
|
||||
{
|
||||
m_count = 0;
|
||||
m_colors.clear();
|
||||
m_statusLabel->setText("Connect to load panels...");
|
||||
update();
|
||||
}
|
||||
|
||||
void PanelsPanel::paintEvent(QPaintEvent *)
|
||||
{
|
||||
if (m_count <= 0) return;
|
||||
|
||||
QPainter p(this);
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
const QRectF bounds = rect();
|
||||
const QRectF drawArea = bounds.adjusted(0, 28, 0, 0);
|
||||
const double side = qMin(drawArea.width(), drawArea.height()) * 0.88;
|
||||
const double cx = drawArea.center().x();
|
||||
const double cy = drawArea.center().y();
|
||||
const double outerR = side / 2.0;
|
||||
const double innerR = outerR * 0.44;
|
||||
|
||||
const QRectF outerRect(cx - outerR, cy - outerR, side, side);
|
||||
const QRectF innerRect(cx - innerR, cy - innerR, innerR * 2, innerR * 2);
|
||||
|
||||
const double gapDeg = (m_count > 1) ? 3.0 : 0.0;
|
||||
const double segSpan = (360.0 - m_count * gapDeg) / m_count;
|
||||
|
||||
static const QColor kDefault(100, 140, 180);
|
||||
|
||||
for (int i = 0; i < m_count; ++i) {
|
||||
const double startAngle = 90.0 - i * (segSpan + gapDeg);
|
||||
const double sweep = -segSpan;
|
||||
|
||||
QPainterPath path;
|
||||
path.arcMoveTo(outerRect, startAngle);
|
||||
path.arcTo(outerRect, startAngle, sweep);
|
||||
path.arcTo(innerRect, startAngle + sweep, -sweep);
|
||||
path.closeSubpath();
|
||||
|
||||
p.setBrush(m_colors.value(i, kDefault));
|
||||
p.setPen(QPen(Qt::white, 2));
|
||||
p.drawPath(path);
|
||||
|
||||
// Label at segment midpoint
|
||||
const double midAngle = startAngle + sweep / 2.0;
|
||||
const double midAngleRad = qDegreesToRadians(midAngle);
|
||||
const double midR = (outerR + innerR) / 2.0;
|
||||
const QPointF tc(cx + midR * qCos(midAngleRad),
|
||||
cy - midR * qSin(midAngleRad));
|
||||
|
||||
QFont font = p.font();
|
||||
font.setBold(true);
|
||||
font.setPointSize(qMax(7, qMin(12, static_cast<int>(outerR / (m_count * 0.55 + 2)))));
|
||||
p.setFont(font);
|
||||
p.setPen(Qt::white);
|
||||
p.drawText(QRectF(tc.x() - 22, tc.y() - 11, 44, 22), Qt::AlignCenter, QString::number(i));
|
||||
}
|
||||
|
||||
// Centre hole: total count
|
||||
QFont cf = p.font();
|
||||
cf.setBold(true);
|
||||
cf.setPointSize(qMax(8, static_cast<int>(innerR * 0.45)));
|
||||
p.setFont(cf);
|
||||
p.setPen(palette().text().color());
|
||||
p.drawText(innerRect, Qt::AlignCenter, QString::number(m_count));
|
||||
}
|
||||
Reference in New Issue
Block a user