diff --git a/PanelsPanel.cpp b/PanelsPanel.cpp index 543f06c..2938c4f 100644 --- a/PanelsPanel.cpp +++ b/PanelsPanel.cpp @@ -57,12 +57,53 @@ void PanelsPanel::reset() update(); } -// Returns a circle radius multiplier (0.0-1.0) based on 3 power tiers static double bubbleScale(int power) { - if (power < 50) return 0.18; // small - if (power < 100) return 0.30; // medium - return 0.85; // large + if (power < 150) return 0.20; + if (power < 500) return 0.40; + return 0.80; +} + +// Draw a radial-gradient bubble at bCentre with radius circR +static void drawBubble(QPainter &p, const QPointF &bCentre, double circR, + bool isHighest, int power) +{ + const QRectF circRect(bCentre.x() - circR, bCentre.y() - circR, + circR * 2, circR * 2); + + // Drop shadow + p.setBrush(QColor(0, 0, 0, 55)); + p.setPen(Qt::NoPen); + p.drawEllipse(circRect.adjusted(2, 3, 2, 3)); + + // Colour scheme: red = highest, orange/amber = others + QColor bright, dark, rim; + if (isHighest) { + bright = QColor(255, 100, 100); + dark = QColor(160, 10, 10); + rim = QColor(255, 200, 200); + } else { + bright = QColor(255, 210, 60); + dark = QColor(200, 100, 0); + rim = QColor(255, 240, 180); + } + + QRadialGradient grad(bCentre, circR, + QPointF(bCentre.x() - circR * 0.3, + bCentre.y() - circR * 0.3)); + grad.setColorAt(0.0, bright); + grad.setColorAt(1.0, dark); + p.setBrush(grad); + p.setPen(QPen(rim, 1.5)); + p.drawEllipse(circRect); + + // Power text + QFont pf = p.font(); + pf.setBold(true); + pf.setPointSize(qMax(5, qMin(11, static_cast(circR * 0.68)))); + p.setFont(pf); + p.setPen(Qt::white); + p.drawText(circRect, Qt::AlignCenter, QString::number(power)); } void PanelsPanel::paintEvent(QPaintEvent *) @@ -79,6 +120,7 @@ void PanelsPanel::paintEvent(QPaintEvent *) const double cy = drawArea.center().y(); const double outerR = side / 2.0; const double innerR = outerR * 0.44; + const double bandW = outerR - innerR; const QRectF outerRect(cx - outerR, cy - outerR, side, side); const QRectF innerRect(cx - innerR, cy - innerR, innerR * 2, innerR * 2); @@ -86,19 +128,28 @@ void PanelsPanel::paintEvent(QPaintEvent *) const double gapDeg = (m_count > 1) ? 3.0 : 0.0; const double segSpan = (360.0 - m_count * gapDeg) / m_count; - // Max bubble radius constrained to fit inside the segment band - const double maxCircR = qMin((outerR - innerR) * 0.48, - (outerR + innerR) / 2.0 * qSin(qDegreesToRadians(segSpan / 2.0)) * 0.88); + const double maxCircR = qMin( + bandW * 0.46, + outerR * qSin(qDegreesToRadians(segSpan / 2.0)) * 0.82 + ); + + // Find the highest-power panel index among active hits + int topIndex = -1; + int topPower = -1; + for (auto it = m_hits.cbegin(); it != m_hits.cend(); ++it) { + if (it.value() > topPower) { topPower = it.value(); topIndex = it.key(); } + } static const QColor kDefault(100, 140, 180); - static const QColor kHit(220, 40, 40); + static const QColor kHit(200, 50, 50); for (int i = 0; i < m_count; ++i) { const bool isHit = m_hits.contains(i); const double startAngle = 90.0 - i * (segSpan + gapDeg); const double sweep = -segSpan; + const double midAngleRad = qDegreesToRadians(startAngle + sweep / 2.0); - // --- Segment path --- + // --- Segment --- QPainterPath path; path.arcMoveTo(outerRect, startAngle); path.arcTo(outerRect, startAngle, sweep); @@ -109,56 +160,36 @@ void PanelsPanel::paintEvent(QPaintEvent *) p.setPen(QPen(Qt::white, isHit ? 3 : 2)); p.drawPath(path); - // --- Midpoint for label / hit circle --- - const double midAngle = startAngle + sweep / 2.0; - const double midAngleRad = qDegreesToRadians(midAngle); - const double midR = (outerR + innerR) / 2.0; - const QPointF mid(cx + midR * qCos(midAngleRad), - cy - midR * qSin(midAngleRad)); - - if (isHit) { - const int power = m_hits[i]; - const double circR = maxCircR * bubbleScale(power); - - // Tier label for legend (small/medium/large) - // Glow halo - p.setBrush(Qt::NoBrush); - p.setPen(QPen(QColor(255, 80, 80, 110), 5)); - p.drawPath(path); - - // Drop shadow - const QRectF circRect(mid.x() - circR, mid.y() - circR, circR * 2, circR * 2); - p.setBrush(QColor(0, 0, 0, 55)); - p.setPen(Qt::NoPen); - p.drawEllipse(circRect.adjusted(2, 3, 2, 3)); - - // Radial gradient fill - QRadialGradient grad(mid, circR, - QPointF(mid.x() - circR * 0.3, mid.y() - circR * 0.3)); - grad.setColorAt(0.0, QColor(255, 100, 100)); - grad.setColorAt(1.0, QColor(160, 10, 10)); - p.setBrush(grad); - p.setPen(QPen(QColor(255, 200, 200), 1.5)); - p.drawEllipse(circRect); - - // Power value text — scale font to circle size - QFont pf = p.font(); - pf.setBold(true); - pf.setPointSize(qMax(6, qMin(12, static_cast(circR * 0.68)))); - p.setFont(pf); - p.setPen(Qt::white); - p.drawText(circRect, Qt::AlignCenter, QString::number(power)); - - } else { - // Normal index label + // --- Panel index label at midpoint --- + const double midR = (outerR + innerR) / 2.0; + const QPointF labelPt(cx + midR * qCos(midAngleRad), + cy - midR * qSin(midAngleRad)); + { QFont font = p.font(); font.setBold(true); font.setPointSize(qMax(7, qMin(12, static_cast(outerR / (m_count * 0.55 + 2))))); p.setFont(font); p.setPen(Qt::white); - p.drawText(QRectF(mid.x() - 22, mid.y() - 11, 44, 22), + p.drawText(QRectF(labelPt.x() - 22, labelPt.y() - 11, 44, 22), Qt::AlignCenter, QString::number(i)); } + + if (isHit) { + const int power = m_hits[i]; + const bool isTop = (i == topIndex); + const double circR = maxCircR * bubbleScale(power); + const double bCentR = outerR - circR - 2.0; + const QPointF bCentre(cx + bCentR * qCos(midAngleRad), + cy - bCentR * qSin(midAngleRad)); + + // Glow halo on segment + p.setBrush(Qt::NoBrush); + p.setPen(QPen(isTop ? QColor(255, 80, 80, 120) + : QColor(255, 200, 50, 100), 5)); + p.drawPath(path); + + drawBubble(p, bCentre, circR, isTop, power); + } } // --- Centre hole: total count ---