diff --git a/viewer/image_viewer/JFJochDiffractionImage.cpp b/viewer/image_viewer/JFJochDiffractionImage.cpp index 1f5ad172..34ee23c7 100644 --- a/viewer/image_viewer/JFJochDiffractionImage.cpp +++ b/viewer/image_viewer/JFJochDiffractionImage.cpp @@ -449,8 +449,6 @@ void JFJochDiffractionImage::addCustomOverlay() { DrawPredictions(); if (show_saturation) DrawSaturation(); - - DrawResolutionText(); } void JFJochDiffractionImage::DrawROIs() { @@ -916,7 +914,7 @@ void JFJochDiffractionImage::loadImage(std::shared_ptr scene()->clear(); resetScenePointers(); hover_resolution = NAN; - hover_resolution_item = nullptr; + DrawResolutionText(); CalcROI(); } @@ -1000,57 +998,56 @@ void JFJochDiffractionImage::setResolutionRingMode(RingMode mode) { updateOverlay(); } -void JFJochDiffractionImage::DrawResolutionText() { - auto scn = scene(); - if (!scn) { - hover_resolution_item = nullptr; // scene gone - return; - } - - // Hide item if no valid hover resolution - if (!image || !std::isfinite(hover_resolution) || hover_resolution <= 0.0f) { - if (hover_resolution_item) - hover_resolution_item->setVisible(false); - return; - } - - const QRectF visibleRect = mapToScene(viewport()->geometry()).boundingRect(); - - // Fixed on-screen font size (no dependence on scale_factor) +static QFont HoverResolutionFont() { QFont font("Arial"); - font.setPixelSize(32); // big, constant size on screen + font.setPixelSize(32); // big, constant size on screen + return font; +} - const QString label = - QString("d = %1 Å").arg(QString::number(hover_resolution, 'f', 2)); +QString JFJochDiffractionImage::HoverResolutionLabel() const { + if (!image || !std::isfinite(hover_resolution) || hover_resolution <= 0.0f) + return {}; + return QString("d = %1 \u00C5").arg(QString::number(hover_resolution, 'f', 2)); +} - // Create the item if it does not exist yet; otherwise reuse it - // NOTE: hover_resolution_item is NOT tracked in overlay_items_ — it is persistent - if (!hover_resolution_item) { - hover_resolution_item = scn->addText(label, font); - hover_resolution_item->setZValue(10.0); - // Make the text ignore zooming / view transforms - hover_resolution_item->setFlag(QGraphicsItem::ItemIgnoresTransformations, true); - } else { - hover_resolution_item->setFont(font); - hover_resolution_item->setPlainText(label); +void JFJochDiffractionImage::drawForeground(QPainter *painter, const QRectF &rect) { + JFJochImage::drawForeground(painter, rect); + + const QString label = HoverResolutionLabel(); + if (label.isEmpty()) + return; + + painter->save(); + painter->resetTransform(); // lay the readout out in viewport pixels, not scene units + painter->setFont(HoverResolutionFont()); + painter->setPen(feature_color); + painter->drawText(hover_text_rect_, Qt::AlignLeft | Qt::AlignTop, label); + painter->restore(); +} + +void JFJochDiffractionImage::DrawResolutionText() { + const QRect previous = hover_text_rect_; + const QString label = HoverResolutionLabel(); + + if (label.isEmpty()) + hover_text_rect_ = QRect(); + else { + constexpr int margin_px = 10; + const QFontMetrics fm(HoverResolutionFont()); + hover_text_rect_ = QRect(QPoint(margin_px, margin_px), fm.size(0, label)); } - hover_resolution_item->setDefaultTextColor(feature_color); - - // Keep a roughly constant ~10 px margin by compensating with scale_factor - const qreal margin_px = 10.0; - const qreal margin_scene = margin_px / std::max(0.0001, scale_factor); - - QPointF topLeft(visibleRect.left() + margin_scene, - visibleRect.top() + margin_scene); - hover_resolution_item->setPos(topLeft); - hover_resolution_item->setVisible(true); + // Repaint just the readout. The previous version was a QGraphicsItem flagged + // ItemIgnoresTransformations, which makes Qt mark the whole viewport dirty every time the + // item moves or its text changes - and it moved on every mouse motion. + const QRect dirty = previous.united(hover_text_rect_).adjusted(-2, -2, 2, 2); + if (!dirty.isEmpty()) + viewport()->update(dirty); } void JFJochDiffractionImage::beforeOverlayCleared() { - // hover_resolution_item is NOT in overlay_items_, so the selective clear won't touch it. - // However, if scene()->clear() is ever called (e.g. on loadImage(nullptr)), - // the caller must also set hover_resolution_item = nullptr separately. + // The resolution readout is painted in drawForeground(), not held as a scene item, so + // clearing the overlay (or the whole scene) cannot leave a dangling pointer behind. } void JFJochDiffractionImage::leaveEvent(QEvent *event) { diff --git a/viewer/image_viewer/JFJochDiffractionImage.h b/viewer/image_viewer/JFJochDiffractionImage.h index 1d9bc6c3..c9a3f847 100644 --- a/viewer/image_viewer/JFJochDiffractionImage.h +++ b/viewer/image_viewer/JFJochDiffractionImage.h @@ -21,7 +21,12 @@ Q_OBJECT QColor second_lattice_color = QColor(0xFA, 0x72, 0x68); // coral, the viewer "finishing" accent float hover_resolution = NAN; - QGraphicsTextItem* hover_resolution_item = nullptr; // big text in top-left + // The "d = ... A" readout is painted in drawForeground() in viewport pixels rather than kept + // as a scene item, so updating it dirties only its own rect. hover_text_rect_ is where it + // currently sits, in viewport coordinates. + QRect hover_text_rect_; + [[nodiscard]] QString HoverResolutionLabel() const; + void drawForeground(QPainter *painter, const QRectF &rect) override; public: enum class RingMode {Auto, Estimation, Manual, None, IceRings}; Q_ENUM(RingMode)