diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index a5ab11f9..99ede29f 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -252,12 +252,14 @@ set(UI_UI source/scwx/qt/ui/about_dialog.ui source/scwx/qt/ui/radar_site_dialog.ui source/scwx/qt/ui/settings_dialog.ui source/scwx/qt/ui/update_dialog.ui) -set(HDR_UI_SETUP source/scwx/qt/ui/setup/finish_page.hpp +set(HDR_UI_SETUP source/scwx/qt/ui/setup/audio_codec_page.hpp + source/scwx/qt/ui/setup/finish_page.hpp source/scwx/qt/ui/setup/map_layout_page.hpp source/scwx/qt/ui/setup/map_provider_page.hpp source/scwx/qt/ui/setup/setup_wizard.hpp source/scwx/qt/ui/setup/welcome_page.hpp) -set(SRC_UI_SETUP source/scwx/qt/ui/setup/finish_page.cpp +set(SRC_UI_SETUP source/scwx/qt/ui/setup/audio_codec_page.cpp + source/scwx/qt/ui/setup/finish_page.cpp source/scwx/qt/ui/setup/map_layout_page.cpp source/scwx/qt/ui/setup/map_provider_page.cpp source/scwx/qt/ui/setup/setup_wizard.cpp diff --git a/scwx-qt/source/scwx/qt/ui/setup/audio_codec_page.cpp b/scwx-qt/source/scwx/qt/ui/setup/audio_codec_page.cpp new file mode 100644 index 00000000..2830ed3e --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/setup/audio_codec_page.cpp @@ -0,0 +1,176 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace ui +{ +namespace setup +{ + +class AudioCodecPage::Impl +{ +public: + explicit Impl(AudioCodecPage* self) : self_ {self} {}; + ~Impl() = default; + + void SetupSettingsInterface(); + void SetInstructionsLabelText(); + + AudioCodecPage* self_; + + QLayout* layout_ {}; + QLayout* topLayout_ {}; + + QScrollArea* scrollArea_ {}; + QWidget* contents_ {}; + QLabel* descriptionLabel_ {}; + QLabel* instructionsLabel_ {}; + QCheckBox* ignoreMissingCodecsCheckBox_ {}; + QSpacerItem* spacer_ {}; + + settings::SettingsInterface ignoreMissingCodecs_ {}; +}; + +AudioCodecPage::AudioCodecPage(QWidget* parent) : + QWizardPage(parent), p {std::make_shared(this)} +{ + setTitle(tr("Media Codecs")); + setSubTitle(tr("Configure system media settings for Supercell Wx.")); + + p->descriptionLabel_ = new QLabel(this); + p->instructionsLabel_ = new QLabel(this); + p->ignoreMissingCodecsCheckBox_ = new QCheckBox(this); + + // Description + p->descriptionLabel_->setText( + tr("Your system does not have the proper codecs installed in order to " + "play the default audio. You may either install the proper codecs, or " + "update Supercell Wx audio settings to change from the default audio " + "files. After installing the proper codecs, you must restart " + "Supercell Wx.")); + p->descriptionLabel_->setWordWrap(true); + p->SetInstructionsLabelText(); + p->instructionsLabel_->setWordWrap(true); + + p->ignoreMissingCodecsCheckBox_->setText(tr("Ignore missing codecs")); + + p->spacer_ = + new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding); + + // Overall layout + p->layout_ = new QVBoxLayout(this); + p->layout_->addWidget(p->descriptionLabel_); + p->layout_->addWidget(p->instructionsLabel_); + p->layout_->addWidget(p->ignoreMissingCodecsCheckBox_); + p->layout_->addItem(p->spacer_); + + p->contents_ = new QWidget(this); + p->contents_->setLayout(p->layout_); + + p->scrollArea_ = new QScrollArea(this); + p->scrollArea_->setHorizontalScrollBarPolicy( + Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + p->scrollArea_->setFrameShape(QFrame::Shape::NoFrame); + p->scrollArea_->setWidgetResizable(true); + p->scrollArea_->setWidget(p->contents_); + + p->topLayout_ = new QVBoxLayout(this); + p->topLayout_->setContentsMargins(0, 0, 0, 0); + p->topLayout_->addWidget(p->scrollArea_); + + setLayout(p->topLayout_); + + // Configure settings interface + p->SetupSettingsInterface(); +} + +AudioCodecPage::~AudioCodecPage() = default; + +void AudioCodecPage::Impl::SetInstructionsLabelText() +{ +#if defined(_WIN32) + instructionsLabel_->setText(tr( + "

Option 1

" // + "

Update your Windows installation. The required media codecs may " + "be available with the latest operating system updates.

" // + "

Option 2

" // + "

Install the Web " + "Media Extensions package from the Windows Store.

" // + "

Option 3

" // + "

Install K-Lite Codec Pack " + "Basic. This is a 3rd party application, and no support or warranty " + "is provided.

")); + instructionsLabel_->setTextInteractionFlags( + Qt::TextInteractionFlag::TextBrowserInteraction); + + QObject::connect(instructionsLabel_, + &QLabel::linkActivated, + self_, + [](const QString& link) + { QDesktopServices::openUrl(QUrl {link}); }); +#else + instructionsLabel_->setText( + tr("Please see the instructions for your Linux distribution for " + "installing media codecs.")); +#endif +} + +void AudioCodecPage::Impl::SetupSettingsInterface() +{ + auto& audioSettings = settings::AudioSettings::Instance(); + + ignoreMissingCodecs_.SetSettingsVariable( + audioSettings.ignore_missing_codecs()); + ignoreMissingCodecs_.SetEditWidget(ignoreMissingCodecsCheckBox_); +} + +bool AudioCodecPage::validatePage() +{ + bool committed = false; + + committed |= p->ignoreMissingCodecs_.Commit(); + + if (committed) + { + manager::SettingsManager::Instance().SaveSettings(); + } + + return true; +} + +bool AudioCodecPage::IsRequired() +{ + auto& audioSettings = settings::AudioSettings::Instance(); + + bool ignoreCodecErrors = audioSettings.ignore_missing_codecs().GetValue(); + + QMediaFormat oggFormat {QMediaFormat::FileFormat::Ogg}; + auto oggCodecs = + oggFormat.supportedAudioCodecs(QMediaFormat::ConversionMode::Decode); + + // Setup is required if codec errors are not ignored, and the default codecs + // are not supported + return (!ignoreCodecErrors && + oggCodecs.contains(QMediaFormat::AudioCodec::Vorbis)); +} + +} // namespace setup +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/setup/audio_codec_page.hpp b/scwx-qt/source/scwx/qt/ui/setup/audio_codec_page.hpp new file mode 100644 index 00000000..94a400e2 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/setup/audio_codec_page.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace scwx +{ +namespace qt +{ +namespace ui +{ +namespace setup +{ + +class AudioCodecPage : public QWizardPage +{ + Q_DISABLE_COPY_MOVE(AudioCodecPage) + +public: + explicit AudioCodecPage(QWidget* parent = nullptr); + ~AudioCodecPage(); + + bool validatePage() override; + + static bool IsRequired(); + +private: + class Impl; + std::shared_ptr p; +}; + +} // namespace setup +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/setup/map_provider_page.cpp b/scwx-qt/source/scwx/qt/ui/setup/map_provider_page.cpp index 6cecf076..fc0c9ef1 100644 --- a/scwx-qt/source/scwx/qt/ui/setup/map_provider_page.cpp +++ b/scwx-qt/source/scwx/qt/ui/setup/map_provider_page.cpp @@ -278,6 +278,18 @@ bool MapProviderPage::validatePage() return true; } +bool MapProviderPage::IsRequired() +{ + auto& generalSettings = settings::GeneralSettings::Instance(); + + std::string mapboxApiKey = generalSettings.mapbox_api_key().GetValue(); + std::string maptilerApiKey = generalSettings.maptiler_api_key().GetValue(); + + // Setup is required if either API key is empty, or contains a single + // character ("?") + return (mapboxApiKey.size() <= 1 && maptilerApiKey.size() <= 1); +} + } // namespace setup } // namespace ui } // namespace qt diff --git a/scwx-qt/source/scwx/qt/ui/setup/map_provider_page.hpp b/scwx-qt/source/scwx/qt/ui/setup/map_provider_page.hpp index 5b7260c7..3e564639 100644 --- a/scwx-qt/source/scwx/qt/ui/setup/map_provider_page.hpp +++ b/scwx-qt/source/scwx/qt/ui/setup/map_provider_page.hpp @@ -22,6 +22,8 @@ public: bool isComplete() const override; bool validatePage() override; + static bool IsRequired(); + private: class Impl; std::shared_ptr p; diff --git a/scwx-qt/source/scwx/qt/ui/setup/setup_wizard.cpp b/scwx-qt/source/scwx/qt/ui/setup/setup_wizard.cpp index 9daf903e..92be250f 100644 --- a/scwx-qt/source/scwx/qt/ui/setup/setup_wizard.cpp +++ b/scwx-qt/source/scwx/qt/ui/setup/setup_wizard.cpp @@ -1,9 +1,9 @@ #include +#include #include #include #include #include -#include #include #include @@ -38,6 +38,7 @@ SetupWizard::SetupWizard(QWidget* parent) : setPage(static_cast(Page::Welcome), new WelcomePage(this)); setPage(static_cast(Page::MapProvider), new MapProviderPage(this)); setPage(static_cast(Page::MapLayout), new MapLayoutPage(this)); + setPage(static_cast(Page::AudioCodec), new AudioCodecPage(this)); setPage(static_cast(Page::Finish), new FinishPage(this)); #if !defined(Q_OS_MAC) @@ -55,16 +56,43 @@ SetupWizard::SetupWizard(QWidget* parent) : SetupWizard::~SetupWizard() = default; +int SetupWizard::nextId() const +{ + int nextId = currentId(); + + while (true) + { + switch (++nextId) + { + case static_cast(Page::MapProvider): + case static_cast(Page::MapLayout): + if (MapProviderPage::IsRequired()) + { + return nextId; + } + break; + + case static_cast(Page::AudioCodec): + if (AudioCodecPage::IsRequired()) + { + return nextId; + } + break; + + case static_cast(Page::Finish): + return nextId; + + default: + return -1; + } + } + + return -1; +} + bool SetupWizard::IsSetupRequired() { - auto& generalSettings = settings::GeneralSettings::Instance(); - - std::string mapboxApiKey = generalSettings.mapbox_api_key().GetValue(); - std::string maptilerApiKey = generalSettings.maptiler_api_key().GetValue(); - - // Setup is required if either API key is empty, or contains a single - // character ("?") - return (mapboxApiKey.size() <= 1 && maptilerApiKey.size() <= 1); + return (MapProviderPage::IsRequired() || AudioCodecPage::IsRequired()); } } // namespace setup diff --git a/scwx-qt/source/scwx/qt/ui/setup/setup_wizard.hpp b/scwx-qt/source/scwx/qt/ui/setup/setup_wizard.hpp index d565c45a..c066cba9 100644 --- a/scwx-qt/source/scwx/qt/ui/setup/setup_wizard.hpp +++ b/scwx-qt/source/scwx/qt/ui/setup/setup_wizard.hpp @@ -19,12 +19,15 @@ public: Welcome = 0, MapProvider, MapLayout, + AudioCodec, Finish }; explicit SetupWizard(QWidget* parent = nullptr); ~SetupWizard(); + int nextId() const override; + static bool IsSetupRequired(); private: