| 3950 | } |
| 3951 | |
| 3952 | void SpectrumWidget::drawConnectionAnimation(QPainter& p, const QRect& contentRect) |
| 3953 | { |
| 3954 | if (!m_connectionAnimationVisible || !m_connectionAnimationClock.isValid()) { |
| 3955 | return; |
| 3956 | } |
| 3957 | |
| 3958 | const qreal insetX = qMin(40.0, contentRect.width() * 0.10); |
| 3959 | const qreal insetTop = qMin(18.0, contentRect.height() * 0.08); |
| 3960 | const qreal insetBottom = qMin(22.0, contentRect.height() * 0.10); |
| 3961 | const QRectF available = QRectF(contentRect).adjusted(insetX, insetTop, -insetX, -insetBottom); |
| 3962 | if (available.width() < 140.0 || available.height() < 96.0) { |
| 3963 | return; |
| 3964 | } |
| 3965 | |
| 3966 | const qreal seconds = m_connectionAnimationClock.elapsed() / 1000.0; |
| 3967 | const qreal towerHeight = qMin(available.height() * 0.27, 90.0); |
| 3968 | const qreal towerWidth = towerHeight * 0.34; |
| 3969 | const qreal anchorX = static_cast<qreal>(mhzToX(m_centerMhz)); |
| 3970 | const qreal centerX = qBound(available.left() + towerWidth * 1.5, |
| 3971 | anchorX, |
| 3972 | available.right() - towerWidth * 1.5); |
| 3973 | const qreal baseY = available.top() + available.height() * 0.66; |
| 3974 | const qreal topY = baseY - towerHeight; |
| 3975 | const qreal phase = std::fmod(seconds * 0.7, 1.0); |
| 3976 | |
| 3977 | auto withAlpha = [](QColor color, int alpha) { |
| 3978 | color.setAlpha(alpha); |
| 3979 | return color; |
| 3980 | }; |
| 3981 | |
| 3982 | p.save(); |
| 3983 | p.setRenderHint(QPainter::Antialiasing, true); |
| 3984 | |
| 3985 | QRadialGradient glow(QPointF(centerX, topY + towerHeight * 0.42), |
| 3986 | towerHeight * 1.05); |
| 3987 | glow.setColorAt(0.0, withAlpha(kAetherBrandBlue(), 48)); |
| 3988 | glow.setColorAt(0.55, withAlpha(kAetherBrandGreen(), 22)); |
| 3989 | glow.setColorAt(1.0, AetherSDR::theme::withAlpha("color.background.spectrum", 0)); |
| 3990 | p.setPen(Qt::NoPen); |
| 3991 | p.setBrush(glow); |
| 3992 | p.drawEllipse(QPointF(centerX, topY + towerHeight * 0.44), |
| 3993 | towerHeight * 0.98, towerHeight * 0.72); |
| 3994 | |
| 3995 | static constexpr qreal kTau = 6.28318530717958647692; |
| 3996 | const qreal pulse = 0.55 + 0.45 * std::sin(seconds * kTau); |
| 3997 | const qreal waveCenterY = topY + towerHeight * 0.38; |
| 3998 | for (int ring = 0; ring < 3; ++ring) { |
| 3999 | const qreal ringProgress = std::fmod(phase + ring * 0.24, 1.0); |
| 4000 | const qreal radiusX = towerWidth * 0.50 + ringProgress * towerHeight * 0.68; |
| 4001 | const qreal radiusY = radiusX * 0.86; |
| 4002 | QColor waveColor = (ring % 2 == 0) ? kAetherBrandBlue() : kAetherBrandGreen(); |
| 4003 | const qreal fade = 1.0 - ringProgress; |
| 4004 | waveColor.setAlphaF(qBound(0.10, 0.16 + fade * 0.48 * pulse, 0.70)); |
| 4005 | QPen wavePen(waveColor, |
| 4006 | qMax(1.8, towerWidth * (0.075 + fade * 0.05)), |
| 4007 | Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); |
| 4008 | p.setPen(wavePen); |
| 4009 | p.setBrush(Qt::NoBrush); |
nothing calls this directly
no test coverage detected