1
0
Fork 0

QML-driven settings UI.

This commit is contained in:
James Turner 2017-02-21 11:01:06 +00:00
parent 5c713a6b55
commit 3732930269
59 changed files with 2768 additions and 2011 deletions

View file

@ -311,7 +311,7 @@ endif (USE_DBUS)
## Qt5 setup setup
if (ENABLE_QT)
message(STATUS "Qt launcher enabled, checking for Qt 5.1 / qmake")
find_package(Qt5 5.1 COMPONENTS Widgets Network)
find_package(Qt5 5.1 COMPONENTS Widgets Network Qml)
if (Qt5Widgets_FOUND)
message(STATUS "Will enable Qt launcher GUI")
message(STATUS " Qt5Widgets version: ${Qt5Widgets_VERSION_STRING}")

View file

@ -1,16 +0,0 @@
#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;
}

View file

@ -1,22 +0,0 @@
#ifndef ADDITIONAL_SETTINGS_H
#define ADDITIONAL_SETTINGS_H
#include <GUI/settingssection.h>
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

View file

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AdditionalSettings</class>
<widget class="SettingsSection" name="AdditionalSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>771</width>
<height>331</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="title" stdset="0">
<string>Additional settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Additional settings can be entered here. For information on available settings see &lt;this page&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="plainTextEdit">
<property name="placeholderText">
<string>--prop:foo=42</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SettingsSection</class>
<extends>QWidget</extends>
<header location="global">GUI/settingssection.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -78,14 +78,7 @@ if (HAVE_QT)
LocationWidget.ui
NoOfficialHangar.ui
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)
@ -102,6 +95,8 @@ if (HAVE_QT)
NavaidDiagram.hxx
EditRatingsFilterDialog.cxx
EditRatingsFilterDialog.hxx
ExtraSettingsSection.cxx
ExtraSettingsSection.hxx
SetupRootDialog.cxx
SetupRootDialog.hxx
AircraftItemDelegate.hxx
@ -122,40 +117,37 @@ if (HAVE_QT)
QtFileDialog.hxx
InstallSceneryDialog.hxx
InstallSceneryDialog.cxx
EditCustomMPServerDialog.cxx
EditCustomMPServerDialog.hxx
previewwindow.cpp
previewwindow.h
SettingsSection.cpp
SettingsSection.h
renderingsettings.cpp
renderingsettings.h
ViewSettings.cpp
ViewSettings.h
MPSettings.cpp
MPSettings.h
SettingsSectionQML.cxx
SettingsSectionQML.hxx
AdvancedSettingsButton.h
AdvancedSettingsButton.cpp
DownloadSettings.cpp
DownloadSettings.h
ToolboxButton.cpp
ToolboxButton.h
EnvironmentPage.cpp
EnvironmentPage.h
AdditionalSettings.cpp
AdditionalSettings.h
LauncherArgumentTokenizer.cxx
LauncherArgumentTokenizer.hxx
AircraftSearchFilterModel.cxx
AircraftSearchFilterModel.hxx
DefaultAircraftLocator.cxx
DefaultAircraftLocator.hxx
SettingsWidgets.cxx
SettingsWidgets.hxx
LaunchConfig.cxx
LaunchConfig.hxx
ViewCommandLinePage.cxx
ViewCommandLinePage.hxx
MPServersModel.cpp
MPServersModel.h
${uic_sources}
${qrc_sources})
set_property(TARGET fglauncher PROPERTY AUTOMOC ON)
target_link_libraries(fglauncher Qt5::Core Qt5::Widgets Qt5::Network SimGearCore)
target_link_libraries(fglauncher Qt5::Core Qt5::Widgets Qt5::Network Qt5::Qml SimGearCore)
target_include_directories(fglauncher PRIVATE ${PROJECT_BINARY_DIR}/src/GUI)
target_include_directories(fglauncher PRIVATE ${Qt5Qml_PRIVATE_INCLUDE_DIRS})
endif()

View file

@ -65,4 +65,82 @@ DefaultAircraftLocator::visit(const SGPath& p)
return VISIT_CONTINUE;
}
WeatherScenariosModel::WeatherScenariosModel(QObject *pr) :
QAbstractListModel(pr)
{
SGPropertyNode_ptr root = loadXMLDefaults();
if (root) {
SGPropertyNode_ptr scenarios = root->getNode("environment/weather-scenarios");
Q_ASSERT(scenarios);
int nChildren = scenarios->nChildren();
for (int i = 0; i < nChildren; i++) {
SGPropertyNode_ptr scenario = scenarios->getChild(i);
if (strcmp(scenario->getName(), "scenario") != 0) {
continue;
}
if (scenario->getStringValue("local-weather/tile-type") == std::string("live")) {
continue;
}
WeatherScenario ws;
ws.name = QString::fromStdString(scenario->getStringValue("name"));
ws.description = QString::fromStdString(scenario->getStringValue("description")).simplified();
ws.metar = QString::fromStdString(scenario->getStringValue("metar"));
m_scenarios.push_back(ws);
}
}
}
int WeatherScenariosModel::rowCount(const QModelIndex &index) const
{
return m_scenarios.size();
}
QVariant WeatherScenariosModel::data(const QModelIndex &index, int role) const
{
const int row = index.row();
if ((row < 0) || (row >= m_scenarios.size())) {
return QVariant();
}
const WeatherScenario& scenario(m_scenarios.at(row));
if ((role == Qt::DisplayRole) || (role == NameRole)) {
return scenario.name;
} else if (role == DescriptionRole) {
return scenario.description;
} else if (role == MetarRole) {
return scenario.metar;
}
return QVariant();
}
QHash<int, QByteArray> WeatherScenariosModel::roleNames() const
{
QHash<int, QByteArray> result;
result[NameRole] = "name";
result[DescriptionRole] = "description";
result[MetarRole] = "metar";
return result;
}
QString WeatherScenariosModel::metarForItem(int index) const
{
if ((index < 0) || (index >= m_scenarios.size())) {
return QString();
}
return m_scenarios.at(index).metar;
}
QString WeatherScenariosModel::descriptionForItem(int index) const
{
if ((index < 0) || (index >= m_scenarios.size())) {
return QString();
}
return m_scenarios.at(index).description;
}
} // of namespace flightgear

View file

@ -6,6 +6,8 @@
#include <Main/AircraftDirVisitorBase.hxx>
#include <QAbstractListModel>
namespace flightgear
{
@ -30,6 +32,38 @@ private:
SGPath _foundPath;
};
class WeatherScenariosModel : public QAbstractListModel
{
Q_OBJECT
public:
WeatherScenariosModel(QObject* pr = nullptr);
int rowCount(const QModelIndex& index) const override;
QVariant data(const QModelIndex& index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE QString metarForItem(int index) const;
Q_INVOKABLE QString descriptionForItem(int index) const;
private:
struct WeatherScenario
{
QString name;
QString description;
QString metar;
};
std::vector<WeatherScenario> m_scenarios;
enum {
NameRole = Qt::UserRole + 1,
DescriptionRole,
MetarRole
};
};
}
#endif // DEFAULTAIRCRAFTLOCATOR_HXX

View file

@ -1,15 +0,0 @@
#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;
}

View file

@ -1,22 +0,0 @@
#ifndef DOWNLOAD_SETTINGS_H
#define DOWNLOAD_SETTINGS_H
#include <GUI/settingssection.h>
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

View file

@ -0,0 +1,36 @@
import FlightGear.Launcher 1.0
Section {
id: downloadSettings
title: "Downloads"
Checkbox {
id: terrasync
label: "Download scenery automatically"
description: "FlightGear can automatically download scenery as needed, and check for updates to "
+ "the scenery. If you disable this option, you will need to download & install scenery "
+ "using an alternative method."
keywords: ["terrasync", "download"]
option: "terrasync"
}
// file path chooser for downloads directory
PathChooser {
id: downloadDir
label: "Download location"
description: "FlightGear stores downloaded files (scenery and aircraft) in this location. "
+ "Depending on your settings, it may grow to a considerable size (many gigabytes)."
+ "If you change the download location, files will need to be downloaded again."
advanced: true
chooseDirectory: true
defaultPath: _config.defaultDownloadDir
option: "download-dir"
dialogPrompt: "Choose a location to store download files."
}
onApply: {
}
summary: terrasync.checked ? "scenery downloads;" : ""
}

View file

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DownloadSettings</class>
<widget class="SettingsSection" name="DownloadSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>771</width>
<height>94</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="title" stdset="0">
<string>Downloads</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string>Download scenery automatically</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>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.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SettingsSection</class>
<extends>QWidget</extends>
<header location="global">GUI/settingssection.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -1,48 +0,0 @@
#include "EditCustomMPServerDialog.hxx"
#include "ui_EditCustomMPServerDialog.h"
#include <QSettings>
#include <QComboBox>
#include "Main/fg_props.hxx"
EditCustomMPServerDialog::EditCustomMPServerDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::EditCustomMPServerDialog)
{
ui->setupUi(this);
QSettings settings;
ui->mpServer->setText(settings.value("mp-custom-host").toString());
ui->port->setText(settings.value("mp-custom-port").toString());
}
EditCustomMPServerDialog::~EditCustomMPServerDialog()
{
delete ui;
}
QString EditCustomMPServerDialog::hostname() const
{
return ui->mpServer->text();
}
void EditCustomMPServerDialog::accept()
{
QSettings settings;
settings.setValue("mp-custom-host", ui->mpServer->text());
settings.setValue("mp-custom-port", ui->port->text());
QDialog::accept();
}
void EditCustomMPServerDialog::addCustomItem(QComboBox* combo)
{
QSettings settings;
QString customMPHost = settings.value("mp-custom-host").toString();
if (customMPHost.isEmpty()) {
combo->addItem(tr("Custom server..."), "custom");
return;
}
combo->addItem(tr("Custom - %1").arg(customMPHost), "custom");
}

View file

@ -1,29 +0,0 @@
#ifndef EDITCUSTOMMPSERVERDIALOG_HXX
#define EDITCUSTOMMPSERVERDIALOG_HXX
#include <QDialog>
namespace Ui {
class EditCustomMPServerDialog;
}
class QComboBox;
class EditCustomMPServerDialog : public QDialog
{
Q_OBJECT
public:
explicit EditCustomMPServerDialog(QWidget *parent = 0);
~EditCustomMPServerDialog();
QString hostname() const;
virtual void accept();
static void addCustomItem(QComboBox* combo);
private:
Ui::EditCustomMPServerDialog *ui;
};
#endif // EDITCUSTOMMPSERVERDIALOG_HXX

View file

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditCustomMPServerDialog</class>
<widget class="QDialog" name="EditCustomMPServerDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>369</width>
<height>172</height>
</rect>
</property>
<property name="windowTitle">
<string>Enter custom server</string>
</property>
<property name="windowIcon">
<iconset resource="resources.qrc">
<normaloff>:/app-icon-large</normaloff>:/app-icon-large</iconset>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="1,1">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Enter the host name and optional port of the multi-player server you wish to connect to.</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Server:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="mpServer">
<property name="placeholderText">
<string>flightgear.example.com</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Port:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="port">
<property name="text">
<string>5000</string>
</property>
<property name="placeholderText">
<string>5000</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>EditCustomMPServerDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>EditCustomMPServerDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -1,17 +0,0 @@
#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;
}

View file

@ -1,22 +0,0 @@
#ifndef ENVIRONMENTPAGE_H
#define ENVIRONMENTPAGE_H
#include <QWidget>
namespace Ui {
class EnvironmentPage;
}
class EnvironmentPage : public QWidget
{
Q_OBJECT
public:
explicit EnvironmentPage(QWidget *parent = 0);
~EnvironmentPage();
private:
Ui::EnvironmentPage *ui;
};
#endif // ENVIRONMENTPAGE_H

View file

@ -1,262 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EnvironmentPage</class>
<widget class="QWidget" name="EnvironmentPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>728</width>
<height>580</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="SettingsSection" name="timeSection" native="true">
<property name="title" stdset="0">
<string>Time and Date</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QRadioButton" name="radioButton">
<property name="text">
<string>Predefined time</string>
</property>
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="radioButton_2">
<property name="text">
<string>Manually selected date and time</string>
</property>
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="comboBox">
<item>
<property name="text">
<string>Current local time</string>
</property>
</item>
<item>
<property name="text">
<string>Dawn</string>
</property>
</item>
<item>
<property name="text">
<string>Morning</string>
</property>
</item>
<item>
<property name="text">
<string>Noon</string>
</property>
</item>
<item>
<property name="text">
<string>Dusk</string>
</property>
</item>
<item>
<property name="text">
<string>Midnight</string>
</property>
</item>
</widget>
</item>
<item row="1" column="2">
<widget class="QDateTimeEdit" name="dateTimeEdit">
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label">
<property name="text">
<string>Time of day:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="simple" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>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.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="SettingsSection" name="weatherSection" native="true">
<property name="title" stdset="0">
<string>Weather</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Weather:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_3">
<item>
<property name="text">
<string>Real-world weather</string>
</property>
</item>
<item>
<property name="text">
<string>Clear and calm</string>
</property>
</item>
<item>
<property name="text">
<string>Thunderstorm</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Choose a standard weather scenario, or download weather reports (METAR) automatically online, from the closest airports.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Season:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_2">
<item>
<property name="text">
<string>Summer</string>
</property>
</item>
<item>
<property name="text">
<string>Winter</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Changing the season affects which textures are used for scenery, but otherwise has no effect.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
<zorder>timeSection</zorder>
<zorder>label_2</zorder>
<zorder>comboBox_2</zorder>
<zorder>weatherSection</zorder>
</widget>
<customwidgets>
<customwidget>
<class>SettingsSection</class>
<extends>QWidget</extends>
<header location="global">GUI/SettingsSection.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,79 @@
#include "ExtraSettingsSection.hxx"
#include <QLabel>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QSettings>
#include "LauncherArgumentTokenizer.hxx"
#include "LaunchConfig.hxx"
#include "AdvancedSettingsButton.h"
ExtraSettingsSection::ExtraSettingsSection(QWidget* pr) :
SettingsSection(pr)
{
setTitle(tr("Additional Settings"));
QVBoxLayout* topLevelVBox = qobject_cast<QVBoxLayout*>(layout());
QLabel* prompt = new QLabel(this);
prompt->setText("Enter additional command-line arguments if any are required. "
"See <a href=\"http://flightgear.sourceforge.net/getstart-en/getstart-enpa2.html#x5-450004.5\">here</a> "
"for documentation on possible arguments.");
prompt->setWordWrap(true);
prompt->setOpenExternalLinks(true);
topLevelVBox->addWidget(prompt);
m_argsEdit = new QTextEdit(this);
m_argsEdit->setAcceptRichText(false);
#if QT_VERSION >= 0x050300
// don't require Qt 5.3
m_argsEdit->setPlaceholderText("--option=value --prop:/sim/name=value");
#endif
topLevelVBox->addWidget(m_argsEdit);
insertSettingsHeader();
setShowAdvanced(false);
m_advancedModeToggle->setVisible(false);
}
QString ExtraSettingsSection::argsText() const
{
return m_argsEdit->toPlainText();
}
void ExtraSettingsSection::setLaunchConfig(LaunchConfig* config)
{
m_config = config;
SettingsSection::setLaunchConfig(config);
}
void ExtraSettingsSection::doApply()
{
LauncherArgumentTokenizer tk;
Q_FOREACH(auto arg, tk.tokenize(m_argsEdit->toPlainText())) {
m_config->setArg(arg.arg, arg.value);
}
}
void ExtraSettingsSection::saveState(QSettings &settings) const
{
settings.setValue("extra-args", m_argsEdit->toPlainText());
}
void ExtraSettingsSection::restoreState(QSettings &settings)
{
m_argsEdit->setText(settings.value("extra-args").toString());
}
QString ExtraSettingsSection::summary() const
{
return QString();
}
void ExtraSettingsSection::validateText()
{
}

