Skip to content

Commit 7cc1854

Browse files
committed
Fix macOS panadapter popout refresh
1 parent 0344533 commit 7cc1854

3 files changed

Lines changed: 179 additions & 1 deletion

File tree

src/gui/MainWindow.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2076,6 +2076,7 @@ MainWindow::MainWindow(QWidget* parent)
20762076
m_layoutRestoreTimer->setSingleShot(true);
20772077
m_layoutRestoreTimer->setInterval(1000);
20782078
connect(m_layoutRestoreTimer, &QTimer::timeout, this, [this]() {
2079+
m_layoutRestoreTimer->setProperty("fired", true);
20792080
// The radio restores pans from the GUIClientID session.
20802081
// Accept whatever the radio gives and arrange based on count.
20812082
const int panCount = m_panStack->count();
@@ -2130,7 +2131,9 @@ MainWindow::MainWindow(QWidget* parent)
21302131
m_panStack->restoreFloatingState();
21312132
});
21322133
}
2133-
m_layoutRestoreTimer->start(); // restart on each new pan
2134+
if (!m_layoutRestoreTimer->property("fired").toBool()) {
2135+
m_layoutRestoreTimer->start();
2136+
}
21342137
});
21352138
// Re-push xpixels/ypixels when the radio requests it (profile change, reconnect, etc.)
21362139
connect(&m_radioModel, &RadioModel::panDimensionsNeeded,
@@ -2151,6 +2154,35 @@ MainWindow::MainWindow(QWidget* parent)
21512154
m_radioModel.panStream()->setYPixels(pan->panStreamId(), ypix);
21522155
});
21532156

2157+
#ifdef Q_OS_MAC
2158+
auto repushPanDimensions = [this]() {
2159+
QTimer::singleShot(200, this, [this]() {
2160+
for (auto* applet : m_panStack->allApplets()) {
2161+
auto* sw = applet->spectrumWidget();
2162+
auto* pan = m_radioModel.panadapter(applet->panId());
2163+
if (!sw || !pan) {
2164+
continue;
2165+
}
2166+
const int xpix = sw->width();
2167+
const int ypix = sw->height();
2168+
if (xpix < 100 || ypix < 100) {
2169+
continue;
2170+
}
2171+
m_radioModel.sendCommand(
2172+
QString("display pan set %1 xpixels=%2 ypixels=%3")
2173+
.arg(pan->panId()).arg(xpix).arg(ypix));
2174+
if (pan->panStreamId()) {
2175+
m_radioModel.panStream()->setYPixels(pan->panStreamId(), ypix);
2176+
}
2177+
}
2178+
});
2179+
};
2180+
connect(m_panStack, &PanadapterStack::panFloated,
2181+
this, [repushPanDimensions](const QString&) { repushPanDimensions(); });
2182+
connect(m_panStack, &PanadapterStack::panDocked,
2183+
this, [repushPanDimensions](const QString&) { repushPanDimensions(); });
2184+
#endif
2185+
21542186
connect(&m_radioModel, &RadioModel::panadapterRemoved,
21552187
this, [this](const QString& panId) {
21562188
// Disconnect all signals from the dying applet's widgets to prevent
@@ -6864,6 +6896,9 @@ void MainWindow::onConnectionStateChanged(bool connected)
68646896
{
68656897
m_connPanel->setConnected(connected);
68666898
if (connected) {
6899+
if (m_layoutRestoreTimer) {
6900+
m_layoutRestoreTimer->setProperty("fired", false);
6901+
}
68676902
m_radioInfoLabel->setText(m_radioModel.model());
68686903
m_radioVersionLabel->setText(m_radioModel.version());
68696904
m_stationLabel->setText(m_radioModel.nickname());

src/gui/PanadapterStack.cpp

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,21 @@
1818
static void refreshAfterReparent(AetherSDR::SpectrumWidget* sw)
1919
{
2020
if (!sw) return;
21+
#if defined(Q_OS_MAC) && defined(AETHER_GPU_SPECTRUM)
22+
const bool wasVisible = sw->isVisible();
23+
sw->hide();
2124
sw->resetGpuResources();
25+
if (QWindow* windowHandle = sw->windowHandle()) {
26+
windowHandle->destroy();
27+
}
28+
sw->setAttribute(Qt::WA_NativeWindow);
29+
if (wasVisible) {
30+
sw->show();
31+
}
32+
QTimer::singleShot(50, sw, [sw]() { sw->update(); });
33+
#else
34+
sw->resetGpuResources();
35+
#endif
2236
}
2337

2438
namespace AetherSDR {
@@ -336,6 +350,126 @@ void PanadapterStack::removeAll()
336350
layout()->addWidget(m_splitter);
337351
}
338352

353+
void PanadapterStack::rebuildDockedSplitter()
354+
{
355+
QList<PanadapterApplet*> docked;
356+
for (auto it = m_pans.cbegin(); it != m_pans.cend(); ++it) {
357+
if (!m_floatingWindows.contains(it.key())) {
358+
docked.append(it.value());
359+
}
360+
}
361+
362+
QSplitter* oldSplitter = m_splitter;
363+
auto* newSplitter = new QSplitter(Qt::Vertical, this);
364+
newSplitter->setHandleWidth(3);
365+
newSplitter->setChildrenCollapsible(false);
366+
layout()->addWidget(newSplitter);
367+
368+
static const QMap<QString, int> layoutPanCount = {
369+
{"1", 1}, {"2v", 2}, {"2h", 2}, {"2h1", 3}, {"12h", 3}, {"3v", 3},
370+
{"2x2", 4}, {"4v", 4}, {"3h2", 5}, {"2x3", 6}, {"4h3", 7}, {"2x4", 8}
371+
};
372+
QString layoutId = AppSettings::instance().value("PanadapterLayout", "1").toString();
373+
if (layoutPanCount.value(layoutId, -1) != docked.size()) {
374+
if (docked.size() == 2) {
375+
layoutId = QStringLiteral("2v");
376+
} else if (docked.size() == 3) {
377+
layoutId = QStringLiteral("2h1");
378+
} else if (docked.size() == 4) {
379+
layoutId = QStringLiteral("2x2");
380+
} else {
381+
layoutId = QStringLiteral("1");
382+
}
383+
}
384+
385+
auto makeSplitter = [](Qt::Orientation orientation) {
386+
auto* splitter = new QSplitter(orientation);
387+
splitter->setHandleWidth(3);
388+
splitter->setChildrenCollapsible(false);
389+
return splitter;
390+
};
391+
392+
auto addVertical = [&]() {
393+
newSplitter->setOrientation(Qt::Vertical);
394+
for (PanadapterApplet* applet : docked) {
395+
newSplitter->addWidget(applet);
396+
applet->show();
397+
}
398+
};
399+
400+
if (layoutId == "2h" && docked.size() >= 2) {
401+
newSplitter->setOrientation(Qt::Horizontal);
402+
newSplitter->addWidget(docked[0]);
403+
newSplitter->addWidget(docked[1]);
404+
} else if (layoutId == "2h1" && docked.size() >= 3) {
405+
auto* topSplit = makeSplitter(Qt::Horizontal);
406+
topSplit->addWidget(docked[0]);
407+
topSplit->addWidget(docked[1]);
408+
newSplitter->addWidget(topSplit);
409+
newSplitter->addWidget(docked[2]);
410+
} else if (layoutId == "12h" && docked.size() >= 3) {
411+
auto* botSplit = makeSplitter(Qt::Horizontal);
412+
botSplit->addWidget(docked[1]);
413+
botSplit->addWidget(docked[2]);
414+
newSplitter->addWidget(docked[0]);
415+
newSplitter->addWidget(botSplit);
416+
} else if (layoutId == "2x2" && docked.size() >= 4) {
417+
auto* topSplit = makeSplitter(Qt::Horizontal);
418+
topSplit->addWidget(docked[0]);
419+
topSplit->addWidget(docked[1]);
420+
auto* botSplit = makeSplitter(Qt::Horizontal);
421+
botSplit->addWidget(docked[2]);
422+
botSplit->addWidget(docked[3]);
423+
newSplitter->addWidget(topSplit);
424+
newSplitter->addWidget(botSplit);
425+
} else if (layoutId == "3h2" && docked.size() >= 5) {
426+
auto* topSplit = makeSplitter(Qt::Horizontal);
427+
topSplit->addWidget(docked[0]);
428+
topSplit->addWidget(docked[1]);
429+
topSplit->addWidget(docked[2]);
430+
auto* botSplit = makeSplitter(Qt::Horizontal);
431+
botSplit->addWidget(docked[3]);
432+
botSplit->addWidget(docked[4]);
433+
newSplitter->addWidget(topSplit);
434+
newSplitter->addWidget(botSplit);
435+
} else if (layoutId == "2x3" && docked.size() >= 6) {
436+
for (int r = 0; r < 3; ++r) {
437+
auto* rowSplit = makeSplitter(Qt::Horizontal);
438+
rowSplit->addWidget(docked[r * 2]);
439+
rowSplit->addWidget(docked[r * 2 + 1]);
440+
newSplitter->addWidget(rowSplit);
441+
}
442+
} else if (layoutId == "4h3" && docked.size() >= 7) {
443+
auto* topSplit = makeSplitter(Qt::Horizontal);
444+
topSplit->addWidget(docked[0]);
445+
topSplit->addWidget(docked[1]);
446+
topSplit->addWidget(docked[2]);
447+
topSplit->addWidget(docked[3]);
448+
auto* botSplit = makeSplitter(Qt::Horizontal);
449+
botSplit->addWidget(docked[4]);
450+
botSplit->addWidget(docked[5]);
451+
botSplit->addWidget(docked[6]);
452+
newSplitter->addWidget(topSplit);
453+
newSplitter->addWidget(botSplit);
454+
} else if (layoutId == "2x4" && docked.size() >= 8) {
455+
for (int r = 0; r < 4; ++r) {
456+
auto* rowSplit = makeSplitter(Qt::Horizontal);
457+
rowSplit->addWidget(docked[r * 2]);
458+
rowSplit->addWidget(docked[r * 2 + 1]);
459+
newSplitter->addWidget(rowSplit);
460+
}
461+
} else {
462+
addVertical();
463+
}
464+
465+
layout()->removeWidget(m_splitter);
466+
oldSplitter->hide();
467+
oldSplitter->deleteLater();
468+
m_splitter = newSplitter;
469+
470+
QTimer::singleShot(0, this, [this]() { equalizeSizes(); });
471+
}
472+
339473
void PanadapterStack::applyLayout(const QString& layoutId, const QStringList& panIds)
340474
{
341475
// Build structure based on layout ID.
@@ -506,10 +640,12 @@ void PanadapterStack::floatPanadapter(const QString& panId)
506640
applet->spectrumWidget()->setFloating(true);
507641

508642
m_floatingWindows[panId] = fw;
643+
rebuildDockedSplitter();
509644
fw->restoreWindowGeometry();
510645
fw->show();
511646
fw->raise();
512647
saveFloatingState();
648+
emit panFloated(panId);
513649

514650
connect(fw, &PanFloatingWindow::dockRequested,
515651
this, &PanadapterStack::dockPanadapter);
@@ -563,6 +699,7 @@ void PanadapterStack::dockPanadapter(const QString& panId)
563699
// the splitter without an intermediate top-level state.
564700
m_splitter->addWidget(applet);
565701
applet->show();
702+
rebuildDockedSplitter();
566703

567704
const int count = m_splitter->count();
568705
if (count > 1) {
@@ -590,6 +727,7 @@ void PanadapterStack::dockPanadapter(const QString& panId)
590727
refreshAfterReparent(sw);
591728
});
592729
}
730+
emit panDocked(panId);
593731
}
594732

595733
bool PanadapterStack::isFloating(const QString& panId) const
@@ -621,6 +759,7 @@ void PanadapterStack::saveFloatingState() const
621759
ids << id;
622760
}
623761
AppSettings::instance().setValue("FloatingPanIds", ids.join(','));
762+
AppSettings::instance().save();
624763
}
625764

626765
void PanadapterStack::restoreFloatingState()

src/gui/PanadapterStack.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,12 @@ class PanadapterStack : public QWidget {
6767

6868
signals:
6969
void activePanChanged(const QString& panId);
70+
void panFloated(const QString& panId);
71+
void panDocked(const QString& panId);
7072

7173
private:
74+
void rebuildDockedSplitter();
75+
7276
BandStackPanel* m_bandStackPanel{nullptr};
7377
QSplitter* m_splitter{nullptr};
7478
QMap<QString, PanadapterApplet*> m_pans;

0 commit comments

Comments
 (0)