From bf1ffb88753714cdcf834eb795775dd1b20a4558 Mon Sep 17 00:00:00 2001 From: James Turner Date: Mon, 30 Jan 2017 08:00:37 +0100 Subject: [PATCH] Proof-of-concept for new settings UI. --- src/GUI/AdditionalSettings.cpp | 16 + src/GUI/AdditionalSettings.h | 22 + src/GUI/AdditionalSettings.ui | 52 ++ src/GUI/AdvancedSettingsButton.cpp | 52 ++ src/GUI/AdvancedSettingsButton.h | 19 + src/GUI/CMakeLists.txt | 24 + src/GUI/DownloadSettings.cpp | 15 + src/GUI/DownloadSettings.h | 22 + src/GUI/DownloadSettings.ui | 52 ++ src/GUI/EnvironmentPage.cpp | 17 + src/GUI/EnvironmentPage.h | 22 + src/GUI/EnvironmentPage.ui | 262 ++++++++++ src/GUI/Launcher.ui | 814 ++++++++++++++--------------- src/GUI/MPSettings.cpp | 15 + src/GUI/MPSettings.h | 22 + src/GUI/MPSettings.ui | 160 ++++++ src/GUI/QtLauncher.cxx | 110 +++- src/GUI/QtLauncher_private.hxx | 1 + src/GUI/ToolboxButton.cpp | 46 ++ src/GUI/ToolboxButton.h | 19 + src/GUI/ViewSettings.cpp | 15 + src/GUI/ViewSettings.h | 22 + src/GUI/ViewSettings.ui | 157 ++++++ src/GUI/aircraftpreviewwindow.cpp | 16 + src/GUI/aircraftpreviewwindow.h | 28 + src/GUI/renderingsettings.cpp | 15 + src/GUI/renderingsettings.h | 22 + src/GUI/renderingsettings.ui | 229 ++++++++ src/GUI/resources.qrc | 7 + src/GUI/settings-gear-white.png | Bin 0 -> 2066 bytes src/GUI/settingssection.cpp | 109 ++++ src/GUI/settingssection.h | 53 ++ src/GUI/toolbox-aircraft.png | Bin 0 -> 1303 bytes src/GUI/toolbox-environment.png | Bin 0 -> 1130 bytes src/GUI/toolbox-fly.png | Bin 0 -> 1369 bytes src/GUI/toolbox-location.png | Bin 0 -> 1683 bytes src/GUI/toolbox-settings.png | Bin 0 -> 2066 bytes src/GUI/toolbox-summary.png | Bin 0 -> 868 bytes 38 files changed, 1979 insertions(+), 456 deletions(-) create mode 100644 src/GUI/AdditionalSettings.cpp create mode 100644 src/GUI/AdditionalSettings.h create mode 100644 src/GUI/AdditionalSettings.ui create mode 100644 src/GUI/AdvancedSettingsButton.cpp create mode 100644 src/GUI/AdvancedSettingsButton.h create mode 100644 src/GUI/DownloadSettings.cpp create mode 100644 src/GUI/DownloadSettings.h create mode 100644 src/GUI/DownloadSettings.ui create mode 100644 src/GUI/EnvironmentPage.cpp create mode 100644 src/GUI/EnvironmentPage.h create mode 100644 src/GUI/EnvironmentPage.ui create mode 100644 src/GUI/MPSettings.cpp create mode 100644 src/GUI/MPSettings.h create mode 100644 src/GUI/MPSettings.ui create mode 100644 src/GUI/ToolboxButton.cpp create mode 100644 src/GUI/ToolboxButton.h create mode 100644 src/GUI/ViewSettings.cpp create mode 100644 src/GUI/ViewSettings.h create mode 100644 src/GUI/ViewSettings.ui create mode 100644 src/GUI/aircraftpreviewwindow.cpp create mode 100644 src/GUI/aircraftpreviewwindow.h create mode 100644 src/GUI/renderingsettings.cpp create mode 100644 src/GUI/renderingsettings.h create mode 100644 src/GUI/renderingsettings.ui create mode 100644 src/GUI/settings-gear-white.png create mode 100644 src/GUI/settingssection.cpp create mode 100644 src/GUI/settingssection.h create mode 100644 src/GUI/toolbox-aircraft.png create mode 100644 src/GUI/toolbox-environment.png create mode 100644 src/GUI/toolbox-fly.png create mode 100644 src/GUI/toolbox-location.png create mode 100644 src/GUI/toolbox-settings.png create mode 100644 src/GUI/toolbox-summary.png diff --git a/src/GUI/AdditionalSettings.cpp b/src/GUI/AdditionalSettings.cpp new file mode 100644 index 000000000..c106be364 --- /dev/null +++ b/src/GUI/AdditionalSettings.cpp @@ -0,0 +1,16 @@ +#include "AdditionalSettings.h" + +#include "ui_AdditionalSettings.h" + +AdditionalSettings::AdditionalSettings(QWidget *parent) : + SettingsSection(parent), + ui(new Ui::AdditionalSettings) +{ + ui->setupUi(this); + insertSettingsHeader(); +} + +AdditionalSettings::~AdditionalSettings() +{ + delete ui; +} diff --git a/src/GUI/AdditionalSettings.h b/src/GUI/AdditionalSettings.h new file mode 100644 index 000000000..797fc387a --- /dev/null +++ b/src/GUI/AdditionalSettings.h @@ -0,0 +1,22 @@ +#ifndef ADDITIONAL_SETTINGS_H +#define ADDITIONAL_SETTINGS_H + +#include + +namespace Ui { +class AdditionalSettings; +} + +class AdditionalSettings : public SettingsSection +{ + Q_OBJECT + +public: + explicit AdditionalSettings(QWidget *parent = 0); + ~AdditionalSettings(); + +private: + Ui::AdditionalSettings *ui; +}; + +#endif // ADDITIONAL_SETTINGS_H diff --git a/src/GUI/AdditionalSettings.ui b/src/GUI/AdditionalSettings.ui new file mode 100644 index 000000000..a26f48c7e --- /dev/null +++ b/src/GUI/AdditionalSettings.ui @@ -0,0 +1,52 @@ + + + AdditionalSettings + + + + 0 + 0 + 771 + 331 + + + + Form + + + Additional settings + + + + + + Additional settings can be entered here. For information on available settings see <this page> + + + true + + + true + + + + + + + --prop:foo=42 + + + + + + + + SettingsSection + QWidget +
GUI/settingssection.h
+ 1 +
+
+ + +
diff --git a/src/GUI/AdvancedSettingsButton.cpp b/src/GUI/AdvancedSettingsButton.cpp new file mode 100644 index 000000000..a3f150909 --- /dev/null +++ b/src/GUI/AdvancedSettingsButton.cpp @@ -0,0 +1,52 @@ +#include "AdvancedSettingsButton.h" + +#include +#include +#include +#include + +const int MARGIN = 3; + +AdvancedSettingsButton::AdvancedSettingsButton() +{ + setCheckable(true); + setChecked(false); + setIcon(QIcon()); + + connect(this, &QAbstractButton::toggled, this, &AdvancedSettingsButton::updateUi); + + updateUi(); +} + +void AdvancedSettingsButton::paintEvent(QPaintEvent *event) +{ + QPixmap icon(":/settings-gear-white"); + + QPainter painter(this); + + painter.setPen(Qt::white); + const int h = height(); + QRect textRect = rect(); + textRect.setRight(textRect.right() - (h + MARGIN)); + painter.drawText(textRect, text(), Qt::AlignVCenter | Qt::AlignRight); + + QRect iconRect = rect(); + iconRect.setLeft(iconRect.right() - h); + iconRect.adjust(MARGIN, MARGIN, -MARGIN, -MARGIN); + painter.drawPixmap(iconRect, icon); +} + +QSize AdvancedSettingsButton::sizeHint() const +{ + const QFontMetrics f(font()); + const QRect bounds = f.boundingRect(text()); + const int height = bounds.height() + (MARGIN * 2); + return QSize(bounds.width() + 100 + height, height); +} + +void AdvancedSettingsButton::updateUi() +{ + const bool showAdvanced = isChecked(); + setText(showAdvanced ? tr("Show less") : tr("Show more")); + updateGeometry(); +} diff --git a/src/GUI/AdvancedSettingsButton.h b/src/GUI/AdvancedSettingsButton.h new file mode 100644 index 000000000..8dbdd4acd --- /dev/null +++ b/src/GUI/AdvancedSettingsButton.h @@ -0,0 +1,19 @@ +#ifndef ADVANCEDSETTINGSBUTTON_H +#define ADVANCEDSETTINGSBUTTON_H + +#include + +class AdvancedSettingsButton : public QAbstractButton +{ +public: + AdvancedSettingsButton(); + +protected: + virtual void paintEvent(QPaintEvent* event) override; + + virtual QSize sizeHint() const override; +private: + void updateUi(); +}; + +#endif // ADVANCEDSETTINGSBUTTON_H diff --git a/src/GUI/CMakeLists.txt b/src/GUI/CMakeLists.txt index 3f2b30cba..0db53282f 100644 --- a/src/GUI/CMakeLists.txt +++ b/src/GUI/CMakeLists.txt @@ -80,6 +80,12 @@ if (HAVE_QT) InstallSceneryDialog.ui EditCustomMPServerDialog.ui UpdateAllAircraft.ui + RenderingSettings.ui + ViewSettings.ui + MPSettings.ui + DownloadSettings.ui + EnvironmentPage.ui + AdditionalSettings.ui ) qt5_add_resources(qrc_sources resources.qrc) @@ -119,6 +125,24 @@ if (HAVE_QT) EditCustomMPServerDialog.hxx previewwindow.cpp previewwindow.h + SettingsSection.cpp + SettingsSection.h + renderingsettings.cpp + renderingsettings.h + ViewSettings.cpp + ViewSettings.h + MPSettings.cpp + MPSettings.h + AdvancedSettingsButton.h + AdvancedSettingsButton.cpp + DownloadSettings.cpp + DownloadSettings.h + ToolboxButton.cpp + ToolboxButton.h + EnvironmentPage.cpp + EnvironmentPage.h + AdditionalSettings.cpp + AdditionalSettings.h ${uic_sources} ${qrc_sources}) diff --git a/src/GUI/DownloadSettings.cpp b/src/GUI/DownloadSettings.cpp new file mode 100644 index 000000000..e80e47e53 --- /dev/null +++ b/src/GUI/DownloadSettings.cpp @@ -0,0 +1,15 @@ +#include "DownloadSettings.h" +#include "ui_DownloadSettings.h" + +DownloadSettings::DownloadSettings(QWidget *parent) : + SettingsSection(parent), + ui(new Ui::DownloadSettings) +{ + ui->setupUi(this); + insertSettingsHeader(); +} + +DownloadSettings::~DownloadSettings() +{ + delete ui; +} diff --git a/src/GUI/DownloadSettings.h b/src/GUI/DownloadSettings.h new file mode 100644 index 000000000..113cf4b3d --- /dev/null +++ b/src/GUI/DownloadSettings.h @@ -0,0 +1,22 @@ +#ifndef DOWNLOAD_SETTINGS_H +#define DOWNLOAD_SETTINGS_H + +#include + +namespace Ui { +class DownloadSettings; +} + +class DownloadSettings : public SettingsSection +{ + Q_OBJECT + +public: + explicit DownloadSettings(QWidget *parent = 0); + ~DownloadSettings(); + +private: + Ui::DownloadSettings *ui; +}; + +#endif // DOWNLOAD_SETTINGS_H diff --git a/src/GUI/DownloadSettings.ui b/src/GUI/DownloadSettings.ui new file mode 100644 index 000000000..106f304b3 --- /dev/null +++ b/src/GUI/DownloadSettings.ui @@ -0,0 +1,52 @@ + + + DownloadSettings + + + + 0 + 0 + 771 + 94 + + + + Form + + + Downloads + + + + + + Download scenery automatically + + + + + + + FlightGear can automatically download and update scenery wherever you fly in the world. This can take some time depening on your Internet connection's speed, but is faster than download the entire world's scenery. + + + true + + + true + + + + + + + + SettingsSection + QWidget +
GUI/settingssection.h
+ 1 +
+
+ + +
diff --git a/src/GUI/EnvironmentPage.cpp b/src/GUI/EnvironmentPage.cpp new file mode 100644 index 000000000..07a2ff7b1 --- /dev/null +++ b/src/GUI/EnvironmentPage.cpp @@ -0,0 +1,17 @@ +#include "EnvironmentPage.h" +#include "ui_EnvironmentPage.h" + +EnvironmentPage::EnvironmentPage(QWidget *parent) : + QWidget(parent), + ui(new Ui::EnvironmentPage) +{ + ui->setupUi(this); + + ui->weatherSection->insertSettingsHeader(); + ui->timeSection->insertSettingsHeader(); +} + +EnvironmentPage::~EnvironmentPage() +{ + delete ui; +} diff --git a/src/GUI/EnvironmentPage.h b/src/GUI/EnvironmentPage.h new file mode 100644 index 000000000..161646dd8 --- /dev/null +++ b/src/GUI/EnvironmentPage.h @@ -0,0 +1,22 @@ +#ifndef ENVIRONMENTPAGE_H +#define ENVIRONMENTPAGE_H + +#include + +namespace Ui { +class EnvironmentPage; +} + +class EnvironmentPage : public QWidget +{ + Q_OBJECT + +public: + explicit EnvironmentPage(QWidget *parent = 0); + ~EnvironmentPage(); + +private: + Ui::EnvironmentPage *ui; +}; + +#endif // ENVIRONMENTPAGE_H diff --git a/src/GUI/EnvironmentPage.ui b/src/GUI/EnvironmentPage.ui new file mode 100644 index 000000000..86084e5b3 --- /dev/null +++ b/src/GUI/EnvironmentPage.ui @@ -0,0 +1,262 @@ + + + EnvironmentPage + + + + 0 + 0 + 728 + 580 + + + + Form + + + + + + Time and Date + + + + + + + + Predefined time + + + true + + + + + + + Manually selected date and time + + + true + + + + + + + + Current local time + + + + + Dawn + + + + + Morning + + + + + Noon + + + + + Dusk + + + + + Midnight + + + + + + + + true + + + + + + + Time of day: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + + + By default the simulator uses your computer's local time as the local time at your chosen startup location. You can select a standard time of day, or enter an exact time and date. + + + true + + + true + + + + + + + + + + Weather + + + + + + + + Weather: + + + + + + + + Real-world weather + + + + + Clear and calm + + + + + Thunderstorm + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Choose a standard weather scenario, or download weather reports (METAR) automatically online, from the closest airports. + + + true + + + true + + + + + + + + + Season: + + + + + + + + Summer + + + + + Winter + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Changing the season affects which textures are used for scenery, but otherwise has no effect. + + + true + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + timeSection + label_2 + comboBox_2 + weatherSection + + + + SettingsSection + QWidget +
GUI/SettingsSection.h
+ 1 +
+
+ + +
diff --git a/src/GUI/Launcher.ui b/src/GUI/Launcher.ui index e7da4408d..22fea7a5d 100644 --- a/src/GUI/Launcher.ui +++ b/src/GUI/Launcher.ui @@ -6,8 +6,8 @@ 0 0 - 642 - 600 + 795 + 658 @@ -18,44 +18,220 @@ :/app-icon-large:/app-icon-large - + + + 0 + - 6 + 2 - 8 + 2 - 6 + 2 - 4 + 2 - - - - 1 + + + + + + + + + 255 + 255 + 255 + + + + + + + 8 + 84 + 236 + + + + + + + + + 255 + 255 + 255 + + + + + + + 8 + 84 + 236 + + + + + + + + + 8 + 84 + 236 + + + + + + + 8 + 84 + 236 + + + + + - - - Summary - - - - - - - 16 - - - - Settings: - - - Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing - - - + + true + + + QFrame::Box + + + QFrame::Plain + + + 0 + + + + 4 + + + 1 + + + 1 + + + 1 + + + 1 + + + + + Summary + + + + :/toolbox-summary:/toolbox-summary + + + 0 + + + + + + + Aircraft + + + + :/toolbox-aircraft:/toolbox-aircraft + + + 1 + + + + + + + Location + + + + :/toolbox-location:/toolbox-location + + + 2 + + + + + + + Environment + + + + :/toolbox-environment:/toolbox-environment + + + 3 + + + + + + + Settings + + + + :/toolbox-settings:/toolbox-settings + + + 4 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Fly! + + + + :/toolbox-fly:/toolbox-fly + + + + + + + + + + 0 + + + @@ -71,26 +247,28 @@ - - + + + + + 16 + + + + Settings: + + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + + + false - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -106,6 +284,13 @@ + + + + false + + + @@ -119,21 +304,6 @@ - - - - - 16 - - - - aircraft - - - true - - - @@ -149,10 +319,33 @@ - - - - false + + + + + 16 + + + + location + + + true + + + + + + + + 16 + + + + aircraft + + + true @@ -174,21 +367,6 @@ - - - - - 16 - - - - location - - - true - - - @@ -208,27 +386,58 @@ + + + + + 48 + 75 + true + + + + FlightGear 2017.1.0 + + + + + + + ©2017, Curtis L Olson. Licensed under the GNU Public License (GPL) version 2. See <here> for more information + + + true + + + + + + + + + + :/app-icon-large + + + - - - Aircraft - + 4 - 4 + 0 - 8 + 2 - 4 + 0 - 4 + 2 @@ -316,14 +525,16 @@ - - - Location - - + + + + 4 + + 4 + 4 @@ -331,358 +542,78 @@ 4 - - - - - - - Settings - - - - 8 - - - 8 - - - 8 - - - - - - 0 - 100 - - - - Multi-player - - + + true - - false - - - - - - Callsign: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Server: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 10 - - - G-FGFS - - - - - - - (Ten characters maximum) - - - - - - - - - - - - - Additional options - - - true - - - - 4 + + + + 0 + 0 + 173 + 28 + - - 4 - - - 4 - - - 4 - - - - - + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + 16 + 75 + true + + + + Settings contents + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Search... + + + + + + + - - - - Start full-screen - - - true - - - - - - - Enable Multi-sample anti-aliasing - - - true - - - - - - - Fetch real weather online - - - - - - - Start paused - - - true - - - - - - - Restore Defaults... - - - false - - - - - - - - - Time of day: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - Current time - - - - - Dawn - - - - - Morning - - - - - Noon - - - - - Afternoon - - - - - Dusk - - - - - Evening - - - - - Midnight - - - - - - - - - - Enable deferred rendering (Rembrandt) - - - true - - - - - - - Enable automatic scenery downloading (TerraSync) - - - - - - - <html><head/><body><p>For information on additional options, please <a href="http://flightgear.sourceforge.net/getstart-en/getstart-enpa2.html#x5-450004.5"><span style=" text-decoration: underline; color:#0000ff;">see here</span></a>.</p></body></html> - - - Qt::RichText - - - true - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 40 - 20 - - - - - - - - <html><head/><body><p>If scenery download is disabled, you may need to download additional files from <a href="http://www.flightgear.org/download/scenery/"><span style=" text-decoration: underline; color:#0000ff;">this page</span></a> and install them in a scenery location; otherwise some objects may be missing from the world.</p></body></html> - - - true - - - true - - - - - - - - - - - Season: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - Summer - - - - - Winter - - - - - - - - - - 0 - - - - - Quit - - - false - - - - - - - Qt::Horizontal - - - - 412 - 20 - - - - - - - - Run - - - false - - - false - - - false - - - - - @@ -693,6 +624,17 @@
GUI/LocationWidget.hxx
1 + + ToolboxButton + QPushButton +
GUI/ToolboxButton.h
+
+ + EnvironmentPage + QWidget +
GUI/EnvironmentPage.h
+ 1 +
diff --git a/src/GUI/MPSettings.cpp b/src/GUI/MPSettings.cpp new file mode 100644 index 000000000..648f45388 --- /dev/null +++ b/src/GUI/MPSettings.cpp @@ -0,0 +1,15 @@ +#include "MPSettings.h" +#include "ui_MPSettings.h" + +MPSettings::MPSettings(QWidget *parent) : + SettingsSection(parent), + ui(new Ui::MPSettings) +{ + ui->setupUi(this); + insertSettingsHeader(); +} + +MPSettings::~MPSettings() +{ + delete ui; +} diff --git a/src/GUI/MPSettings.h b/src/GUI/MPSettings.h new file mode 100644 index 000000000..9f01e553a --- /dev/null +++ b/src/GUI/MPSettings.h @@ -0,0 +1,22 @@ +#ifndef MP_SETTINGS_H +#define MP_SETTINGS_H + +#include + +namespace Ui { +class MPSettings; +} + +class MPSettings : public SettingsSection +{ + Q_OBJECT + +public: + explicit MPSettings(QWidget *parent = 0); + ~MPSettings(); + +private: + Ui::MPSettings *ui; +}; + +#endif // MP_SETTINGS_H diff --git a/src/GUI/MPSettings.ui b/src/GUI/MPSettings.ui new file mode 100644 index 000000000..6583e9a4a --- /dev/null +++ b/src/GUI/MPSettings.ui @@ -0,0 +1,160 @@ + + + MPSettings + + + + 0 + 0 + 771 + 331 + + + + Form + + + Multi-player + + + + + + Connect to the multi-player network + + + + + + + Fly with hundreds of other pilots around the world. + + + true + + + true + + + + + + + + + Callsign: + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Your call-sign identifies you to other pliots and controllers on the network. Callsigns are limited to ten characters. + + + true + + + true + + + + + + + + + Server: + + + true + + + + + + + true + + + + Automatic + + + + + Thread for culling and drawing + + + + + Separate threads for culling and drawing + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Choose a specific multiplayer server, or enter a custom server + + + true + + + true + + + true + + + + + + + + SettingsSection + QWidget +
GUI/settingssection.h
+ 1 +
+
+ + +
diff --git a/src/GUI/QtLauncher.cxx b/src/GUI/QtLauncher.cxx index 085ba9875..c804c2076 100644 --- a/src/GUI/QtLauncher.cxx +++ b/src/GUI/QtLauncher.cxx @@ -85,6 +85,12 @@ #include #include +#include "renderingsettings.h" +#include "ViewSettings.h" +#include "MPSettings.h" +#include "DownloadSettings.h" +#include "AdditionalSettings.h" + using namespace flightgear; using namespace simgear::pkg; using std::string; @@ -749,7 +755,7 @@ QtLauncher::QtLauncher() : #if QT_VERSION >= 0x050300 // don't require Qt 5.3 - m_ui->commandLineArgs->setPlaceholderText("--option=value --prop:/sim/name=value"); + //m_ui->commandLineArgs->setPlaceholderText("--option=value --prop:/sim/name=value"); #endif #if QT_VERSION >= 0x050200 @@ -778,8 +784,15 @@ QtLauncher::QtLauncher() : connect(m_ui->aircraftFilter, &QLineEdit::textChanged, m_aircraftProxy, &AircraftProxyModel::setAircraftFilterString); - connect(m_ui->runButton, SIGNAL(clicked()), this, SLOT(onRun())); - connect(m_ui->quitButton, SIGNAL(clicked()), this, SLOT(onQuit())); + connect(m_ui->flyButton, SIGNAL(clicked()), this, SLOT(onRun())); + connect(m_ui->summaryButton, &QAbstractButton::clicked, this, &QtLauncher::onClickToolboxButton); + connect(m_ui->aircraftButton, &QAbstractButton::clicked, this, &QtLauncher::onClickToolboxButton); + connect(m_ui->locationButton, &QAbstractButton::clicked, this, &QtLauncher::onClickToolboxButton); + connect(m_ui->environmentButton, &QAbstractButton::clicked, this, &QtLauncher::onClickToolboxButton); + connect(m_ui->settingsButton, &QAbstractButton::clicked, this, &QtLauncher::onClickToolboxButton); + + + // connect(m_ui->quitButton, SIGNAL(clicked()), this, SLOT(onQuit())); connect(m_ui->aircraftHistory, &QPushButton::clicked, this, &QtLauncher::onPopupAircraftHistory); @@ -803,6 +816,7 @@ QtLauncher::QtLauncher() : m_ui->aircraftHistory->setIcon(historyIcon); m_ui->locationHistory->setIcon(historyIcon); +#if 0 connect(m_ui->timeOfDayCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSettingsSummary())); connect(m_ui->seasonCombo, SIGNAL(currentIndexChanged(int)), @@ -827,11 +841,14 @@ QtLauncher::QtLauncher() : this, SLOT(onRembrandtToggled(bool))); connect(m_ui->terrasyncCheck, &QCheckBox::toggled, this, &QtLauncher::onToggleTerrasync); +#endif + updateSettingsSummary(); +#if 0 connect(m_ui->mpServerCombo, SIGNAL(activated(int)), this, SLOT(onMPServerActivated(int))); - +#endif m_aircraftModel = new AircraftItemModel(this); m_aircraftProxy->setSourceModel(m_aircraftModel); @@ -864,9 +881,10 @@ QtLauncher::QtLauncher() : this, &QtLauncher::onAircraftInstallFailed); connect(m_aircraftModel, &AircraftItemModel::scanCompleted, this, &QtLauncher::updateSelectedAircraft); +#if 0 connect(m_ui->restoreDefaultsButton, &QPushButton::clicked, this, &QtLauncher::onRestoreDefaults); - +#endif AddOnsPage* addOnsPage = new AddOnsPage(NULL, globals->packageRoot()); connect(addOnsPage, &AddOnsPage::downloadDirChanged, @@ -876,7 +894,7 @@ QtLauncher::QtLauncher() : connect(addOnsPage, &AddOnsPage::aircraftPathsChanged, this, &QtLauncher::onAircraftPathsChanged); - m_ui->tabWidget->addTab(addOnsPage, tr("Add-ons")); + // m_ui->tabWidget->addTab(addOnsPage, tr("Add-ons")); // after any kind of reset, try to restore selection and scroll // to match the m_selectedAircraft. This needs to be delayed // fractionally otherwise the scrollTo seems to be ignored, @@ -893,6 +911,24 @@ QtLauncher::QtLauncher() : restoreSettings(); onRefreshMPServers(); + + RenderingSettings* renderSettings = new RenderingSettings(m_ui->settingsScrollContents); + QVBoxLayout* settingsVBox = static_cast(m_ui->settingsScrollContents->layout()); + settingsVBox->addWidget(renderSettings); + + ViewSettings* viewSettings = new ViewSettings(m_ui->settingsScrollContents); + settingsVBox->addWidget(viewSettings); + + MPSettings* mpSettings = new MPSettings(m_ui->settingsScrollContents); + settingsVBox->addWidget(mpSettings); + + DownloadSettings* downloadSettings = new DownloadSettings(m_ui->settingsScrollContents); + settingsVBox->addWidget(downloadSettings); + + AdditionalSettings* addSettings = new AdditionalSettings(m_ui->settingsScrollContents); + settingsVBox->addWidget(addSettings); + + settingsVBox->addStretch(1); } QtLauncher::~QtLauncher() @@ -936,14 +972,14 @@ void QtLauncher::setSceneryPaths() // static method bool QtLauncher::execInApp() { m_inAppMode = true; - m_ui->tabWidget->removeTab(3); - m_ui->tabWidget->removeTab(3); + // m_ui->tabWidget->removeTab(3); + // m_ui->tabWidget->removeTab(3); - m_ui->runButton->setText(tr("Apply")); - m_ui->quitButton->setText(tr("Cancel")); + // m_ui->runButton->setText(tr("Apply")); + // m_ui->quitButton->setText(tr("Cancel")); - disconnect(m_ui->runButton, SIGNAL(clicked()), this, SLOT(onRun())); - connect(m_ui->runButton, SIGNAL(clicked()), this, SLOT(onApply())); + disconnect(m_ui->flyButton, SIGNAL(clicked()), this, SLOT(onRun())); + connect(m_ui->flyButton, SIGNAL(clicked()), this, SLOT(onApply())); m_runInApp = true; show(); @@ -961,6 +997,7 @@ void QtLauncher::restoreSettings() restoreGeometry(settings.value("window-geometry").toByteArray()); +#if 0 m_ui->rembrandtCheckbox->setChecked(settings.value("enable-rembrandt", false).toBool()); m_ui->terrasyncCheck->setChecked(settings.value("enable-terrasync", true).toBool()); m_ui->fullScreenCheckbox->setChecked(settings.value("start-fullscreen", false).toBool()); @@ -969,7 +1006,7 @@ void QtLauncher::restoreSettings() m_ui->startPausedCheck->setChecked(settings.value("start-paused", false).toBool()); m_ui->timeOfDayCombo->setCurrentIndex(settings.value("timeofday", 0).toInt()); m_ui->seasonCombo->setCurrentIndex(settings.value("season", 0).toInt()); - +#endif // full paths to -set.xml files m_recentAircraft = QUrl::fromStringList(settings.value("recent-aircraft").toStringList()); @@ -1026,11 +1063,12 @@ void QtLauncher::restoreSettings() updateSelectedAircraft(); maybeRestoreAircraftSelection(); - +#if 0 m_ui->commandLineArgs->setPlainText(settings.value("additional-args").toString()); m_ui->mpBox->setChecked(settings.value("mp-enabled").toBool()); m_ui->mpCallsign->setText(settings.value("mp-callsign").toString()); +#endif // don't restore MP server here, we do it after a refresh m_doRestoreMPServer = true; } @@ -1059,17 +1097,21 @@ void QtLauncher::maybeRestoreAircraftSelection() void QtLauncher::saveSettings() { QSettings settings; +#if 0 settings.setValue("enable-rembrandt", m_ui->rembrandtCheckbox->isChecked()); settings.setValue("enable-terrasync", m_ui->terrasyncCheck->isChecked()); settings.setValue("enable-msaa", m_ui->msaaCheckbox->isChecked()); settings.setValue("start-fullscreen", m_ui->fullScreenCheckbox->isChecked()); settings.setValue("enable-realwx", m_ui->fetchRealWxrCheckbox->isChecked()); settings.setValue("start-paused", m_ui->startPausedCheck->isChecked()); +#endif + settings.setValue("ratings-filter", m_ui->ratingsFilterCheck->isChecked()); settings.setValue("only-show-installed", m_ui->onlyShowInstalledCheck->isChecked()); settings.setValue("recent-aircraft", QUrl::toStringList(m_recentAircraft)); settings.setValue("recent-location-sets", m_recentLocations); +#if 0 settings.setValue("timeofday", m_ui->timeOfDayCombo->currentIndex()); settings.setValue("season", m_ui->seasonCombo->currentIndex()); settings.setValue("additional-args", m_ui->commandLineArgs->toPlainText()); @@ -1077,7 +1119,7 @@ void QtLauncher::saveSettings() settings.setValue("mp-callsign", m_ui->mpCallsign->text()); settings.setValue("mp-server", m_ui->mpServerCombo->currentData()); settings.setValue("mp-enabled", m_ui->mpBox->isChecked()); - +#endif settings.setValue("window-geometry", saveGeometry()); } @@ -1100,6 +1142,7 @@ void QtLauncher::closeEvent(QCloseEvent *event) void QtLauncher::onRun() { flightgear::Options* opt = flightgear::Options::sharedInstance(); +#if 0 setEnableDisableOptionFromCheckbox(m_ui->terrasyncCheck, "terrasync"); setEnableDisableOptionFromCheckbox(m_ui->fetchRealWxrCheckbox, "real-weather-fetch"); setEnableDisableOptionFromCheckbox(m_ui->rembrandtCheckbox, "rembrandt"); @@ -1111,7 +1154,9 @@ void QtLauncher::onRun() if (startPaused) { opt->addOption("enable-freeze", ""); } +#endif +#if 0 // MSAA is more complex if (!m_ui->rembrandtCheckbox->isChecked()) { if (m_ui->msaaCheckbox->isChecked()) { @@ -1121,6 +1166,7 @@ void QtLauncher::onRun() globals->get_props()->setIntValue("/sim/rendering/multi-sample-buffers", 0); } } +#endif // aircraft if (!m_selectedAircraft.isEmpty()) { @@ -1148,6 +1194,7 @@ void QtLauncher::onRun() m_recentAircraft.pop_back(); } +#if 0 if (m_ui->mpBox->isChecked()) { std::string callSign = m_ui->mpCallsign->text().toStdString(); if (!callSign.empty()) { @@ -1169,10 +1216,12 @@ void QtLauncher::onRun() globals->get_props()->setStringValue("/sim/multiplay/txhost", host.toStdString()); globals->get_props()->setIntValue("/sim/multiplay/txport", port); } +#endif m_ui->location->setLocationProperties(); updateLocationHistory(); +#if 0 // time of day if (m_ui->timeOfDayCombo->currentIndex() != 0) { QString dayval = m_ui->timeOfDayCombo->currentText().toLower(); @@ -1183,6 +1232,7 @@ void QtLauncher::onRun() QString seasonName = m_ui->seasonCombo->currentText().toLower(); opt->addOption("season", seasonName.toStdString()); } +#endif QSettings settings; QString downloadDir = settings.value("download-dir").toString(); @@ -1216,6 +1266,7 @@ void QtLauncher::onRun() } // additional arguments +#if 0 ArgumentsTokenizer tk; Q_FOREACH(ArgumentsTokenizer::Arg a, tk.tokenize(m_ui->commandLineArgs->toPlainText())) { if (a.arg.startsWith("prop:")) { @@ -1230,6 +1281,7 @@ void QtLauncher::onRun() opt->addOption(a.arg.toStdString(), a.value.toStdString()); } } +#endif if (settings.contains("restore-defaults-on-run")) { settings.remove("restore-defaults-on-run"); @@ -1329,7 +1381,7 @@ void QtLauncher::onToggleTerrasync(bool enabled) int result = msg.exec(); if (result == QMessageBox::Cancel) { - m_ui->terrasyncCheck->setChecked(false); + //m_ui->terrasyncCheck->setChecked(false); return; } @@ -1472,7 +1524,7 @@ void QtLauncher::updateSelectedAircraft() int status = index.data(AircraftPackageStatusRole).toInt(); bool canRun = (status == PackageInstalled); - m_ui->runButton->setEnabled(canRun); + m_ui->flyButton->setEnabled(canRun); LauncherAircraftType aircraftType = Airplane; if (index.data(AircraftIsHelicopterRole).toBool()) { @@ -1486,7 +1538,7 @@ void QtLauncher::updateSelectedAircraft() m_ui->thumbnail->setPixmap(QPixmap()); m_ui->aircraftName->setText(""); m_ui->aircraftDescription->hide(); - m_ui->runButton->setEnabled(false); + m_ui->flyButton->setEnabled(false); } } @@ -1504,6 +1556,15 @@ void QtLauncher::onPackagesNeedUpdate(bool yes) checkUpdateAircraft(); } +void QtLauncher::onClickToolboxButton() +{ + int pageIndex = sender()->property("pageIndex").toInt(); + m_ui->stack->setCurrentIndex(pageIndex); + Q_FOREACH (ToolboxButton* tb, findChildren()) { + tb->setChecked(tb->property("pageIndex").toInt() == pageIndex); + } +} + QModelIndex QtLauncher::proxyIndexForAircraftURI(QUrl uri) const { return m_aircraftProxy->mapFromSource(sourceIndexForAircraftURI(uri)); @@ -1589,6 +1650,7 @@ void QtLauncher::onEditRatingsFilter() void QtLauncher::updateSettingsSummary() { QStringList summary; +#if 0 if (m_ui->timeOfDayCombo->currentIndex() > 0) { summary.append(QString(m_ui->timeOfDayCombo->currentText().toLower())); } @@ -1622,12 +1684,13 @@ void QtLauncher::updateSettingsSummary() QString s = summary.join(", "); s[0] = s[0].toUpper(); m_ui->settingsDescription->setText(s); +#endif } void QtLauncher::onRembrandtToggled(bool b) { // Rembrandt and multi-sample are exclusive - m_ui->msaaCheckbox->setEnabled(!b); + // m_ui->msaaCheckbox->setEnabled(!b); } void QtLauncher::onShowInstalledAircraftToggled(bool b) @@ -1750,6 +1813,7 @@ void QtLauncher::onRefreshMPServers() void QtLauncher::onRefreshMPServersDone(simgear::HTTP::Request*) { +#if 0 // parse the properties SGPropertyNode *targetnode = fgGetNode("/sim/multiplay/server-list", true); m_ui->mpServerCombo->clear(); @@ -1773,7 +1837,7 @@ void QtLauncher::onRefreshMPServersDone(simgear::HTTP::Request*) EditCustomMPServerDialog::addCustomItem(m_ui->mpServerCombo); restoreMPServerSelection(); - +#endif m_mpServerRequest.clear(); } @@ -1781,12 +1845,15 @@ void QtLauncher::onRefreshMPServersFailed(simgear::HTTP::Request*) { qWarning() << "refreshing MP servers failed:" << QString::fromStdString(m_mpServerRequest->responseReason()); m_mpServerRequest.clear(); +#if 0 EditCustomMPServerDialog::addCustomItem(m_ui->mpServerCombo); restoreMPServerSelection(); +#endif } void QtLauncher::restoreMPServerSelection() { +#if 0 if (m_doRestoreMPServer) { QSettings settings; int index = m_ui->mpServerCombo->findData(settings.value("mp-server")); @@ -1795,10 +1862,12 @@ void QtLauncher::restoreMPServerSelection() } m_doRestoreMPServer = false; } +#endif } void QtLauncher::onMPServerActivated(int index) { +#if 0 if (m_ui->mpServerCombo->itemData(index) == "custom") { EditCustomMPServerDialog dlg(this); dlg.exec(); @@ -1806,6 +1875,7 @@ void QtLauncher::onMPServerActivated(int index) m_ui->mpServerCombo->setItemText(index, tr("Custom - %1").arg(dlg.hostname())); } } +#endif } int QtLauncher::findMPServerPort(const std::string& host) diff --git a/src/GUI/QtLauncher_private.hxx b/src/GUI/QtLauncher_private.hxx index ed6430a53..3ca4d7080 100644 --- a/src/GUI/QtLauncher_private.hxx +++ b/src/GUI/QtLauncher_private.hxx @@ -109,6 +109,7 @@ private slots: void onPackagesNeedUpdate(bool yes); + void onClickToolboxButton(); void onAircraftPathsChanged(); private: diff --git a/src/GUI/ToolboxButton.cpp b/src/GUI/ToolboxButton.cpp new file mode 100644 index 000000000..fe6d8706d --- /dev/null +++ b/src/GUI/ToolboxButton.cpp @@ -0,0 +1,46 @@ +#include "ToolboxButton.h" + +#include +#include + +const int ICON_SIZE = 50; +const int INDICATOR_WIDTH = 4; +const int PADDING = 8; + +ToolboxButton::ToolboxButton(QWidget *pr) : + QAbstractButton(pr) +{ + setCheckable(true); +} + +void ToolboxButton::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + + if (isChecked()) { + QRect indicatorRect = rect(); + indicatorRect.setWidth(INDICATOR_WIDTH); + painter.fillRect(indicatorRect, Qt::white); + } + + const int iconLeft = (width() - ICON_SIZE) / 2; + QRect iconRect(iconLeft, PADDING, ICON_SIZE, ICON_SIZE); + + icon().paint(&painter, iconRect); + + painter.setPen(Qt::white); + QRect textRect = rect(); + textRect.setTop(iconRect.bottom()); + painter.drawText(textRect, Qt::AlignHCenter, text()); +} + +QSize ToolboxButton::sizeHint() const +{ + QSize icon(ICON_SIZE, ICON_SIZE); + + QFontMetrics metrics(font()); + QRect bounds = metrics.boundingRect(text()); + + const int PAD_2 = PADDING * 2; + return QSize(qMax(ICON_SIZE, bounds.width()) + PAD_2, ICON_SIZE + bounds.height() + PAD_2); +} diff --git a/src/GUI/ToolboxButton.h b/src/GUI/ToolboxButton.h new file mode 100644 index 000000000..6946b710c --- /dev/null +++ b/src/GUI/ToolboxButton.h @@ -0,0 +1,19 @@ +#ifndef TOOLBOXBUTTON_H +#define TOOLBOXBUTTON_H + +#include + +class ToolboxButton : public QAbstractButton +{ +public: + ToolboxButton(QWidget* pr = nullptr); + +protected: + virtual void paintEvent(QPaintEvent* event) override; + + virtual QSize sizeHint() const override; + +private: +}; + +#endif // TOOLBOXBUTTON_H diff --git a/src/GUI/ViewSettings.cpp b/src/GUI/ViewSettings.cpp new file mode 100644 index 000000000..6ea6d8843 --- /dev/null +++ b/src/GUI/ViewSettings.cpp @@ -0,0 +1,15 @@ +#include "ViewSettings.h" +#include "ui_ViewSettings.h" + +ViewSettings::ViewSettings(QWidget *parent) : + SettingsSection(parent), + ui(new Ui::ViewSettings) +{ + ui->setupUi(this); + insertSettingsHeader(); +} + +ViewSettings::~ViewSettings() +{ + delete ui; +} diff --git a/src/GUI/ViewSettings.h b/src/GUI/ViewSettings.h new file mode 100644 index 000000000..f1f64e7f9 --- /dev/null +++ b/src/GUI/ViewSettings.h @@ -0,0 +1,22 @@ +#ifndef VIEWSETTINGS_H +#define VIEWSETTINGS_H + +#include + +namespace Ui { +class ViewSettings; +} + +class ViewSettings : public SettingsSection +{ + Q_OBJECT + +public: + explicit ViewSettings(QWidget *parent = 0); + ~ViewSettings(); + +private: + Ui::ViewSettings *ui; +}; + +#endif // VIEWSETTINGS_H diff --git a/src/GUI/ViewSettings.ui b/src/GUI/ViewSettings.ui new file mode 100644 index 000000000..6e732fba6 --- /dev/null +++ b/src/GUI/ViewSettings.ui @@ -0,0 +1,157 @@ + + + ViewSettings + + + + 0 + 0 + 740 + 338 + + + + Form + + + View + + + + + + Start full-screen + + + + + + + Full-screen mode can be toggled inside the simulator by pressing F10. + + + true + + + true + + + + + + + + + Window size: + + + true + + + + + + + true + + + + 800 x 600 + + + + + 1024 x 768 + + + + + Custom size... + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Field-of-view angle: + + + true + + + + + + + 180 + + + 90 + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Field-of-view depends on your monitor size. It can be adjusted in the simulator using the x/X keys + + + true + + + true + + + true + + + + + + + + SettingsSection + QWidget +
GUI/settingssection.h
+ 1 +
+
+ + +
diff --git a/src/GUI/aircraftpreviewwindow.cpp b/src/GUI/aircraftpreviewwindow.cpp new file mode 100644 index 000000000..3c641a527 --- /dev/null +++ b/src/GUI/aircraftpreviewwindow.cpp @@ -0,0 +1,16 @@ +#include "aircraftpreviewwindow.h" + +AircraftPreviewWindow::AircraftPreviewWindow(QWidget *parent) : QWidget(parent) +{ + // setWindowFlags(); // frameless ? +} + +void AircraftPreviewWindow::setUrls(QList urls) +{ + +} + +void AircraftPreviewWindow::paintEvent(QPaintEvent *event) +{ + +} diff --git a/src/GUI/aircraftpreviewwindow.h b/src/GUI/aircraftpreviewwindow.h new file mode 100644 index 000000000..f60dd2807 --- /dev/null +++ b/src/GUI/aircraftpreviewwindow.h @@ -0,0 +1,28 @@ +#ifndef AIRCRAFTPREVIEWWINDOW_H +#define AIRCRAFTPREVIEWWINDOW_H + +#include +#include + +class AircraftPreviewWindow : public QWidget +{ + Q_OBJECT +public: + explicit AircraftPreviewWindow(QWidget *parent = 0); + + void setUrls(QList urls); +signals: + +public slots: + +protected: + virtual void paintEvent(QPaintEvent* event) override; + +private: + unsigned int m_currentIndex = 0; + + QList m_urls; + QList m_pixmaps; // lazily populated +}; + +#endif // AIRCRAFTPREVIEWWINDOW_H diff --git a/src/GUI/renderingsettings.cpp b/src/GUI/renderingsettings.cpp new file mode 100644 index 000000000..2d00bfd94 --- /dev/null +++ b/src/GUI/renderingsettings.cpp @@ -0,0 +1,15 @@ +#include "renderingsettings.h" +#include "ui_renderingsettings.h" + +RenderingSettings::RenderingSettings(QWidget *parent) : + SettingsSection(parent), + ui(new Ui::RenderingSettings) +{ + ui->setupUi(this); + insertSettingsHeader(); +} + +RenderingSettings::~RenderingSettings() +{ + delete ui; +} diff --git a/src/GUI/renderingsettings.h b/src/GUI/renderingsettings.h new file mode 100644 index 000000000..fb16ef323 --- /dev/null +++ b/src/GUI/renderingsettings.h @@ -0,0 +1,22 @@ +#ifndef RENDERINGSETTINGS_H +#define RENDERINGSETTINGS_H + +#include + +namespace Ui { +class RenderingSettings; +} + +class RenderingSettings : public SettingsSection +{ + Q_OBJECT + +public: + explicit RenderingSettings(QWidget *parent = 0); + ~RenderingSettings(); + +private: + Ui::RenderingSettings *ui; +}; + +#endif // RENDERINGSETTINGS_H diff --git a/src/GUI/renderingsettings.ui b/src/GUI/renderingsettings.ui new file mode 100644 index 000000000..d141c060e --- /dev/null +++ b/src/GUI/renderingsettings.ui @@ -0,0 +1,229 @@ + + + RenderingSettings + + + + 0 + 0 + 771 + 331 + + + + Form + + + Rendering + + + + + + + + Renderer: + + + + + + + + ALS + + + + + Rembrandt + + + + + Default + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Lots of information about which renderer is selcted + + + true + + + + + + + Enable multi-sample anti-aliasingg + + + + + + + Multi-sample anti-aliasing (MSAA) reduces the appearance of jagged edges. Depending on your graphics card, this may reduce framerates + + + true + + + true + + + + + + + + + Multi-sampling setting: + + + true + + + + + + + true + + + + 2x + + + + + 4x + + + + + 8x + + + + + 16x + + + + + Custom... + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Renderer threading model: + + + true + + + + + + + true + + + + Automatic + + + + + Thread for culling and drawing + + + + + Separate threads for culling and drawing + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Choose how the rendering code uses multiple CPU cores to get the best performance. Automatic selection is usually recommended, and some settings can lead to problems including crashes. + + + true + + + true + + + true + + + + + + + + SettingsSection + QWidget +
GUI/settingssection.h
+ 1 +
+
+ + +
diff --git a/src/GUI/resources.qrc b/src/GUI/resources.qrc index 45be6a206..a726a7c01 100644 --- a/src/GUI/resources.qrc +++ b/src/GUI/resources.qrc @@ -20,6 +20,13 @@ airplane-icon.png airport-closed-icon.png preview-icon.png + settings-gear-white.png + toolbox-aircraft.png + toolbox-environment.png + toolbox-fly.png + toolbox-location.png + toolbox-settings.png + toolbox-summary.png preview-close.png diff --git a/src/GUI/settings-gear-white.png b/src/GUI/settings-gear-white.png new file mode 100644 index 0000000000000000000000000000000000000000..b5205728924da25681edda3f5bd83128800768b9 GIT binary patch literal 2066 zcmV+t2<`WYP)Px+%t=H+RA>d&nrVoYRT#$|cg%20P|F2v(NfdQHPI>Six7$}YC%O|rG-T+6e@~_ zX$vMqnIl?a^&zxHsnjG>(P_gaGo8F@VF_BASvu;x{r=~k=W_0QulJ7Qy)*Q{f1dR` z&pGdVw)bkidUZ%q6m|Dx?+UiL;0Txpu8#ZbT&Gj@!JFU=Fp}KQI)_{es?6!- z#qbh~sdG+eS_d6`5BXiMe+_Q{8i5_&HXr`BmrubP*ZBa#4$z@JzH`0d7lQ*{-yg_3 zksE{IK(r;y5z6&LrIzJQzTS|Ml9J=d6Tw-~33LRN;9-2?1AwSJ$uj@e+CX@kEn?-5 zc-?i94zEOS2iky3KznTK;iBu3%ni)E1mn#TaQvnh-C7P3uK(C5^C+2B(3M9)xx}@hj7Ui=j~D zSs?lt^aGQ?A~4$OA!|Fn2do9^m`IEN5s;ex$hQE!O}(Ku;0+*}Z@G%bDe|2w6-DpE zo5u@b(;##{7#&0S(-imzAY&b1>i{&xM7!d73$9b-NnlfAAM(hs2>L@n^cT1rXkaB^ zEI0u~Q(|rI!)AjOzccg~O{P#^P!2>IR9h>CyiG=EoY{J40GrIELId)hjXAG=MhiXgrj_CI`^-{5zd zuc(|t4+1+!4kF(X7DU&!E7G<*4Ycx@0N0cgO^UVAn%nF=$v;a&e^F%WZ1M$Hz~k2x zJ$3C+b9{`L-k6;w(%%9Z(@r*E?GDwb^Caj4Z2LoWq($i#ahMd_<4Je42Cgag09XLV z#^P?pwh^2HdJ{{*D3JR8K)xU7(A1%*?Rhy6%?Wc=Tc+VW*F5vj%y<$)T7thbL*0{q zG)sI#Vr@aE+}NJVl0zoFy^IH#YM4u)p`EDi!iPQ{h?Zw-hkd&9Mo|L347>m;foO8J zHld9eTlBhHJqKoj&%t3ZJ&aA0akc>Za?||G*y6D1<44q84dK0<#-5*+DCyH1QJzmh zYKTMMsSY+g{bslx#1CHI1>Xepu#N-0CB0Sk;UAFyo1LJ= zK(rTh0=iaA0oEZzH@7uE2gL?52-|89#;W)%psR>FlmMb7;9n;t+ejDf22GV0UM2(d z70@)dx79bSn^h**cB8Gxb~RAa!C)=W8|jd>u{YxH2<8KArKJ{&+yp4E=ru46*zFe4 zy@4Bp_}18dm%~#fd=aSD8);6Uo{DI$B`pLepDoxu$Zj3MHDxA)a_~&N4z>|M4`eE6 zANS|fX)q9IdgxV_<_xZ;lRU$GKII);&1M%KMlsE6(I?rmVQ&aZfext!o=dk|ZCW$z z>wsuhnxlY9*23g(=4)(?*P=5$u`L1i6HOSR&)R$W8D~dmME)6+f-|6Yh>qwBOxI-X zD*AmXMd&*Cv?YpkzAOY2J(n($zgMae0(v)~sroBO9g1Ph1U&;Yh0S$T;P~F0;84`tCAgcQjKt(UNPKu+Ck`vks z++H90eN0pDSKO%3kFKkSrk-v9A)N^0YAgpCMSVqOX!k1|k@y%0Npn~y?G<4a^g^r=Z34P#gmf&d zQ)8Ko{ecd^4?zXcHYrN`l^Z?WwaU=b){=Bkon7k;ak{3g0IJ)+#+}dAki@#I9R)f^ z+J>>{JwZ**k*>7U13CzrhdGNXQ*0g(&5jqsrontGXBLt@WA0*LDuK#Y@lgjbQ0ks&?oE!y0-DvKp#&=+NpFg zR37C^0MW9rZNX&Q#ZCt{DCJ22k@6Sk zDj(}mI2aYyH@tQ!N67kK5$QZ}hay~urGBcZ0>Gu5pAv%8zIN;xcu?hs8@^wQ00eJ$B{_^Zy$^ZZW07*qoM6N<$f~u +#include +#include +#include +#include +#include + +#include "AdvancedSettingsButton.h" + +SettingsSection::SettingsSection(QWidget* pr) : + QFrame(pr) +{ + m_titleLabel = new QLabel; + QFont titleFont = m_titleLabel->font(); + titleFont.setPointSize(14); + titleFont.setBold(true); + m_titleLabel->setFont(titleFont); + + QPalette pal = palette(); + pal.setColor(QPalette::Normal, QPalette::WindowText, Qt::white); + m_titleLabel->setPalette(pal); +} + +void SettingsSection::setShowAdvanced(bool showAdvanced) +{ + if (m_showAdvanced == showAdvanced) + return; + + m_showAdvanced = showAdvanced; + internalUpdateAdvanced(); + emit showAdvancedChanged(showAdvanced); +} + +void SettingsSection::setTitle(QString title) +{ + if (m_title == title) + return; + + m_title = title; + m_titleLabel->setText(m_title); + emit titleChanged(title); +} + +void SettingsSection::toggleShowAdvanced() +{ + setShowAdvanced(!m_showAdvanced); +} + +void SettingsSection::insertSettingsHeader() +{ + QVBoxLayout* topLevelVBox = qobject_cast(layout()); + Q_ASSERT(topLevelVBox); + + topLevelVBox->setMargin(0); + + QFrame* headerPanel = new QFrame(this); + headerPanel->setFrameStyle(QFrame::Box); + headerPanel->setAutoFillBackground(true); + + QPalette p = headerPanel->palette(); + p.setColor(QPalette::Normal, QPalette::Background, QColor(0x7f, 0x7f, 0x7f)); + p.setColor(QPalette::Normal, QPalette::Foreground, Qt::black); + p.setColor(QPalette::Normal, QPalette::WindowText, Qt::white); + headerPanel->setPalette(p); + + topLevelVBox->insertWidget(0, headerPanel); + + QHBoxLayout* hbox = new QHBoxLayout(headerPanel); + hbox->setContentsMargins(32, 0, 32, 0); + headerPanel->setLayout(hbox); + + hbox->addWidget(m_titleLabel); + hbox->addStretch(1); + + m_advancedModeToggle = new AdvancedSettingsButton; + connect(m_advancedModeToggle, &QPushButton::toggled, this, &SettingsSection::toggleShowAdvanced); + + hbox->addWidget(m_advancedModeToggle); + + QFont helpLabelFont; + helpLabelFont.setPointSize(helpLabelFont.pointSize() - 1); + + QPalette pal = palette(); + pal.setColor(QPalette::Normal, QPalette::WindowText, QColor(0x3f, 0x3f, 0x3f)); + + Q_FOREACH(QLabel* w, findChildren()) { + if (w->property("help").toBool()) { + w->setFont(helpLabelFont); + w->setPalette(pal); + } + } + + internalUpdateAdvanced(); +} + +void SettingsSection::internalUpdateAdvanced() +{ + Q_FOREACH(QWidget* w, findChildren()) { + if (w->property("advanced").toBool()) { + w->setVisible(m_showAdvanced); + } + + if (w->property("simple").toBool()) { + w->setVisible(!m_showAdvanced); + } + } +} diff --git a/src/GUI/settingssection.h b/src/GUI/settingssection.h new file mode 100644 index 000000000..cbb20ccff --- /dev/null +++ b/src/GUI/settingssection.h @@ -0,0 +1,53 @@ +#ifndef SETTINGSSECTION_H +#define SETTINGSSECTION_H + +#include +#include + +class AdvancedSettingsButton; + +class SettingsSection : public QFrame +{ + Q_OBJECT + + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) + + Q_PROPERTY(bool showAdvanced READ showAdvanced WRITE setShowAdvanced NOTIFY showAdvancedChanged) + +public: + SettingsSection(QWidget* pr = nullptr); + + bool showAdvanced() const + { + return m_showAdvanced; + } + + QString title() const + { + return m_title; + } + + void insertSettingsHeader(); + +public slots: + void setShowAdvanced(bool showAdvanced); + + void setTitle(QString title); + + void toggleShowAdvanced(); +signals: + void showAdvancedChanged(bool showAdvanced); + + void titleChanged(QString title); + +private: + void internalUpdateAdvanced(); + + QString m_title; + bool m_showAdvanced = false; + + QLabel* m_titleLabel; + AdvancedSettingsButton* m_advancedModeToggle; +}; + +#endif // SETTINGSSECTION_H diff --git a/src/GUI/toolbox-aircraft.png b/src/GUI/toolbox-aircraft.png new file mode 100644 index 0000000000000000000000000000000000000000..bcf167bc27bce729d0983b7bd41b5c61569a3e57 GIT binary patch literal 1303 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 t7M%U~hYfkXoxf^T3V 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