View file

@ -0,0 +1,36 @@
#ifndef EXTRASETTINGSSECTION_HXX
#define EXTRASETTINGSSECTION_HXX
#include "settingssection.h"
class QTextEdit;
class LaunchConfig;
class ExtraSettingsSection : public SettingsSection
{
Q_OBJECT
public:
ExtraSettingsSection(QWidget* pr = nullptr);
QString argsText() const;
void setLaunchConfig(LaunchConfig* config) override;
virtual void doApply() override;
void saveState(QSettings &settings) const override;
void restoreState(QSettings &settings) override;
QString summary() const;
protected:
private:
void validateText();
QTextEdit* m_argsEdit;
LaunchConfig* m_config;
};
#endif // EXTRASETTINGSSECTION_HXX

View file

@ -0,0 +1,32 @@
import FlightGear.Launcher 1.0
Section {
id: generalSettings
title: "General"
Checkbox {
id: startPaused
label: "Start paused"
description: "Automatically pause the simulator when launching. This is useful "
+ "when starting in the air."
keywords: ["pause", "freeze"]
}
Checkbox {
id: autoCoordination
label: "Enable auto-coordination"
description: "When flying with the mouse, or a joystick lacking a rudder axis, "
+ "it's difficult to manually coordinate aileron and rudder movements during "
+ "turn. This option automatically commands the rudder to maintain zero "
+ "slip angle when banking";
advanced: true
keywords: ["input", "mouse", "control", "rudder"]
option: "auto-coordination"
}
onApply: {
if (startPaused.checked) {
_config.setArg("enable-freeze")
}
}
}

53
src/GUI/LaunchConfig.cxx Normal file
View file

@ -0,0 +1,53 @@
#include "LaunchConfig.hxx"
#include <Main/options.hxx>
#include <simgear/misc/sg_path.hxx>
LaunchConfig::LaunchConfig(QObject* parent) :
QObject(parent)
{
}
void LaunchConfig::reset()
{
m_values.clear();
}
void LaunchConfig::applyToOptions() const
{
flightgear::Options* options = flightgear::Options::sharedInstance();
std::for_each(m_values.begin(), m_values.end(), [options](const Arg& arg)
{
options->addOption(arg.arg.toStdString(), arg.value.toStdString());
});
}
void LaunchConfig::setArg(QString name, QString value)
{
m_values.push_back(Arg(name, value));
}
void LaunchConfig::setArg(const std::string &name, const std::string &value)
{
setArg(QString::fromStdString(name), QString::fromStdString(value));
}
void LaunchConfig::setProperty(QString path, QVariant value)
{
m_values.push_back(Arg("prop", path + "=" + value.toString()));
}
void LaunchConfig::setEnableDisableOption(QString name, bool value)
{
m_values.push_back(Arg((value ? "enable-" : "disable-") + name));
}
QString LaunchConfig::defaultDownloadDir() const
{
return QString::fromStdString(flightgear::defaultDownloadDir().utf8Str());
}
auto LaunchConfig::values() const -> std::vector<Arg>
{
return m_values;
}

54
src/GUI/LaunchConfig.hxx Normal file
View file

@ -0,0 +1,54 @@
#ifndef FG_GUI_LAUNCHCONFIG_HXX
#define FG_GUI_LAUNCHCONFIG_HXX
#include <QObject>
#include <QVariant>
namespace flightgear { class Options; }
class LaunchConfig : public QObject
{
Q_OBJECT
Q_PROPERTY(QString defaultDownloadDir READ defaultDownloadDir CONSTANT)
public:
class Arg
{
public:
explicit Arg(QString k, QString v = QString()) : arg(k), value(v) {}
QString arg;
QString value;
};
LaunchConfig(QObject* parent = nullptr);
void reset();
void applyToOptions() const;
std::vector<Arg> values() const;
Q_INVOKABLE void setArg(QString name, QString value = QString());
Q_INVOKABLE void setArg(const std::string& name, const std::string& value = std::string());
Q_INVOKABLE void setProperty(QString path, QVariant value);
Q_INVOKABLE void setEnableDisableOption(QString name, bool value);
// ensure a property is /not/ set?
// save and restore API?
QString defaultDownloadDir() const;
signals:
void collect();
private:
std::vector<Arg> m_values;
QString m_defaultDownloadDir;
};
#endif

View file

@ -198,6 +198,20 @@
</property>
</widget>
</item>
<item>
<widget class="ToolboxButton" name="addOnsButton">
<property name="text">
<string>Add-ons</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/toolbox-addons</normaloff>:/toolbox-addons</iconset>
</property>
<property name="pageIndex" stdset="0">
<number>5</number>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
@ -227,6 +241,9 @@
</item>
<item>
<widget class="QStackedWidget" name="stack">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="currentIndex">
<number>0</number>
</property>
@ -403,11 +420,14 @@
<item row="1" column="3" colspan="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>©2017, Curtis L Olson. Licensed under the GNU Public License (GPL) version 2. See &lt;here&gt; for more information</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;©2017 FlightGear contributiors. Licensed under the GNU Public License. See &lt;a href=&quot;http://www.flightgear.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;here&lt;/span&gt;&lt;/a&gt; for more information&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2" rowspan="2">
@ -428,16 +448,16 @@
<number>4</number>
</property>
<property name="leftMargin">
<number>0</number>
<number>4</number>
</property>
<property name="topMargin">
<number>2</number>
<number>4</number>
</property>
<property name="rightMargin">
<number>0</number>
<number>4</number>
</property>
<property name="bottomMargin">
<number>2</number>
<number>4</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
@ -526,7 +546,39 @@
</layout>
</widget>
<widget class="LocationWidget" name="location"/>
<widget class="EnvironmentPage" name="environmentPage"/>
<widget class="QWidget" name="environmentPage">
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<item>
<widget class="QScrollArea" name="scrollArea_2">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="environmentScrollContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>643</width>
<height>644</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="newSettingsPage">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
@ -551,8 +603,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>173</width>
<height>28</height>
<width>643</width>
<height>644</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
@ -598,7 +650,7 @@
</spacer>
</item>
<item>
<widget class="QLineEdit" name="lineEdit">
<widget class="QLineEdit" name="settingsSearchEdit">
<property name="placeholderText">
<string>Search...</string>
</property>
@ -629,12 +681,6 @@
<extends>QPushButton</extends>
<header location="global">GUI/ToolboxButton.h</header>
</customwidget>
<customwidget>
<class>EnvironmentPage</class>
<extends>QWidget</extends>
<header location="global">GUI/EnvironmentPage.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="resources.qrc"/>

View file

@ -5,12 +5,19 @@
#include <QSettings>
#include <QDebug>
#include <QMenu>
#include <QMenuBar>
#include <QMenu>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQmlContext>
#include <private/qqmlglobal_p.h>
// simgear headers
#include <simgear/package/Install.hxx>
// FlightGear headers
#include <Network/RemoteXMLRequest.hxx>
#include <Network/HTTPClient.hxx>
#include <Main/globals.hxx>
#include <Airports/airport.hxx>
@ -20,19 +27,19 @@
// launcher headers
#include "QtLauncher.hxx"
#include "renderingsettings.h"
#include "ViewSettings.h"
#include "MPSettings.h"
#include "DownloadSettings.h"
#include "AdditionalSettings.h"
#include "EditRatingsFilterDialog.hxx"
#include "AircraftItemDelegate.hxx"
#include "AircraftModel.hxx"
#include "PathsDialog.hxx"
#include "EditCustomMPServerDialog.hxx"
#include "LauncherArgumentTokenizer.hxx"
#include "AircraftSearchFilterModel.hxx"
#include "DefaultAircraftLocator.hxx"
#include "SettingsWidgets.hxx"
#include "previewwindow.h"
#include "LaunchConfig.hxx"
#include "SettingsSectionQML.hxx"
#include "ExtraSettingsSection.hxx"
#include "ViewCommandLinePage.hxx"
#include "MPServersModel.h"
#include "ui_Launcher.h"
#include "ui_NoOfficialHangar.h"
@ -86,29 +93,52 @@ private:
#include "LauncherMainWindow.moc"
QQmlPrivate::AutoParentResult launcher_autoParent(QObject* thing, QObject* parent)
{
SettingsSection* ss = qobject_cast<SettingsSection*>(parent);
SettingsControl* sc = qobject_cast<SettingsControl*>(thing);
if (ss && sc) {
qInfo() << "let's do this!" << ss << sc;
sc->setParent(ss);
return QQmlPrivate::Parented;
}
qWarning() << "Unsuitable" << thing << parent;
return QQmlPrivate::IncompatibleObject;
}
//////////////////////////////////////////////////////////////////////////////
LauncherMainWindow::LauncherMainWindow() :
QMainWindow(),
m_ui(NULL),
m_subsystemIdleTimer(NULL),
m_doRestoreMPServer(false)
m_subsystemIdleTimer(NULL)
{
m_ui.reset(new Ui::Launcher);
m_ui->setupUi(this);
#if QT_VERSION >= 0x050300
// don't require Qt 5.3
//m_ui->commandLineArgs->setPlaceholderText("--option=value --prop:/sim/name=value");
#endif
QMenuBar* mb = menuBar();
QMenu* toolsMenu = mb->addMenu(tr("Tools"));
QAction* restoreDefaultsAction = toolsMenu->addAction(tr("Restore defaults..."));
connect(restoreDefaultsAction, &QAction::triggered,
this, &LauncherMainWindow::onRestoreDefaults);
QAction* changeDataAction = toolsMenu->addAction(tr("Select data files location..."));
connect(changeDataAction, &QAction::triggered,
this, &LauncherMainWindow::onChangeDataDir);
QAction* viewCommandLineAction = toolsMenu->addAction(tr("View command-line"));
connect(viewCommandLineAction, &QAction::triggered,
this, &LauncherMainWindow::onViewCommandLine);
#if QT_VERSION >= 0x050200
m_ui->aircraftFilter->setClearButtonEnabled(true);
#endif
for (int i=0; i<4; ++i) {
m_ratingFilters[i] = 3;
}
m_serversModel = new MPServersModel(this);
m_serversModel->refresh();
initQML();
m_subsystemIdleTimer = new QTimer(this);
m_subsystemIdleTimer->setInterval(0);
@ -134,9 +164,7 @@ LauncherMainWindow::LauncherMainWindow() :
connect(m_ui->locationButton, &QAbstractButton::clicked, this, &LauncherMainWindow::onClickToolboxButton);
connect(m_ui->environmentButton, &QAbstractButton::clicked, this, &LauncherMainWindow::onClickToolboxButton);
connect(m_ui->settingsButton, &QAbstractButton::clicked, this, &LauncherMainWindow::onClickToolboxButton);
// connect(m_ui->quitButton, SIGNAL(clicked()), this, SLOT(onQuit()));
connect(m_ui->addOnsButton, &QAbstractButton::clicked, this, &LauncherMainWindow::onClickToolboxButton);
connect(m_ui->aircraftHistory, &QPushButton::clicked,
this, &LauncherMainWindow::onPopupAircraftHistory);
@ -160,39 +188,6 @@ LauncherMainWindow::LauncherMainWindow() :
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)),
this, SLOT(updateSettingsSummary()));
connect(m_ui->fetchRealWxrCheckbox, SIGNAL(toggled(bool)),
this, SLOT(updateSettingsSummary()));
connect(m_ui->rembrandtCheckbox, SIGNAL(toggled(bool)),
this, SLOT(updateSettingsSummary()));
connect(m_ui->terrasyncCheck, SIGNAL(toggled(bool)),
this, SLOT(updateSettingsSummary()));
connect(m_ui->startPausedCheck, SIGNAL(toggled(bool)),
this, SLOT(updateSettingsSummary()));
connect(m_ui->msaaCheckbox, SIGNAL(toggled(bool)),
this, SLOT(updateSettingsSummary()));
connect(m_ui->mpBox, SIGNAL(toggled(bool)),
this, SLOT(updateSettingsSummary()));
connect(m_ui->mpCallsign, SIGNAL(textChanged(QString)),
this, SLOT(updateSettingsSummary()));
connect(m_ui->rembrandtCheckbox, SIGNAL(toggled(bool)),
this, SLOT(onRembrandtToggled(bool)));
connect(m_ui->terrasyncCheck, &QCheckBox::toggled,
this, &LauncherMainWindow::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);
@ -216,6 +211,8 @@ LauncherMainWindow::LauncherMainWindow() :
this, &LauncherMainWindow::onRequestPackageUninstall);
connect(delegate, &AircraftItemDelegate::cancelDownload,
this, &LauncherMainWindow::onCancelDownload);
connect(delegate, &AircraftItemDelegate::showPreviews,
this, &LauncherMainWindow::onShowPreviews);
connect(m_aircraftModel, &AircraftItemModel::aircraftInstallCompleted,
this, &LauncherMainWindow::onAircraftInstalledCompleted);
@ -223,18 +220,14 @@ LauncherMainWindow::LauncherMainWindow() :
this, &LauncherMainWindow::onAircraftInstallFailed);
connect(m_aircraftModel, &AircraftItemModel::scanCompleted,
this, &LauncherMainWindow::updateSelectedAircraft);
#if 0
connect(m_ui->restoreDefaultsButton, &QPushButton::clicked,
this, &LauncherMainWindow::onRestoreDefaults);
#endif
AddOnsPage* addOnsPage = new AddOnsPage(NULL, globals->packageRoot());
connect(addOnsPage, &AddOnsPage::downloadDirChanged,
this, &LauncherMainWindow::onDownloadDirChanged);
connect(addOnsPage, &AddOnsPage::sceneryPathsChanged,
this, &LauncherMainWindow::setSceneryPaths);
connect(addOnsPage, &AddOnsPage::aircraftPathsChanged,
this, &LauncherMainWindow::onAircraftPathsChanged);
m_ui->stack->addWidget(addOnsPage);
// 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,
@ -247,47 +240,118 @@ LauncherMainWindow::LauncherMainWindow() :
m_aircraftModel->setPackageRoot(globals->packageRoot());
m_aircraftModel->scanDirs();
buildSettingsSections();
buildEnvironmentSections();
m_viewCommandLinePage = new ViewCommandLinePage;
m_viewCommandLinePage->setLaunchConfig(m_config);
m_ui->stack->addWidget(m_viewCommandLinePage);
checkOfficialCatalogMessage();
restoreSettings();
updateSettingsSummary();
}
onRefreshMPServers();
void LauncherMainWindow::initQML()
{
QQmlPrivate::RegisterAutoParent autoparent = { 0, &launcher_autoParent };
QQmlPrivate::qmlregister(QQmlPrivate::AutoParentRegistration, &autoparent);
RenderingSettings* renderSettings = new RenderingSettings(m_ui->settingsScrollContents);
qmlRegisterType<SettingsSectionQML>("FlightGear.Launcher", 1, 0, "Section");
qmlRegisterType<SettingsCheckbox>("FlightGear.Launcher", 1, 0, "Checkbox");
qmlRegisterType<SettingsComboBox>("FlightGear.Launcher", 1, 0, "Combo");
qmlRegisterType<SettingsIntSpinbox>("FlightGear.Launcher", 1, 0, "Spinbox");
qmlRegisterType<SettingsText>("FlightGear.Launcher", 1, 0, "LineEdit");
qmlRegisterType<SettingsDateTime>("FlightGear.Launcher", 1, 0, "DateTime");
qmlRegisterType<SettingsPath>("FlightGear.Launcher", 1, 0, "PathChooser");
qmlRegisterUncreatableType<QAbstractItemModel>("FlightGear.Launcher", 1, 0, "QAIM", "no");
qmlRegisterUncreatableType<SettingsControl>("FlightGear.Launcher", 1, 0, "Control", "Base class");
qmlRegisterUncreatableType<LaunchConfig>("FlightGear.Launcher", 1, 0, "LaunchConfig", "Singleton API");
m_config = new LaunchConfig(this);
connect(m_config, &LaunchConfig::collect, this, &LauncherMainWindow::collectAircraftArgs);
m_ui->location->setLaunchConfig(m_config);
m_qmlEngine = new QQmlEngine(this);
m_qmlEngine->rootContext()->setContextProperty("_config", m_config);
m_qmlEngine->rootContext()->setContextProperty("_launcher", this);
m_qmlEngine->rootContext()->setContextProperty("_mpServers", m_serversModel);
flightgear::WeatherScenariosModel* weatherScenariosModel = new flightgear::WeatherScenariosModel(this);
m_qmlEngine->rootContext()->setContextProperty("_weatherScenarios", weatherScenariosModel);
}
void LauncherMainWindow::buildSettingsSections()
{
QVBoxLayout* settingsVBox = static_cast<QVBoxLayout*>(m_ui->settingsScrollContents->layout());
settingsVBox->addWidget(renderSettings);
ViewSettings* viewSettings = new ViewSettings(m_ui->settingsScrollContents);
settingsVBox->addWidget(viewSettings);
QStringList sections = QStringList() << "general" << "mp" << "downloads" << "view" << "render";
Q_FOREACH (QString section, sections) {
QQmlComponent* comp = new QQmlComponent(m_qmlEngine, "qrc:/settings/" + section, this);
if (comp->isError()) {
qWarning() << "Errors parsing settings section:" << section << "\n" << comp->errorString();
} else {
SettingsSection* ss = qobject_cast<SettingsSection*>(comp->create());
if (!ss) {
qWarning() << "failed to create settings section from" << section;
} else {
ss->insertSettingsHeader();
ss->setLaunchConfig(m_config);
ss->setParent(m_ui->settingsScrollContents);
settingsVBox->addWidget(ss);
connect(ss, &SettingsSection::summaryChanged,
this, &LauncherMainWindow::updateSettingsSummary);
}
}
}
MPSettings* mpSettings = new MPSettings(m_ui->settingsScrollContents);
settingsVBox->addWidget(mpSettings);
m_extraSettings = new ExtraSettingsSection(m_ui->settingsScrollContents);
m_extraSettings->setLaunchConfig(m_config);
settingsVBox->addWidget(m_extraSettings);
settingsVBox->addStretch(1);
DownloadSettings* downloadSettings = new DownloadSettings(m_ui->settingsScrollContents);
settingsVBox->addWidget(downloadSettings);
// disable search for the moment, not implemented
m_ui->settingsSearchEdit->hide();
}
AdditionalSettings* addSettings = new AdditionalSettings(m_ui->settingsScrollContents);
settingsVBox->addWidget(addSettings);
void LauncherMainWindow::buildEnvironmentSections()
{
QVBoxLayout* settingsVBox = new QVBoxLayout;
m_ui->environmentScrollContents->setLayout(settingsVBox);
QStringList sections = QStringList() << "time" << "weather";
Q_FOREACH (QString section, sections) {
QQmlComponent* comp = new QQmlComponent(m_qmlEngine, "qrc:/environment/" + section, this);
if (comp->isError()) {
qWarning() << "Errors parsing environment section:" << section << "\n" << comp->errorString();
} else {
SettingsSection* ss = qobject_cast<SettingsSection*>(comp->create());
if (!ss) {
qWarning() << "failed to create environment section from" << section;
} else {
ss->insertSettingsHeader();
ss->setLaunchConfig(m_config);
ss->setParent(m_ui->environmentScrollContents);
settingsVBox->addWidget(ss);
connect(ss, &SettingsSection::summaryChanged,
this, &LauncherMainWindow::updateSettingsSummary);
}
}
}
settingsVBox->addStretch(1);
}
LauncherMainWindow::~LauncherMainWindow()
{
// if we don't cancel this now, it may complete after we are gone,
// causing a crash when the SGCallback fires (SGCallbacks don't clean up
// when their subject is deleted)
globals->get_subsystem<FGHTTPClient>()->client()->cancelRequest(m_mpServerRequest);
}
bool LauncherMainWindow::execInApp()
{
m_inAppMode = true;
// m_ui->tabWidget->removeTab(3);
// m_ui->tabWidget->removeTab(3);
// m_ui->runButton->setText(tr("Apply"));
// m_ui->quitButton->setText(tr("Cancel"));
m_ui->addOnsButton->hide();
m_ui->settingsButton->hide();
disconnect(m_ui->flyButton, SIGNAL(clicked()), this, SLOT(onRun()));
connect(m_ui->flyButton, SIGNAL(clicked()), this, SLOT(onApply()));
m_runInApp = true;
@ -307,16 +371,6 @@ void LauncherMainWindow::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());
m_ui->msaaCheckbox->setChecked(settings.value("enable-msaa", false).toBool());
m_ui->fetchRealWxrCheckbox->setChecked(settings.value("enable-realwx", true).toBool());
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());
@ -373,15 +427,13 @@ void LauncherMainWindow::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;
}
Q_FOREACH(SettingsSection* ss, findChildren<SettingsSection*>()) {
ss->restoreState(settings);
}
m_serversModel->requestRestore();
}
void LauncherMainWindow::delayedAircraftModelReset()
{
@ -407,40 +459,16 @@ void LauncherMainWindow::maybeRestoreAircraftSelection()
void LauncherMainWindow::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());
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());
}
void LauncherMainWindow::setEnableDisableOptionFromCheckbox(QCheckBox* cbox, QString name) const
{
flightgear::Options* opt = flightgear::Options::sharedInstance();
std::string stdName(name.toStdString());
if (cbox->isChecked()) {
opt->addOption("enable-" + stdName, "");
} else {
opt->addOption("disable-" + stdName, "");
Q_FOREACH(SettingsSection* ss, findChildren<SettingsSection*>()) {
ss->saveState(settings);
}
}
@ -449,53 +477,35 @@ void LauncherMainWindow::closeEvent(QCloseEvent *event)
qApp->exit(-1);
}
void LauncherMainWindow::onRun()
void LauncherMainWindow::collectAircraftArgs()
{
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");
setEnableDisableOptionFromCheckbox(m_ui->fullScreenCheckbox, "fullscreen");
// setEnableDisableOptionFromCheckbox(m_ui->startPausedCheck, "freeze");
bool startPaused = m_ui->startPausedCheck->isChecked() ||
m_ui->location->shouldStartPaused();
if (startPaused) {
opt->addOption("enable-freeze", "");
}
#endif
#if 0
// MSAA is more complex
if (!m_ui->rembrandtCheckbox->isChecked()) {
if (m_ui->msaaCheckbox->isChecked()) {
globals->get_props()->setIntValue("/sim/rendering/multi-sample-buffers", 1);
globals->get_props()->setIntValue("/sim/rendering/multi-samples", 4);
} else {
globals->get_props()->setIntValue("/sim/rendering/multi-sample-buffers", 0);
}
}
#endif
// aircraft
if (!m_selectedAircraft.isEmpty()) {
if (m_selectedAircraft.isLocalFile()) {
QFileInfo setFileInfo(m_selectedAircraft.toLocalFile());
opt->addOption("aircraft-dir", setFileInfo.dir().absolutePath().toStdString());
m_config->setArg("aircraft-dir", setFileInfo.dir().absolutePath());
QString setFile = setFileInfo.fileName();
Q_ASSERT(setFile.endsWith("-set.xml"));
setFile.truncate(setFile.count() - 8); // drop the '-set.xml' portion
opt->addOption("aircraft", setFile.toStdString());
m_config->setArg("aircraft", setFile);
} else if (m_selectedAircraft.scheme() == "package") {
QString qualifiedId = m_selectedAircraft.path();
// no need to set aircraft-dir, handled by the corresponding code
// in fgInitAircraft
opt->addOption("aircraft", qualifiedId.toStdString());
m_config->setArg("aircraft", m_selectedAircraft.path());
} else {
qWarning() << "unsupported aircraft launch URL" << m_selectedAircraft;
}
}
}
void LauncherMainWindow::onRun()
{
flightgear::Options* opt = flightgear::Options::sharedInstance();
m_config->reset();
m_config->collect();
// aircraft
if (!m_selectedAircraft.isEmpty()) {
// manage aircraft history
if (m_recentAircraft.contains(m_selectedAircraft))
m_recentAircraft.removeOne(m_selectedAircraft);
@ -504,46 +514,9 @@ void LauncherMainWindow::onRun()
m_recentAircraft.pop_back();
}
#if 0
if (m_ui->mpBox->isChecked()) {
std::string callSign = m_ui->mpCallsign->text().toStdString();
if (!callSign.empty()) {
opt->addOption("callsign", callSign);
}
QString host = m_ui->mpServerCombo->currentData().toString();
int port = DEFAULT_MP_PORT;
if (host == "custom") {
QSettings settings;
host = settings.value("mp-custom-host").toString();
} else {
port = findMPServerPort(host.toStdString());
}
if (port == 0) {
port = DEFAULT_MP_PORT;
}
globals->get_props()->setStringValue("/sim/multiplay/txhost", host.toStdString());
globals->get_props()->setIntValue("/sim/multiplay/txport", port);
}
#endif
m_ui->location->setLocationProperties();
// m_ui->location->setLocationProperties();
updateLocationHistory();
#if 0
// time of day
if (m_ui->timeOfDayCombo->currentIndex() != 0) {
QString dayval = m_ui->timeOfDayCombo->currentText().toLower();
opt->addOption("timeofday", dayval.toStdString());
}
if (m_ui->seasonCombo->currentIndex() != 0) {
QString seasonName = m_ui->seasonCombo->currentText().toLower();
opt->addOption("season", seasonName.toStdString());
}
#endif
QSettings settings;
QString downloadDir = settings.value("download-dir").toString();
if (!downloadDir.isEmpty()) {
@ -560,8 +533,6 @@ void LauncherMainWindow::onRun()
d.mkpath(downloadDir);
}
}
opt->addOption("download-dir", downloadDir.toStdString());
}
// scenery paths
@ -575,24 +546,12 @@ void LauncherMainWindow::onRun()
globals->append_aircraft_path(path.toStdString());
}
// additional arguments
#if 0
ArgumentsTokenizer tk;
Q_FOREACH(ArgumentsTokenizer::Arg a, tk.tokenize(m_ui->commandLineArgs->toPlainText())) {
if (a.arg.startsWith("prop:")) {
QString v = a.arg.mid(5) + "=" + a.value;
opt->addOption("prop", v.toStdString());
} else {
opt->addOption(a.arg.toStdString(), a.value.toStdString());
}
}
#endif
if (settings.contains("restore-defaults-on-run")) {
settings.remove("restore-defaults-on-run");
opt->addOption("restore-defaults", "");
}
m_config->applyToOptions();
saveSettings();
// set a positive value here so we can detect this case in runLauncherDialog
@ -667,6 +626,7 @@ void LauncherMainWindow::onQuit()
}
}
#if 0
void LauncherMainWindow::onToggleTerrasync(bool enabled)
{
if (enabled) {
@ -695,6 +655,7 @@ void LauncherMainWindow::onToggleTerrasync(bool enabled)
}
} // of is enabled
}
#endif
void LauncherMainWindow::onAircraftInstalledCompleted(QModelIndex index)
{
@ -766,6 +727,14 @@ void LauncherMainWindow::onRequestPackageUninstall(const QModelIndex& index)
}
}
void LauncherMainWindow::onShowPreviews(const QModelIndex &index)
{
QVariant urls = index.data(AircraftPreviewsRole);
PreviewWindow* previewWindow = new PreviewWindow;
previewWindow->setUrls(urls.toList());
}
void LauncherMainWindow::onCancelDownload(const QModelIndex& index)
{
QString pkg = index.data(AircraftPackageIdRole).toString();
@ -798,6 +767,15 @@ void LauncherMainWindow::onRestoreDefaults()
flightgear::restartTheApp();
}
void LauncherMainWindow::onViewCommandLine()
{
m_ui->stack->setCurrentIndex(6);
Q_FOREACH (ToolboxButton* tb, findChildren<ToolboxButton*>()) {
tb->setChecked(false);
}
m_viewCommandLinePage->update();
}
void LauncherMainWindow::maybeUpdateSelectedAircraft(QModelIndex index)
{
QUrl u = index.data(AircraftURIRole).toUrl();
@ -860,6 +838,7 @@ void LauncherMainWindow::onClickToolboxButton()
Q_FOREACH (ToolboxButton* tb, findChildren<ToolboxButton*>()) {
tb->setChecked(tb->property("pageIndex").toInt() == pageIndex);
}
saveSettings();
}
void LauncherMainWindow::setSceneryPaths()
@ -952,47 +931,18 @@ void LauncherMainWindow::onEditRatingsFilter()
void LauncherMainWindow::updateSettingsSummary()
{
QStringList summary;
#if 0
if (m_ui->timeOfDayCombo->currentIndex() > 0) {
summary.append(QString(m_ui->timeOfDayCombo->currentText().toLower()));
}
if (m_ui->seasonCombo->currentIndex() > 0) {
summary.append(QString(m_ui->seasonCombo->currentText().toLower()));
Q_FOREACH(SettingsSection* ss, findChildren<SettingsSection*>()) {
QString s = ss->summary();
if (!s.isEmpty()) {
QStringList pieces = s.split(';', QString::SkipEmptyParts);
summary.append(pieces);
}
if (m_ui->rembrandtCheckbox->isChecked()) {
summary.append("Rembrandt enabled");
} else if (m_ui->msaaCheckbox->isChecked()) {
summary.append("anti-aliasing");
}
if (m_ui->fetchRealWxrCheckbox->isChecked()) {
summary.append("live weather");
}
if (m_ui->terrasyncCheck->isChecked()) {
summary.append("automatic scenery downloads");
}
if (m_ui->startPausedCheck->isChecked()) {
summary.append("paused");
}
if (m_ui->mpBox->isChecked()) {
summary.append(tr("multiplayer: %1").arg(m_ui->mpCallsign->text()));
}
QString s = summary.join(", ");
s[0] = s[0].toUpper();
m_ui->settingsDescription->setText(s);
#endif
}
void LauncherMainWindow::onRembrandtToggled(bool b)
{
// Rembrandt and multi-sample are exclusive
// m_ui->msaaCheckbox->setEnabled(!b);
}
void LauncherMainWindow::onShowInstalledAircraftToggled(bool b)
@ -1060,7 +1010,7 @@ void LauncherMainWindow::onOfficialCatalogMessageLink(QUrl link)
QSettings settings;
settings.setValue("hide-official-catalog-message", true);
} else if (s == "action:add-official") {
AddOnsPage::addDefaultCatalog(this);
AddOnsPage::addDefaultCatalog(this, false /* not silent */);
}
checkOfficialCatalogMessage();
@ -1084,110 +1034,6 @@ void LauncherMainWindow::checkUpdateAircraft()
}
}
void LauncherMainWindow::onRefreshMPServers()
{
if (m_mpServerRequest.get()) {
return; // in-progress
}
string url(fgGetString("/sim/multiplay/serverlist-url",
"http://liveries.flightgear.org/mpstatus/mpservers.xml"));
if (url.empty()) {
SG_LOG(SG_IO, SG_ALERT, "do_multiplayer.refreshserverlist: no URL given");
return;
}
SGPropertyNode *targetnode = fgGetNode("/sim/multiplay/server-list", true);
m_mpServerRequest.reset(new RemoteXMLRequest(url, targetnode));
m_mpServerRequest->done(this, &LauncherMainWindow::onRefreshMPServersDone);
m_mpServerRequest->fail(this, &LauncherMainWindow::onRefreshMPServersFailed);
globals->get_subsystem<FGHTTPClient>()->makeRequest(m_mpServerRequest);
}
void LauncherMainWindow::onRefreshMPServersDone(simgear::HTTP::Request*)
{
#if 0
// parse the properties
SGPropertyNode *targetnode = fgGetNode("/sim/multiplay/server-list", true);
m_ui->mpServerCombo->clear();
for (int i=0; i<targetnode->nChildren(); ++i) {
SGPropertyNode* c = targetnode->getChild(i);
if (c->getName() != std::string("server")) {
continue;
}
if (c->getBoolValue("online") != true) {
// only list online servers
continue;
}
QString name = QString::fromStdString(c->getStringValue("name"));
QString loc = QString::fromStdString(c->getStringValue("location"));
QString host = QString::fromStdString(c->getStringValue("hostname"));
m_ui->mpServerCombo->addItem(tr("%1 - %2").arg(name,loc), host);
}
EditCustomMPServerDialog::addCustomItem(m_ui->mpServerCombo);
restoreMPServerSelection();
#endif
m_mpServerRequest.clear();
}
void LauncherMainWindow::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 LauncherMainWindow::restoreMPServerSelection()
{
#if 0
if (m_doRestoreMPServer) {
QSettings settings;
int index = m_ui->mpServerCombo->findData(settings.value("mp-server"));
if (index >= 0) {
m_ui->mpServerCombo->setCurrentIndex(index);
}
m_doRestoreMPServer = false;
}
#endif
}
void LauncherMainWindow::onMPServerActivated(int index)
{
#if 0
if (m_ui->mpServerCombo->itemData(index) == "custom") {
EditCustomMPServerDialog dlg(this);
dlg.exec();
if (dlg.result() == QDialog::Accepted) {
m_ui->mpServerCombo->setItemText(index, tr("Custom - %1").arg(dlg.hostname()));
}
}
#endif
}
int LauncherMainWindow::findMPServerPort(const std::string& host)
{
SGPropertyNode *targetnode = fgGetNode("/sim/multiplay/server-list", true);
for (int i=0; i<targetnode->nChildren(); ++i) {
SGPropertyNode* c = targetnode->getChild(i);
if (c->getName() != std::string("server")) {
continue;
}
if (c->getStringValue("hostname") == host) {
return c->getIntValue("port");
}
}
return 0;
}
simgear::pkg::PackageRef LauncherMainWindow::packageForAircraftURI(QUrl uri) const
{
@ -1206,3 +1052,40 @@ void LauncherMainWindow::onAircraftPathsChanged()
m_aircraftModel->setPaths(settings.value("aircraft-paths").toStringList());
m_aircraftModel->scanDirs();
}
void LauncherMainWindow::onChangeDataDir()
{
QString currentLocText;
QSettings settings;
QString root = settings.value("fg-root").toString();
if (root.isNull()) {
currentLocText = tr("Currently the built-in data files are being used");
} else {
currentLocText = tr("Currently using location: %1").arg(root);
}
QMessageBox mbox(this);
mbox.setText(tr("Change the data files used by FlightGear?"));
mbox.setInformativeText(tr("FlightGear requires additional files to operate. "
"(Also called the base package, or fg-data) "
"You can restart FlightGear and choose a "
"different data files location, or restore the default setting. %1").arg(currentLocText));
QPushButton* quitButton = mbox.addButton(tr("Restart FlightGear now"), QMessageBox::YesRole);
mbox.addButton(QMessageBox::Cancel);
mbox.setDefaultButton(QMessageBox::Cancel);
mbox.setIconPixmap(QPixmap(":/app-icon-large"));
mbox.exec();
if (mbox.clickedButton() != quitButton) {
return;
}
{
QSettings settings;
// set the option to the magic marker value
settings.setValue("fg-root", "!ask");
} // scope the ensure settings are written nicely
flightgear::restartTheApp();
}

View file

@ -41,7 +41,11 @@ class AircraftProxyModel;
class AircraftItemModel;
class QCheckBox;
class CatalogListModel;
class RemoteXMLRequest;
class QQmlEngine;
class LaunchConfig;
class ExtraSettingsSection;
class ViewCommandLinePage;
class MPServersModel;
class LauncherMainWindow : public QMainWindow
{
@ -67,7 +71,6 @@ private slots:
void onQuit();
void onAircraftSelected(const QModelIndex& index);
void onRequestPackageInstall(const QModelIndex& index);
void onRequestPackageUninstall(const QModelIndex& index);
@ -81,10 +84,6 @@ private slots:
void updateSettingsSummary();
void onRembrandtToggled(bool b);
void onToggleTerrasync(bool enabled);
void onSubsytemIdleTimeout();
void onAircraftInstalledCompleted(QModelIndex index);
@ -95,11 +94,9 @@ private slots:
void maybeRestoreAircraftSelection();
void onRestoreDefaults();
void onViewCommandLine();
void onDownloadDirChanged();
void onRefreshMPServers();
void onMPServerActivated(int index);
Q_INVOKABLE void onDownloadDirChanged();
void onUpdateAllAircraft();
@ -109,6 +106,8 @@ private slots:
void setSceneryPaths();
void onAircraftPathsChanged();
void onChangeDataDir();
private:
/**
@ -124,20 +123,12 @@ private:
QModelIndex proxyIndexForAircraftURI(QUrl uri) const;
QModelIndex sourceIndexForAircraftURI(QUrl uri) const;
void setEnableDisableOptionFromCheckbox(QCheckBox* cbox, QString name) const;
simgear::pkg::PackageRef packageForAircraftURI(QUrl uri) const;
void checkOfficialCatalogMessage();
void onOfficialCatalogMessageLink(QUrl link);
void checkUpdateAircraft();
void onRefreshMPServersDone(simgear::HTTP::Request*);
void onRefreshMPServersFailed(simgear::HTTP::Request*);
int findMPServerPort(const std::string& host);
void restoreMPServerSelection();
// need to wait after a model reset before restoring selection and
// scrolling, to give the view time it seems.
void delayedAircraftModelReset();
@ -146,9 +137,15 @@ private:
void updateLocationHistory();
bool shouldShowOfficialCatalogMessage() const;
void buildSettingsSections();
void buildEnvironmentSections();
void collectAircraftArgs();
void initQML();
QScopedPointer<Ui::Launcher> m_ui;
AircraftProxyModel* m_aircraftProxy;
AircraftItemModel* m_aircraftModel;
MPServersModel* m_serversModel = nullptr;
QUrl m_selectedAircraft;
QList<QUrl> m_recentAircraft;
@ -156,13 +153,12 @@ private:
bool m_inAppMode = false;
bool m_runInApp = false;
bool m_accepted = false;
int m_ratingFilters[4];
SGSharedPtr<RemoteXMLRequest> m_mpServerRequest;
bool m_doRestoreMPServer;
int m_ratingFilters[4] = {3, 3, 3, 3};
QVariantList m_recentLocations;
QQmlEngine* m_qmlEngine = nullptr;
LaunchConfig* m_config = nullptr;
ExtraSettingsSection* m_extraSettings = nullptr;
ViewCommandLinePage* m_viewCommandLinePage = nullptr;
};
#endif // of LAUNCHER_MAIN_WINDOW_HXX

View file

@ -31,6 +31,7 @@
#include "AirportDiagram.hxx"
#include "NavaidDiagram.hxx"
#include "LaunchConfig.hxx"
#include <Airports/airport.hxx>
#include <Airports/groundnetwork.hxx>
@ -423,6 +424,12 @@ LocationWidget::~LocationWidget()
delete m_ui;
}
void LocationWidget::setLaunchConfig(LaunchConfig *config)
{
m_config = config;
connect(m_config, &LaunchConfig::collect, this, &LocationWidget::onCollectConfig);
}
void LocationWidget::restoreSettings()
{
QSettings settings;
@ -489,8 +496,6 @@ bool LocationWidget::shouldStartPaused() const
// navaid, start paused
return true;
}
return false;
}
QVariantMap LocationWidget::saveLocation() const
@ -646,42 +651,120 @@ void LocationWidget::setLocationProperties()
void LocationWidget::applyPositionOffset()
{
fgSetDouble("/sim/presets/altitude-ft", m_ui->altitudeSpinbox->value());
fgSetBool("/sim/presets/on-ground", m_ui->altitudeSpinbox->value() > 0);
if (m_ui->altitudeSpinbox->value() > 0) {
m_config->setArg("altitude", QString::number(m_ui->altitudeSpinbox->value()));
}
fgSetString("/sim/presets/speed-set", "knots");
fgSetDouble("/sim/presets/airspeed-kt", m_ui->airspeedSpinbox->value());
fgSetDouble("/sim/presets/heading-deg", m_ui->headingSpinbox->value());
m_config->setArg("vc", QString::number(m_ui->airspeedSpinbox->value()));
m_config->setArg("heading", QString::number(m_ui->headingSpinbox->value()));
if (m_ui->offsetGroup->isChecked()) {
// flip direction of azimuth to balance the flip done in fgApplyStartOffset
// I don't know why that flip exists but changing it there will break
// command-line compatability so compensating here instead
int offsetAzimuth = m_ui->offsetBearingSpinbox->value() - 180;
fgSetDouble("/sim/presets/offset-azimuth-deg", offsetAzimuth);
fgSetDouble("/sim/presets/offset-distance-nm", m_ui->offsetNmSpinbox->value());
m_config->setArg("offset-azimuth", QString::number(offsetAzimuth));
m_config->setArg("offset-distance", QString::number(m_ui->offsetNmSpinbox->value()));
}
}
void LocationWidget::onCollectConfig()
{
if (m_locationIsLatLon) {
m_config->setArg("lat", QString::number(m_geodLocation.getLatitudeDeg()));
m_config->setArg("lon", QString::number(m_geodLocation.getLongitudeDeg()));
applyPositionOffset();
return;
}
if (!m_location) {
return;
}
if (FGAirport::isAirportType(m_location.ptr())) {
FGAirport* apt = static_cast<FGAirport*>(m_location.ptr());
m_config->setArg("airport", QString::fromStdString(apt->ident()));
if (m_ui->runwayRadio->isChecked()) {
if (apt->type() == FGPositioned::AIRPORT) {
int index = m_ui->runwayCombo->itemData(m_ui->runwayCombo->currentIndex()).toInt();
if (index >= 0) {
// explicit runway choice
FGRunwayRef runway = apt->getRunwayByIndex(index);
m_config->setArg("runway", QString::fromStdString(runway->ident()));
// set nav-radio 1 based on selected runway
if (runway->ILS()) {
double mhz = runway->ILS()->get_freq() / 100.0;
m_config->setArg("nav1", QString("%1:%2").arg(runway->headingDeg()).arg(mhz));
}
}
if (m_ui->onFinalCheckbox->isChecked()) {
m_config->setArg("glideslope", std::string("3.0"));
m_config->setArg("offset-distance", QString::number(m_ui->approachDistanceSpin->value()));
m_config->setArg("on-ground", std::string("false"));
}
} else if (apt->type() == FGPositioned::HELIPORT) {
int index = m_ui->runwayCombo->itemData(m_ui->runwayCombo->currentIndex()).toInt();
if (index >= 0) {
// explicit pad choice
FGHelipadRef pad = apt->getHelipadByIndex(index);
m_config->setArg("runway", pad->ident());
}
} else {
qWarning() << Q_FUNC_INFO << "implement me";
}
} else if (m_ui->parkingRadio->isChecked()) {
// parking selection
m_config->setArg("parkpos", m_ui->parkingCombo->currentText());
}
// of location is an airport
} else {
// location is a navaid
// note setting the ident here is ambigious, we really only need and
// want the 'navaid-id' property. However setting the 'real' option
// gives a better UI experience (eg existing Position in Air dialog)
FGPositioned::Type ty = m_location->type();
switch (ty) {
case FGPositioned::VOR:
m_config->setArg("vor", m_location->ident());
setNavRadioOption();
break;
case FGPositioned::NDB:
m_config->setArg("ndb", m_location->ident());
setNavRadioOption();
break;
case FGPositioned::FIX:
m_config->setArg("fix", m_location->ident());
break;
default:
break;
};
// set disambiguation property
m_config->setProperty("/sim/presets/navaid-id", QString::number(m_location->guid()));
applyPositionOffset();
} // of navaid location
}
void LocationWidget::setNavRadioOption()
{
flightgear::Options* opt = flightgear::Options::sharedInstance();
if (m_location->type() == FGPositioned::VOR) {
FGNavRecordRef nav(static_cast<FGNavRecord*>(m_location.ptr()));
double mhz = nav->get_freq() / 100.0;
int heading = 0; // add heading support
QString navOpt = QString("%1:%2").arg(heading).arg(mhz);
opt->addOption("nav1", navOpt.toStdString());
m_config->setArg("nav1", navOpt);
} else {
FGNavRecordRef nav(static_cast<FGNavRecord*>(m_location.ptr()));
int khz = nav->get_freq() / 100;
int heading = 0;
QString adfOpt = QString("%1:%2").arg(heading).arg(khz);
qDebug() << "ADF opt is:" << adfOpt;
opt->addOption("adf1", adfOpt.toStdString());
m_config->setArg("adf1", adfOpt);
}
}

View file

@ -28,6 +28,7 @@
#include <Navaids/positioned.hxx>
#include <Airports/airports_fwd.hxx>
#include "LaunchConfig.hxx"
#include "QtLauncher_fwd.hxx"
namespace Ui {
@ -44,6 +45,8 @@ public:
explicit LocationWidget(QWidget *parent = 0);
~LocationWidget();
void setLaunchConfig(LaunchConfig* config);
QString locationDescription() const;
void setBaseLocation(FGPositionedRef ref);
@ -66,6 +69,8 @@ private Q_SLOTS:
void onLocationChanged();
void onOffsetDataChanged();
void onHeadingChanged();
void onCollectConfig();
private:
void onSearch();
@ -98,6 +103,8 @@ private:
FGPositionedList m_recentLocations;
LauncherAircraftType m_aircraftType;
LaunchConfig* m_config = nullptr;
};
#endif // LOCATIONWIDGET_H

184
src/GUI/MPServersModel.cpp Normal file
View file

@ -0,0 +1,184 @@
#include "MPServersModel.h"
#include <QDebug>
#include <QSettings>
#include <Network/RemoteXMLRequest.hxx>
#include <Network/HTTPClient.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include "LaunchConfig.hxx"
const int IsCustomIndexRole = Qt::UserRole + 1;
MPServersModel::MPServersModel(QObject* parent) :
QAbstractListModel(parent)
{
}
MPServersModel::~MPServersModel()
{
// if we don't cancel this now, it may complete after we are gone,
// causing a crash when the SGCallback fires (SGCallbacks don't clean up
// when their subject is deleted)
globals->get_subsystem<FGHTTPClient>()->client()->cancelRequest(m_mpServerRequest);
}
int MPServersModel::rowCount(const QModelIndex&) const
{
return m_servers.size() + 1;
}
QVariant MPServersModel::data(const QModelIndex &index, int role) const
{
int row = index.row();
if ((row < 0) || (row > m_servers.size())) {
return QVariant();
}
if (row == m_servers.size()) {
if (role == Qt::DisplayRole) {
return tr("Custom server");
} else if (role == IsCustomIndexRole) {
return true;
}
return QVariant();
}
const ServerInfo& sv(m_servers.at(row));
if (role == Qt::DisplayRole) {
return tr("%1 - %2").arg(sv.name).arg(sv.location);
} else if (role == IsCustomIndexRole) {
return false;
}
return QVariant();
}
QHash<int, QByteArray> MPServersModel::roleNames() const
{
QHash<int, QByteArray> result;
result[IsCustomIndexRole] = "isCustomIndex";
return result;
}
void MPServersModel::refresh()
{
if (m_mpServerRequest.get()) {
return; // in-progress
}
string url(fgGetString("/sim/multiplay/serverlist-url",
"http://liveries.flightgear.org/mpstatus/mpservers.xml"));
if (url.empty()) {
return;
}
SGPropertyNode *targetnode = fgGetNode("/sim/multiplay/server-list", true);
m_mpServerRequest.reset(new RemoteXMLRequest(url, targetnode));
m_mpServerRequest->done(this, &MPServersModel::onRefreshMPServersDone);
m_mpServerRequest->fail(this, &MPServersModel::onRefreshMPServersFailed);
globals->get_subsystem<FGHTTPClient>()->makeRequest(m_mpServerRequest);
}
void MPServersModel::onRefreshMPServersDone(simgear::HTTP::Request*)
{
beginResetModel();
// parse the properties
SGPropertyNode *targetnode = fgGetNode("/sim/multiplay/server-list", true);
m_servers.clear();
for (int i=0; i<targetnode->nChildren(); ++i) {
SGPropertyNode* c = targetnode->getChild(i);
if (c->getName() != std::string("server")) {
continue;
}
if (c->getBoolValue("online") != true) {
// only list online servers
continue;
}
QString name = QString::fromStdString(c->getStringValue("name"));
QString loc = QString::fromStdString(c->getStringValue("location"));
QString host = QString::fromStdString(c->getStringValue("hostname"));
int port = c->getIntValue("port");
m_servers.push_back(ServerInfo(name, loc, host, port));
}
endResetModel();
restoreMPServerSelection();
m_mpServerRequest.clear();
}
void MPServersModel::onRefreshMPServersFailed(simgear::HTTP::Request*)
{
qWarning() << "refreshing MP servers failed:" << QString::fromStdString(m_mpServerRequest->responseReason());
m_mpServerRequest.clear();
beginResetModel();
m_servers.clear();
endResetModel();
restoreMPServerSelection();
}
void MPServersModel::restoreMPServerSelection()
{
if (m_doRestoreMPServer) {
QSettings settings;
settings.beginGroup("mpSettings");
QString host = settings.value("mp-server").toString();
if (host == "__custom__") {
emit restoreIndex(m_servers.size());
} else {
// restore a built-in server
auto it = std::find_if(m_servers.begin(), m_servers.end(), [host](const ServerInfo& info)
{ return (info.host == host); });
if (it != m_servers.end()) {
emit restoreIndex(std::distance(m_servers.begin(), it));
}
}
m_doRestoreMPServer = false;
}
}
void MPServersModel::requestRestore()
{
m_doRestoreMPServer = true;
}
QString MPServersModel::serverForIndex(int index) const
{
if ((index < 0) || (index > m_servers.size())) {
return QString();
}
if (index == m_servers.size()) {
return "__custom__";
}
return m_servers.at(index).host;
}
int MPServersModel::portForIndex(int index) const
{
if ((index < 0) || (index >= m_servers.size())) {
return 0;
}
return m_servers.at(index).port;
}
MPServersModel::ServerInfo::ServerInfo(QString n, QString l, QString h, int p)
{
name = n;
location = l;
host = h;
port = p;
}

53
src/GUI/MPServersModel.h Normal file
View file

@ -0,0 +1,53 @@
#ifndef MPSERVERSMODEL_H
#define MPSERVERSMODEL_H
#include <QAbstractListModel>
#include <Network/RemoteXMLRequest.hxx>
class MPServersModel : public QAbstractListModel
{
Q_OBJECT
public:
MPServersModel(QObject* parent = nullptr);
~MPServersModel();
int rowCount(const QModelIndex& index) const override;
QVariant data(const QModelIndex& index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
void onRefreshMPServersDone(simgear::HTTP::Request*);
void onRefreshMPServersFailed(simgear::HTTP::Request*);
int findMPServerPort(const std::string& host);
void restoreMPServerSelection();
void refresh();
void requestRestore();
Q_INVOKABLE QString serverForIndex(int index) const;
Q_INVOKABLE int portForIndex(int index) const;
signals:
void restoreIndex(int index);
private:
SGSharedPtr<RemoteXMLRequest> m_mpServerRequest;
bool m_doRestoreMPServer = false;
struct ServerInfo
{
ServerInfo(QString n, QString l, QString h, int port);
QString name, location, host;
int port = 0;
};
std::vector<ServerInfo> m_servers;
};
#endif // MPSERVERSMODEL_H

View file

@ -1,15 +0,0 @@
#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;
}

View file

@ -1,22 +0,0 @@
#ifndef MP_SETTINGS_H
#define MP_SETTINGS_H
#include <GUI/settingssection.h>
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

88
src/GUI/MPSettings.qml Normal file
View file

@ -0,0 +1,88 @@
import FlightGear.Launcher 1.0
import QtQml 2.0
Section {
// note this id is used, hard-coded, in MPServersModel
id: mpSettings
title: "Multi-player"
Checkbox {
id: enableMP
label: "Connect to the multi-player network"
description: "Flightgear supporters maintain a network of server to enable global multi-user "
+ "flight. This requires a moderately fast Inernet connection to be usable. Your aircraft "
+ "will be visible to other users online, and you will see their aircraft."
keywords: ["network", "mp"]
}
LineEdit {
id: callSign
enabled: enableMP.checked
label: "Call-sign"
description: "Enter a call-sign you will use online. This is visible to all users and is " +
"how ATC services and other pilots will refer to you. " +
"(Maximum of ten charatcers permitted)"
placeholder: "D-FGFS"
}
Combo {
id: mpServer
label: "Server"
enabled: enableMP.checked
description: "Select a server close to you for better responsiveness and reduced lag when flying online."
model: _mpServers
readonly property bool currentIsCustom: (model.serverForIndex(selectedIndex) == "__custom__")
}
Connections
{
target: _mpServers
onRestoreIndex: {
mpServer.selectedIndex = index
}
}
LineEdit {
id: mpCustomServer
enabled: enableMP.checked
label: "Custom server"
visible: mpServer.currentIsCustom
description: "Enter a server hostname or IP address, and a port number. For example 'localhost:5001'"
placeholder: "localhost:5001"
}
onApply: {
if (enableMP.checked) {
if (mpServer.currentIsCustom) {
var pieces = mpCustomServer.value.split(':')
_config.setProperty("/sim/multiplay/txhost", pieces[0]);
_config.setProperty("/sim/multiplay/txport", pieces[1]);
} else {
var sel = mpServer.selectedIndex
_config.setProperty("/sim/multiplay/txhost", _mpServers.serverForIndex(sel));
var port = _mpServers.portForIndex(sel);
if (port == 0) {
port = 5000; // default MP port
}
_config.setProperty("/sim/multiplay/txport", port);
}
if (callSign.value.length > 0) {
_config.setArg("callsign", callSign.value)
}
}
}
onRestore: {
// nothing to do, restoration is done by the C++ code
// in MPServersModel::restoreMPServerSelection
}
onSave: {
saveSetting("mp-server", _mpServers.serverForIndex(mpServer.selectedIndex));
}
summary: enableMP.checked ? "multi-player;" : ""
}

View file

@ -1,160 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MPSettings</class>
<widget class="SettingsSection" name="MPSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>771</width>
<height>331</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="title" stdset="0">
<string>Multi-player</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string>Connect to the multi-player network</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Fly with hundreds of other pilots around the world.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0,0">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Callsign:</string>
</property>
<property name="advanced" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Your call-sign identifies you to other pliots and controllers on the network. Callsigns are limited to ten characters.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Server:</string>
</property>
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_3">
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>Automatic</string>
</property>
</item>
<item>
<property name="text">
<string>Thread for culling and drawing</string>
</property>
</item>
<item>
<property name="text">
<string>Separate threads for culling and drawing</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Choose a specific multiplayer server, or enter a custom server</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SettingsSection</class>
<extends>QWidget</extends>
<header location="global">GUI/settingssection.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -53,26 +53,12 @@ AddOnsPage::AddOnsPage(QWidget *parent, simgear::pkg::RootRef root) :
connect(m_ui->removeAircraftPath, &QToolButton::clicked,
this, &AddOnsPage::onRemoveAircraftPath);
connect(m_ui->changeDownloadDir, &QPushButton::clicked,
this, &AddOnsPage::onChangeDownloadDir);
connect(m_ui->clearDownloadDir, &QPushButton::clicked,
this, &AddOnsPage::onClearDownloadDir);
connect(m_ui->changeDataDir, &QPushButton::clicked,
this, &AddOnsPage::onChangeDataDir);
connect(m_ui->installSceneryButton, &QPushButton::clicked,
this, &AddOnsPage::onInstallScenery);
m_ui->sceneryPathsList->setToolTip(
tr("After changing this list, please restart the launcher to avoid "
"possibly inconsistent behavior."));
m_ui->changeDownloadDir->setToolTip(
tr("After changing this location, you may have to restart the launcher "
"to avoid inconsistent behavior."));
m_ui->clearDownloadDir->setToolTip(
tr("If you use this button, you may have to restart the launcher "
"to avoid inconsistent behavior."));
m_ui->installSceneryButton->setToolTip(
tr("After installing scenery, you may have to restart the launcher "
"to avoid inconsistent behavior."));
@ -85,11 +71,6 @@ AddOnsPage::AddOnsPage(QWidget *parent, simgear::pkg::RootRef root) :
QStringList aircraftPaths = settings.value("aircraft-paths").toStringList();
m_ui->aircraftPathsList->addItems(aircraftPaths);
QVariant downloadDir = settings.value("download-dir");
if (downloadDir.isValid()) {
m_downloadDir = downloadDir.toString();
}
updateUi();
}
@ -294,76 +275,11 @@ void AddOnsPage::onRemoveCatalog()
updateUi();
}
void AddOnsPage::onChangeDownloadDir()
{
QString path = QFileDialog::getExistingDirectory(this,
tr("Choose downloads folder"),
m_downloadDir);
if (path.isEmpty()) {
return; // user cancelled
}
m_downloadDir = path;
setDownloadDir();
}
void AddOnsPage::onClearDownloadDir()
{
// does this need an 'are you sure'?
m_downloadDir.clear();
setDownloadDir();
}
void AddOnsPage::setDownloadDir()
{
QSettings settings;
if (m_downloadDir.isEmpty()) {
settings.remove("download-dir");
} else {
settings.setValue("download-dir", m_downloadDir);
}
if (m_downloadDir.isEmpty()) {
flightgear::Options::sharedInstance()->clearOption("download-dir");
} else {
flightgear::Options::sharedInstance()->setOption("download-dir", m_downloadDir.toStdString());
}
emit downloadDirChanged();
updateUi();
}
void AddOnsPage::onChangeDataDir()
{
QMessageBox mbox(this);
mbox.setText(tr("Change the data files used by FlightGear?"));
mbox.setInformativeText(tr("FlightGear requires additional files to operate. "
"(Also called the base package, or fg-data) "
"You can restart FlightGear and choose a "
"different data files location, or restore the default setting."));
QPushButton* quitButton = mbox.addButton(tr("Restart FlightGear now"), QMessageBox::YesRole);
mbox.addButton(QMessageBox::Cancel);
mbox.setDefaultButton(QMessageBox::Cancel);
mbox.setIconPixmap(QPixmap(":/app-icon-large"));
mbox.exec();
if (mbox.clickedButton() != quitButton) {
return;
}
{
QSettings settings;
// set the option to the magic marker value
settings.setValue("fg-root", "!ask");
} // scope the ensure settings are written nicely
flightgear::restartTheApp();
}
void AddOnsPage::onInstallScenery()
{
InstallSceneryDialog dlg(this, m_downloadDir);
QSettings settings;
QString downloadDir = settings.value("download-dir").toString();
InstallSceneryDialog dlg(this, downloadDir);
if (dlg.exec() == QDialog::Accepted) {
if (!haveSceneryPath(dlg.sceneryPath())) {
m_ui->sceneryPathsList->addItem(dlg.sceneryPath());
@ -374,30 +290,6 @@ void AddOnsPage::onInstallScenery()
void AddOnsPage::updateUi()
{
QString s = m_downloadDir;
if (s.isEmpty()) {
s = QString::fromStdString(flightgear::defaultDownloadDir().utf8Str());
s.append(tr(" (default)"));
m_ui->clearDownloadDir->setEnabled(false);
} else {
m_ui->clearDownloadDir->setEnabled(true);
}
QString m = tr("Download location: %1").arg(s);
m_ui->downloadLocation->setText(m);
QString dataLoc;
QSettings settings;
QString root = settings.value("fg-root").toString();
if (root.isNull()) {
dataLoc = tr("built-in");
} else {
dataLoc = root;
}
m_ui->dataLocation->setText(tr("Data location: %1").arg(dataLoc));
FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();
m_ui->addDefaultCatalogButton->setEnabled(!http->isDefaultCatalogInstalled());
}

View file

@ -23,7 +23,6 @@ public:
static void addDefaultCatalog(QWidget* pr, bool silent);
signals:
void downloadDirChanged();
void sceneryPathsChanged();
void aircraftPathsChanged();
@ -38,14 +37,9 @@ private slots:
void onRemoveCatalog();
void onAddDefaultCatalog();
void onChangeDownloadDir();
void onClearDownloadDir();
void onChangeDataDir();
void onInstallScenery();
private:
void updateUi();
void setDownloadDir();
void saveAircraftPaths();
void saveSceneryPaths();
@ -54,7 +48,6 @@ private:
Ui::AddOnsPage* m_ui;
CatalogListModel* m_catalogsModel;
simgear::pkg::RootRef m_packageRoot;
QString m_downloadDir;
};

View file

@ -29,108 +29,6 @@
<property name="bottomMargin">
<number>4</number>
</property>
<item>
<widget class="QLabel" name="dataLocation">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,1,0">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>16</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<pointsize>11</pointsize>
</font>
</property>
<property name="text">
<string>FlightGear needs certain files (sometimes called 'fg-data') to function - these are included as part of stable releases.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="changeDataDir">
<property name="text">
<string>Change...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="downloadLocation">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,0,0">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>16</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="font">
<font>
<pointsize>11</pointsize>
</font>
</property>
<property name="text">
<string>Aircraft hangars and automatic scenery downloads may cause this location to contain large numbers of files. Changing this location will cause files to be downloaded again.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="changeDownloadDir">
<property name="text">
<string>Change...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearDownloadDir">
<property name="text">
<string>Use default</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>

View file

@ -0,0 +1,54 @@
import FlightGear.Launcher 1.0
Section {
id: renderingSetttings
title: "Rendering"
readonly property bool rembrandt: (renderer.selectedIndex == 2)
readonly property bool alsEnabled: (renderer.selectedIndex == 1)
readonly property bool msaaEnabled: !rembrandt && (msaa.selectedIndex > 0)
Combo {
id: renderer
label: "Renderer"
choices: ["Default", "Atmospheric Light-Scattering", "Rembrandt"]
description: descriptions[selectedIndex]
defaultIndex: 0
readonly property var descriptions: [
"The default renderer provides standard visuals with maximum compatability",
"The ALS renderer uses a sophisticated physical atmospheric model and several " +
"other effects to give realistic rendering of large distances.",
"Rembrandt is a configurable multi-pass renderer which supports shadow-maps, cinematic " +
"effects and more. However, not all aircraft appear correctly and performance will " +
"depend greatly on your system hardware."
]
}
Combo {
id: msaa
label: "Anti-aliasing"
description: "Anti-aliasing improves the appearance of high-contrast edges and lines." +
"This is especially noticeable on sloping or diagonal egdes. " +
"Higher settings can reduce performance."
keywords: ["msaa"]
choices: ["Off", "2x", "4x"]
enabled: !rembrandt
property var data: [0, 2, 4];
defaultIndex: 0
}
onApply: {
_config.setProperty("/sim/rendering/multi-sample-buffers", msaaEnabled)
_config.setProperty("/sim/rendering/multi-samples", msaa.data[msaa.selectedIndex])
_config.setEnableDisableOption("rembrandt", rembrandt);
if (alsEnabled) {
_config.setProperty("/sim/rendering/shaders/skydome", true);
}
}
summary: (rembrandt ? "Rembrandt;" : (alsEnabled ? "ALS;" : ""))
+ (msaaEnabled ? "anti-aliasing;" : "")
}

View file

@ -0,0 +1,161 @@
#include "SettingsSectionQML.hxx"
#include <QVBoxLayout>
#include <QSettings>
#include <QQmlEngine>
#include <QQmlContext>
#include <QDebug>
#include "AdvancedSettingsButton.h"
#include "SettingsWidgets.hxx"
#include "LaunchConfig.hxx"
SettingsSectionQML::SettingsSectionQML()
{
}
void SettingsSectionQML::internalUpdateAdvanced()
{
Q_FOREACH (SettingsControl* w, controls()) {
if (w->advanced()) {
w->setVisible(m_showAdvanced);
}
if (w->property("simple").toBool()) {
w->setVisible(!m_showAdvanced);
}
}
}
void SettingsSectionQML::controls_append(QQmlListProperty<QObject> *prop, QObject *item)
{
SettingsSectionQML* self = qobject_cast<SettingsSectionQML*>(prop->object);
QVBoxLayout* topLevelVBox = qobject_cast<QVBoxLayout*>(self->layout());
self->m_controls.append(item);
SettingsControl* control = qobject_cast<SettingsControl*>(item);
if (control) {
// following two lines would not be needed if the custom
// setParent function was working :(
control->setParent(nullptr);
control->setParent(self);
topLevelVBox->addWidget(control);
}
}
void SettingsSectionQML::controls_clear(QQmlListProperty<QObject> *prop)
{
SettingsSectionQML* self = qobject_cast<SettingsSectionQML*>(prop->object);
QVBoxLayout* topLevelVBox = qobject_cast<QVBoxLayout*>(self->layout());
Q_FOREACH (QObject* c, self->m_controls) {
SettingsControl* control = qobject_cast<SettingsControl*>(c);
if (control) {
topLevelVBox->removeWidget(control);
}
}
}
int SettingsSectionQML::controls_count(QQmlListProperty<QObject> *prop)
{
SettingsSectionQML* self = qobject_cast<SettingsSectionQML*>(prop->object);
return self->m_controls.count();
}
QObject *SettingsSectionQML::control_at(QQmlListProperty<QObject> *prop, int index)
{
SettingsSectionQML* self = qobject_cast<SettingsSectionQML*>(prop->object);
return self->m_controls.at(index);
}
QQmlListProperty<QObject> SettingsSectionQML::qmlControls()
{
return QQmlListProperty<QObject>(this, nullptr,
&SettingsSectionQML::controls_append,
&SettingsSectionQML::controls_count,
&SettingsSectionQML::control_at,
&SettingsSectionQML::controls_clear);
}
QList<SettingsControl *> SettingsSectionQML::controls() const
{
return findChildren<SettingsControl*>();
}
void SettingsSectionQML::updateShowAdvanced()
{
bool needsShowAdvanced = false;
Q_FOREACH (SettingsControl* w, controls()) {
needsShowAdvanced |= w->advanced();
}
m_advancedModeToggle->setVisible(needsShowAdvanced);
}
void SettingsSectionQML::saveState(QSettings &settings) const
{
QQmlContext* context = QQmlEngine::contextForObject(this);
QString s = context->nameForObject(const_cast<SettingsSectionQML*>(this));
settings.beginGroup(s);
Q_FOREACH (SettingsControl* control, controls()) {
control->saveState(settings);
}
const_cast<SettingsSectionQML*>(this)->save();
settings.endGroup();
}
void SettingsSectionQML::restoreState(QSettings &settings)
{
QQmlContext* context = QQmlEngine::contextForObject(this);
QString s = context->nameForObject(const_cast<SettingsSectionQML*>(this));
settings.beginGroup(s);
Q_FOREACH (SettingsControl* control, controls()) {
control->restoreState(settings);
}
settings.endGroup();
emit restore();
}
void SettingsSectionQML::doApply()
{
LaunchConfig* config = qobject_cast<LaunchConfig*>(sender());
Q_FOREACH (SettingsControl* control, controls()) {
control->apply(config);
}
emit apply();
}
QString SettingsSectionQML::summary() const
{
return m_summary;
}
void SettingsSectionQML::saveSetting(QString key, QVariant value)
{
QSettings settings;
QQmlContext* context = QQmlEngine::contextForObject(this);
QString s = context->nameForObject(const_cast<SettingsSectionQML*>(this));
settings.beginGroup(s);
settings.setValue(key, value);
}
QVariant SettingsSectionQML::restoreSetting(QString key)
{
QSettings settings;
QQmlContext* context = QQmlEngine::contextForObject(this);
QString s = context->nameForObject(const_cast<SettingsSectionQML*>(this));
settings.beginGroup(s);
return settings.value(key);
}
void SettingsSectionQML::setSummary(QString summary)
{
if (m_summary == summary)
return;
m_summary = summary;
emit qmlSummaryChanged(summary);
emit summaryChanged(summary);
}

View file

@ -0,0 +1,68 @@
#ifndef SETTINGSSECTIONQML_HXX
#define SETTINGSSECTIONQML_HXX
#include "settingssection.h"
#include <QQmlListProperty>
class SettingsControl;
class SettingsSectionQML : public SettingsSection
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<QObject> controls READ qmlControls)
Q_PROPERTY(QString summary READ summary WRITE setSummary NOTIFY qmlSummaryChanged)
Q_CLASSINFO("DefaultProperty", "controls")
public:
SettingsSectionQML();
QQmlListProperty<QObject> qmlControls();
QList<SettingsControl*> controls() const;
void saveState(QSettings& settings) const override;
void restoreState(QSettings& settings) override;
void doApply() override;
virtual QString summary() const override;
Q_INVOKABLE void saveSetting(QString key, QVariant value);
Q_INVOKABLE QVariant restoreSetting(QString key);
public slots:
void setSummary(QString summary);
signals:
void controlsChanged();
/**
* @brief apply - change the launch configuration according to the values
* in this settings section.
*/
void apply();
void save();
void restore();
void qmlSummaryChanged(QString summary);
private:
static void controls_append( QQmlListProperty<QObject>* prop,
QObject* item );
static void controls_clear( QQmlListProperty<QObject>* prop );
static int controls_count( QQmlListProperty<QObject>* prop );
static QObject* control_at( QQmlListProperty<QObject>* prop, int index );
void internalUpdateAdvanced() override;
void updateShowAdvanced() override;
QString m_summary;
QObjectList m_controls;
};
#endif // SETTINGSSECTIONQML_HXX

627
src/GUI/SettingsWidgets.cxx Normal file
View file

@ -0,0 +1,627 @@
#include "SettingsWidgets.hxx"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QCheckBox>
#include <QLabel>
#include <QComboBox>
#include <QSpinBox>
#include <QSettings>
#include <QLineEdit>
#include <QDebug>
#include <QPushButton>
#include <QFileDialog>
#include <QQmlEngine>
#include <QQmlContext>
#include <QDateTimeEdit>
#include "LaunchConfig.hxx"
SettingsCheckbox::SettingsCheckbox(QWidget* parent) :
SettingsControl(parent)
{
QVBoxLayout* vbox = new QVBoxLayout(this);
setLayout(vbox);
m_check = new QCheckBox(this);
vbox->addWidget(m_check);
createDescription();
vbox->addWidget(m_description);
connect(m_check, &QCheckBox::toggled, this, &SettingsCheckbox::checkedChanged);
}
QString SettingsCheckbox::label() const
{
return m_check->text();
}
bool SettingsCheckbox::isChecked() const
{
return m_check->isChecked();
}
void SettingsCheckbox::setChecked(bool checked)
{
if (checked == isChecked()) {
return;
}
m_check->setChecked(checked);
emit checkedChanged(checked);
}
void SettingsCheckbox::setLabel(QString label)
{
m_check->setText(label);
}
void SettingsCheckbox::apply(LaunchConfig* lconfig) const
{
if (option().isEmpty()) {
return;
}
lconfig->setEnableDisableOption(option(), isChecked());
}
void SettingsCheckbox::saveState(QSettings &settings) const
{
settings.setValue(qmlName(), isChecked());
}
void SettingsCheckbox::restoreState(QSettings &settings)
{
setChecked(settings.value(qmlName(), isChecked()).toBool());
}
QString SettingsControl::label() const
{
return QString();
}
QString SettingsControl::description() const
{
if (m_description) {
return m_description->text();
}
return QString();
}
QStringList SettingsControl::keywords() const
{
return m_keywords;
}
QString SettingsControl::option() const
{
return m_option;
}
void SettingsControl::setAdvanced(bool advanced)
{
if (m_advanced == advanced)
return;
m_advanced = advanced;
emit advancedChanged(advanced);
}
void SettingsControl::setDescription(QString desc)
{
if (m_description) {
m_description->setText(desc);
}
emit descriptionChanged();
}
void SettingsControl::apply(LaunchConfig *lconfig) const
{
Q_UNUSED(lconfig)
}
void SettingsControl::setKeywords(QStringList keywords)
{
if (m_keywords == keywords)
return;
m_keywords = keywords;
emit keywordsChanged(keywords);
}
void SettingsControl::setOption(QString option)
{
if (m_option == option)
return;
m_option = option;
emit optionChanged(option);
}
SettingsControl::SettingsControl(QWidget *pr) :
QWidget(pr)
{
}
void SettingsControl::createDescription()
{
m_description = new QLabel(this);
m_description->setWordWrap(true);
QFont f = m_description->font();
f.setPointSize(f.pointSize() - 2);
m_description->setFont(f);
}
QString SettingsControl::qmlName() const
{
QQmlContext* context = QQmlEngine::contextForObject(this);
QString s = context->nameForObject(const_cast<SettingsControl*>(this));
return s;
}
SettingsComboBox::SettingsComboBox(QWidget *pr) :
SettingsControl(pr)
{
QVBoxLayout* vbox = new QVBoxLayout(this);
setLayout(vbox);
QHBoxLayout* hbox = new QHBoxLayout;
vbox->addLayout(hbox);
m_combo = new QComboBox(this);
m_label = new QLabel(this);
hbox->addWidget(m_label);
hbox->addWidget(m_combo);
hbox->addStretch(1);
createDescription();
vbox->addWidget(m_description);
connect(m_combo, SIGNAL(currentIndexChanged(int)),
this, SIGNAL(selectedIndexChanged(int)));
}
QStringList SettingsComboBox::choices() const
{
QStringList result;
for (int i=0; i < m_combo->count(); ++i) {
result.append(m_combo->itemText(i));
}
return result;
}
int SettingsComboBox::selectedIndex() const
{
return m_combo->currentIndex();
}
void SettingsComboBox::saveState(QSettings &settings) const
{
// if selected index is custom, need to save something else?
if (selectedIndex() == m_defaultIndex) {
settings.remove(qmlName());
} else {
settings.setValue(qmlName(), selectedIndex());
}
}
void SettingsComboBox::restoreState(QSettings &settings)
{
QString id = qmlName();
setSelectedIndex(settings.value(id, m_defaultIndex).toInt());
}
void SettingsComboBox::setChoices(QStringList aChoices)
{
if (choices() == aChoices)
return;
m_combo->clear();
Q_FOREACH (QString choice, aChoices) {
m_combo->addItem(choice);
}
emit choicesChanged(aChoices);
}
void SettingsComboBox::setSelectedIndex(int selectedIndex)
{
if (m_combo->currentIndex() == selectedIndex)
return;
m_combo->setCurrentIndex(selectedIndex);
emit selectedIndexChanged(selectedIndex);
}
void SettingsComboBox::setLabel(QString label)
{
m_label->setText(label);
emit labelChanged();
}
QAbstractItemModel *SettingsComboBox::model() const
{
return m_combo->model();
}
int SettingsComboBox::defaultIndex() const
{
return m_defaultIndex;
}
void SettingsComboBox::setModel(QAbstractItemModel *model)
{
if (model == m_combo->model()) {
return;
}
m_combo->setModel(model);
emit modelChanged(model);
}
void SettingsComboBox::setDefaultIndex(int defaultIndex)
{
if (m_defaultIndex == defaultIndex)
return;
m_defaultIndex = defaultIndex;
emit defaultIndexChanged(defaultIndex);
}
/////////////////////////////////////////////////////////////////////////////////
SettingsIntSpinbox::SettingsIntSpinbox(QWidget *pr) :
SettingsControl(pr)
{
QVBoxLayout* vbox = new QVBoxLayout(this);
setLayout(vbox);
QHBoxLayout* hbox = new QHBoxLayout;
vbox->addLayout(hbox);
m_spin = new QSpinBox(this);
m_label = new QLabel(this);
hbox->addWidget(m_label);
hbox->addWidget(m_spin);
hbox->addStretch(1);
createDescription();
vbox->addWidget(m_description);
connect(m_spin, SIGNAL(valueChanged(int)), this, SIGNAL(valueChanged(int)));
}
int SettingsIntSpinbox::value() const
{
return m_spin->value();
}
int SettingsIntSpinbox::min() const
{
return m_spin->minimum();
}
int SettingsIntSpinbox::max() const
{
return m_spin->maximum();
}
void SettingsIntSpinbox::apply(LaunchConfig *lconfig) const
{
if (option().isEmpty()) {
return;
}
lconfig->setArg(option(), QString::number(value()));
}
void SettingsIntSpinbox::saveState(QSettings &settings) const
{
settings.setValue(qmlName(), value());
}
void SettingsIntSpinbox::restoreState(QSettings &settings)
{
setValue(settings.value(qmlName(), value()).toInt());
}
void SettingsIntSpinbox::setValue(int aValue)
{
if (value() == aValue)
return;
m_spin->setValue(aValue);
emit valueChanged(aValue);
}
void SettingsIntSpinbox::setMin(int aMin)
{
if (min() == aMin)
return;
m_spin->setMinimum(aMin);
emit minChanged(aMin);
}
void SettingsIntSpinbox::setMax(int aMax)
{
if (max() == aMax)
return;
m_spin->setMaximum(aMax);
emit maxChanged(aMax);
}
void SettingsIntSpinbox::setLabel(QString label)
{
m_label->setText(label);
emit labelChanged();
}
SettingsText::SettingsText(QWidget *pr) :
SettingsControl(pr)
{
QVBoxLayout* vbox = new QVBoxLayout(this);
setLayout(vbox);
QHBoxLayout* hbox = new QHBoxLayout;
vbox->addLayout(hbox);
m_edit = new QLineEdit(this);
m_label = new QLabel(this);
hbox->addWidget(m_label);
hbox->addWidget(m_edit, 1);
// hbox->addStretch(1);
createDescription();
vbox->addWidget(m_description);
connect(m_edit, &QLineEdit::textChanged, this, &SettingsText::valueChanged);
}
QString SettingsText::value() const
{
return m_edit->text();
}
void SettingsText::apply(LaunchConfig *lconfig) const
{
if (option().isEmpty()) {
return;
}
lconfig->setArg(option(), value());
}
void SettingsText::saveState(QSettings &settings) const
{
settings.setValue(qmlName(), value());
}
void SettingsText::restoreState(QSettings &settings)
{
setValue(settings.value(qmlName(), value()).toString());
}
void SettingsText::setLabel(QString label)
{
m_label->setText(label);
}
void SettingsText::setValue(QString newVal)
{
if (value() == newVal)
return;
m_edit->setText(newVal);
emit valueChanged(newVal);
}
QString SettingsText::placeholder() const
{
#if QT_VERSION >= 0x050300
return m_edit->placeholderText();
#else
return QString();
#endif
}
void SettingsText::setPlaceholder(QString hold)
{
if (placeholder() == hold)
return;
#if QT_VERSION >= 0x050300
// don't require Qt 5.3
m_edit->setPlaceholderText(hold);
#endif
emit placeholderChanged(hold);
}
SettingsPath::SettingsPath(QWidget *pr) :
SettingsControl(pr)
{
QVBoxLayout* vbox = new QVBoxLayout(this);
setLayout(vbox);
QHBoxLayout* hbox = new QHBoxLayout;
vbox->addLayout(hbox);
m_changeButton = new QPushButton(tr("Change"), this);
connect(m_changeButton, &QPushButton::clicked, this, &SettingsPath::choosePath);
m_defaultButton = new QPushButton(tr("Default"), this);
connect(m_defaultButton, &QPushButton::clicked, this, &SettingsPath::restoreDefaultPath);
m_label = new QLabel(this);
hbox->addWidget(m_label, 1);
hbox->addWidget(m_changeButton);
hbox->addWidget(m_defaultButton);
createDescription();
vbox->addWidget(m_description);
}
QString SettingsPath::path() const
{
return m_path;
}
void SettingsPath::setPath(QString path)
{
if (m_path == path)
return;
m_path = path;
emit pathChanged(path);
updateLabel();
}
void SettingsPath::setLabel(QString label)
{
m_labelPrefix = label;
updateLabel();
}
void SettingsPath::apply(LaunchConfig *lconfig) const
{
if (m_option.isEmpty()) {
return;
}
if (m_path.isEmpty()) {
return;
}
lconfig->setArg(option(), path());
}
void SettingsPath::setDefaultPath(QString path)
{
if (m_defaultPath == path)
return;
m_defaultPath = path;
m_defaultButton->setVisible(!m_defaultPath.isEmpty());
emit defaultPathChanged(path);
updateLabel();
}
void SettingsPath::setChooseDirectory(bool chooseDirectory)
{
if (m_chooseDirectory == chooseDirectory)
return;
m_chooseDirectory = chooseDirectory;
emit chooseDirectoryChanged(chooseDirectory);
}
void SettingsPath::choosePath()
{
QString path;
if (m_chooseDirectory) {
path = QFileDialog::getExistingDirectory(this,
m_dialogPrompt,
m_path);
} else {
// if we're going to use this, add filter support
path = QFileDialog::getOpenFileName(this, m_dialogPrompt, m_path);
}
if (path.isEmpty()) {
return; // user cancelled
}
setPath(path);
}
void SettingsPath::restoreDefaultPath()
{
setPath(QString());
}
void SettingsPath::setDialogPrompt(QString dialogPrompt)
{
if (m_dialogPrompt == dialogPrompt)
return;
m_dialogPrompt = dialogPrompt;
emit dialogPromptChanged(dialogPrompt);
}
void SettingsPath::setOption(QString option)
{
if (m_option == option)
return;
m_option = option;
emit optionChanged(option);
}
void SettingsPath::updateLabel()
{
const bool isDefault = (m_path.isEmpty());
QString s = isDefault ? tr("%1: %2 (default)") : tr("%1: %2");
QString path = isDefault ? defaultPath() : m_path;
m_label->setText(s.arg(m_labelPrefix).arg(path));
m_defaultButton->setEnabled(!isDefault);
}
void SettingsPath::saveState(QSettings &settings) const
{
settings.setValue(qmlName(), m_path);
}
void SettingsPath::restoreState(QSettings &settings)
{
QString s = settings.value(qmlName(), QString()).toString();
setPath(s);
}
SettingsDateTime::SettingsDateTime(QWidget *pr) :
SettingsControl(pr)
{
QVBoxLayout* vbox = new QVBoxLayout(this);
setLayout(vbox);
QHBoxLayout* hbox = new QHBoxLayout;
vbox->addLayout(hbox);
m_edit = new QDateTimeEdit;
m_label = new QLabel(this);
hbox->addWidget(m_label);
hbox->addWidget(m_edit);
hbox->addStretch(1);
createDescription();
vbox->addWidget(m_description);
}
void SettingsDateTime::saveState(QSettings &settings) const
{
settings.setValue(qmlName(), value());
}
void SettingsDateTime::restoreState(QSettings &settings)
{
m_edit->setDateTime(settings.value(qmlName()).toDateTime());
}
void SettingsDateTime::setLabel(QString label)
{
m_label->setText(label);
}
QDateTime SettingsDateTime::value() const
{
return m_edit->dateTime();
}
void SettingsDateTime::setValue(QDateTime value)
{
if (m_edit->dateTime() == value) {
}
emit valueChanged(value);
}

352
src/GUI/SettingsWidgets.hxx Normal file
View file

@ -0,0 +1,352 @@
#ifndef SETTINGSWIDGETS_HXX
#define SETTINGSWIDGETS_HXX
#include <QWidget>
#include <QDateTime>
class QCheckBox;
class QComboBox;
class QSpinBox;
class QLineEdit;
class QLabel;
class QSettings;
class LaunchConfig;
class QPushButton;
class QAbstractItemModel;
class QDateTimeEdit;
class SettingsControl : public QWidget
{
Q_OBJECT
Q_PROPERTY(bool advanced READ advanced WRITE setAdvanced NOTIFY advancedChanged)
Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged)
Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged)
Q_PROPERTY(QStringList keywords READ keywords WRITE setKeywords NOTIFY keywordsChanged)
Q_PROPERTY(QString option READ option WRITE setOption NOTIFY optionChanged)
public:
bool advanced() const
{
return m_advanced;
}
virtual QString label() const;
virtual QString description() const;
QStringList keywords() const;
QString option() const;
virtual void saveState(QSettings& settings) const = 0;
virtual void restoreState(QSettings& settings) = 0;
public slots:
void setAdvanced(bool advanced);
virtual void setDescription(QString desc);
virtual void setLabel(QString label) = 0;
virtual void apply(LaunchConfig* lconfig) const;
void setKeywords(QStringList keywords);
void setOption(QString option);
signals:
void advancedChanged(bool advanced);
void labelChanged();
void descriptionChanged();
void keywordsChanged(QStringList keywords);
void optionChanged(QString option);
protected:
SettingsControl(QWidget* pr = nullptr);
void createDescription();
QString qmlName() const;
QLabel* m_description = nullptr;
private:
bool m_advanced = false;
QStringList m_keywords;
QString m_option;
};
class SettingsCheckbox : public SettingsControl
{
Q_OBJECT
Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY checkedChanged)
bool isChecked() const;
public:
SettingsCheckbox(QWidget* pr = nullptr);
virtual QString label() const override;
virtual void setLabel(QString label) override;
virtual void apply(LaunchConfig* lconfig) const override;
virtual void saveState(QSettings& settings) const override;
virtual void restoreState(QSettings& settings) override;
public slots:
void setChecked(bool checked);
signals:
void checkedChanged(bool checked);
private:
QCheckBox* m_check;
};
class SettingsComboBox : public SettingsControl
{
Q_OBJECT
Q_PROPERTY(int selectedIndex READ selectedIndex WRITE setSelectedIndex NOTIFY selectedIndexChanged)
Q_PROPERTY(QStringList choices READ choices WRITE setChoices NOTIFY choicesChanged)
Q_PROPERTY(QAbstractItemModel* model READ model WRITE setModel NOTIFY modelChanged)
Q_PROPERTY(int defaultIndex READ defaultIndex WRITE setDefaultIndex NOTIFY defaultIndexChanged)
public:
SettingsComboBox(QWidget* pr = nullptr);
QStringList choices() const;
int selectedIndex() const;
virtual void saveState(QSettings& settings) const override;
virtual void restoreState(QSettings& settings) override;
QAbstractItemModel* model() const;
int defaultIndex() const;
public slots:
void setChoices(QStringList choices);
void setSelectedIndex(int selectedIndex);
void setModel(QAbstractItemModel* model);
void setDefaultIndex(int defaultIndex);
signals:
void choicesChanged(QStringList choices);
void selectedIndexChanged(int selectedIndex);
void modelChanged(QAbstractItemModel* model);
void defaultIndexChanged(int defaultIndex);
protected:
virtual void setLabel(QString label) override;
private:
QLabel* m_label;
QComboBox* m_combo;
QStringList m_choices;
int m_selectedIndex = 0;
int m_defaultIndex = -1;
};
class SettingsIntSpinbox : public SettingsControl
{
Q_OBJECT
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
Q_PROPERTY(int min READ min WRITE setMin NOTIFY minChanged)
Q_PROPERTY(int max READ max WRITE setMax NOTIFY maxChanged)
// suffix / wrap information
public:
SettingsIntSpinbox(QWidget* pr = nullptr);
int value() const;
int min() const;
int max() const;
virtual void apply(LaunchConfig* lconfig) const override;
virtual void saveState(QSettings& settings) const override;
virtual void restoreState(QSettings& settings) override;
public slots:
void setValue(int value);
void setMin(int min);
void setMax(int max);
signals:
void valueChanged(int value);
void minChanged(int min);
void maxChanged(int max);
protected:
virtual void setLabel(QString label) override;
private:
QSpinBox* m_spin;
QLabel* m_label;
int m_value;
int m_min;
int m_max;
};
class SettingsText : public SettingsControl
{
Q_OBJECT
Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged)
Q_PROPERTY(QString placeholder READ placeholder WRITE setPlaceholder NOTIFY placeholderChanged)
public:
SettingsText(QWidget *pr = nullptr);
QString value() const;
virtual void apply(LaunchConfig* lconfig) const override;
virtual void saveState(QSettings& settings) const override;
virtual void restoreState(QSettings& settings) override;
virtual void setLabel(QString label) override;
QString placeholder() const;
public slots:
void setValue(QString value);
void setPlaceholder(QString placeholder);
signals:
void valueChanged(QString value);
void placeholderChanged(QString placeholder);
private:
QLineEdit* m_edit;
QLabel* m_label;
};
class SettingsPath : public SettingsControl
{
Q_OBJECT
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
Q_PROPERTY(QString defaultPath READ defaultPath WRITE setDefaultPath
NOTIFY defaultPathChanged)
Q_PROPERTY(bool chooseDirectory READ chooseDirectory
WRITE setChooseDirectory NOTIFY chooseDirectoryChanged)
Q_PROPERTY(QString dialogPrompt READ dialogPrompt
WRITE setDialogPrompt NOTIFY dialogPromptChanged)
Q_PROPERTY(QString option READ option WRITE setOption NOTIFY optionChanged)
public:
SettingsPath(QWidget *pr = nullptr);
QString path() const;
virtual void saveState(QSettings& settings) const override;
virtual void restoreState(QSettings& settings) override;
virtual void setLabel(QString label) override;
virtual void apply(LaunchConfig* lconfig) const override;
QString defaultPath() const
{
return m_defaultPath;
}
bool chooseDirectory() const
{
return m_chooseDirectory;
}
QString dialogPrompt() const
{
return m_dialogPrompt;
}
QString option() const
{
return m_option;
}
public slots:
void setPath(QString path);
void setDefaultPath(QString path);
void setChooseDirectory(bool chooseDirectory);
void choosePath();
void restoreDefaultPath();
void setDialogPrompt(QString dialogPrompt);
void setOption(QString option);
signals:
void defaultPathChanged(QString defaultPath);
void pathChanged(QString path);
void chooseDirectoryChanged(bool chooseDirectory);
void dialogPromptChanged(QString dialogPrompt);
void optionChanged(QString option);
private:
void updateLabel();
QPushButton* m_changeButton;
QPushButton* m_defaultButton;
QString m_path;
QString m_defaultPath;
QLabel* m_label;
QString m_labelPrefix;
bool m_chooseDirectory = false;
QString m_dialogPrompt;
QString m_option;
};
class SettingsDateTime : public SettingsControl
{
Q_OBJECT
Q_PROPERTY(QDateTime value READ value WRITE setValue NOTIFY valueChanged)
public:
SettingsDateTime(QWidget *pr = nullptr);
virtual void saveState(QSettings& settings) const override;
virtual void restoreState(QSettings& settings) override;
virtual void setLabel(QString label) override;
QDateTime value() const;
public slots:
void setValue(QDateTime value);
signals:
void valueChanged(QDateTime value);
private:
QDateTimeEdit* m_edit;
QLabel* m_label;
QDateTime m_value;
};
#endif // SETTINGSWIDGETS_HXX

72
src/GUI/TimeSettings.qml Normal file
View file

@ -0,0 +1,72 @@
import FlightGear.Launcher 1.0
Section {
id: timeSettings
title: "Time & Date"
Combo {
id: timeOfDay
label: "Time of day"
description: "Select the time of day used when the simulator starts, or enter a "
+ "custom date and time."
choices: ["Current time", "Dawn", "Morning", "Noon", "Afternoon",
"Dusk", "Evening", "Midnight", "Custom time & date"]
defaultIndex: 0
readonly property var args: ["", "dawn", "morning", "noon", "afternoon",
"dusk", "evening", "midnight"]
readonly property bool isCustom: (selectedIndex == 8)
readonly property bool isDefault: (selectedIndex == 0)
function summary()
{
if (!timeOfDay.isCustom && !timeOfDay.isDefault) {
return choices[selectedIndex].toLowerCase() + ";";
}
return "";
}
}
DateTime {
id: customTime
label: "Enter custom time & date"
visible: timeOfDay.isCustom
// description: "Enter a date and time."
}
Checkbox {
id: customTimeIsGMT
label: "Custom time is GMT / UTC"
visible: timeOfDay.isCustom
}
Combo {
id: season
label: "Season"
description: "Select if normal (summer) or winter textures are used for the scenery. "
+ "This does not affect other aspects of the simulation at present."
keywords: ["season", "scenery", "texture", "winter"]
choices: ["Summer (default)", "Winter"]
defaultIndex: 0
readonly property var args: ["summer", "winter"]
}
onApply: {
if (timeOfDay.isCustom) {
var timeString = Qt.formatDateTime(customTime.value, "yyyy:MM:dd:hh:mm:ss");
if (customTimeIsGMT.checked) {
_config.setArg("start-date-gmt", timeString)
} else {
_config.setArg("start-date-sys", timeString)
}
} else if (timeOfDay.selectedIndex > 0) {
_config.setArg("timeofday", timeOfDay.args[timeOfDay.selectedIndex])
}
_config.setArg("season", season.args[season.selectedIndex])
}
summary: timeOfDay.summary()
}

View file

@ -5,6 +5,7 @@
class ToolboxButton : public QAbstractButton
{
Q_OBJECT
public:
ToolboxButton(QWidget* pr = nullptr);

View file

@ -0,0 +1,73 @@
#include "ViewCommandLinePage.hxx"
#include <QTextEdit>
#include <QVBoxLayout>
#include <Main/options.hxx>
#include "LaunchConfig.hxx"
#if 0
#include "ExtraSettingsSection.hxx"
#include "LauncherArgumentTokenizer.hxx"
#endif
ViewCommandLinePage::ViewCommandLinePage(QWidget *parent) : QWidget(parent)
{
QVBoxLayout* vbox = new QVBoxLayout(this);
setLayout(vbox);
m_browser = new QTextEdit(this);
m_browser->setReadOnly(true);
vbox->addWidget(m_browser);
}
#if 0
void ViewCommandLinePage::setExtraSettingsSection(ExtraSettingsSection *ess)
{
m_extraSettings = ess;
}
#endif
void ViewCommandLinePage::setLaunchConfig(LaunchConfig *config)
{
m_config = config;
}
void ViewCommandLinePage::update()
{
QString html;
string_list commandLineOpts = flightgear::Options::sharedInstance()->extractOptions();
if (!commandLineOpts.empty()) {
html += "<p>Options passed on the command line:</p>\n";
html += "<ul>\n";
for (auto opt : commandLineOpts) {
html += QString("<li>--") + QString::fromStdString(opt) + "</li>\n";
}
html += "</ul>\n";
}
#if 0
if (m_extraSettings) {
LauncherArgumentTokenizer tk;
Q_FOREACH(auto arg, tk.tokenize(m_extraSettings->argsText())) {
// m_config->setArg(arg.arg, arg.value);
}
}
#endif
m_config->reset();
m_config->collect();
html += "<p>Options set in the launcher:</p>\n";
html += "<ul>\n";
for (auto arg : m_config->values()) {
if (arg.value.isEmpty()) {
html += QString("<li>--") + arg.arg + "</li>\n";
} else if (arg.arg == "prop") {
html += QString("<li>--") + arg.arg + ":" + arg.value + "</li>\n";
} else {
html += QString("<li>--") + arg.arg + "=" + arg.value + "</li>\n";
}
}
html += "</ul>\n";
m_browser->setHtml(html);
}

View file

@ -0,0 +1,27 @@
#ifndef VIEWCOMMANDLINEPAGE_HXX
#define VIEWCOMMANDLINEPAGE_HXX
#include <QWidget>
class QTextEdit;
class LaunchConfig;
class ViewCommandLinePage : public QWidget
{
Q_OBJECT
public:
explicit ViewCommandLinePage(QWidget *parent = 0);
void setLaunchConfig(LaunchConfig* config);
void update();
signals:
public slots:
private:
QTextEdit* m_browser;
LaunchConfig* m_config = nullptr;
};
#endif // VIEWCOMMANDLINEPAGE_HXX

View file

@ -1,15 +0,0 @@
#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;
}

View file

@ -1,22 +0,0 @@
#ifndef VIEWSETTINGS_H
#define VIEWSETTINGS_H
#include <GUI/settingssection.h>
namespace Ui {
class ViewSettings;
}
class ViewSettings : public SettingsSection
{
Q_OBJECT
public:
explicit ViewSettings(QWidget *parent = 0);
~ViewSettings();
private:
Ui::ViewSettings *ui;
};
#endif // VIEWSETTINGS_H

33
src/GUI/ViewSettings.qml Normal file
View file

@ -0,0 +1,33 @@
import FlightGear.Launcher 1.0
Section {
id: viewSettings
title: "View & Window"
Checkbox {
id: fullscreen
label: "Start full-screen"
description: "Start the simulator in full-screen mode"
keywords: ["window", "full", "screen"]
option: "fullscreen"
}
Combo {
id: windowSize
enabled: !fullscreen.checked
label: "Window size"
description: "Select the initial size of the window. (This has no effct in full-screen mode)"
advanced: true
choices: ["640x480", "800x600", "1024x768", "1920x1080", "2560x1600" ]
defaultIndex: 2
readonly property bool isDefault: selectedIndex == defaultIndex
}
onApply: {
if (!windowSize.isDefault) {
_config.setArg("geometry", windowSize.choices[windowSize.selectedIndex]);
}
}
summary: fullscreen.checked ? "full-screen;" : ""
}

View file

@ -1,157 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ViewSettings</class>
<widget class="SettingsSection" name="ViewSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>740</width>
<height>338</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="title" stdset="0">
<string>View</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string>Start full-screen</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Full-screen mode can be toggled inside the simulator by pressing F10.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Window size:</string>
</property>
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox">
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>800 x 600</string>
</property>
</item>
<item>
<property name="text">
<string>1024 x 768</string>
</property>
</item>
<item>
<property name="text">
<string>Custom size...</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Field-of-view angle:</string>
</property>
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox">
<property name="maximum">
<number>180</number>
</property>
<property name="value">
<number>90</number>
</property>
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Field-of-view depends on your monitor size. It can be adjusted in the simulator using the x/X keys</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SettingsSection</class>
<extends>QWidget</extends>
<header location="global">GUI/settingssection.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

44
src/GUI/Weather.qml Normal file
View file

@ -0,0 +1,44 @@
import FlightGear.Launcher 1.0
Section {
id: weatherSettings
title: "Weather"
Checkbox {
id: fetchMetar
label: "Real-world weather"
description: "Download real-world weather from the NOAA servers based on location."
option: "real-weather-fetch"
}
Combo {
id: weatherScenario
enabled: !fetchMetar.checked
label: "Weather scenario"
model: _weatherScenarios
readonly property bool isCustomMETAR: (selectedIndex == 0);
description: _weatherScenarios.descriptionForItem(selectedIndex)
defaultIndex: 1
}
LineEdit {
id: customMETAR
visible: weatherScenario.isCustomMETAR
enabled: !fetchMetar.checked
label: "METAR"
placeholder: "XXXX 012345Z 28035G50KT 250V300 9999 TSRA SCT022CB BKN030 13/09 Q1005"
description: "Enter a custom METAR string"
}
onApply: {
if (!fetchMetar.checked) {
if (weatherScenario.isCustomMETAR) {
_config.setArg("metar", customMETAR.value)
} else {
_config.setArg("metar", _weatherScenarios.metarForItem(weatherScenario.selectedIndex))
}
}
}
summary: fetchMetar.checked ? "real-world weather;" : ""
}

View file

@ -1,15 +0,0 @@
#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;
}

View file

@ -1,22 +0,0 @@
#ifndef RENDERINGSETTINGS_H
#define RENDERINGSETTINGS_H
#include <GUI/settingssection.h>
namespace Ui {
class RenderingSettings;
}
class RenderingSettings : public SettingsSection
{
Q_OBJECT
public:
explicit RenderingSettings(QWidget *parent = 0);
~RenderingSettings();
private:
Ui::RenderingSettings *ui;
};
#endif // RENDERINGSETTINGS_H

View file

@ -1,229 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RenderingSettings</class>
<widget class="SettingsSection" name="RenderingSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>771</width>
<height>331</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="title" stdset="0">
<string>Rendering</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Renderer:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox">
<item>
<property name="text">
<string>ALS</string>
</property>
</item>
<item>
<property name="text">
<string>Rembrandt</string>
</property>
</item>
<item>
<property name="text">
<string>Default</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Lots of information about which renderer is selcted</string>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string>Enable multi-sample anti-aliasingg</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Multi-sample anti-aliasing (MSAA) reduces the appearance of jagged edges. Depending on your graphics card, this may reduce framerates</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0,0">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Multi-sampling setting:</string>
</property>
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_2">
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>2x</string>
</property>
</item>
<item>
<property name="text">
<string>4x</string>
</property>
</item>
<item>
<property name="text">
<string>8x</string>
</property>
</item>
<item>
<property name="text">
<string>16x</string>
</property>
</item>
<item>
<property name="text">
<string>Custom...</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Renderer threading model:</string>
</property>
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_3">
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>Automatic</string>
</property>
</item>
<item>
<property name="text">
<string>Thread for culling and drawing</string>
</property>
</item>
<item>
<property name="text">
<string>Separate threads for culling and drawing</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>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.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="advanced" stdset="0">
<bool>true</bool>
</property>
<property name="help" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SettingsSection</class>
<extends>QWidget</extends>
<header location="global">GUI/settingssection.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -27,10 +27,22 @@
<file alias="toolbox-location">toolbox-location.png</file>
<file alias="toolbox-settings">toolbox-settings.png</file>
<file alias="toolbox-summary">toolbox-summary.png</file>
<file alias="toolbox-addons">toolbox-addons.png</file>
</qresource>
<qresource prefix="/preview">
<file alias="close-icon">preview-close.png</file>
<file alias="left-arrow-icon">preview-left-arrow.png</file>
<file alias="right-arrow-icon">preview-right-arrow.png</file>
</qresource>
<qresource prefix="/settings">
<file alias="downloads">DownloadSettings.qml</file>
<file alias="general">GeneralSettings.qml</file>
<file alias="mp">MPSettings.qml</file>
<file alias="render">RenderSettings.qml</file>
<file alias="view">ViewSettings.qml</file>
</qresource>
<qresource prefix="/environment">
<file alias="time">TimeSettings.qml</file>
<file alias="weather">Weather.qml</file>
</qresource>
</RCC>

View file

@ -6,8 +6,12 @@
#include <QPalette>
#include <QPushButton>
#include <QVariant>
#include <QDebug>
#include <QSettings>
#include "AdvancedSettingsButton.h"
#include "SettingsWidgets.hxx"
#include "LaunchConfig.hxx"
SettingsSection::SettingsSection(QWidget* pr) :
QFrame(pr)
@ -21,6 +25,16 @@ SettingsSection::SettingsSection(QWidget* pr) :
QPalette pal = palette();
pal.setColor(QPalette::Normal, QPalette::WindowText, Qt::white);
m_titleLabel->setPalette(pal);
if (!layout()) {
QVBoxLayout* vbox = new QVBoxLayout(this);
setLayout(vbox);
}
}
void SettingsSection::setLaunchConfig(LaunchConfig* config)
{
connect(config, &LaunchConfig::collect, this, &SettingsSection::doApply);
}
void SettingsSection::setShowAdvanced(bool showAdvanced)
@ -76,34 +90,25 @@ void SettingsSection::insertSettingsHeader()
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<QLabel*>()) {
if (w->property("help").toBool()) {
w->setFont(helpLabelFont);
w->setPalette(pal);
}
}
updateShowAdvanced();
internalUpdateAdvanced();
}
void SettingsSection::internalUpdateAdvanced()
{
Q_FOREACH(QWidget* w, findChildren<QWidget*>()) {
if (w->property("advanced").toBool()) {
w->setVisible(m_showAdvanced);
}
if (w->property("simple").toBool()) {
w->setVisible(!m_showAdvanced);
}
}
}
void SettingsSection::saveState(QSettings &settings) const
{
}
void SettingsSection::restoreState(QSettings &settings)
{
}
void SettingsSection::updateShowAdvanced()
{
}

View file

@ -5,6 +5,8 @@
#include <QLabel>
class AdvancedSettingsButton;
class QSettings;
class LaunchConfig;
class SettingsSection : public QFrame
{
@ -17,6 +19,8 @@ class SettingsSection : public QFrame
public:
SettingsSection(QWidget* pr = nullptr);
virtual void setLaunchConfig(LaunchConfig* config);
bool showAdvanced() const
{
return m_showAdvanced;
@ -29,19 +33,31 @@ public:
void insertSettingsHeader();
virtual void saveState(QSettings& settings) const;
virtual void restoreState(QSettings& settings);
virtual void doApply() = 0;
virtual QString summary() const = 0;
public slots:
void setShowAdvanced(bool showAdvanced);
void setTitle(QString title);
void toggleShowAdvanced();
signals:
void showAdvancedChanged(bool showAdvanced);
void titleChanged(QString title);
private:
void internalUpdateAdvanced();
void summaryChanged(QString summary);
protected:
virtual void internalUpdateAdvanced();
virtual void updateShowAdvanced();
QString m_title;
bool m_showAdvanced = false;

BIN
src/GUI/toolbox-addons.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -2775,8 +2775,29 @@ SGPath Options::platformDefaultRoot() const
{
return SGPath::fromUtf8(PKGLIBDIR);
}
#endif
string_list Options::extractOptions() const
{
string_list result;
for (auto opt : p->values) {
if (opt.desc == nullptr) {
continue;
}
if (!strcmp(opt.desc->option,"prop")) {
result.push_back("prop:" + opt.value);
} else if (opt.value.empty()) {
result.push_back(opt.desc->option);
} else {
result.push_back(std::string(opt.desc->option) + "=" + opt.value);
}
}
return result;
}
void Options::setupRoot(int argc, char **argv)
{
SGPath root;

View file

@ -156,6 +156,14 @@ public:
static bool checkForArg(int argc, char* argv[], const char* arg);
SGPath platformDefaultRoot() const;
/**
* @brief extractOptions - extract the currently set options as
* a string array. This can be used to examine what options were
* requested / set so far.
* @return
*/
string_list extractOptions() const;
private:
void showUsage() const;
void showVersion() const;