From ec78344f88f5392ce827b2267847d5fd1d68b855 Mon Sep 17 00:00:00 2001
From: Jon Beniston <jon@beniston.com>
Date: Sun, 2 Oct 2022 20:06:52 +0100
Subject: [PATCH 1/2] Size spectrum measurements table.

---
 sdrgui/gui/glspectrum.cpp           | 74 +++++++++++++++++++++++++++
 sdrgui/gui/glspectrum.h             |  6 +--
 sdrgui/gui/spectrummeasurements.cpp | 79 +++++++++++++++++++++--------
 sdrgui/gui/spectrummeasurements.h   | 12 ++++-
 4 files changed, 144 insertions(+), 27 deletions(-)

diff --git a/sdrgui/gui/glspectrum.cpp b/sdrgui/gui/glspectrum.cpp
index f65b59157..4d15f7d57 100644
--- a/sdrgui/gui/glspectrum.cpp
+++ b/sdrgui/gui/glspectrum.cpp
@@ -32,6 +32,7 @@ GLSpectrum::GLSpectrum(QWidget *parent) :
     m_spectrum->setMeasurements(m_measurements);
     m_splitter->addWidget(m_spectrum);
     m_splitter->addWidget(m_measurements);
+    m_position = SpectrumSettings::PositionBelow;
     QVBoxLayout *layout = new QVBoxLayout(this);
     layout->setContentsMargins(0, 0, 0, 0);
     layout->addWidget(m_splitter);
@@ -66,4 +67,77 @@ void GLSpectrum::setMeasurementsPosition(SpectrumSettings::MeasurementsPosition
         m_splitter->insertWidget(0, m_spectrum);
         break;
     }
+    m_position = position;
+}
+
+void GLSpectrum::setMeasurementParams(SpectrumSettings::Measurement measurement,
+                                      int centerFrequencyOffset, int bandwidth, int chSpacing, int adjChBandwidth,
+                                      int harmonics, int peaks, bool highlight, int precision)
+{
+    m_spectrum->setMeasurementParams(measurement, centerFrequencyOffset, bandwidth, chSpacing, adjChBandwidth, harmonics, peaks, highlight, precision);
+    // Resize splitter so there's just enough space for the measurements table
+    // But don't use more than 50%
+    QList<int> sizes = m_splitter->sizes();
+    if ((sizes[0] == 0) && (sizes[1] == 0))
+    {
+        // Initial sizing when first created
+        QSize s = parentWidget()->size();
+        switch (m_position)
+        {
+        case SpectrumSettings::PositionAbove:
+            sizes[0] = m_measurements->sizeHint().height();
+            sizes[1] = s.height() - sizes[0] - m_splitter->handleWidth();
+            sizes[1] = std::max(sizes[1], sizes[0]);
+            break;
+        case SpectrumSettings::PositionLeft:
+            sizes[0] = m_measurements->sizeHint().width();
+            sizes[1] = s.width() - sizes[0] - m_splitter->handleWidth();
+            sizes[1] = std::max(sizes[1], sizes[0]);
+            break;
+        case SpectrumSettings::PositionBelow:
+            sizes[1] = m_measurements->sizeHint().height();
+            sizes[0] = s.height() - sizes[1] - m_splitter->handleWidth();
+            sizes[0] = std::max(sizes[0], sizes[1]);
+            break;
+        case SpectrumSettings::PositionRight:
+            sizes[1] = m_measurements->sizeHint().width();
+            sizes[0] = s.width() - sizes[1] - m_splitter->handleWidth();
+            sizes[0] = std::max(sizes[0], sizes[1]);
+            break;
+        }
+    }
+    else
+    {
+        // When measurement type is changed when already visible
+        int diff = 0;
+        switch (m_position)
+        {
+        case SpectrumSettings::PositionAbove:
+            diff = m_measurements->sizeHint().height() - sizes[0];
+            sizes[0] += diff;
+            sizes[1] -= diff;
+            sizes[1] = std::max(sizes[1], sizes[0]);
+            break;
+        case SpectrumSettings::PositionLeft:
+            diff = m_measurements->sizeHint().width() - sizes[0];
+            sizes[0] += diff;
+            sizes[1] -= diff;
+            sizes[1] = std::max(sizes[1], sizes[0]);
+            break;
+        case SpectrumSettings::PositionBelow:
+            diff = m_measurements->sizeHint().height() - sizes[1];
+            sizes[1] += diff;
+            sizes[0] -= diff;
+            sizes[0] = std::max(sizes[0], sizes[1]);
+            break;
+        case SpectrumSettings::PositionRight:
+            diff = m_measurements->sizeHint().width() - sizes[1];
+            sizes[1] += diff;
+            sizes[0] -= diff;
+            sizes[0] = std::max(sizes[0], sizes[1]);
+            break;
+        }
+    }
+    m_splitter->setSizes(sizes);
+    //resize(size().expandedTo(minimumSizeHint()));
 }
diff --git a/sdrgui/gui/glspectrum.h b/sdrgui/gui/glspectrum.h
index dcc0f077e..2e784e5fe 100644
--- a/sdrgui/gui/glspectrum.h
+++ b/sdrgui/gui/glspectrum.h
@@ -67,10 +67,7 @@ public:
     void setUseCalibration(bool useCalibration) { m_spectrum->setUseCalibration(useCalibration); }
     void setMeasurementParams(SpectrumSettings::Measurement measurement,
                               int centerFrequencyOffset, int bandwidth, int chSpacing, int adjChBandwidth,
-                              int harmonics, int peaks, bool highlight, int precision)
-    {
-        m_spectrum->setMeasurementParams(measurement, centerFrequencyOffset, bandwidth, chSpacing, adjChBandwidth, harmonics, peaks, highlight, precision);
-    }
+                              int harmonics, int peaks, bool highlight, int precision);
     qint32 getSampleRate() const { return m_spectrum->getSampleRate(); }
     void addChannelMarker(ChannelMarker* channelMarker) { m_spectrum->addChannelMarker(channelMarker); }
     void removeChannelMarker(ChannelMarker* channelMarker) { m_spectrum->removeChannelMarker(channelMarker); }
@@ -110,6 +107,7 @@ private:
     QSplitter *m_splitter;
     GLSpectrumView *m_spectrum;
     SpectrumMeasurements *m_measurements;
+    SpectrumSettings::MeasurementsPosition m_position;
 
 };
 
diff --git a/sdrgui/gui/spectrummeasurements.cpp b/sdrgui/gui/spectrummeasurements.cpp
index f7bd9be33..b90d42d59 100644
--- a/sdrgui/gui/spectrummeasurements.cpp
+++ b/sdrgui/gui/spectrummeasurements.cpp
@@ -24,10 +24,39 @@
 #include <QGuiApplication>
 #include <QDebug>
 #include <QPainter>
+#include <QStyledItemDelegate>
 
 #include "gui/spectrummeasurements.h"
 
-#include <QStyledItemDelegate>
+QSize SpectrumMeasurementsTable::sizeHint() const
+{
+    // QAbstractScrollArea::sizeHint() always returns 256x192 when sizeAdjustPolicy == AdjustIgnored
+    // If using AdjustToContents policy, the default sizeHint includes the stretched empty column
+    // which we don't want, as that prevents the Auto Stack feature from reducing it
+    // So we need some custom code to set size ignoring this column
+    int width = 0;
+    int height = 0;
+    for (int i = 0; i < columnCount() - 1; i++) {   // -1 to ignore empty column at end of row
+        width += columnWidth(i);
+    }
+    for (int i = 0; i < rowCount(); i++) {
+        height += rowHeight(i);
+    }
+
+    int doubleFrame = 2 * frameWidth();
+
+    width += verticalHeader()->width() + doubleFrame;
+    height += horizontalHeader()->height() + doubleFrame;
+
+    return QSize(width, height);
+}
+
+QSize SpectrumMeasurementsTable::minimumSizeHint() const
+{
+    QSize min1 = QTableWidget::minimumSizeHint(); // This seems to include vertical space for scroll bar, which we don't need
+    int height = horizontalHeader()->height() + 2 * frameWidth() + rowHeight(0);
+    return QSize(min1.width(), height);
+}
 
 class SDRGUI_API UnitsDelegate : public QStyledItemDelegate {
 
@@ -138,7 +167,6 @@ void UnitsDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
     painter->drawText(option.rect.x() + option.rect.width() - 1 - sWidth, y, s);
 }
 
