mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-11-04 13:10:06 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1499 lines
		
	
	
	
		
			55 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1499 lines
		
	
	
	
		
			55 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "settings_dialog.hpp"
 | 
						|
#include "ui_settings_dialog.h"
 | 
						|
 | 
						|
#include <scwx/awips/phenomenon.hpp>
 | 
						|
#include <scwx/common/color_table.hpp>
 | 
						|
#include <scwx/qt/config/county_database.hpp>
 | 
						|
#include <scwx/qt/config/radar_site.hpp>
 | 
						|
#include <scwx/qt/manager/media_manager.hpp>
 | 
						|
#include <scwx/qt/manager/position_manager.hpp>
 | 
						|
#include <scwx/qt/manager/settings_manager.hpp>
 | 
						|
#include <scwx/qt/map/map_provider.hpp>
 | 
						|
#include <scwx/qt/settings/audio_settings.hpp>
 | 
						|
#include <scwx/qt/settings/general_settings.hpp>
 | 
						|
#include <scwx/qt/settings/palette_settings.hpp>
 | 
						|
#include <scwx/qt/settings/product_settings.hpp>
 | 
						|
#include <scwx/qt/settings/settings_interface.hpp>
 | 
						|
#include <scwx/qt/settings/text_settings.hpp>
 | 
						|
#include <scwx/qt/settings/unit_settings.hpp>
 | 
						|
#include <scwx/qt/types/alert_types.hpp>
 | 
						|
#include <scwx/qt/types/font_types.hpp>
 | 
						|
#include <scwx/qt/types/location_types.hpp>
 | 
						|
#include <scwx/qt/types/qt_types.hpp>
 | 
						|
#include <scwx/qt/types/text_types.hpp>
 | 
						|
#include <scwx/qt/types/time_types.hpp>
 | 
						|
#include <scwx/qt/types/unit_types.hpp>
 | 
						|
#include <scwx/qt/ui/county_dialog.hpp>
 | 
						|
#include <scwx/qt/ui/radar_site_dialog.hpp>
 | 
						|
#include <scwx/qt/ui/serial_port_dialog.hpp>
 | 
						|
#include <scwx/qt/ui/settings/alert_palette_settings_widget.hpp>
 | 
						|
#include <scwx/qt/ui/settings/hotkey_settings_widget.hpp>
 | 
						|
#include <scwx/qt/ui/settings/unit_settings_widget.hpp>
 | 
						|
#include <scwx/qt/ui/wfo_dialog.hpp>
 | 
						|
#include <scwx/qt/util/color.hpp>
 | 
						|
#include <scwx/qt/util/file.hpp>
 | 
						|
#include <scwx/util/logger.hpp>
 | 
						|
#include <scwx/util/threads.hpp>
 | 
						|
 | 
						|
#include <boost/algorithm/string.hpp>
 | 
						|
#include <fmt/format.h>
 | 
						|
#include <QColorDialog>
 | 
						|
#include <QFileDialog>
 | 
						|
#include <QFontDatabase>
 | 
						|
#include <QFontDialog>
 | 
						|
#include <QGeoPositionInfo>
 | 
						|
#include <QPushButton>
 | 
						|
#include <QStandardItemModel>
 | 
						|
#include <QToolButton>
 | 
						|
 | 
						|
