|
18 | 18 | static void refreshAfterReparent(AetherSDR::SpectrumWidget* sw) |
19 | 19 | { |
20 | 20 | if (!sw) return; |
| 21 | +#if defined(Q_OS_MAC) && defined(AETHER_GPU_SPECTRUM) |
| 22 | + const bool wasVisible = sw->isVisible(); |
| 23 | + sw->hide(); |
21 | 24 | 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 |
22 | 36 | } |
23 | 37 |
|
24 | 38 | namespace AetherSDR { |
@@ -336,6 +350,126 @@ void PanadapterStack::removeAll() |
336 | 350 | layout()->addWidget(m_splitter); |
337 | 351 | } |
338 | 352 |
|
| 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 | + |
339 | 473 | void PanadapterStack::applyLayout(const QString& layoutId, const QStringList& panIds) |
340 | 474 | { |
341 | 475 | // Build structure based on layout ID. |
@@ -506,10 +640,12 @@ void PanadapterStack::floatPanadapter(const QString& panId) |
506 | 640 | applet->spectrumWidget()->setFloating(true); |
507 | 641 |
|
508 | 642 | m_floatingWindows[panId] = fw; |
| 643 | + rebuildDockedSplitter(); |
509 | 644 | fw->restoreWindowGeometry(); |
510 | 645 | fw->show(); |
511 | 646 | fw->raise(); |
512 | 647 | saveFloatingState(); |
| 648 | + emit panFloated(panId); |
513 | 649 |
|
514 | 650 | connect(fw, &PanFloatingWindow::dockRequested, |
515 | 651 | this, &PanadapterStack::dockPanadapter); |
@@ -563,6 +699,7 @@ void PanadapterStack::dockPanadapter(const QString& panId) |
563 | 699 | // the splitter without an intermediate top-level state. |
564 | 700 | m_splitter->addWidget(applet); |
565 | 701 | applet->show(); |
| 702 | + rebuildDockedSplitter(); |
566 | 703 |
|
567 | 704 | const int count = m_splitter->count(); |
568 | 705 | if (count > 1) { |
@@ -590,6 +727,7 @@ void PanadapterStack::dockPanadapter(const QString& panId) |
590 | 727 | refreshAfterReparent(sw); |
591 | 728 | }); |
592 | 729 | } |
| 730 | + emit panDocked(panId); |
593 | 731 | } |
594 | 732 |
|
595 | 733 | bool PanadapterStack::isFloating(const QString& panId) const |
@@ -621,6 +759,7 @@ void PanadapterStack::saveFloatingState() const |
621 | 759 | ids << id; |
622 | 760 | } |
623 | 761 | AppSettings::instance().setValue("FloatingPanIds", ids.join(',')); |
| 762 | + AppSettings::instance().save(); |
624 | 763 | } |
625 | 764 |
|
626 | 765 | void PanadapterStack::restoreFloatingState() |
|
0 commit comments