From 11171c8e6293518e92483d2154c508859d761ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Est=C3=A9vez?= Date: Tue, 25 Oct 2022 22:32:26 +0200 Subject: [PATCH] Display annotation comments as tooltips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the mouse is moved over a SigMF annotation rectangle on the waterfall, a tooltip showing the annotation comment is displayed (if the annotation has a comment field). This feature can be enabled/disabled with a checkbox, in the same way as annotations. If annotations are disabled, the annotation comments checkbox is grayed out and the tooltips are not shown. Signed-off-by: Daniel Estévez --- src/inputsource.cpp | 4 +++- src/mainwindow.cpp | 2 ++ src/plotview.cpp | 42 +++++++++++++++++++++++++++++++++++++ src/plotview.h | 5 +++++ src/samplesource.h | 7 +++++-- src/spectrogramcontrols.cpp | 8 +++++++ src/spectrogramcontrols.h | 2 ++ src/spectrogramplot.cpp | 22 +++++++++++++++++++ src/spectrogramplot.h | 26 +++++++++++++++++++++++ 9 files changed, 115 insertions(+), 3 deletions(-) diff --git a/src/inputsource.cpp b/src/inputsource.cpp index 4cca129..ebbf749 100644 --- a/src/inputsource.cpp +++ b/src/inputsource.cpp @@ -340,7 +340,9 @@ void InputSource::readMetaData(const QString &filename) auto label = sigmf_annotation["core:label"].toString(); - annotationList.emplace_back(sampleRange, frequencyRange, label); + auto comment = sigmf_annotation["core:comment"].toString(); + + annotationList.emplace_back(sampleRange, frequencyRange, label, comment); } } } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7b72057..dc62d76 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -51,6 +51,8 @@ MainWindow::MainWindow() connect(dock->cursorsCheckBox, &QCheckBox::stateChanged, plots, &PlotView::enableCursors); connect(dock->scalesCheckBox, &QCheckBox::stateChanged, plots, &PlotView::enableScales); connect(dock->annosCheckBox, &QCheckBox::stateChanged, plots, &PlotView::enableAnnotations); + connect(dock->annosCheckBox, &QCheckBox::stateChanged, dock, &SpectrogramControls::enableAnnotations); + connect(dock->commentsCheckBox, &QCheckBox::stateChanged, plots, &PlotView::enableAnnotationCommentsTooltips); connect(dock->cursorSymbolsSpinBox, static_cast(&QSpinBox::valueChanged), plots, &PlotView::setCursorSegments); // Connect dock outputs diff --git a/src/plotview.cpp b/src/plotview.cpp index d5bc424..d1c6bea 100644 --- a/src/plotview.cpp +++ b/src/plotview.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "plots.h" @@ -50,6 +51,7 @@ PlotView::PlotView(InputSource *input) : cursors(this), viewRange({0, 0}) enableScales(true); enableAnnotations(true); + enableAnnotationCommentsTooltips(true); addPlot(spectrogramPlot); @@ -62,6 +64,39 @@ void PlotView::addPlot(Plot *plot) connect(plot, &Plot::repaint, this, &PlotView::repaint); } +void PlotView::mouseMoveEvent(QMouseEvent *event) +{ + updateAnnotationTooltip(event); + QGraphicsView::mouseMoveEvent(event); +} + +void PlotView::mouseReleaseEvent(QMouseEvent *event) +{ + // This is used to show the tooltip again on drag release if the mouse is + // hovering over an annotation. + updateAnnotationTooltip(event); + QGraphicsView::mouseReleaseEvent(event); +} + +void PlotView::updateAnnotationTooltip(QMouseEvent *event) +{ + // If there are any mouse buttons pressed, we assume + // that the plot is being dragged and hide the tooltip. + bool isDrag = event->buttons() != Qt::NoButton; + if (!annotationCommentsEnabled + || !spectrogramPlot->isAnnotationsEnabled() + || isDrag) { + QToolTip::hideText(); + } else { + QString* comment = spectrogramPlot->mouseAnnotationComment(event); + if (comment != nullptr) { + QToolTip::showText(event->globalPos(), *comment); + } else { + QToolTip::hideText(); + } + } +} + void PlotView::contextMenuEvent(QContextMenuEvent * event) { QMenu menu; @@ -612,6 +647,13 @@ void PlotView::enableAnnotations(bool enabled) viewport()->update(); } +void PlotView::enableAnnotationCommentsTooltips(bool enabled) +{ + annotationCommentsEnabled = enabled; + + viewport()->update(); +} + int PlotView::sampleToColumn(size_t sample) { return sample / samplesPerColumn(); diff --git a/src/plotview.h b/src/plotview.h index c698b07..326d547 100644 --- a/src/plotview.h +++ b/src/plotview.h @@ -47,6 +47,7 @@ public slots: void enableCursors(bool enabled); void enableScales(bool enabled); void enableAnnotations(bool enabled); + void enableAnnotationCommentsTooltips(bool enabled); void invalidateEvent() override; void repaint(); void setCursorSegments(int segments); @@ -55,6 +56,8 @@ public slots: void setPowerMax(int power); protected: + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; void contextMenuEvent(QContextMenuEvent * event) override; void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent * event) override; @@ -80,6 +83,7 @@ public slots: double sampleRate = 0.0; bool timeScaleEnabled; int scrollZoomStepsAccumulated = 0; + bool annotationCommentsEnabled; void addPlot(Plot *plot); void emitTimeSelection(); @@ -91,6 +95,7 @@ public slots: void updateViewRange(bool reCenter); void updateView(bool reCenter = false, bool expanding = false); void paintTimeScale(QPainter &painter, QRect &rect, range_t sampleRange); + void updateAnnotationTooltip(QMouseEvent *event); int sampleToColumn(size_t sample); size_t columnToSample(int col); diff --git a/src/samplesource.h b/src/samplesource.h index 1c1304d..3f0b299 100644 --- a/src/samplesource.h +++ b/src/samplesource.h @@ -33,9 +33,12 @@ class Annotation range_t sampleRange; range_t frequencyRange; QString label; + QString comment; - Annotation(range_t sampleRange, range_tfrequencyRange, QString label) - : sampleRange(sampleRange), frequencyRange(frequencyRange), label(label) {} + Annotation(range_t sampleRange, range_tfrequencyRange, QString label, + QString comment) + : sampleRange(sampleRange), frequencyRange(frequencyRange), label(label), + comment(comment) {} }; template diff --git a/src/spectrogramcontrols.cpp b/src/spectrogramcontrols.cpp index 495dfe7..0e0f9aa 100644 --- a/src/spectrogramcontrols.cpp +++ b/src/spectrogramcontrols.cpp @@ -99,6 +99,8 @@ SpectrogramControls::SpectrogramControls(const QString & title, QWidget * parent annosCheckBox = new QCheckBox(widget); layout->addRow(new QLabel(tr("Display Annotations:")), annosCheckBox); + commentsCheckBox = new QCheckBox(widget); + layout->addRow(new QLabel(tr("Display annotation comments tooltips:")), commentsCheckBox); widget->setLayout(layout); setWidget(widget); @@ -134,6 +136,7 @@ void SpectrogramControls::setDefaults() cursorSymbolsSpinBox->setValue(1); annosCheckBox->setCheckState(Qt::Checked); + commentsCheckBox->setCheckState(Qt::Checked); // Try to set the sample rate from the last-used value QSettings settings; @@ -235,3 +238,8 @@ void SpectrogramControls::zoomOut() { zoomLevelSlider->setValue(zoomLevelSlider->value() - 1); } + +void SpectrogramControls::enableAnnotations(bool enabled) { + // disable annotation comments checkbox when annotations are disabled + commentsCheckBox->setEnabled(enabled); +} diff --git a/src/spectrogramcontrols.h b/src/spectrogramcontrols.h index 1120619..69e7d60 100644 --- a/src/spectrogramcontrols.h +++ b/src/spectrogramcontrols.h @@ -44,6 +44,7 @@ public slots: void timeSelectionChanged(float time); void zoomIn(); void zoomOut(); + void enableAnnotations(bool enabled); private slots: void fftSizeChanged(int value); @@ -74,4 +75,5 @@ private slots: QLabel *symbolPeriodLabel; QCheckBox *scalesCheckBox; QCheckBox *annosCheckBox; + QCheckBox *commentsCheckBox; }; diff --git a/src/spectrogramplot.cpp b/src/spectrogramplot.cpp index 3c6f787..3ab57ec 100644 --- a/src/spectrogramplot.cpp +++ b/src/spectrogramplot.cpp @@ -169,6 +169,8 @@ void SpectrogramPlot::paintAnnotations(QPainter &painter, QRect &rect, range_tannotationList.size(); i++) { Annotation a = inputSource->annotationList.at(i); @@ -195,12 +197,27 @@ void SpectrogramPlot::paintAnnotations(QPainter &painter, QRect &rect, range_tpos(); + int mouse_x = pos.x(); + int mouse_y = pos.y(); + + for (auto& a : visibleAnnotationLocations) { + if (a.isInside(mouse_x, mouse_y)) { + return &a.annotation.comment; + } + } + return nullptr; +} + void SpectrogramPlot::paintMid(QPainter &painter, QRect &rect, range_t sampleRange) { if (!inputSource || inputSource->count() == 0) @@ -395,6 +412,11 @@ void SpectrogramPlot::enableAnnotations(bool enabled) sigmfAnnotationsEnabled = enabled; } +bool SpectrogramPlot::isAnnotationsEnabled(void) +{ + return sigmfAnnotationsEnabled; +} + bool SpectrogramPlot::tunerEnabled() { return (tunerTransform->subscriberCount() > 0); diff --git a/src/spectrogramplot.h b/src/spectrogramplot.h index e7d0891..2e52cb4 100644 --- a/src/spectrogramplot.h +++ b/src/spectrogramplot.h @@ -20,6 +20,7 @@ #pragma once #include +#include #include #include "fft.h" #include "inputsource.h" @@ -30,8 +31,10 @@ #include #include #include +#include class TileCacheKey; +class AnnotationLocation; class SpectrogramPlot : public Plot { @@ -49,6 +52,8 @@ class SpectrogramPlot : public Plot bool tunerEnabled(); void enableScales(bool enabled); void enableAnnotations(bool enabled); + bool isAnnotationsEnabled(); + QString *mouseAnnotationComment(const QMouseEvent *event); public slots: void setFFTSize(int size); @@ -62,6 +67,7 @@ public slots: static const int tileSize = 65536; // This must be a multiple of the maximum FFT size std::shared_ptr>> inputSource; + std::vector visibleAnnotationLocations; std::unique_ptr fft; std::unique_ptr window; QCache pixmapCache; @@ -110,3 +116,23 @@ class TileCacheKey int zoomLevel; size_t sample; }; + +class AnnotationLocation +{ +public: + Annotation annotation; + + AnnotationLocation(Annotation annotation, int x, int y, int width, int height) + : annotation(annotation), x(x), y(y), width(width), height(height) {} + + bool isInside(int pos_x, int pos_y) { + return (x <= pos_x) && (pos_x <= x + width) + && (y <= pos_y) && (pos_y <= y + height); + } + +private: + int x; + int y; + int width; + int height; +};