-
 const QStringList SpectrumMeasurements::m_measurementColumns = {
     "Current",
     "Mean",
@@ -184,7 +212,7 @@ SpectrumMeasurements::SpectrumMeasurements(QWidget *parent) :
 
 void SpectrumMeasurements::createMeasurementsTable(const QStringList &rows, const QStringList &units)
 {
-    m_table = new QTableWidget();
+    m_table = new SpectrumMeasurementsTable();
 
     m_table->horizontalHeader()->setSectionsMovable(true);
     m_table->verticalHeader()->setSectionsMovable(true);
@@ -196,16 +224,7 @@ void SpectrumMeasurements::createMeasurementsTable(const QStringList &rows, cons
         item->setToolTip(m_tooltips[i]);
         m_table->setHorizontalHeaderItem(i, item);
     }
-
-    // Cell context menu
-    m_table->setContextMenuPolicy(Qt::CustomContextMenu);
-    connect(m_table, &QTableWidget::customContextMenuRequested, this, &SpectrumMeasurements::tableContextMenu);
-
-    m_table->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
-    m_table->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
-
-    // Fill up space at end of rows
-    m_table->horizontalHeader()->setSectionResizeMode(COL_EMPTY, QHeaderView::Stretch);
+    m_table->horizontalHeader()->setStretchLastSection(true);
 
     m_table->setRowCount(rows.size());
     for (int i = 0; i < rows.size(); i++)
@@ -232,16 +251,23 @@ void SpectrumMeasurements::createMeasurementsTable(const QStringList &rows, cons
         m_measurements.append(m);
     }
     resizeMeasurementsTable();
+
+    m_table->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+    m_table->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
+
     for (int i = 0; i < COL_COUNT; i++) {
         m_table->setItemDelegateForColumn(i, new UnitsDelegate());
     }
     createTableMenus();
 
+    // Cell context menu
+    m_table->setContextMenuPolicy(Qt::CustomContextMenu);
+    connect(m_table, &QTableWidget::customContextMenuRequested, this, &SpectrumMeasurements::tableContextMenu);
 }
 
 void SpectrumMeasurements::createPeakTable(int peaks)
 {
-    m_peakTable = new QTableWidget();
+    m_peakTable = new SpectrumMeasurementsTable();
     m_peakTable->horizontalHeader()->setSectionsMovable(true);
 
     QStringList columns = QStringList{"Frequency", "Power", ""};
@@ -252,6 +278,8 @@ void SpectrumMeasurements::createPeakTable(int peaks)
     for (int i = 0; i < columns.size(); i++) {
         m_peakTable->setHorizontalHeaderItem(i, new QTableWidgetItem(columns[i]));
     }
+    m_peakTable->horizontalHeader()->setStretchLastSection(true);
+
     for (int i = 0; i < peaks; i++)
     {
         for (int j = 0; j < 3; j++)
@@ -269,15 +297,12 @@ void SpectrumMeasurements::createPeakTable(int peaks)
     }
     resizePeakTable();
 
-    m_peakTable->setItemDelegateForColumn(COL_FREQUENCY, new UnitsDelegate());
-    m_peakTable->setItemDelegateForColumn(COL_POWER, new UnitsDelegate());
-
-    // Fill up space at end of rows
-    m_peakTable->horizontalHeader()->setSectionResizeMode(COL_PEAK_EMPTY, QHeaderView::Stretch);
-
     m_peakTable->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
     m_peakTable->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
 
+    m_peakTable->setItemDelegateForColumn(COL_FREQUENCY, new UnitsDelegate());
+    m_peakTable->setItemDelegateForColumn(COL_POWER, new UnitsDelegate());
+
     // Cell context menu
     m_peakTable->setContextMenuPolicy(Qt::CustomContextMenu);
     connect(m_peakTable, &QTableWidget::customContextMenuRequested, this, &SpectrumMeasurements::peakTableContextMenu);
@@ -287,7 +312,7 @@ void SpectrumMeasurements::createTableMenus()
 {
     // Add context menu to allow hiding/showing of columns
     m_rowMenu = new QMenu(m_table);
-    for (int i = 0; i < m_table->verticalHeader()->count(); i++)
+    for (int i = 0; i < m_table->verticalHeader()->count() - 1; i++) // -1 to skip empty column
     {
         QString text = m_table->verticalHeaderItem(i)->text();
         m_rowMenu->addAction(createCheckableItem(text, i, true, true));
@@ -495,6 +520,18 @@ void SpectrumMeasurements::setMeasurementParams(SpectrumSettings::Measurement me
         default:
             break;
         }
+
+        // Set size to show full table
+        if (m_peakTable)
+        {
+            m_peakTable->show();  // Need to call show() so that sizeHint() is not 0,0
+            resize(sizeHint());
+        }
+        else if (m_table)
+        {
+            m_table->show();
+            resize(sizeHint());
+        }
     }
 }
 
diff --git a/sdrgui/gui/spectrummeasurements.h b/sdrgui/gui/spectrummeasurements.h
index 41fa5aeab..ab14999b6 100644
--- a/sdrgui/gui/spectrummeasurements.h
+++ b/sdrgui/gui/spectrummeasurements.h
@@ -25,6 +25,14 @@
 #include "dsp/spectrumsettings.h"
 #include "export.h"
 
+class SDRGUI_API SpectrumMeasurementsTable : public QTableWidget {
+    Q_OBJECT
+
+public:
+    virtual QSize sizeHint() const override;
+    virtual QSize minimumSizeHint() const override;
+};
+
 // Displays spectrum measurements in a table
 class SDRGUI_API SpectrumMeasurements : public QWidget {
     Q_OBJECT
@@ -113,12 +121,12 @@ private:
     SpectrumSettings::Measurement m_measurement;
     int m_precision;
 
-    QTableWidget *m_table;
+    SpectrumMeasurementsTable *m_table;
     QMenu *m_rowMenu;
     QMenu *m_columnMenu;
     QList<Measurement> m_measurements;
 
-    QTableWidget *m_peakTable;
+    SpectrumMeasurementsTable *m_peakTable;
     QBrush m_textBrush;
     QBrush m_redBrush;
 

From 081696f3a942b2069927e966d0c52ab1931a351e Mon Sep 17 00:00:00 2001
From: Jon Beniston <jon@beniston.com>
Date: Sun, 2 Oct 2022 20:07:28 +0100
Subject: [PATCH 2/2] Rollupwidgets: Handle child layout requests

---
 sdrgui/gui/rollupcontents.cpp | 4 ++++
 sdrgui/gui/rollupwidget.cpp   | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/sdrgui/gui/rollupcontents.cpp b/sdrgui/gui/rollupcontents.cpp
index 148fc66ea..f40c0183d 100644
--- a/sdrgui/gui/rollupcontents.cpp
+++ b/sdrgui/gui/rollupcontents.cpp
@@ -373,6 +373,10 @@ bool RollupContents::event(QEvent* event)
         ((QChildEvent*)event)->child()->removeEventFilter(this);
         arrangeRollups();
     }
+    else if (event->type() == QEvent::LayoutRequest)
+    {
+        arrangeRollups();
+    }
 
     return QWidget::event(event);
 }
diff --git a/sdrgui/gui/rollupwidget.cpp b/sdrgui/gui/rollupwidget.cpp
index 5b89eb355..307260d29 100644
--- a/sdrgui/gui/rollupwidget.cpp
+++ b/sdrgui/gui/rollupwidget.cpp
@@ -576,6 +576,10 @@ bool RollupWidget::event(QEvent* event)
         ((QChildEvent*)event)->child()->removeEventFilter(this);
         arrangeRollups();
     }
+    else if (event->type() == QEvent::LayoutRequest)
+    {
+        arrangeRollups();
+    }
 
     return QWidget::event(event);
 }