namespace scwx
 | 
						|
{
 | 
						|
namespace qt
 | 
						|
{
 | 
						|
namespace ui
 | 
						|
{
 | 
						|
 | 
						|
static const std::string logPrefix_ = "scwx::qt::ui::settings_dialog";
 | 
						|
static const auto        logger_    = scwx::util::Logger::Create(logPrefix_);
 | 
						|
 | 
						|
struct ColorTableConversions
 | 
						|
{
 | 
						|
   uint16_t rangeMin {0u};
 | 
						|
   uint16_t rangeMax {255u};
 | 
						|
   float    offset {0.0f};
 | 
						|
   float    scale {1.0f};
 | 
						|
};
 | 
						|
 | 
						|
static const std::array<std::pair<std::string, std::string>, 16>
 | 
						|
   kColorTableTypes_ {std::pair {"BR", "BR"},
 | 
						|
                      std::pair {"BV", "BV"},
 | 
						|
                      std::pair {"SW", "SW"},
 | 
						|
                      std::pair {"ZDR", "ZDR"},
 | 
						|
                      std::pair {"PHI2", "KDP (L2)"},
 | 
						|
                      std::pair {"CC", "CC"},
 | 
						|
                      std::pair {"DOD", "DOD"},
 | 
						|
                      std::pair {"DSD", "DSD"},
 | 
						|
                      std::pair {"ET", "ET"},
 | 
						|
                      std::pair {"HC", "HC"},
 | 
						|
                      std::pair {"OHP", "OHP"},
 | 
						|
                      std::pair {"PHI3", "KDP"},
 | 
						|
                      std::pair {"SRV", "SRV"},
 | 
						|
                      std::pair {"STP", "STP"},
 | 
						|
                      std::pair {"VIL", "VIL"},
 | 
						|
                      std::pair {"???", "Default"}};
 | 
						|
 | 
						|
// Color table conversions for display, roughly based upon:
 | 
						|
// - ICD for RDA-RPG: Data Moment Characteristics and Conversion for Data Names
 | 
						|
// - ICD for the RPG to Class 1 User
 | 
						|
static const std::unordered_map<std::string, ColorTableConversions>
 | 
						|
   kColorTableConversions_ {{"BR", {0u, 255u, 66.0f, 2.0f}},
 | 
						|
                            {"BV", {0u, 255u, 129.0f, 2.0f}},
 | 
						|
                            {"SW", {0u, 255u, 129.0f, 2.0f}},
 | 
						|
                            {"ZDR", {0u, 1058u, 418.0f, 32.0f}},
 | 
						|
                            {"PHI2", {0u, 1023u, 2.0f, 2.8361f}},
 | 
						|
                            {"CC", {0u, 255u, -60.5f, 300.0f}},
 | 
						|
                            {"DOD", {0u, 255u, 128.0f, 1.5f}},
 | 
						|
                            {"DSD", {0u, 255u, 128.0f, 1.5f}},
 | 
						|
                            {"ET", {0u, 255u, 2.0f, 1.0f}},
 | 
						|
                            {"HC", {10u, 160u, 0.0f, 1.0f}},
 | 
						|
                            {"OHP", {0u, 255u, 0.0f, 2.5f}},
 | 
						|
                            {"PHI3", {0u, 255u, 43.0f, 20.0f}},
 | 
						|
                            {"SRV", {0u, 255u, 128.0f, 2.0f}},
 | 
						|
                            {"STP", {0u, 255u, 0.0f, 1.25f}},
 | 
						|
                            {"VIL", {0u, 255u, 1.0f, 2.5f}},
 | 
						|
                            {"???", {0u, 15u, 0.0f, 1.0f}}};
 | 
						|
 | 
						|
class SettingsDialogImpl
 | 
						|
{
 | 
						|
public:
 | 
						|
   explicit SettingsDialogImpl(SettingsDialog* self) :
 | 
						|
       self_ {self},
 | 
						|
       radarSiteDialog_ {new RadarSiteDialog(self)},
 | 
						|
       alertAudioRadarSiteDialog_ {new RadarSiteDialog(self)},
 | 
						|
       gpsSourceDialog_ {new SerialPortDialog(self)},
 | 
						|
       countyDialog_ {new CountyDialog(self)},
 | 
						|
       wfoDialog_ {new WFODialog(self)},
 | 
						|
       fontDialog_ {new QFontDialog(self)},
 | 
						|
       fontCategoryModel_ {new QStandardItemModel(self)},
 | 
						|
       settings_ {std::initializer_list<settings::SettingsInterfaceBase*> {
 | 
						|
          &defaultRadarSite_,
 | 
						|
          &gridWidth_,
 | 
						|
          &gridHeight_,
 | 
						|
          &mapProvider_,
 | 
						|
          &mapboxApiKey_,
 | 
						|
          &mapTilerApiKey_,
 | 
						|
          &theme_,
 | 
						|
          &themeFile_,
 | 
						|
          &defaultAlertAction_,
 | 
						|
          &clockFormat_,
 | 
						|
          &customStyleDrawLayer_,
 | 
						|
          &customStyleUrl_,
 | 
						|
          &defaultTimeZone_,
 | 
						|
          &positioningPlugin_,
 | 
						|
          &nmeaBaudRate_,
 | 
						|
          &nmeaSource_,
 | 
						|
          &warningsProvider_,
 | 
						|
          &radarSiteThreshold_,
 | 
						|
          &antiAliasingEnabled_,
 | 
						|
          &showMapAttribution_,
 | 
						|
          &showMapCenter_,
 | 
						|
          &showMapLogo_,
 | 
						|
          &showSmoothedRangeFolding_,
 | 
						|
          &updateNotificationsEnabled_,
 | 
						|
          &cursorIconAlwaysOn_,
 | 
						|
          &debugEnabled_,
 | 
						|
          &alertAudioSoundFile_,
 | 
						|
          &alertAudioLocationMethod_,
 | 
						|
          &alertAudioLatitude_,
 | 
						|
          &alertAudioLongitude_,
 | 
						|
          &alertAudioRadarSite_,
 | 
						|
          &alertAudioRadius_,
 | 
						|
          &alertAudioCounty_,
 | 
						|
          &alertAudioWFO_,
 | 
						|
          &hoverTextWrap_,
 | 
						|
          &tooltipMethod_,
 | 
						|
          &placefileTextDropShadowEnabled_,
 | 
						|
          &radarSiteHoverTextEnabled_}}
 | 
						|
   {
 | 
						|
      // Configure default alert phenomena colors
 | 
						|
      auto& paletteSettings = settings::PaletteSettings::Instance();
 | 
						|
      int   index           = 0;
 | 
						|
 | 
						|
      for (auto& phenomenon : settings::PaletteSettings::alert_phenomena())
 | 
						|
      {
 | 
						|
         QColorDialog::setCustomColor(
 | 
						|
            index++,
 | 
						|
            QColor(QString::fromStdString(
 | 
						|
               paletteSettings.alert_color(phenomenon, true).GetDefault())));
 | 
						|
         QColorDialog::setCustomColor(
 | 
						|
            index++,
 | 
						|
            QColor(QString::fromStdString(
 | 
						|
               paletteSettings.alert_color(phenomenon, false).GetDefault())));
 | 
						|
      }
 | 
						|
 | 
						|
      // Configure font dialog
 | 
						|
      fontDialog_->setOptions(
 | 
						|
         QFontDialog::FontDialogOption::DontUseNativeDialog |
 | 
						|
         QFontDialog::FontDialogOption::ScalableFonts);
 | 
						|
      fontDialog_->setWindowModality(Qt::WindowModality::WindowModal);
 | 
						|
   }
 | 
						|
   ~SettingsDialogImpl() = default;
 | 
						|
 | 
						|
   void ConnectSignals();
 | 
						|
   void SetupGeneralTab();
 | 
						|
   void SetupPalettesColorTablesTab();
 | 
						|
   void SetupPalettesAlertsTab();
 | 
						|
   void SetupUnitsTab();
 | 
						|
   void SetupAudioTab();
 | 
						|
   void SetupTextTab();
 | 
						|
   void SetupHotkeysTab();
 | 
						|
 | 
						|
   void UpdateRadarDialogLocation(const std::string& id);
 | 
						|
   void UpdateAlertRadarDialogLocation(const std::string& id);
 | 
						|
 | 
						|
   QFont GetSelectedFont();
 | 
						|
   void  SelectFontCategory(types::FontCategory fontCategory);
 | 
						|
   void  UpdateFontDisplayData();
 | 
						|
 | 
						|
   void ApplyChanges();
 | 
						|
   void DiscardChanges();
 | 
						|
   void ResetToDefault();
 | 
						|
 | 
						|
   static QImage
 | 
						|
   GenerateColorTableImage(std::shared_ptr<common::ColorTable> colorTable,
 | 
						|
                           std::uint16_t                       min,
 | 
						|
                           std::uint16_t                       max,
 | 
						|
                           float                               offset,
 | 
						|
                           float                               scale);
 | 
						|
   static void LoadColorTablePreview(const std::string& key,
 | 
						|
                                     const std::string& value,
 | 
						|
                                     QLabel*            imageLabel);
 | 
						|
   static std::string
 | 
						|
   RadarSiteLabel(std::shared_ptr<config::RadarSite>& radarSite);
 | 
						|
 | 
						|
   SettingsDialog*   self_;
 | 
						|
   RadarSiteDialog*  radarSiteDialog_;
 | 
						|
   RadarSiteDialog*  alertAudioRadarSiteDialog_;
 | 
						|
   SerialPortDialog* gpsSourceDialog_;
 | 
						|
   CountyDialog*     countyDialog_;
 | 
						|
   WFODialog*        wfoDialog_;
 | 
						|
   QFontDialog*      fontDialog_;
 | 
						|
 | 
						|
   QStandardItemModel* fontCategoryModel_;
 | 
						|
 | 
						|
   types::FontCategory selectedFontCategory_ {types::FontCategory::Unknown};
 | 
						|
 | 
						|
   std::shared_ptr<manager::MediaManager> mediaManager_ {
 | 
						|
      manager::MediaManager::Instance()};
 | 
						|
   std::shared_ptr<manager::PositionManager> positionManager_ {
 | 
						|
      manager::PositionManager::Instance()};
 | 
						|
 | 
						|
   std::vector<SettingsPageWidget*> settingsPages_ {};
 | 
						|
   AlertPaletteSettingsWidget*      alertPaletteSettingsWidget_ {};
 | 
						|
   HotkeySettingsWidget*            hotkeySettingsWidget_ {};
 | 
						|
   UnitSettingsWidget*              unitSettingsWidget_ {};
 | 
						|
 | 
						|
   settings::SettingsInterface<std::string>  defaultRadarSite_ {};
 | 
						|
   settings::SettingsInterface<std::int64_t> gridWidth_ {};
 | 
						|
   settings::SettingsInterface<std::int64_t> gridHeight_ {};
 | 
						|
   settings::SettingsInterface<std::string>  mapProvider_ {};
 | 
						|
   settings::SettingsInterface<std::string>  mapboxApiKey_ {};
 | 
						|
   settings::SettingsInterface<std::string>  mapTilerApiKey_ {};
 | 
						|
   settings::SettingsInterface<std::string>  defaultAlertAction_ {};
 | 
						|
   settings::SettingsInterface<std::string>  clockFormat_ {};
 | 
						|
   settings::SettingsInterface<std::string>  customStyleDrawLayer_ {};
 | 
						|
   settings::SettingsInterface<std::string>  customStyleUrl_ {};
 | 
						|
   settings::SettingsInterface<std::string>  defaultTimeZone_ {};
 | 
						|
   settings::SettingsInterface<std::string>  positioningPlugin_ {};
 | 
						|
   settings::SettingsInterface<std::int64_t> nmeaBaudRate_ {};
 | 
						|
   settings::SettingsInterface<std::string>  nmeaSource_ {};
 | 
						|
   settings::SettingsInterface<std::string>  theme_ {};
 | 
						|
   settings::SettingsInterface<std::string>  themeFile_ {};
 | 
						|
   settings::SettingsInterface<std::string>  warningsProvider_ {};
 | 
						|
   settings::SettingsInterface<double>       radarSiteThreshold_ {};
 | 
						|
   settings::SettingsInterface<bool>         antiAliasingEnabled_ {};
 | 
						|
   settings::SettingsInterface<bool>         showMapAttribution_ {};
 | 
						|
   settings::SettingsInterface<bool>         showMapCenter_ {};
 | 
						|
   settings::SettingsInterface<bool>         showMapLogo_ {};
 | 
						|
   settings::SettingsInterface<bool>         showSmoothedRangeFolding_ {};
 | 
						|
   settings::SettingsInterface<bool>         updateNotificationsEnabled_ {};
 | 
						|
   settings::SettingsInterface<bool>         cursorIconAlwaysOn_ {};
 | 
						|
   settings::SettingsInterface<bool>         debugEnabled_ {};
 | 
						|
 | 
						|
   std::unordered_map<std::string, settings::SettingsInterface<std::string>>
 | 
						|
      colorTables_ {};
 | 
						|
 | 
						|
   settings::SettingsInterface<std::string> alertAudioSoundFile_ {};
 | 
						|
   settings::SettingsInterface<std::string> alertAudioLocationMethod_ {};
 | 
						|
   settings::SettingsInterface<double>      alertAudioLatitude_ {};
 | 
						|
   settings::SettingsInterface<double>      alertAudioLongitude_ {};
 | 
						|
   settings::SettingsInterface<std::string> alertAudioRadarSite_ {};
 | 
						|
   settings::SettingsInterface<double>      alertAudioRadius_ {};
 | 
						|
   settings::SettingsInterface<std::string> alertAudioCounty_ {};
 | 
						|
   settings::SettingsInterface<std::string> alertAudioWFO_ {};
 | 
						|
 | 
						|
   std::unordered_map<awips::Phenomenon, settings::SettingsInterface<bool>>
 | 
						|
      alertAudioEnabled_ {};
 | 
						|
 | 
						|
   std::unordered_map<types::FontCategory,
 | 
						|
                      settings::SettingsInterface<std::string>>
 | 
						|
      fontFamilies_ {};
 | 
						|
   std::unordered_map<types::FontCategory,
 | 
						|
                      settings::SettingsInterface<std::string>>
 | 
						|
      fontStyles_ {};
 | 
						|
   std::unordered_map<types::FontCategory, settings::SettingsInterface<double>>
 | 
						|
      fontPointSizes_ {};
 | 
						|
 | 
						|
   settings::SettingsInterface<std::int64_t> hoverTextWrap_ {};
 | 
						|
   settings::SettingsInterface<std::string>  tooltipMethod_ {};
 | 
						|
   settings::SettingsInterface<bool>         placefileTextDropShadowEnabled_ {};
 | 
						|
   settings::SettingsInterface<bool>         radarSiteHoverTextEnabled_ {};
 | 
						|
 | 
						|
   std::vector<settings::SettingsInterfaceBase*> settings_;
 | 
						|
};
 | 
						|
 | 
						|
SettingsDialog::SettingsDialog(QWidget* parent) :
 | 
						|
    QDialog(parent),
 | 
						|
    p {std::make_unique<SettingsDialogImpl>(this)},
 | 
						|
    ui(new Ui::SettingsDialog)
 | 
						|
{
 | 
						|
   ui->setupUi(this);
 | 
						|
 | 
						|
   // Set OK as default
 | 
						|
   ui->buttonBox->button(QDialogButtonBox::StandardButton::Ok)
 | 
						|
      ->setDefault(true);
 | 
						|
 | 
						|
   // General
 | 
						|
   p->SetupGeneralTab();
 | 
						|
 | 
						|
   // Palettes > Color Tables
 | 
						|
   p->SetupPalettesColorTablesTab();
 | 
						|
 | 
						|
   // Palettes > Alerts
 | 
						|
   p->SetupPalettesAlertsTab();
 | 
						|
 | 
						|
   // Units
 | 
						|
   p->SetupUnitsTab();
 | 
						|
 | 
						|
   // Audio
 | 
						|
   p->SetupAudioTab();
 | 
						|
 | 
						|
   // Text
 | 
						|
   p->SetupTextTab();
 | 
						|
 | 
						|
   // Hotkeys
 | 
						|
   p->SetupHotkeysTab();
 | 
						|
 | 
						|
   p->ConnectSignals();
 | 
						|
}
 | 
						|
 | 
						|
SettingsDialog::~SettingsDialog()
 | 
						|
{
 | 
						|
   delete ui;
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::ConnectSignals()
 | 
						|
{
 | 
						|
   QObject::connect(self_->ui->listWidget,
 | 
						|
                    &QListWidget::currentRowChanged,
 | 
						|
                    self_->ui->stackedWidget,
 | 
						|
                    &QStackedWidget::setCurrentIndex);
 | 
						|
 | 
						|
   QObject::connect(self_->ui->radarSiteSelectButton,
 | 
						|
                    &QAbstractButton::clicked,
 | 
						|
                    self_,
 | 
						|
                    [this]() { radarSiteDialog_->show(); });
 | 
						|
 | 
						|
   QObject::connect(radarSiteDialog_,
 | 
						|
                    &RadarSiteDialog::accepted,
 | 
						|
                    self_,
 | 
						|
                    [this]()
 | 
						|
                    {
 | 
						|
                       std::string id = radarSiteDialog_->radar_site();
 | 
						|
 | 
						|
                       std::shared_ptr<config::RadarSite> radarSite =
 | 
						|
                          config::RadarSite::Get(id);
 | 
						|
 | 
						|
                       if (radarSite != nullptr)
 | 
						|
                       {
 | 
						|
                          self_->ui->radarSiteComboBox->setCurrentText(
 | 
						|
                             QString::fromStdString(RadarSiteLabel(radarSite)));
 | 
						|
                       }
 | 
						|
                    });
 | 
						|
 | 
						|
   QObject::connect(self_->ui->alertAudioRadarSiteSelectButton,
 | 
						|
                    &QAbstractButton::clicked,
 | 
						|
                    self_,
 | 
						|
                    [this]() { alertAudioRadarSiteDialog_->show(); });
 | 
						|
 | 
						|
   QObject::connect(
 | 
						|
      alertAudioRadarSiteDialog_,
 | 
						|
      &RadarSiteDialog::accepted,
 | 
						|
      self_,
 | 
						|
      [this]()
 | 
						|
      {
 | 
						|
         std::string id = alertAudioRadarSiteDialog_->radar_site();
 | 
						|
 | 
						|
         std::shared_ptr<config::RadarSite> radarSite =
 | 
						|
            config::RadarSite::Get(id);
 | 
						|
 | 
						|
         if (radarSite != nullptr)
 | 
						|
         {
 | 
						|
            self_->ui->alertAudioRadarSiteComboBox->setCurrentText(
 | 
						|
               QString::fromStdString(RadarSiteLabel(radarSite)));
 | 
						|
         }
 | 
						|
      });
 | 
						|
 | 
						|
   QObject::connect(self_->ui->gpsSourceSelectButton,
 | 
						|
                    &QAbstractButton::clicked,
 | 
						|
                    self_,
 | 
						|
                    [this]() { gpsSourceDialog_->show(); });
 | 
						|
 | 
						|
   QObject::connect(gpsSourceDialog_,
 | 
						|
                    &SerialPortDialog::accepted,
 | 
						|
                    self_,
 | 
						|
                    [this]()
 | 
						|
                    {
 | 
						|
                       std::string serialPort = gpsSourceDialog_->serial_port();
 | 
						|
                       int         baudRate   = gpsSourceDialog_->baud_rate();
 | 
						|
 | 
						|
                       if (!serialPort.empty() && serialPort != "?")
 | 
						|
                       {
 | 
						|
                          std::string source =
 | 
						|
                             fmt::format("serial:{}", serialPort);
 | 
						|
                          nmeaSource_.StageValue(source);
 | 
						|
                       }
 | 
						|
 | 
						|
                       if (baudRate > 0)
 | 
						|
                       {
 | 
						|
                          self_->ui->nmeaBaudRateSpinBox->setValue(baudRate);
 | 
						|
                       }
 | 
						|
                    });
 | 
						|
 | 
						|
   // Update the Radar Site dialog "map" location with the currently selected
 | 
						|
   // radar site
 | 
						|
   auto& defaultRadarSite = *defaultRadarSite_.GetSettingsVariable();
 | 
						|
   defaultRadarSite.RegisterValueStagedCallback(
 | 
						|
      [this](const std::string& newValue)
 | 
						|
      { UpdateRadarDialogLocation(newValue); });
 | 
						|
 | 
						|
   QObject::connect(
 | 
						|
      self_->ui->alertAudioSoundTestButton,
 | 
						|
      &QAbstractButton::clicked,
 | 
						|
      self_,
 | 
						|
      [this]()
 | 
						|
      {
 | 
						|
         mediaManager_->Play(
 | 
						|
            self_->ui->alertAudioSoundLineEdit->text().toStdString());
 | 
						|
      });
 | 
						|
   QObject::connect(self_->ui->alertAudioSoundStopButton,
 | 
						|
                    &QAbstractButton::clicked,
 | 
						|
                    self_,
 | 
						|
                    [this]() { mediaManager_->Stop(); });
 | 
						|
 | 
						|
   QObject::connect(
 | 
						|
      self_->ui->fontListView->selectionModel(),
 | 
						|
      &QItemSelectionModel::selectionChanged,
 | 
						|
      self_,
 | 
						|
      [this](const QItemSelection& selected, const QItemSelection& deselected)
 | 
						|
      {
 | 
						|
         if (selected.size() == 0 && deselected.size() == 0)
 | 
						|
         {
 | 
						|
            // Items which stay selected but change their index are not
 | 
						|
            // included in selected and deselected. Thus, this signal might
 | 
						|
            // be emitted with both selected and deselected empty, if only
 | 
						|
            // the indices of selected items change.
 | 
						|
            return;
 | 
						|
         }
 | 
						|
 | 
						|
         if (selected.size() > 0)
 | 
						|
         {
 | 
						|
            QModelIndex selectedIndex = selected[0].indexes()[0];
 | 
						|
            QVariant    variantData =
 | 
						|
               self_->ui->fontListView->model()->data(selectedIndex);
 | 
						|
            if (variantData.typeId() == QMetaType::QString)
 | 
						|
            {
 | 
						|
               types::FontCategory fontCategory =
 | 
						|
                  types::GetFontCategory(variantData.toString().toStdString());
 | 
						|
               SelectFontCategory(fontCategory);
 | 
						|
               UpdateFontDisplayData();
 | 
						|
            }
 | 
						|
         }
 | 
						|
      });
 | 
						|
 | 
						|
   QObject::connect(self_->ui->fontSelectButton,
 | 
						|
                    &QAbstractButton::clicked,
 | 
						|
                    self_,
 | 
						|
                    [this]()
 | 
						|
                    {
 | 
						|
                       fontDialog_->setCurrentFont(GetSelectedFont());
 | 
						|
                       fontDialog_->show();
 | 
						|
                    });
 | 
						|
 | 
						|
   QObject::connect(fontDialog_,
 | 
						|
                    &QFontDialog::fontSelected,
 | 
						|
                    self_,
 | 
						|
                    [this](const QFont& font)
 | 
						|
                    {
 | 
						|
                       fontFamilies_.at(selectedFontCategory_)
 | 
						|
                          .StageValue(font.family().toStdString());
 | 
						|
                       fontStyles_.at(selectedFontCategory_)
 | 
						|
                          .StageValue(font.styleName().toStdString());
 | 
						|
                       fontPointSizes_.at(selectedFontCategory_)
 | 
						|
                          .StageValue(font.pointSizeF());
 | 
						|
 | 
						|
                       UpdateFontDisplayData();
 | 
						|
                    });
 | 
						|
 | 
						|
   QObject::connect(self_->ui->resetFontButton,
 | 
						|
                    &QAbstractButton::clicked,
 | 
						|
                    self_,
 | 
						|
                    [this]()
 | 
						|
                    {
 | 
						|
                       fontFamilies_.at(selectedFontCategory_).StageDefault();
 | 
						|
                       fontStyles_.at(selectedFontCategory_).StageDefault();
 | 
						|
                       fontPointSizes_.at(selectedFontCategory_).StageDefault();
 | 
						|
 | 
						|
                       UpdateFontDisplayData();
 | 
						|
                    });
 | 
						|
 | 
						|
   QObject::connect(
 | 
						|
      self_->ui->buttonBox,
 | 
						|
      &QDialogButtonBox::clicked,
 | 
						|
      self_,
 | 
						|
      [this](QAbstractButton* button)
 | 
						|
      {
 | 
						|
         QDialogButtonBox::ButtonRole role =
 | 
						|
            self_->ui->buttonBox->buttonRole(button);
 | 
						|
 | 
						|
         switch (role)
 | 
						|
         {
 | 
						|
         case QDialogButtonBox::ButtonRole::AcceptRole: // OK
 | 
						|
         case QDialogButtonBox::ButtonRole::ApplyRole:  // Apply
 | 
						|
            ApplyChanges();
 | 
						|
            break;
 | 
						|
 | 
						|
         case QDialogButtonBox::ButtonRole::DestructiveRole: // Discard
 | 
						|
         case QDialogButtonBox::ButtonRole::RejectRole:      // Cancel
 | 
						|
            DiscardChanges();
 | 
						|
            break;
 | 
						|
 | 
						|
         case QDialogButtonBox::ButtonRole::ResetRole: // Restore Defaults
 | 
						|
            ResetToDefault();
 | 
						|
            break;
 | 
						|
 | 
						|
         default:
 | 
						|
            break;
 | 
						|
         }
 | 
						|
      });
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::SetupGeneralTab()
 | 
						|
{
 | 
						|
   settings::GeneralSettings& generalSettings =
 | 
						|
      settings::GeneralSettings::Instance();
 | 
						|
   settings::ProductSettings& productSettings =
 | 
						|
      settings::ProductSettings::Instance();
 | 
						|
 | 
						|
   QObject::connect(
 | 
						|
      self_->ui->themeComboBox,
 | 
						|
      &QComboBox::currentTextChanged,
 | 
						|
      self_,
 | 
						|
      [this](const QString& text)
 | 
						|
      {
 | 
						|
         const types::UiStyle style  = types::GetUiStyle(text.toStdString());
 | 
						|
         const bool themeFileEnabled = style == types::UiStyle::FusionCustom;
 | 
						|
 | 
						|
         self_->ui->themeFileLineEdit->setEnabled(themeFileEnabled);
 | 
						|
         self_->ui->themeFileSelectButton->setEnabled(themeFileEnabled);
 | 
						|
         self_->ui->resetThemeFileButton->setEnabled(themeFileEnabled);
 | 
						|
      });
 | 
						|
 | 
						|
   theme_.SetSettingsVariable(generalSettings.theme());
 | 
						|
   SCWX_SETTINGS_COMBO_BOX(theme_,
 | 
						|
                           self_->ui->themeComboBox,
 | 
						|
                           types::UiStyleIterator(),
 | 
						|
                           types::GetUiStyleName);
 | 
						|
   theme_.SetResetButton(self_->ui->resetThemeButton);
 | 
						|
 | 
						|
   themeFile_.SetSettingsVariable(generalSettings.theme_file());
 | 
						|
   themeFile_.SetEditWidget(self_->ui->themeFileLineEdit);
 | 
						|
   themeFile_.SetResetButton(self_->ui->resetThemeFileButton);
 | 
						|
   themeFile_.EnableTrimming();
 | 
						|
 | 
						|
   QObject::connect(
 | 
						|
      self_->ui->themeFileSelectButton,
 | 
						|
      &QAbstractButton::clicked,
 | 
						|
      self_,
 | 
						|
      [this]()
 | 
						|
      {
 | 
						|
         static const std::string themeFilter = "Qt6Ct Theme File (*.conf)";
 | 
						|
         static const std::string allFilter   = "All Files (*)";
 | 
						|
 | 
						|
         QFileDialog* dialog = new QFileDialog(self_);
 | 
						|
 | 
						|
         dialog->setFileMode(QFileDialog::ExistingFile);
 | 
						|
 | 
						|
         dialog->setNameFilters(
 | 
						|
            {QObject::tr(themeFilter.c_str()), QObject::tr(allFilter.c_str())});
 | 
						|
         dialog->setAttribute(Qt::WA_DeleteOnClose);
 | 
						|
 | 
						|
         QObject::connect(
 | 
						|
            dialog,
 | 
						|
            &QFileDialog::fileSelected,
 | 
						|
            self_,
 | 
						|
            [this](const QString& file)
 | 
						|
            {
 | 
						|
               QString path = QDir::toNativeSeparators(file);
 | 
						|
               logger_->info("Selected theme file: {}", path.toStdString());
 | 
						|
               self_->ui->themeFileLineEdit->setText(path);
 | 
						|
 | 
						|
               // setText does not emit the textEdited signal
 | 
						|
               Q_EMIT self_->ui->themeFileLineEdit->textEdited(path);
 | 
						|
            });
 | 
						|
 | 
						|
         dialog->open();
 | 
						|
      });
 | 
						|
 | 
						|
   auto radarSites = config::RadarSite::GetAll();
 | 
						|
 | 
						|
   // Sort radar sites by ID
 | 
						|
   std::sort(radarSites.begin(),
 | 
						|
             radarSites.end(),
 | 
						|
             [](const std::shared_ptr<config::RadarSite>& a,
 | 
						|
                const std::shared_ptr<config::RadarSite>& b)
 | 
						|
             { return a->id() < b->id(); });
 | 
						|
 | 
						|
   // Add default and follow options to radar sites
 | 
						|
   self_->ui->alertAudioRadarSiteComboBox->addItem(
 | 
						|
      QString::fromStdString("default"));
 | 
						|
   self_->ui->alertAudioRadarSiteComboBox->addItem(
 | 
						|
      QString::fromStdString("follow"));
 | 
						|
 | 
						|
   // Add sorted radar sites
 | 
						|
   for (std::shared_ptr<config::RadarSite>& radarSite : radarSites)
 | 
						|
   {
 | 
						|
      QString text = QString::fromStdString(RadarSiteLabel(radarSite));
 | 
						|
      self_->ui->radarSiteComboBox->addItem(text);
 | 
						|
      self_->ui->alertAudioRadarSiteComboBox->addItem(text);
 | 
						|
   }
 | 
						|
 | 
						|
   defaultRadarSite_.SetSettingsVariable(generalSettings.default_radar_site());
 | 
						|
   defaultRadarSite_.SetMapFromValueFunction(
 | 
						|
      [](const std::string& id) -> std::string
 | 
						|
      {
 | 
						|
         // Get the radar site associated with the ID
 | 
						|
         std::shared_ptr<config::RadarSite> radarSite =
 | 
						|
            config::RadarSite::Get(id);
 | 
						|
 | 
						|
         if (radarSite == nullptr)
 | 
						|
         {
 | 
						|
            // No radar site found, just return the ID
 | 
						|
            return id;
 | 
						|
         }
 | 
						|
 | 
						|
         // Add location details to the radar site
 | 
						|
         return RadarSiteLabel(radarSite);
 | 
						|
      });
 | 
						|
   defaultRadarSite_.SetMapToValueFunction(
 | 
						|
      [](const std::string& text) -> std::string
 | 
						|
      {
 | 
						|
         // Find the position of location details
 | 
						|
         size_t pos = text.find(" (");
 | 
						|
 | 
						|
         if (pos == std::string::npos)
 | 
						|
         {
 | 
						|
            // No location details found, just return the text
 | 
						|
            return text;
 | 
						|
         }
 | 
						|
 | 
						|
         // Remove location details from the radar site
 | 
						|
         return text.substr(0, pos);
 | 
						|
      });
 | 
						|
   defaultRadarSite_.SetEditWidget(self_->ui->radarSiteComboBox);
 | 
						|
   defaultRadarSite_.SetResetButton(self_->ui->resetRadarSiteButton);
 | 
						|
   UpdateRadarDialogLocation(generalSettings.default_radar_site().GetValue());
 | 
						|
 | 
						|
   gridWidth_.SetSettingsVariable(generalSettings.grid_width());
 | 
						|
   gridWidth_.SetEditWidget(self_->ui->gridWidthSpinBox);
 | 
						|
   gridWidth_.SetResetButton(self_->ui->resetGridWidthButton);
 | 
						|
 | 
						|
   gridHeight_.SetSettingsVariable(generalSettings.grid_height());
 | 
						|
   gridHeight_.SetEditWidget(self_->ui->gridHeightSpinBox);
 | 
						|
   gridHeight_.SetResetButton(self_->ui->resetGridHeightButton);
 | 
						|
 | 
						|
   mapProvider_.SetSettingsVariable(generalSettings.map_provider());
 | 
						|
   SCWX_SETTINGS_COMBO_BOX(mapProvider_,
 | 
						|
                           self_->ui->mapProviderComboBox,
 | 
						|
                           map::MapProviderIterator(),
 | 
						|
                           map::GetMapProviderName);
 | 
						|
   mapProvider_.SetResetButton(self_->ui->resetMapProviderButton);
 | 
						|
 | 
						|
   mapboxApiKey_.SetSettingsVariable(generalSettings.mapbox_api_key());
 | 
						|
   mapboxApiKey_.SetEditWidget(self_->ui->mapboxApiKeyLineEdit);
 | 
						|
   mapboxApiKey_.SetResetButton(self_->ui->resetMapboxApiKeyButton);
 | 
						|
   mapboxApiKey_.EnableTrimming();
 | 
						|
 | 
						|
   mapTilerApiKey_.SetSettingsVariable(generalSettings.maptiler_api_key());
 | 
						|
   mapTilerApiKey_.SetEditWidget(self_->ui->mapTilerApiKeyLineEdit);
 | 
						|
   mapTilerApiKey_.SetResetButton(self_->ui->resetMapTilerApiKeyButton);
 | 
						|
   mapTilerApiKey_.EnableTrimming();
 | 
						|
 | 
						|
   customStyleUrl_.SetSettingsVariable(generalSettings.custom_style_url());
 | 
						|
   customStyleUrl_.SetEditWidget(self_->ui->customMapUrlLineEdit);
 | 
						|
   customStyleUrl_.SetResetButton(self_->ui->resetCustomMapUrlButton);
 | 
						|
   customStyleUrl_.EnableTrimming();
 | 
						|
 | 
						|
   customStyleDrawLayer_.SetSettingsVariable(
 | 
						|
      generalSettings.custom_style_draw_layer());
 | 
						|
   customStyleDrawLayer_.SetEditWidget(self_->ui->customMapLayerLineEdit);
 | 
						|
   customStyleDrawLayer_.SetResetButton(self_->ui->resetCustomMapLayerButton);
 | 
						|
 | 
						|
   defaultAlertAction_.SetSettingsVariable(
 | 
						|
      generalSettings.default_alert_action());
 | 
						|
   SCWX_SETTINGS_COMBO_BOX(defaultAlertAction_,
 | 
						|
                           self_->ui->defaultAlertActionComboBox,
 | 
						|
                           types::AlertActionIterator(),
 | 
						|
                           types::GetAlertActionName);
 | 
						|
   defaultAlertAction_.SetResetButton(self_->ui->resetDefaultAlertActionButton);
 | 
						|
 | 
						|
   clockFormat_.SetSettingsVariable(generalSettings.clock_format());
 | 
						|
   SCWX_SETTINGS_COMBO_BOX(clockFormat_,
 | 
						|
                           self_->ui->clockFormatComboBox,
 | 
						|
                           scwx::util::ClockFormatIterator(),
 | 
						|
                           scwx::util::GetClockFormatName);
 | 
						|
   clockFormat_.SetResetButton(self_->ui->resetClockFormatButton);
 | 
						|
 | 
						|
   defaultTimeZone_.SetSettingsVariable(generalSettings.default_time_zone());
 | 
						|
   SCWX_SETTINGS_COMBO_BOX(defaultTimeZone_,
 | 
						|
                           self_->ui->defaultTimeZoneComboBox,
 | 
						|
                           types::DefaultTimeZoneIterator(),
 | 
						|
                           types::GetDefaultTimeZoneName);
 | 
						|
   defaultTimeZone_.SetResetButton(self_->ui->resetDefaultTimeZoneButton);
 | 
						|
 | 
						|
   QObject::connect(
 | 
						|
      self_->ui->positioningPluginComboBox,
 | 
						|
      &QComboBox::currentTextChanged,
 | 
						|
      self_,
 | 
						|
      [this](const QString& text)
 | 
						|
      {
 | 
						|
         types::PositioningPlugin positioningPlugin =
 | 
						|
            types::GetPositioningPlugin(text.toStdString());
 | 
						|
 | 
						|
         bool gpsSourceEnabled =
 | 
						|
            positioningPlugin == types::PositioningPlugin::Nmea;
 | 
						|
 | 
						|
         self_->ui->nmeaSourceLineEdit->setEnabled(gpsSourceEnabled);
 | 
						|
         self_->ui->gpsSourceSelectButton->setEnabled(gpsSourceEnabled);
 | 
						|
         self_->ui->nmeaBaudRateSpinBox->setEnabled(gpsSourceEnabled);
 | 
						|
         self_->ui->resetNmeaSourceButton->setEnabled(gpsSourceEnabled);
 | 
						|
         self_->ui->resetNmeaBaudRateButton->setEnabled(gpsSourceEnabled);
 | 
						|
      });
 | 
						|
 | 
						|
   positioningPlugin_.SetSettingsVariable(generalSettings.positioning_plugin());
 | 
						|
   SCWX_SETTINGS_COMBO_BOX(positioningPlugin_,
 | 
						|
                           self_->ui->positioningPluginComboBox,
 | 
						|
                           types::PositioningPluginIterator(),
 | 
						|
                           types::GetPositioningPluginName);
 | 
						|
   positioningPlugin_.SetResetButton(self_->ui->resetPositioningPluginButton);
 | 
						|
 | 
						|
   nmeaBaudRate_.SetSettingsVariable(generalSettings.nmea_baud_rate());
 | 
						|
   nmeaBaudRate_.SetEditWidget(self_->ui->nmeaBaudRateSpinBox);
 | 
						|
   nmeaBaudRate_.SetResetButton(self_->ui->resetNmeaBaudRateButton);
 | 
						|
 | 
						|
   nmeaSource_.SetSettingsVariable(generalSettings.nmea_source());
 | 
						|
   nmeaSource_.SetEditWidget(self_->ui->nmeaSourceLineEdit);
 | 
						|
   nmeaSource_.SetResetButton(self_->ui->resetNmeaSourceButton);
 | 
						|
   nmeaSource_.EnableTrimming();
 | 
						|
 | 
						|
   warningsProvider_.SetSettingsVariable(generalSettings.warnings_provider());
 | 
						|
   warningsProvider_.SetEditWidget(self_->ui->warningsProviderLineEdit);
 | 
						|
   warningsProvider_.SetResetButton(self_->ui->resetWarningsProviderButton);
 | 
						|
   warningsProvider_.EnableTrimming();
 | 
						|
 | 
						|
   radarSiteThreshold_.SetSettingsVariable(
 | 
						|
      generalSettings.radar_site_threshold());
 | 
						|
   radarSiteThreshold_.SetEditWidget(self_->ui->radarSiteThresholdSpinBox);
 | 
						|
   radarSiteThreshold_.SetResetButton(self_->ui->resetRadarSiteThresholdButton);
 | 
						|
   radarSiteThreshold_.SetUnitLabel(self_->ui->radarSiteThresholdUnitLabel);
 | 
						|
   auto radarSiteThresholdUpdateUnits = [this](const std::string& newValue)
 | 
						|
   {
 | 
						|
      const types::DistanceUnits radiusUnits =
 | 
						|
         types::GetDistanceUnitsFromName(newValue);
 | 
						|
      const double      radiusScale = types::GetDistanceUnitsScale(radiusUnits);
 | 
						|
      const std::string abbreviation =
 | 
						|
         types::GetDistanceUnitsAbbreviation(radiusUnits);
 | 
						|
 | 
						|
      radarSiteThreshold_.SetUnit(radiusScale, abbreviation);
 | 
						|
   };
 | 
						|
   settings::UnitSettings::Instance()
 | 
						|
      .distance_units()
 | 
						|
      .RegisterValueStagedCallback(radarSiteThresholdUpdateUnits);
 | 
						|
   radarSiteThresholdUpdateUnits(
 | 
						|
      settings::UnitSettings::Instance().distance_units().GetValue());
 | 
						|
 | 
						|
   antiAliasingEnabled_.SetSettingsVariable(
 | 
						|
      generalSettings.anti_aliasing_enabled());
 | 
						|
   antiAliasingEnabled_.SetEditWidget(self_->ui->antiAliasingEnabledCheckBox);
 | 
						|
 | 
						|
   showMapAttribution_.SetSettingsVariable(
 | 
						|
      generalSettings.show_map_attribution());
 | 
						|
   showMapAttribution_.SetEditWidget(self_->ui->showMapAttributionCheckBox);
 | 
						|
 | 
						|
   showMapCenter_.SetSettingsVariable(generalSettings.show_map_center());
 | 
						|
   showMapCenter_.SetEditWidget(self_->ui->showMapCenterCheckBox);
 | 
						|
 | 
						|
   showMapLogo_.SetSettingsVariable(generalSettings.show_map_logo());
 | 
						|
   showMapLogo_.SetEditWidget(self_->ui->showMapLogoCheckBox);
 | 
						|
 | 
						|
   showSmoothedRangeFolding_.SetSettingsVariable(
 | 
						|
      productSettings.show_smoothed_range_folding());
 | 
						|
   showSmoothedRangeFolding_.SetEditWidget(
 | 
						|
      self_->ui->showSmoothedRangeFoldingCheckBox);
 | 
						|
 | 
						|
   updateNotificationsEnabled_.SetSettingsVariable(
 | 
						|
      generalSettings.update_notifications_enabled());
 | 
						|
   updateNotificationsEnabled_.SetEditWidget(
 | 
						|
      self_->ui->enableUpdateNotificationsCheckBox);
 | 
						|
 | 
						|
   cursorIconAlwaysOn_.SetSettingsVariable(
 | 
						|
      generalSettings.cursor_icon_always_on());
 | 
						|
   cursorIconAlwaysOn_.SetEditWidget(self_->ui->cursorIconAlwaysOnCheckBox);
 | 
						|
 | 
						|
   debugEnabled_.SetSettingsVariable(generalSettings.debug_enabled());
 | 
						|
   debugEnabled_.SetEditWidget(self_->ui->debugEnabledCheckBox);
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::SetupPalettesColorTablesTab()
 | 
						|
{
 | 
						|
   settings::PaletteSettings& paletteSettings =
 | 
						|
      settings::PaletteSettings::Instance();
 | 
						|
 | 
						|
   // Palettes > Color Tables
 | 
						|
   QGridLayout* colorTableLayout =
 | 
						|
      reinterpret_cast<QGridLayout*>(self_->ui->colorTableContents->layout());
 | 
						|
 | 
						|
   colorTables_.reserve(kColorTableTypes_.size());
 | 
						|
 | 
						|
   int colorTableRow = 0;
 | 
						|
   for (auto& colorTableType : kColorTableTypes_)
 | 
						|
   {
 | 
						|
      QLabel*      imageLabel     = new QLabel(self_);
 | 
						|
      QLineEdit*   lineEdit       = new QLineEdit(self_);
 | 
						|
      QToolButton* openFileButton = new QToolButton(self_);
 | 
						|
      QToolButton* resetButton    = new QToolButton(self_);
 | 
						|
 | 
						|
      openFileButton->setText(QObject::tr("..."));
 | 
						|
 | 
						|
      resetButton->setIcon(
 | 
						|
         QIcon {":/res/icons/font-awesome-6/rotate-left-solid.svg"});
 | 
						|
      resetButton->setVisible(false);
 | 
						|
 | 
						|
      imageLabel->setFrameShape(QFrame::Shape::Box);
 | 
						|
      imageLabel->setFrameShadow(QFrame::Shadow::Plain);
 | 
						|
      imageLabel->setVisible(false);
 | 
						|
 | 
						|
      colorTableLayout->addWidget(
 | 
						|
         new QLabel(colorTableType.second.c_str(), self_), colorTableRow, 0);
 | 
						|
      colorTableLayout->addWidget(imageLabel, colorTableRow, 1);
 | 
						|
      colorTableLayout->addWidget(lineEdit, colorTableRow, 2);
 | 
						|
      colorTableLayout->addWidget(openFileButton, colorTableRow, 3);
 | 
						|
      colorTableLayout->addWidget(resetButton, colorTableRow, 4);
 | 
						|
      ++colorTableRow;
 | 
						|
 | 
						|
      // Create settings interface
 | 
						|
      auto result = colorTables_.emplace(
 | 
						|
         colorTableType.first, settings::SettingsInterface<std::string> {});
 | 
						|
      auto& pair       = *result.first;
 | 
						|
      auto& colorTable = pair.second;
 | 
						|
 | 
						|
      // Add to settings list
 | 
						|
      settings_.push_back(&colorTable);
 | 
						|
 | 
						|
      auto& colorTableVariable = paletteSettings.palette(colorTableType.first);
 | 
						|
      colorTable.SetSettingsVariable(colorTableVariable);
 | 
						|
      colorTable.SetEditWidget(lineEdit);
 | 
						|
      colorTable.SetResetButton(resetButton);
 | 
						|
      colorTable.EnableTrimming();
 | 
						|
 | 
						|
      colorTableVariable.RegisterValueStagedCallback(
 | 
						|
         [colorTableType, imageLabel](const std::string& value)
 | 
						|
         { LoadColorTablePreview(colorTableType.first, value, imageLabel); });
 | 
						|
 | 
						|
      LoadColorTablePreview(
 | 
						|
         colorTableType.first, colorTableVariable.GetValue(), imageLabel);
 | 
						|
 | 
						|
      QObject::connect(
 | 
						|
         openFileButton,
 | 
						|
         &QAbstractButton::clicked,
 | 
						|
         self_,
 | 
						|
         [this, lineEdit]()
 | 
						|
         {
 | 
						|
            static const std::string paletteFilter = "Color Palettes (*.pal)";
 | 
						|
            static const std::string allFilter     = "All Files (*)";
 | 
						|
 | 
						|
            QFileDialog* dialog = new QFileDialog(self_);
 | 
						|
 | 
						|
            dialog->setFileMode(QFileDialog::ExistingFile);
 | 
						|
            dialog->setNameFilters({QObject::tr(paletteFilter.c_str()),
 | 
						|
                                    QObject::tr(allFilter.c_str())});
 | 
						|
            dialog->setAttribute(Qt::WA_DeleteOnClose);
 | 
						|
 | 
						|
            QObject::connect(dialog,
 | 
						|
                             &QFileDialog::fileSelected,
 | 
						|
                             self_,
 | 
						|
                             [lineEdit](const QString& file)
 | 
						|
                             {
 | 
						|
                                QString path = QDir::toNativeSeparators(file);
 | 
						|
 | 
						|
                                logger_->info("Selected palette: {}",
 | 
						|
                                              path.toStdString());
 | 
						|
                                lineEdit->setText(path);
 | 
						|
 | 
						|
                                // setText does not emit the textEdited signal
 | 
						|
                                Q_EMIT lineEdit->textEdited(path);
 | 
						|
                             });
 | 
						|
 | 
						|
            dialog->open();
 | 
						|
         });
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::SetupPalettesAlertsTab()
 | 
						|
{
 | 
						|
   // Palettes > Alerts
 | 
						|
   QVBoxLayout* layout = new QVBoxLayout(self_->ui->alertsPalette);
 | 
						|
 | 
						|
   alertPaletteSettingsWidget_ =
 | 
						|
      new AlertPaletteSettingsWidget(self_->ui->hotkeys);
 | 
						|
   layout->addWidget(alertPaletteSettingsWidget_);
 | 
						|
 | 
						|
   settingsPages_.push_back(alertPaletteSettingsWidget_);
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::SetupUnitsTab()
 | 
						|
{
 | 
						|
   QVBoxLayout* layout = new QVBoxLayout(self_->ui->units);
 | 
						|
 | 
						|
   unitSettingsWidget_ = new UnitSettingsWidget(self_->ui->units);
 | 
						|
   layout->addWidget(unitSettingsWidget_);
 | 
						|
 | 
						|
   settingsPages_.push_back(unitSettingsWidget_);
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::SetupAudioTab()
 | 
						|
{
 | 
						|
   QObject::connect(
 | 
						|
      self_->ui->alertAudioLocationMethodComboBox,
 | 
						|
      &QComboBox::currentTextChanged,
 | 
						|
      self_,
 | 
						|
      [this](const QString& text)
 | 
						|
      {
 | 
						|
         types::LocationMethod locationMethod =
 | 
						|
            types::GetLocationMethod(text.toStdString());
 | 
						|
 | 
						|
         bool coordinateEntryEnabled =
 | 
						|
            locationMethod == types::LocationMethod::Fixed;
 | 
						|
         bool radarSiteEntryEnable =
 | 
						|
            locationMethod == types::LocationMethod::RadarSite;
 | 
						|
         bool radiusEntryEnable =
 | 
						|
            locationMethod == types::LocationMethod::Fixed ||
 | 
						|
            locationMethod == types::LocationMethod::Track ||
 | 
						|
            locationMethod == types::LocationMethod::RadarSite;
 | 
						|
         bool countyEntryEnabled =
 | 
						|
            locationMethod == types::LocationMethod::County;
 | 
						|
         bool wfoEntryEnabled = locationMethod == types::LocationMethod::WFO;
 | 
						|
 | 
						|
         self_->ui->alertAudioLatitudeSpinBox->setEnabled(
 | 
						|
            coordinateEntryEnabled);
 | 
						|
         self_->ui->alertAudioLongitudeSpinBox->setEnabled(
 | 
						|
            coordinateEntryEnabled);
 | 
						|
         self_->ui->resetAlertAudioLatitudeButton->setEnabled(
 | 
						|
            coordinateEntryEnabled);
 | 
						|
         self_->ui->resetAlertAudioLongitudeButton->setEnabled(
 | 
						|
            coordinateEntryEnabled);
 | 
						|
 | 
						|
         self_->ui->alertAudioRadarSiteComboBox->setEnabled(
 | 
						|
            radarSiteEntryEnable);
 | 
						|
         self_->ui->alertAudioRadarSiteSelectButton->setEnabled(
 | 
						|
            radarSiteEntryEnable);
 | 
						|
         self_->ui->resetAlertAudioRadarSiteButton->setEnabled(
 | 
						|
            radarSiteEntryEnable);
 | 
						|
 | 
						|
         self_->ui->alertAudioRadiusSpinBox->setEnabled(radiusEntryEnable);
 | 
						|
         self_->ui->resetAlertAudioRadiusButton->setEnabled(radiusEntryEnable);
 | 
						|
 | 
						|
         self_->ui->alertAudioCountyLineEdit->setEnabled(countyEntryEnabled);
 | 
						|
         self_->ui->alertAudioCountySelectButton->setEnabled(
 | 
						|
            countyEntryEnabled);
 | 
						|
         self_->ui->resetAlertAudioCountyButton->setEnabled(countyEntryEnabled);
 | 
						|
 | 
						|
         self_->ui->alertAudioWFOLineEdit->setEnabled(wfoEntryEnabled);
 | 
						|
         self_->ui->alertAudioWFOSelectButton->setEnabled(wfoEntryEnabled);
 | 
						|
         self_->ui->resetAlertAudioWFOButton->setEnabled(wfoEntryEnabled);
 | 
						|
      });
 | 
						|
 | 
						|
   settings::AudioSettings& audioSettings = settings::AudioSettings::Instance();
 | 
						|
 | 
						|
   alertAudioSoundFile_.SetSettingsVariable(audioSettings.alert_sound_file());
 | 
						|
   alertAudioSoundFile_.SetEditWidget(self_->ui->alertAudioSoundLineEdit);
 | 
						|
   alertAudioSoundFile_.SetResetButton(self_->ui->resetAlertAudioSoundButton);
 | 
						|
   alertAudioSoundFile_.EnableTrimming();
 | 
						|
 | 
						|
   QObject::connect(
 | 
						|
      self_->ui->alertAudioSoundSelectButton,
 | 
						|
      &QAbstractButton::clicked,
 | 
						|
      self_,
 | 
						|
      [this]()
 | 
						|
      {
 | 
						|
         static const std::string audioFilter =
 | 
						|
            "Audio Files (*.3ga *.669 *.a52 *.aac *.ac3 *.adt *.adts *.aif "
 | 
						|
            "*.aifc *.aiff *.amb *.amr *.aob *.ape *.au *.awb *.caf *.dts "
 | 
						|
            "*.flac *.it *.kar *.m4a *.m4b *.m4p *.m5p *.mid *.mka *.mlp *.mod "
 | 
						|
            "*.mpa *.mp1 *.mp2 *.mp3 *.mpc *.mpga *.mus *.oga *.ogg *.oma "
 | 
						|
            "*.opus *.qcp *.ra *.rmi *.s3m *.sid *.spx *.tak *.thd *.tta *.voc "
 | 
						|
            "*.vqf *.w64 *.wav *.wma *.wv *.xa *.xm)";
 | 
						|
         static const std::string allFilter = "All Files (*)";
 | 
						|
 | 
						|
         QFileDialog* dialog = new QFileDialog(self_);
 | 
						|
 | 
						|
         dialog->setFileMode(QFileDialog::ExistingFile);
 | 
						|
         dialog->setNameFilters(
 | 
						|
            {QObject::tr(audioFilter.c_str()), QObject::tr(allFilter.c_str())});
 | 
						|
         dialog->setAttribute(Qt::WA_DeleteOnClose);
 | 
						|
 | 
						|
         QObject::connect(
 | 
						|
            dialog,
 | 
						|
            &QFileDialog::fileSelected,
 | 
						|
            self_,
 | 
						|
            [this](const QString& file)
 | 
						|
            {
 | 
						|
               QString path = QDir::toNativeSeparators(file);
 | 
						|
 | 
						|
               logger_->info("Selected alert sound file: {}",
 | 
						|
                             path.toStdString());
 | 
						|
               self_->ui->alertAudioSoundLineEdit->setText(path);
 | 
						|
 | 
						|
               // setText does not emit the textEdited signal
 | 
						|
               Q_EMIT self_->ui->alertAudioSoundLineEdit->textEdited(path);
 | 
						|
            });
 | 
						|
 | 
						|
         dialog->open();
 | 
						|
      });
 | 
						|
 | 
						|
   alertAudioLocationMethod_.SetSettingsVariable(
 | 
						|
      audioSettings.alert_location_method());
 | 
						|
   SCWX_SETTINGS_COMBO_BOX(alertAudioLocationMethod_,
 | 
						|
                           self_->ui->alertAudioLocationMethodComboBox,
 | 
						|
                           types::LocationMethodIterator(),
 | 
						|
                           types::GetLocationMethodName);
 | 
						|
   alertAudioLocationMethod_.SetResetButton(
 | 
						|
      self_->ui->resetAlertAudioLocationMethodButton);
 | 
						|
 | 
						|
   alertAudioLatitude_.SetSettingsVariable(audioSettings.alert_latitude());
 | 
						|
   alertAudioLatitude_.SetEditWidget(self_->ui->alertAudioLatitudeSpinBox);
 | 
						|
   alertAudioLatitude_.SetResetButton(self_->ui->resetAlertAudioLatitudeButton);
 | 
						|
 | 
						|
   alertAudioLongitude_.SetSettingsVariable(audioSettings.alert_longitude());
 | 
						|
   alertAudioLongitude_.SetEditWidget(self_->ui->alertAudioLongitudeSpinBox);
 | 
						|
   alertAudioLongitude_.SetResetButton(
 | 
						|
      self_->ui->resetAlertAudioLongitudeButton);
 | 
						|
 | 
						|
   alertAudioRadarSite_.SetSettingsVariable(audioSettings.alert_radar_site());
 | 
						|
   alertAudioRadarSite_.SetMapFromValueFunction(
 | 
						|
      [](const std::string& id) -> std::string
 | 
						|
      {
 | 
						|
         // Get the radar site associated with the ID
 | 
						|
         std::shared_ptr<config::RadarSite> radarSite =
 | 
						|
            config::RadarSite::Get(id);
 | 
						|
 | 
						|
         if (radarSite == nullptr)
 | 
						|
         {
 | 
						|
            // No radar site found, just return the ID
 | 
						|
            return id;
 | 
						|
         }
 | 
						|
 | 
						|
         // Add location details to the radar site
 | 
						|
         return RadarSiteLabel(radarSite);
 | 
						|
      });
 | 
						|
   alertAudioRadarSite_.SetMapToValueFunction(
 | 
						|
      [](const std::string& text) -> std::string
 | 
						|
      {
 | 
						|
         // Find the position of location details
 | 
						|
         size_t pos = text.find(" (");
 | 
						|
 | 
						|
         if (pos == std::string::npos)
 | 
						|
         {
 | 
						|
            // No location details found, just return the text
 | 
						|
            return text;
 | 
						|
         }
 | 
						|
 | 
						|
         // Remove location details from the radar site
 | 
						|
         return text.substr(0, pos);
 | 
						|
      });
 | 
						|
   alertAudioRadarSite_.SetEditWidget(self_->ui->alertAudioRadarSiteComboBox);
 | 
						|
   alertAudioRadarSite_.SetResetButton(
 | 
						|
      self_->ui->resetAlertAudioRadarSiteButton);
 | 
						|
   UpdateAlertRadarDialogLocation(audioSettings.alert_radar_site().GetValue());
 | 
						|
 | 
						|
   alertAudioRadius_.SetSettingsVariable(audioSettings.alert_radius());
 | 
						|
   alertAudioRadius_.SetEditWidget(self_->ui->alertAudioRadiusSpinBox);
 | 
						|
   alertAudioRadius_.SetResetButton(self_->ui->resetAlertAudioRadiusButton);
 | 
						|
   alertAudioRadius_.SetUnitLabel(self_->ui->alertAudioRadiusUnitsLabel);
 | 
						|
   auto alertAudioRadiusUpdateUnits = [this](const std::string& newValue)
 | 
						|
   {
 | 
						|
      const types::DistanceUnits radiusUnits =
 | 
						|
         types::GetDistanceUnitsFromName(newValue);
 | 
						|
      const double      radiusScale = types::GetDistanceUnitsScale(radiusUnits);
 | 
						|
      const std::string abbreviation =
 | 
						|
         types::GetDistanceUnitsAbbreviation(radiusUnits);
 | 
						|
 | 
						|
      alertAudioRadius_.SetUnit(radiusScale, abbreviation);
 | 
						|
   };
 | 
						|
   settings::UnitSettings::Instance()
 | 
						|
      .distance_units()
 | 
						|
      .RegisterValueStagedCallback(alertAudioRadiusUpdateUnits);
 | 
						|
   alertAudioRadiusUpdateUnits(
 | 
						|
      settings::UnitSettings::Instance().distance_units().GetValue());
 | 
						|
 | 
						|
   auto& alertAudioPhenomena = types::GetAlertAudioPhenomena();
 | 
						|
   auto  alertAudioLayout =
 | 
						|
      static_cast<QGridLayout*>(self_->ui->alertAudioGroupBox->layout());
 | 
						|
 | 
						|
   alertAudioEnabled_.reserve(alertAudioPhenomena.size());
 | 
						|
 | 
						|
   for (const auto& phenomenon : alertAudioPhenomena)
 | 
						|
   {
 | 
						|
      QCheckBox* alertAudioCheckbox = new QCheckBox(self_);
 | 
						|
      alertAudioCheckbox->setText(
 | 
						|
         QString::fromStdString(awips::GetPhenomenonText(phenomenon)));
 | 
						|
 | 
						|
      static_cast<QGridLayout*>(self_->ui->alertAudioGroupBox->layout())
 | 
						|
         ->addWidget(
 | 
						|
            alertAudioCheckbox, alertAudioLayout->rowCount(), 0, 1, -1);
 | 
						|
 | 
						|
      // Create settings interface
 | 
						|
      auto result = alertAudioEnabled_.emplace(
 | 
						|
         phenomenon, settings::SettingsInterface<bool> {});
 | 
						|
      auto& alertAudioEnabled = result.first->second;
 | 
						|
 | 
						|
      // Add to settings list
 | 
						|
      settings_.push_back(&alertAudioEnabled);
 | 
						|
 | 
						|
      alertAudioEnabled.SetSettingsVariable(
 | 
						|
         audioSettings.alert_enabled(phenomenon));
 | 
						|
      alertAudioEnabled.SetEditWidget(alertAudioCheckbox);
 | 
						|
   }
 | 
						|
 | 
						|
   QObject::connect(
 | 
						|
      positionManager_.get(),
 | 
						|
      &manager::PositionManager::PositionUpdated,
 | 
						|
      self_,
 | 
						|
      [this](const QGeoPositionInfo& info)
 | 
						|
      {
 | 
						|
         settings::AudioSettings& audioSettings =
 | 
						|
            settings::AudioSettings::Instance();
 | 
						|
 | 
						|
         if (info.isValid() &&
 | 
						|
             types::GetLocationMethod(
 | 
						|
                audioSettings.alert_location_method().GetValue()) ==
 | 
						|
                types::LocationMethod::Track)
 | 
						|
         {
 | 
						|
            QGeoCoordinate coordinate = info.coordinate();
 | 
						|
            self_->ui->alertAudioLatitudeSpinBox->setValue(
 | 
						|
               coordinate.latitude());
 | 
						|
            self_->ui->alertAudioLongitudeSpinBox->setValue(
 | 
						|
               coordinate.longitude());
 | 
						|
         }
 | 
						|
      });
 | 
						|
 | 
						|
   QObject::connect(
 | 
						|
      self_->ui->alertAudioCountySelectButton,
 | 
						|
      &QAbstractButton::clicked,
 | 
						|
      self_,
 | 
						|
      [this]()
 | 
						|
      {
 | 
						|
         std::string countyId =
 | 
						|
            self_->ui->alertAudioCountyLineEdit->text().toStdString();
 | 
						|
 | 
						|
         if (countyId.length() >= 2)
 | 
						|
         {
 | 
						|
            countyDialog_->SelectState(countyId.substr(0, 2));
 | 
						|
         }
 | 
						|
 | 
						|
         countyDialog_->show();
 | 
						|
      });
 | 
						|
   QObject::connect(countyDialog_,
 | 
						|
                    &CountyDialog::accepted,
 | 
						|
                    self_,
 | 
						|
                    [this]()
 | 
						|
                    {
 | 
						|
                       std::string countyId  = countyDialog_->county_fips_id();
 | 
						|
                       QString     qCountyId = QString::fromStdString(countyId);
 | 
						|
                       self_->ui->alertAudioCountyLineEdit->setText(qCountyId);
 | 
						|
 | 
						|
                       // setText does not emit the textEdited signal
 | 
						|
                       Q_EMIT self_->ui->alertAudioCountyLineEdit->textEdited(
 | 
						|
                          qCountyId);
 | 
						|
                    });
 | 
						|
   QObject::connect(self_->ui->alertAudioCountyLineEdit,
 | 
						|
                    &QLineEdit::textChanged,
 | 
						|
                    self_,
 | 
						|
                    [this](const QString& text)
 | 
						|
                    {
 | 
						|
                       std::string countyName =
 | 
						|
                          config::CountyDatabase::GetCountyName(
 | 
						|
                             text.toStdString());
 | 
						|
                       self_->ui->alertAudioCountyLabel->setText(
 | 
						|
                          QString::fromStdString(countyName));
 | 
						|
                    });
 | 
						|
 | 
						|
   alertAudioCounty_.SetSettingsVariable(audioSettings.alert_county());
 | 
						|
   alertAudioCounty_.SetEditWidget(self_->ui->alertAudioCountyLineEdit);
 | 
						|
   alertAudioCounty_.SetResetButton(self_->ui->resetAlertAudioCountyButton);
 | 
						|
   alertAudioCounty_.EnableTrimming();
 | 
						|
 | 
						|
   QObject::connect(self_->ui->alertAudioWFOSelectButton,
 | 
						|
                    &QAbstractButton::clicked,
 | 
						|
                    self_,
 | 
						|
                    [this]() { wfoDialog_->show(); });
 | 
						|
   QObject::connect(wfoDialog_,
 | 
						|
                    &WFODialog::accepted,
 | 
						|
                    self_,
 | 
						|
                    [this]()
 | 
						|
                    {
 | 
						|
                       std::string wfoId  = wfoDialog_->wfo_id();
 | 
						|
                       QString     qWFOId = QString::fromStdString(wfoId);
 | 
						|
                       self_->ui->alertAudioWFOLineEdit->setText(qWFOId);
 | 
						|
 | 
						|
                       // setText does not emit the textEdited signal
 | 
						|
                       Q_EMIT self_->ui->alertAudioWFOLineEdit->textEdited(
 | 
						|
                          qWFOId);
 | 
						|
                    });
 | 
						|
   QObject::connect(self_->ui->alertAudioWFOLineEdit,
 | 
						|
                    &QLineEdit::textChanged,
 | 
						|
                    self_,
 | 
						|
                    [this](const QString& text)
 | 
						|
                    {
 | 
						|
                       std::string wfoName = config::CountyDatabase::GetWFOName(
 | 
						|
                          text.toStdString());
 | 
						|
                       self_->ui->alertAudioWFOLabel->setText(
 | 
						|
                          QString::fromStdString(wfoName));
 | 
						|
                    });
 | 
						|
 | 
						|
   alertAudioWFO_.SetSettingsVariable(audioSettings.alert_wfo());
 | 
						|
   alertAudioWFO_.SetEditWidget(self_->ui->alertAudioWFOLineEdit);
 | 
						|
   alertAudioWFO_.SetResetButton(self_->ui->resetAlertAudioWFOButton);
 | 
						|
   alertAudioWFO_.EnableTrimming();
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::SetupTextTab()
 | 
						|
{
 | 
						|
   settings::TextSettings& textSettings = settings::TextSettings::Instance();
 | 
						|
 | 
						|
   self_->ui->fontListView->setModel(fontCategoryModel_);
 | 
						|
 | 
						|
   const auto fontCategoryCount = types::FontCategoryIterator().count();
 | 
						|
   fontFamilies_.reserve(fontCategoryCount);
 | 
						|
   fontStyles_.reserve(fontCategoryCount);
 | 
						|
   fontPointSizes_.reserve(fontCategoryCount);
 | 
						|
 | 
						|
   for (const auto& fontCategory : types::FontCategoryIterator())
 | 
						|
   {
 | 
						|
      // Add font category to list view
 | 
						|
      fontCategoryModel_->appendRow(new QStandardItem(
 | 
						|
         QString::fromStdString(types::GetFontCategoryName(fontCategory))));
 | 
						|
 | 
						|
      // Create settings interface
 | 
						|
      auto fontFamilyResult = fontFamilies_.emplace(
 | 
						|
         fontCategory, settings::SettingsInterface<std::string> {});
 | 
						|
      auto fontStyleResult = fontStyles_.emplace(
 | 
						|
         fontCategory, settings::SettingsInterface<std::string> {});
 | 
						|
      auto fontSizeResult = fontPointSizes_.emplace(
 | 
						|
         fontCategory, settings::SettingsInterface<double> {});
 | 
						|
 | 
						|
      auto& fontFamily = (*fontFamilyResult.first).second;
 | 
						|
      auto& fontStyle  = (*fontStyleResult.first).second;
 | 
						|
      auto& fontSize   = (*fontSizeResult.first).second;
 | 
						|
 | 
						|
      // Add to settings list
 | 
						|
      settings_.push_back(&fontFamily);
 | 
						|
      settings_.push_back(&fontStyle);
 | 
						|
      settings_.push_back(&fontSize);
 | 
						|
 | 
						|
      // Set settings variables
 | 
						|
      fontFamily.SetSettingsVariable(textSettings.font_family(fontCategory));
 | 
						|
      fontStyle.SetSettingsVariable(textSettings.font_style(fontCategory));
 | 
						|
      fontSize.SetSettingsVariable(textSettings.font_point_size(fontCategory));
 | 
						|
   }
 | 
						|
   self_->ui->fontListView->setCurrentIndex(fontCategoryModel_->index(0, 0));
 | 
						|
   SelectFontCategory(*types::FontCategoryIterator().begin());
 | 
						|
   UpdateFontDisplayData();
 | 
						|
 | 
						|
   hoverTextWrap_.SetSettingsVariable(textSettings.hover_text_wrap());
 | 
						|
   hoverTextWrap_.SetEditWidget(self_->ui->hoverTextWrapSpinBox);
 | 
						|
   hoverTextWrap_.SetResetButton(self_->ui->resetHoverTextWrapButton);
 | 
						|
 | 
						|
   tooltipMethod_.SetSettingsVariable(textSettings.tooltip_method());
 | 
						|
   SCWX_SETTINGS_COMBO_BOX(tooltipMethod_,
 | 
						|
                           self_->ui->tooltipMethodComboBox,
 | 
						|
                           types::TooltipMethodIterator(),
 | 
						|
                           types::GetTooltipMethodName);
 | 
						|
   tooltipMethod_.SetResetButton(self_->ui->resetTooltipMethodButton);
 | 
						|
 | 
						|
   placefileTextDropShadowEnabled_.SetSettingsVariable(
 | 
						|
      textSettings.placefile_text_drop_shadow_enabled());
 | 
						|
   placefileTextDropShadowEnabled_.SetEditWidget(
 | 
						|
      self_->ui->placefileTextDropShadowCheckBox);
 | 
						|
 | 
						|
   radarSiteHoverTextEnabled_.SetSettingsVariable(
 | 
						|
      textSettings.radar_site_hover_text_enabled());
 | 
						|
   radarSiteHoverTextEnabled_.SetEditWidget(
 | 
						|
      self_->ui->radarSiteHoverTextCheckBox);
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::SetupHotkeysTab()
 | 
						|
{
 | 
						|
   QVBoxLayout* layout = new QVBoxLayout(self_->ui->hotkeys);
 | 
						|
 | 
						|
   hotkeySettingsWidget_ = new HotkeySettingsWidget(self_->ui->hotkeys);
 | 
						|
   layout->addWidget(hotkeySettingsWidget_);
 | 
						|
 | 
						|
   settingsPages_.push_back(hotkeySettingsWidget_);
 | 
						|
}
 | 
						|
 | 
						|
QImage SettingsDialogImpl::GenerateColorTableImage(
 | 
						|
   std::shared_ptr<common::ColorTable> colorTable,
 | 
						|
   std::uint16_t                       min,
 | 
						|
   std::uint16_t                       max,
 | 
						|
   float                               offset,
 | 
						|
   float                               scale)
 | 
						|
{
 | 
						|
   std::size_t width  = max - min + 1u;
 | 
						|
   std::size_t height = 1u;
 | 
						|
   QImage      image(static_cast<int>(width),
 | 
						|
                static_cast<int>(height),
 | 
						|
                QImage::Format::Format_ARGB32);
 | 
						|
 | 
						|
   for (std::size_t i = min; i <= max; ++i)
 | 
						|
   {
 | 
						|
      const float               value = (i - offset) / scale;
 | 
						|
      boost::gil::rgba8_pixel_t pixel = colorTable->Color(value);
 | 
						|
      image.setPixel(static_cast<int>(i - min),
 | 
						|
                     0,
 | 
						|
                     qRgba(static_cast<int>(pixel[0]),
 | 
						|
                           static_cast<int>(pixel[1]),
 | 
						|
                           static_cast<int>(pixel[2]),
 | 
						|
                           static_cast<int>(pixel[3])));
 | 
						|
   }
 | 
						|
 | 
						|
   return image;
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::LoadColorTablePreview(const std::string& key,
 | 
						|
                                               const std::string& value,
 | 
						|
                                               QLabel*            imageLabel)
 | 
						|
{
 | 
						|
   scwx::util::async(
 | 
						|
      [key, value, imageLabel]()
 | 
						|
      {
 | 
						|
         std::unique_ptr<std::istream>       is = util::OpenFile(value);
 | 
						|
         std::shared_ptr<common::ColorTable> colorTable =
 | 
						|
            common::ColorTable::Load(*is);
 | 
						|
 | 
						|
         if (colorTable->IsValid())
 | 
						|
         {
 | 
						|
            auto&   conversions = kColorTableConversions_.at(key);
 | 
						|
            QPixmap image =
 | 
						|
               QPixmap::fromImage(GenerateColorTableImage(colorTable,
 | 
						|
                                                          conversions.rangeMin,
 | 
						|
                                                          conversions.rangeMax,
 | 
						|
                                                          conversions.offset,
 | 
						|
                                                          conversions.scale))
 | 
						|
                  .scaled(64, 20);
 | 
						|
            imageLabel->setPixmap(image);
 | 
						|
 | 
						|
            QMetaObject::invokeMethod(
 | 
						|
               imageLabel, [imageLabel] { imageLabel->setVisible(true); });
 | 
						|
         }
 | 
						|
         else
 | 
						|
         {
 | 
						|
            imageLabel->clear();
 | 
						|
 | 
						|
            QMetaObject::invokeMethod(
 | 
						|
               imageLabel, [imageLabel] { imageLabel->setVisible(false); });
 | 
						|
         }
 | 
						|
      });
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::UpdateRadarDialogLocation(const std::string& id)
 | 
						|
{
 | 
						|
   std::shared_ptr<config::RadarSite> radarSite = config::RadarSite::Get(id);
 | 
						|
 | 
						|
   if (radarSite != nullptr)
 | 
						|
   {
 | 
						|
      radarSiteDialog_->HandleMapUpdate(radarSite->latitude(),
 | 
						|
                                        radarSite->longitude());
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::UpdateAlertRadarDialogLocation(const std::string& id)
 | 
						|
{
 | 
						|
   std::shared_ptr<config::RadarSite> radarSite = config::RadarSite::Get(id);
 | 
						|
 | 
						|
   if (radarSite != nullptr)
 | 
						|
   {
 | 
						|
      alertAudioRadarSiteDialog_->HandleMapUpdate(radarSite->latitude(),
 | 
						|
                                                  radarSite->longitude());
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
QFont SettingsDialogImpl::GetSelectedFont()
 | 
						|
{
 | 
						|
   std::string fontFamily = fontFamilies_.at(selectedFontCategory_)
 | 
						|
                               .GetSettingsVariable()
 | 
						|
                               ->GetStagedOrValue();
 | 
						|
   std::string fontStyle = fontStyles_.at(selectedFontCategory_)
 | 
						|
                              .GetSettingsVariable()
 | 
						|
                              ->GetStagedOrValue();
 | 
						|
   units::font_size::points<double> fontSize {
 | 
						|
      fontPointSizes_.at(selectedFontCategory_)
 | 
						|
         .GetSettingsVariable()
 | 
						|
         ->GetStagedOrValue()};
 | 
						|
 | 
						|
   QFont font = QFontDatabase::font(QString::fromStdString(fontFamily),
 | 
						|
                                    QString::fromStdString(fontStyle),
 | 
						|
                                    static_cast<int>(fontSize.value()));
 | 
						|
   font.setPointSizeF(fontSize.value());
 | 
						|
 | 
						|
   return font;
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::SelectFontCategory(types::FontCategory fontCategory)
 | 
						|
{
 | 
						|
   selectedFontCategory_ = fontCategory;
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::UpdateFontDisplayData()
 | 
						|
{
 | 
						|
   QFont font = GetSelectedFont();
 | 
						|
 | 
						|
   self_->ui->fontNameLabel->setText(font.family());
 | 
						|
   self_->ui->fontStyleLabel->setText(font.styleName());
 | 
						|
   self_->ui->fontSizeLabel->setText(QString::number(font.pointSizeF()));
 | 
						|
 | 
						|
   self_->ui->fontPreviewLabel->setFont(font);
 | 
						|
 | 
						|
   if (selectedFontCategory_ != types::FontCategory::Unknown)
 | 
						|
   {
 | 
						|
      auto& fontFamily = fontFamilies_.at(selectedFontCategory_);
 | 
						|
      auto& fontStyle  = fontStyles_.at(selectedFontCategory_);
 | 
						|
      auto& fontSize   = fontPointSizes_.at(selectedFontCategory_);
 | 
						|
 | 
						|
      self_->ui->resetFontButton->setVisible(!fontFamily.IsDefault() ||
 | 
						|
                                             !fontStyle.IsDefault() ||
 | 
						|
                                             !fontSize.IsDefault());
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::ApplyChanges()
 | 
						|
{
 | 
						|
   logger_->info("Applying settings changes");
 | 
						|
 | 
						|
   bool committed = false;
 | 
						|
 | 
						|
   for (auto& setting : settings_)
 | 
						|
   {
 | 
						|
      committed |= setting->Commit();
 | 
						|
   }
 | 
						|
 | 
						|
   for (auto& page : settingsPages_)
 | 
						|
   {
 | 
						|
      committed |= page->CommitChanges();
 | 
						|
   }
 | 
						|
 | 
						|
   if (committed)
 | 
						|
   {
 | 
						|
      manager::SettingsManager::Instance().SaveSettings();
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::DiscardChanges()
 | 
						|
{
 | 
						|
   logger_->info("Discarding settings changes");
 | 
						|
 | 
						|
   for (auto& setting : settings_)
 | 
						|
   {
 | 
						|
      setting->Reset();
 | 
						|
   }
 | 
						|
 | 
						|
   for (auto& page : settingsPages_)
 | 
						|
   {
 | 
						|
      page->DiscardChanges();
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
void SettingsDialogImpl::ResetToDefault()
 | 
						|
{
 | 
						|
   logger_->info("Restoring settings to default");
 | 
						|
 | 
						|
   for (auto& setting : settings_)
 | 
						|
   {
 | 
						|
      setting->StageDefault();
 | 
						|
   }
 | 
						|
 | 
						|
   for (auto& page : settingsPages_)
 | 
						|
   {
 | 
						|
      page->ResetToDefault();
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
std::string SettingsDialogImpl::RadarSiteLabel(
 | 
						|
   std::shared_ptr<config::RadarSite>& radarSite)
 | 
						|
{
 | 
						|
   return fmt::format("{} ({})", radarSite->id(), radarSite->location_name());
 | 
						|
}
 | 
						|
 | 
						|
} // namespace ui
 | 
						|
} // namespace qt
 | 
						|
} // namespace scwx
 |