GLSpectrum touchscreen updates

Add "show all controls" button, that allows most of the "set once"
controls to be hidden on small screens. Please feel free to make a
better icon! Could also be hidden if !ANDROID, if you don't like it.
Add pinch and pan gestures, for frequency scrolling and zooming in to
spectrum.
Queue frequencies requested by scrolling, so intermediate frequencies
can be omitted, if device is slow to update its frequency.
Support non-integer pixel ratios.
Add popup sliders for dials.
Add DialogPositioner for dialogs.
Add layout to spectrum markers dialog, so that it can be resized, to fit
on smaller screens.
pull/1540/head
Jon Beniston 2022-12-20 14:39:39 +00:00
rodzic 95120cc50d
commit 1c9cc7a989
11 zmienionych plików z 1998 dodań i 1690 usunięć

Wyświetl plik

@ -80,6 +80,11 @@ void SpectrumSettings::resetToDefaults()
m_measurementsPosition = PositionBelow;
m_measurementPrecision = 1;
m_findHistogramPeaks = false;
#ifdef ANDROID
m_showAllControls = false;
#else
m_showAllControls = true;
#endif
}
QByteArray SpectrumSettings::serialize() const
@ -132,6 +137,7 @@ QByteArray SpectrumSettings::serialize() const
s.writeS32(46, m_measurementCenterFrequencyOffset);
s.writeBool(47, m_findHistogramPeaks);
s.writeBool(48, m_truncateFreqScale);
s.writeBool(49, m_showAllControls);
s.writeS32(100, m_histogramMarkers.size());
for (int i = 0; i < m_histogramMarkers.size(); i++) {
@ -236,6 +242,11 @@ bool SpectrumSettings::deserialize(const QByteArray& data)
d.readS32(46, &m_measurementCenterFrequencyOffset, 0);
d.readBool(47, &m_findHistogramPeaks, false);
d.readBool(48, &m_truncateFreqScale, false);
#ifdef ANDROID
d.readBool(49, &m_showAllControls, false);
#else
d.readBool(49, &m_showAllControls, true);
#endif
int histogramMarkersSize;
d.readS32(100, &histogramMarkersSize, 0);

Wyświetl plik

@ -138,6 +138,7 @@ public:
bool m_measurementHighlight;
MeasurementsPosition m_measurementsPosition;
int m_measurementPrecision;
bool m_showAllControls;
static const int m_log2FFTSizeMin = 6; // 64
static const int m_log2FFTSizeMax = 15; // 32k

Wyświetl plik

@ -24,6 +24,10 @@
#include <QVector4D>
#include <QDebug>
#ifdef ANDROID
#include <GLES3/gl3.h>
#endif
#include "gui/glshadercolormap.h"
#include "util/colormap.h"

Wyświetl plik

@ -26,6 +26,10 @@
#include <QVector4D>
#include <QDebug>
#ifdef ANDROID
#include <GLES3/gl3.h>
#endif
#include "gui/glshaderspectrogram.h"
#include "util/colormap.h"
@ -314,7 +318,7 @@ void GLShaderSpectrogram::initTextureMutable(const QImage& image)
glGenTextures(1, &m_textureId);
glBindTexture(GL_TEXTURE_2D, m_textureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED,
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8,
image.width(), image.height(), 0, GL_RED, GL_UNSIGNED_BYTE, image.constScanLine(0));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

Wyświetl plik

@ -24,6 +24,10 @@
#include <QVector4D>
#include <QDebug>
#ifdef ANDROID
#include <GLES3/gl3.h>
#endif
#include "gui/glshadertextured.h"
GLShaderTextured::GLShaderTextured() :
@ -296,7 +300,11 @@ bool GLShaderTextured::useImmutableStorage()
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
#ifdef ANDROID
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1);
#else
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
#endif
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data);
GLenum err = glGetError();
glDeleteTextures(1, &textureId);

Wyświetl plik

@ -37,6 +37,8 @@
#include "gui/spectrummeasurementsdialog.h"
#include "gui/spectrummeasurements.h"
#include "gui/flowlayout.h"
#include "gui/dialogpositioner.h"
#include "gui/dialpopup.h"
#include "util/colormap.h"
#include "util/simpleserializer.h"
#include "util/db.h"
@ -94,6 +96,8 @@ GLSpectrumGUI::GLSpectrumGUI(QWidget* parent) :
CRightClickEnabler *calibrationPointsRightClickEnabler = new CRightClickEnabler(ui->calibration);
connect(calibrationPointsRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openCalibrationPointsDialog(const QPoint &)));
DialPopup::addPopupsToChildDials(this);
displaySettings();
setAveragingCombo();
applySettings();
@ -168,6 +172,7 @@ void GLSpectrumGUI::updateSettings()
void GLSpectrumGUI::displaySettings()
{
blockApplySettings(true);
ui->showAllControls->setChecked(m_settings.m_showAllControls);
ui->refLevel->setValue(m_settings.m_refLevel + m_calibrationShiftdB);
ui->levelRange->setValue(m_settings.m_powerRange);
ui->decay->setSliderPosition(m_settings.m_decay);
@ -176,7 +181,7 @@ void GLSpectrumGUI::displaySettings()
ui->waterfall->setChecked(m_settings.m_displayWaterfall);
ui->spectrogram->setChecked(m_settings.m_display3DSpectrogram);
ui->spectrogramStyle->setCurrentIndex((int) m_settings.m_3DSpectrogramStyle);
ui->spectrogramStyle->setVisible(m_settings.m_display3DSpectrogram);
ui->spectrogramStyle->setVisible(m_settings.m_display3DSpectrogram && m_settings.m_showAllControls);
ui->colorMap->setCurrentText(m_settings.m_colorMap);
ui->currentLine->blockSignals(true);
ui->currentFill->blockSignals(true);
@ -236,6 +241,7 @@ void GLSpectrumGUI::displaySettings()
setAveragingToolitp();
ui->calibration->setChecked(m_settings.m_useCalibration);
displayGotoMarkers();
displayControls();
ui->fftWindow->blockSignals(false);
ui->averaging->blockSignals(false);
@ -246,6 +252,37 @@ void GLSpectrumGUI::displaySettings()
updateMeasurements();
}
void GLSpectrumGUI::displayControls()
{
ui->grid->setVisible(m_settings.m_showAllControls);
ui->gridIntensity->setVisible(m_settings.m_showAllControls);
ui->truncateScale->setVisible(m_settings.m_showAllControls);
ui->clearSpectrum->setVisible(m_settings.m_showAllControls);
ui->histogram->setVisible(m_settings.m_showAllControls);
ui->maxHold->setVisible(m_settings.m_showAllControls);
ui->decay->setVisible(m_settings.m_showAllControls);
ui->decayDivisor->setVisible(m_settings.m_showAllControls);
ui->stroke->setVisible(m_settings.m_showAllControls);
ui->currentLine->setVisible(m_settings.m_showAllControls);
ui->currentFill->setVisible(m_settings.m_showAllControls);
ui->currentGradient->setVisible(m_settings.m_showAllControls);
ui->traceIntensity->setVisible(m_settings.m_showAllControls);
ui->colorMap->setVisible(m_settings.m_showAllControls);
ui->invertWaterfall->setVisible(m_settings.m_showAllControls);
ui->waterfall->setVisible(m_settings.m_showAllControls);
ui->spectrogram->setVisible(m_settings.m_showAllControls);
ui->spectrogramStyle->setVisible(m_settings.m_showAllControls);
ui->fftWindow->setVisible(m_settings.m_showAllControls);
ui->fftSize->setVisible(m_settings.m_showAllControls);
ui->fftOverlap->setVisible(m_settings.m_showAllControls);
ui->fps->setVisible(m_settings.m_showAllControls);
ui->linscale->setVisible(m_settings.m_showAllControls);
ui->save->setVisible(m_settings.m_showAllControls);
ui->wsSpectrum->setVisible(m_settings.m_showAllControls);
ui->calibration->setVisible(m_settings.m_showAllControls);
ui->markers->setVisible(m_settings.m_showAllControls);
}
void GLSpectrumGUI::displayGotoMarkers()
{
ui->gotoMarker->clear();
@ -484,6 +521,7 @@ void GLSpectrumGUI::on_markers_clicked(bool checked)
QRect mouseScreenGeometry = screen->geometry();
QPoint localCursorPos = globalCursorPos - mouseScreenGeometry.topLeft();
m_markersDialog->move(localCursorPos);
new DialogPositioner(m_markersDialog, false);
m_markersDialog->show();
}
@ -616,7 +654,7 @@ void GLSpectrumGUI::on_spectrogram_toggled(bool checked)
ui->waterfall->setChecked(false);
blockApplySettings(false);
}
ui->spectrogramStyle->setVisible(m_settings.m_display3DSpectrogram);
ui->spectrogramStyle->setVisible(m_settings.m_display3DSpectrogram && m_settings.m_showAllControls);
applySettings();
}
@ -677,6 +715,13 @@ void GLSpectrumGUI::on_invertWaterfall_toggled(bool checked)
applySettings();
}
void GLSpectrumGUI::on_showAllControls_toggled(bool checked)
{
m_settings.m_showAllControls = checked;
displayControls();
applySettings();
}
void GLSpectrumGUI::on_grid_toggled(bool checked)
{
m_settings.m_displayGrid = checked;
@ -987,6 +1032,7 @@ void GLSpectrumGUI::openWebsocketSpectrumSettingsDialog(const QPoint& p)
dialog.setPort(m_settings.m_wsSpectrumPort);
dialog.move(p);
new DialogPositioner(&dialog, false);
dialog.exec();
if (dialog.hasChanged())
@ -1010,6 +1056,7 @@ void GLSpectrumGUI::openCalibrationPointsDialog(const QPoint& p)
dialog.setCenterFrequency(m_glSpectrum->getCenterFrequency());
connect(&dialog, SIGNAL(updateCalibrationPoints()), this, SLOT(updateCalibrationPoints()));
dialog.move(p);
new DialogPositioner(&dialog, false);
dialog.exec();
m_settings.m_histogramMarkers = m_glSpectrum->getHistogramMarkers();

Wyświetl plik

@ -79,6 +79,7 @@ private:
void applySettings();
void applySpectrumSettings();
void displaySettings();
void displayControls();
void setAveragingCombo();
void setNumberStr(int n, QString& s);
void setNumberStr(float v, int decimalPlaces, QString& s);
@ -125,6 +126,7 @@ private slots:
void on_freeze_toggled(bool checked);
void on_calibration_toggled(bool checked);
void on_gotoMarker_currentIndexChanged(int index);
void on_showAllControls_toggled(bool checked);
void on_measure_clicked(bool checked);

Wyświetl plik

@ -1130,6 +1130,29 @@
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="showAllControls">
<property name="toolTip">
<string>Toggle all controls</string>
</property>
<property name="text">
<string>Grid</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/listing.png</normaloff>:/listing.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="gotoMarker">
<property name="minimumSize">

Wyświetl plik

@ -24,6 +24,9 @@
#include <QPainter>
#include <QFontDatabase>
#include <QWindow>
#include <QGestureEvent>
#include <QPanGesture>
#include <QPinchGesture>
#include "maincore.h"
#include "dsp/spectrumvis.h"
#include "gui/glspectrumview.h"
@ -98,6 +101,10 @@ GLSpectrumView::GLSpectrumView(QWidget* parent) :
m_colorMapName("Angel"),
m_scrollFrequency(false),
m_scrollStartCenterFreq(0),
m_pinching(false),
m_pinching3D(false),
m_frequencyRequested(false),
m_nextFrequencyValid(false),
m_histogramBuffer(nullptr),
m_histogram(nullptr),
m_displayHistogram(true),
@ -223,6 +230,8 @@ GLSpectrumView::GLSpectrumView(QWidget* parent) :
// Handle KeyEvents
setFocusPolicy(Qt::StrongFocus);
installEventFilter(this);
grabGesture(Qt::PinchGesture);
}
GLSpectrumView::~GLSpectrumView()
@ -260,11 +269,37 @@ GLSpectrumView::~GLSpectrumView()
}
}
void GLSpectrumView::queueRequestCenterFrequency(qint64 frequency)
{
if (!m_frequencyRequested)
{
m_frequencyRequested = true;
m_requestedFrequency = frequency;
emit requestCenterFrequency(frequency);
}
else
{
m_nextFrequencyValid = true;
m_nextFrequency = frequency;
}
}
void GLSpectrumView::setCenterFrequency(qint64 frequency)
{
m_mutex.lock();
m_centerFrequency = frequency;
// Handle queued frequency requests
if (m_frequencyRequested && (frequency == m_requestedFrequency))
{
m_frequencyRequested = false;
if (m_nextFrequencyValid)
{
m_nextFrequencyValid = false;
queueRequestCenterFrequency(m_nextFrequency);
}
}
if (m_useCalibration) {
updateCalibrationPoints();
}
@ -944,7 +979,7 @@ void GLSpectrumView::paintGL()
glFunctions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 spectrogramGridMatrix;
int devicePixelRatio;
float devicePixelRatio;
if (m_display3DSpectrogram)
{
@ -972,7 +1007,7 @@ void GLSpectrumView::paintGL()
if (window()->windowHandle()) {
devicePixelRatio = window()->windowHandle()->devicePixelRatio();
} else {
devicePixelRatio = 1;
devicePixelRatio = 1.0f;
}
glFunctions->glViewport(0, m_3DSpectrogramBottom*devicePixelRatio, width()*devicePixelRatio, m_waterfallHeight*devicePixelRatio);
m_glShaderSpectrogram.drawSurface(m_3DSpectrogramStyle, spectrogramGridMatrix, prop_y, m_invertedWaterfall);
@ -3676,9 +3711,81 @@ void GLSpectrumView::updateCalibrationPoints()
m_changesPending = true;
}
bool GLSpectrumView::event(QEvent* event)
{
if (event->type() == QEvent::Gesture)
{
QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(event);
if (QPanGesture *pan = static_cast<QPanGesture *>(gestureEvent->gesture(Qt::PanGesture)))
{
if (pan->state() == Qt::GestureStarted)
{
m_scrollStartCenterFreq = m_centerFrequency;
}
else if (pan->state() == Qt::GestureUpdated)
{
QPointF offset = pan->offset();
float histogramWidth = width() - m_leftMargin - m_rightMargin;
qint64 frequency = (qint64)(m_scrollStartCenterFreq + -offset.x()/histogramWidth * m_frequencyScale.getRange());
queueRequestCenterFrequency(frequency);
}
return true;
}
else if (QPinchGesture *pinch = static_cast<QPinchGesture *>(gestureEvent->gesture(Qt::PinchGesture)))
{
// Don't get GestureStarted and startCenterPoint is always 0,0
// https://bugreports.qt.io/browse/QTBUG-109205
if (!m_pinching)
{
m_scrollStartCenterFreq = m_centerFrequency;
m_pinchStart = pinch->centerPoint();
m_pinching = true;
m_pinching3D = m_display3DSpectrogram && pointInWaterfallOrSpectrogram(mapFromGlobal(m_pinchStart.toPoint()));
}
else
{
if (pinch->changeFlags() & QPinchGesture::CenterPointChanged)
{
if (!m_pinching3D)
{
// Scroll frequency up or down
QPointF offset = pinch->centerPoint() - m_pinchStart;
float histogramWidth = width() - m_leftMargin - m_rightMargin;
qint64 frequency = (qint64)(m_scrollStartCenterFreq + -offset.x()/histogramWidth * m_frequencyScale.getRange());
queueRequestCenterFrequency(frequency);
}
}
if (pinch->changeFlags() & QPinchGesture::ScaleFactorChanged)
{
if (!m_pinching3D)
{
// Zoom in/out of spectrum
QPoint p = mapFromGlobal(pinch->centerPoint().toPoint());
zoomFactor(p, pinch->scaleFactor());
}
else
{
// Scale Z axis of 3D spectragram
m_glShaderSpectrogram.userScaleZ(pinch->scaleFactor());
}
}
if (pinch->state() == Qt::GestureFinished)
{
m_pinching = false;
m_pinching3D = false;
}
}
return true;
}
}
return QOpenGLWidget::event(event);
}
void GLSpectrumView::mouseMoveEvent(QMouseEvent* event)
{
if (m_rotate3DSpectrogram)
if (m_rotate3DSpectrogram && !m_pinching3D)
{
// Rotate 3D Spectrogram
QPointF delta = m_mousePrevLocalPos - event->localPos();
@ -3718,7 +3825,7 @@ void GLSpectrumView::mouseMoveEvent(QMouseEvent* event)
QPointF delta = m_mousePrevLocalPos - event->localPos();
float histogramWidth = width() - m_leftMargin - m_rightMargin;
qint64 frequency = (qint64)(m_scrollStartCenterFreq + delta.x()/histogramWidth * m_frequencyScale.getRange());
emit requestCenterFrequency(frequency);
queueRequestCenterFrequency(frequency);
return;
}
@ -3775,13 +3882,14 @@ void GLSpectrumView::mouseMoveEvent(QMouseEvent* event)
{
// Determine if user is trying to move the channel outside of the current frequency range
// and if so, request an adjustment to the center frequency
// FIXME: This doesn't take zoom into account, so only works when zoomed out
Real freqAbs = m_frequencyScale.getValueFromPos(event->x() - m_leftMarginPixmap.width() - 1);
Real freqMin = m_centerFrequency - m_sampleRate / 2.0f;
Real freqMax = m_centerFrequency + m_sampleRate / 2.0f;
if (freqAbs < freqMin) {
emit requestCenterFrequency(m_centerFrequency - (freqMin - freqAbs));
queueRequestCenterFrequency(m_centerFrequency - (freqMin - freqAbs));
} else if (freqAbs > freqMax) {
emit requestCenterFrequency(m_centerFrequency + (freqAbs - freqMax));
queueRequestCenterFrequency(m_centerFrequency + (freqAbs - freqMax));
}
Real freq = freqAbs - m_centerFrequency;
@ -4174,14 +4282,8 @@ void GLSpectrumView::wheelEvent(QWheelEvent *event)
}
}
void GLSpectrumView::zoom(QWheelEvent *event)
void GLSpectrumView::zoomFactor(const QPointF& p, float factor)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
const QPointF& p = event->position();
#else
const QPointF& p = event->pos();
#endif
float pwx = (p.x() - m_leftMargin) / (width() - m_leftMargin - m_rightMargin); // x position in window
if ((pwx >= 0.0f) && (pwx <= 1.0f))
@ -4200,7 +4302,45 @@ void GLSpectrumView::zoom(QWheelEvent *event)
// Calculate what that difference would be if there was no zoom
float freqDiffZoom1 = freqDiff * m_frequencyZoomFactor;
if (event->angleDelta().y() > 0) // zoom in
m_frequencyZoomFactor *= factor;
m_frequencyZoomFactor = std::min(m_frequencyZoomFactor, m_maxFrequencyZoom);
m_frequencyZoomFactor = std::max(m_frequencyZoomFactor, 1.0f);
// Calculate what frequency difference should be at new zoom
float zoomedFreqDiff = freqDiffZoom1 / m_frequencyZoomFactor;
// Then calculate what the center frequency should be
float zoomedCF = zoomFreq + zoomedFreqDiff;
// Calculate zoom position which will set the desired center frequency
float zoomPos = (zoomedCF - m_centerFrequency) / m_sampleRate + 0.5;
zoomPos = std::max(0.0f, zoomPos);
zoomPos = std::min(1.0f, zoomPos);
frequencyZoom(zoomPos);
}
}
void GLSpectrumView::zoom(const QPointF& p, int y)
{
float pwx = (p.x() - m_leftMargin) / (width() - m_leftMargin - m_rightMargin); // x position in window
if ((pwx >= 0.0f) && (pwx <= 1.0f))
{
// When we zoom, we want the frequency under the cursor to remain the same
// Determine frequency at cursor position
float zoomFreq = m_frequencyScale.getRangeMin() + pwx*m_frequencyScale.getRange();
// Calculate current centre frequency
float currentCF = (m_frequencyZoomFactor == 1) ? m_centerFrequency : ((m_frequencyZoomPos - 0.5) * m_sampleRate + m_centerFrequency);
// Calculate difference from frequency under cursor to centre frequency
float freqDiff = (currentCF - zoomFreq);
// Calculate what that difference would be if there was no zoom
float freqDiffZoom1 = freqDiff * m_frequencyZoomFactor;
if (y > 0) // zoom in
{
if (m_frequencyZoomFactor < m_maxFrequencyZoom) {
m_frequencyZoomFactor += 0.5f;
@ -4247,11 +4387,11 @@ void GLSpectrumView::zoom(QWheelEvent *event)
//qDebug("GLSpectrumView::zoom: pwyh: %f pwyw: %f", pwyh, pwyw);
if ((pwyw >= 0.0f) && (pwyw <= 1.0f)) {
timeZoom(event->angleDelta().y() > 0);
timeZoom(y > 0);
}
if ((pwyh >= 0.0f) && (pwyh <= 1.0f) && !m_linear) {
powerZoom(pwyh, event->angleDelta().y() > 0);
powerZoom(pwyh, y > 0);
}
}
}
@ -4427,7 +4567,7 @@ void GLSpectrumView::channelMarkerMove(QWheelEvent *event, int mul)
}
}
zoom(event);
zoom(event->position(), event->angleDelta().y());
}
// Return if specified point is within the bounds of the waterfall / 3D spectrogram screen area

Wyświetl plik

@ -358,6 +358,14 @@ private:
bool m_scrollFrequency;
qint64 m_scrollStartCenterFreq;
bool m_pinching;
bool m_pinching3D;
QPointF m_pinchStart;
bool m_frequencyRequested; //!< Set when we have emitted requestCenterFrequency
qint64 m_requestedFrequency;
qint64 m_nextFrequency; //!< Next frequency to request when previous request completes
qint64 m_nextFrequencyValid;
QRgb m_histogramPalette[240];
QImage* m_histogramBuffer;
@ -448,12 +456,14 @@ private:
void stopDrag();
void applyChanges();
bool event(QEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void wheelEvent(QWheelEvent*);
void channelMarkerMove(QWheelEvent*, int mul);
void zoom(QWheelEvent*);
void zoomFactor(const QPointF& p, float factor);
void zoom(const QPointF& p, int y);
void frequencyZoom(float pw);
void frequencyPan(QMouseEvent*);
void timeZoom(bool zoomInElseOut);
@ -494,6 +504,7 @@ private:
const QRectF& glRect);
void formatTextInfo(QString& info);
void updateSortedAnnotationMarkers();
void queueRequestCenterFrequency(qint64 frequency);
static bool annotationDisplayLessThan(const SpectrumAnnotationMarker *m1, const SpectrumAnnotationMarker *m2)
{