| 8420 | } |
| 8421 | |
| 8422 | void SpectrumWidget::renderGpuFrame(QRhiCommandBuffer* cb) |
| 8423 | { |
| 8424 | // Guard: QRhiWidget surface recreation (add/remove panadapter, reparent) |
| 8425 | // can silently clear mouse tracking on macOS. Re-assert cheaply per frame. |
| 8426 | if (!hasMouseTracking()) { |
| 8427 | setMouseTracking(true); |
| 8428 | } |
| 8429 | |
| 8430 | // Tune guide recovery: after reparenting (add/remove panadapter), Qt may |
| 8431 | // not deliver mouseMoveEvents even with mouse tracking enabled (missing |
| 8432 | // enterEvent, stale widget state). Poll the actual cursor position to |
| 8433 | // detect when the mouse is inside the widget but events aren't flowing. |
| 8434 | { |
| 8435 | QPoint localPos = mapFromGlobal(QCursor::pos()); |
| 8436 | if (rect().contains(localPos)) { |
| 8437 | updateTrackedCursorState(localPos, true); |
| 8438 | if (!anyDragActive()) { |
| 8439 | Qt::CursorShape cursorShape = Qt::ArrowCursor; |
| 8440 | if (sliceCursorShapeAt(localPos, cursorShape)) { |
| 8441 | setSpectrumCursor(cursorShape); |
| 8442 | setVfoCursorOverride(cursorShape); |
| 8443 | } else if (spectrumDefaultsToCrosshairAt(localPos)) { |
| 8444 | clearVfoCursorOverride(); |
| 8445 | setSpectrumCursor(Qt::CrossCursor); |
| 8446 | } |
| 8447 | } |
| 8448 | } else if (m_cursorPos.x() >= 0 || m_hoveredTnfId >= 0 || m_tuneGuideVisible) { |
| 8449 | // Mouse left the widget without a leaveEvent |
| 8450 | updateTrackedCursorState(QPoint(-1, -1), false); |
| 8451 | } |
| 8452 | } |
| 8453 | |
| 8454 | QRhi* r = rhi(); |
| 8455 | const int w = width(); |
| 8456 | const int h = height(); |
| 8457 | if (w <= 0 || h <= freqScaleH() + DIVIDER_H + 2) return; |
| 8458 | const bool perfEnabled = PerfTelemetry::instance().enabled(); |
| 8459 | const qint64 perfStartNs = perfEnabled ? PerfTelemetry::nowNs() : 0; |
| 8460 | |
| 8461 | // panstats: whole CPU-side frame prep + encode (RAII catches every exit). |
| 8462 | m_panStats.gpuFrames++; |
| 8463 | struct FrameCost { |
| 8464 | quint64& acc; |
| 8465 | QElapsedTimer t; |
| 8466 | explicit FrameCost(quint64& a) : acc(a) { t.start(); } |
| 8467 | ~FrameCost() { acc += static_cast<quint64>(t.nsecsElapsed() / 1000); } |
| 8468 | } panStatsFrameCost(m_panStats.gpuFrameUs); |
| 8469 | |
| 8470 | const int chromeH = freqScaleH() + DIVIDER_H; |
| 8471 | const int contentH = h - chromeH; |
| 8472 | const int specH = static_cast<int>(contentH * m_spectrumFrac); |
| 8473 | const int wfY = specH + DIVIDER_H + freqScaleH(); |
| 8474 | const int wfH = h - wfY; |
| 8475 | const QRect specRect(0, 0, w, specH); |
| 8476 | const QRect wfRect(0, wfY, w, wfH); |
| 8477 | int fftTracePointCount = 0; |
| 8478 | |
| 8479 | // 3DSS replaces only the spectrum trace: the surface fills specRect and the |
nothing calls this directly
no test coverage detected