From e69f9a8008d9bacc17adac262b20640e25d3d044 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 6 Sep 2022 08:08:14 -0500 Subject: [PATCH] Add available products to Level 3 Products Widget --- scwx-qt/source/scwx/qt/main/main_window.cpp | 78 ++++++++---- .../scwx/qt/ui/level3_products_widget.cpp | 111 +++++++++++++++++- .../scwx/qt/ui/level3_products_widget.hpp | 2 + 3 files changed, 167 insertions(+), 24 deletions(-) diff --git a/scwx-qt/source/scwx/qt/main/main_window.cpp b/scwx-qt/source/scwx/qt/main/main_window.cpp index 2cb43b51..ececc023 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.cpp +++ b/scwx-qt/source/scwx/qt/main/main_window.cpp @@ -73,6 +73,7 @@ public: ~MainWindowImpl() = default; void ConfigureMapLayout(); + void ConnectMapSignals(); void HandleFocusChange(QWidget* focused); void SelectElevation(map::MapWidget* mapWidget, float elevation); void SelectRadarProduct(map::MapWidget* mapWidget, @@ -80,6 +81,7 @@ public: const std::string& productName, int16_t productCode); void SetActiveMap(map::MapWidget* mapWidget); + void UpdateAvailableLevel3Products(); void UpdateElevationSelection(float elevation); void UpdateRadarProductSelection(common::RadarProductGroup group, const std::string& product); @@ -151,6 +153,8 @@ MainWindow::MainWindow(QWidget* parent) : 0); } + p->ConnectMapSignals(); + connect(qApp, &QApplication::focusChanged, this, @@ -301,29 +305,6 @@ void MainWindowImpl::ConfigureMapLayout() if (maps_.at(mapIndex) == nullptr) { maps_[mapIndex] = new map::MapWidget(settings_); - - connect(maps_[mapIndex], - &map::MapWidget::MapParametersChanged, - this, - &MainWindowImpl::UpdateMapParameters); - - connect( - maps_[mapIndex], - &map::MapWidget::RadarSweepUpdated, - this, - [=]() - { - if (maps_[mapIndex] == activeMap_) - { - UpdateRadarProductSelection( - activeMap_->GetRadarProductGroup(), - activeMap_->GetRadarProductName()); - UpdateRadarProductSettings(); - UpdateRadarSite(); - UpdateVcp(); - } - }, - Qt::QueuedConnection); } hs->addWidget(maps_[mapIndex]); @@ -337,6 +318,50 @@ void MainWindowImpl::ConfigureMapLayout() SetActiveMap(maps_.at(0)); } +void MainWindowImpl::ConnectMapSignals() +{ + std::for_each(maps_.cbegin(), + maps_.cend(), + [&](auto& mapWidget) + { + connect(mapWidget, + &map::MapWidget::MapParametersChanged, + this, + &MainWindowImpl::UpdateMapParameters); + + connect( + mapWidget, + &map::MapWidget::RadarSweepUpdated, + this, + [&]() + { + if (mapWidget == activeMap_) + { + UpdateRadarProductSelection( + mapWidget->GetRadarProductGroup(), + mapWidget->GetRadarProductName()); + UpdateRadarProductSettings(); + UpdateRadarSite(); + UpdateVcp(); + } + }, + Qt::QueuedConnection); + + connect( + mapWidget, + &map::MapWidget::Level3ProductsChanged, + this, + [&]() + { + if (mapWidget == activeMap_) + { + UpdateAvailableLevel3Products(); + } + }, + Qt::QueuedConnection); + }); +} + void MainWindowImpl::HandleFocusChange(QWidget* focused) { map::MapWidget* mapWidget = dynamic_cast(focused); @@ -344,6 +369,7 @@ void MainWindowImpl::HandleFocusChange(QWidget* focused) if (mapWidget != nullptr) { SetActiveMap(mapWidget); + UpdateAvailableLevel3Products(); UpdateRadarProductSelection(mapWidget->GetRadarProductGroup(), mapWidget->GetRadarProductName()); UpdateRadarProductSettings(); @@ -395,6 +421,12 @@ void MainWindowImpl::SetActiveMap(map::MapWidget* mapWidget) } } +void MainWindowImpl::UpdateAvailableLevel3Products() +{ + level3ProductsWidget_->UpdateAvailableProducts( + activeMap_->GetAvailableLevel3Categories()); +} + void MainWindowImpl::UpdateElevationSelection(float elevation) { level2SettingsWidget_->UpdateElevationSelection(elevation); diff --git a/scwx-qt/source/scwx/qt/ui/level3_products_widget.cpp b/scwx-qt/source/scwx/qt/ui/level3_products_widget.cpp index 5f72aa43..12add0f5 100644 --- a/scwx-qt/source/scwx/qt/ui/level3_products_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/level3_products_widget.cpp @@ -3,7 +3,9 @@ #include #include +#include +#include #include namespace scwx @@ -22,7 +24,11 @@ class Level3ProductsWidgetImpl : public QObject public: explicit Level3ProductsWidgetImpl(Level3ProductsWidget* self) : - self_ {self}, layout_ {new ui::FlowLayout(self)}, categoryButtons_ {} + self_ {self}, + layout_ {new ui::FlowLayout(self)}, + categoryButtons_ {}, + availableCategoryMap_ {}, + availableCategoryMutex_ {} { layout_->setContentsMargins(0, 0, 0, 0); @@ -42,6 +48,30 @@ public: &QToolButton::clicked, this, [=]() { SelectProductCategory(category); }); + + QMenu* categoryMenu = new QMenu(); + toolButton->setMenu(categoryMenu); + + const auto& products = common::GetLevel3ProductsByCategory(category); + auto& productMenus = categoryMenuMap_[category]; + + for (const auto& product : products) + { + QMenu* productMenu = categoryMenu->addMenu(QString::fromStdString( + common::GetLevel3ProductDescription(product))); + + for (size_t tilt = 1; tilt <= common::kLevel3ProductMaxTilts; + ++tilt) + { + productMenu->addAction(tr("Tilt %1").arg(tilt)); + } + + productMenus[product] = productMenu; + + productMenu->menuAction()->setVisible(false); + } + + toolButton->setEnabled(false); } } ~Level3ProductsWidgetImpl() = default; @@ -53,6 +83,12 @@ public: Level3ProductsWidget* self_; QLayout* layout_; std::list categoryButtons_; + std::unordered_map> + categoryMenuMap_; + + common::Level3ProductCategoryMap availableCategoryMap_; + std::shared_mutex availableCategoryMutex_; }; Level3ProductsWidget::Level3ProductsWidget(QWidget* parent) : @@ -105,6 +141,79 @@ void Level3ProductsWidgetImpl::SelectProductCategory( 0); } +void Level3ProductsWidget::UpdateAvailableProducts( + const common::Level3ProductCategoryMap& updatedCategoryMap) +{ + logger_->debug("UpdateAvailableProducts()"); + + { + std::unique_lock lock {p->availableCategoryMutex_}; + p->availableCategoryMap_ = updatedCategoryMap; + } + + // Iterate through each category tool button + std::for_each( + // std::execution::par_unseq, + p->categoryButtons_.cbegin(), + p->categoryButtons_.cend(), + [&](QToolButton* toolButton) + { + const std::string& categoryName = toolButton->text().toStdString(); + const common::Level3ProductCategory category = + common::GetLevel3Category(categoryName); + + auto availableProductMapIter = updatedCategoryMap.find(category); + const bool categoryEnabled = + (availableProductMapIter != updatedCategoryMap.cend()); + + // Enable category if any products are available + toolButton->setEnabled(categoryEnabled); + + if (categoryEnabled) + { + const auto& availableProductMap = availableProductMapIter->second; + auto& productMenus = p->categoryMenuMap_.at(category); + + // Iterate through each product menu + std::for_each( + // std::execution::par_unseq, + productMenus.cbegin(), + productMenus.cend(), + [&](const auto productMenu) + { + auto availableAwipsIdIter = + availableProductMap.find(productMenu.first); + const bool productEnabled = + (availableAwipsIdIter != availableProductMap.cend()); + + // Enable product if it has AWIPS IDs available + productMenu.second->menuAction()->setVisible(productEnabled); + + if (productEnabled) + { + // Determine number of tilts to display + size_t numTilts = + std::min(availableAwipsIdIter->second.size(), + common::kLevel3ProductMaxTilts); + size_t currentTilt = 0; + + QList tiltActionList = + productMenu.second->findChildren( + Qt::FindDirectChildrenOnly); + + for (QAction* tiltAction : tiltActionList) + { + // Set the first n tilts to visible. The QAction list + // includes the productMenu's action, so one is + // added. + tiltAction->setVisible(++currentTilt <= numTilts + 1); + } + } + }); + } + }); +} + void Level3ProductsWidget::UpdateProductSelection( common::RadarProductGroup group, const std::string& productName) { diff --git a/scwx-qt/source/scwx/qt/ui/level3_products_widget.hpp b/scwx-qt/source/scwx/qt/ui/level3_products_widget.hpp index 591c0e6a..c7eb79ed 100644 --- a/scwx-qt/source/scwx/qt/ui/level3_products_widget.hpp +++ b/scwx-qt/source/scwx/qt/ui/level3_products_widget.hpp @@ -23,6 +23,8 @@ public: void showEvent(QShowEvent* event) override; + void UpdateAvailableProducts( + const common::Level3ProductCategoryMap& updatedCategoryMap); void UpdateProductSelection(common::RadarProductGroup group, const std::string& productName);