Basic menu for the launcher
This commit is contained in:
parent
31f80e2431
commit
5229f8eabf
12 changed files with 302 additions and 86 deletions
|
@ -10,6 +10,7 @@
|
|||
#include <QSettings>
|
||||
#include <QQuickWindow>
|
||||
#include <QQmlComponent>
|
||||
#include <QPushButton>
|
||||
|
||||
// simgear headers
|
||||
#include <simgear/package/Install.hxx>
|
||||
|
@ -494,6 +495,16 @@ void LauncherController::fly()
|
|||
}
|
||||
}
|
||||
|
||||
void LauncherController::quit()
|
||||
{
|
||||
if (m_inAppMode) {
|
||||
m_keepRunningInAppMode = false;
|
||||
m_appModeResult = false;
|
||||
} else {
|
||||
qApp->exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList LauncherController::combinedSummary() const
|
||||
{
|
||||
return m_settingsSummary + m_environmentSummary;
|
||||
|
@ -638,3 +649,64 @@ QPointF LauncherController::mapToGlobal(QQuickItem *item, const QPointF &pos) co
|
|||
QQuickWindow* win = item->window();
|
||||
return win->mapToGlobal(scenePos.toPoint());
|
||||
}
|
||||
|
||||
void LauncherController::requestRestoreDefaults()
|
||||
{
|
||||
QMessageBox mbox;
|
||||
mbox.setText(tr("Restore all settings to defaults?"));
|
||||
mbox.setInformativeText(tr("Restoring settings to their defaults may affect available add-ons such as scenery or aircraft."));
|
||||
QPushButton* quitButton = mbox.addButton(tr("Restore and restart 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;
|
||||
settings.clear();
|
||||
settings.setValue("restore-defaults-on-run", true);
|
||||
}
|
||||
|
||||
flightgear::restartTheApp();
|
||||
}
|
||||
|
||||
void LauncherController::requestChangeDataPath()
|
||||
{
|
||||
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;
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -193,7 +193,11 @@ public slots:
|
|||
void setEnvironmentSummary(QStringList environmentSummary);
|
||||
|
||||
void fly();
|
||||
void quit();
|
||||
|
||||
void requestRestoreDefaults();
|
||||
|
||||
void requestChangeDataPath();
|
||||
private slots:
|
||||
|
||||
void onAircraftInstalledCompleted(QModelIndex index);
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include <QDebug>
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <QQuickItem>
|
||||
#include <QQmlEngine>
|
||||
|
@ -27,8 +26,6 @@
|
|||
#include "LocationController.hxx"
|
||||
|
||||
|
||||
extern void restartTheApp(QStringList fgArgs);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LauncherMainWindow::LauncherMainWindow() :
|
||||
|
@ -45,11 +42,11 @@ LauncherMainWindow::LauncherMainWindow() :
|
|||
QMenu* toolsMenu = mb->addMenu(tr("Tools"));
|
||||
QAction* restoreDefaultsAction = toolsMenu->addAction(tr("Restore defaults..."));
|
||||
connect(restoreDefaultsAction, &QAction::triggered,
|
||||
this, &LauncherMainWindow::onRestoreDefaults);
|
||||
m_controller, &LauncherController::requestRestoreDefaults);
|
||||
|
||||
QAction* changeDataAction = toolsMenu->addAction(tr("Select data files location..."));
|
||||
connect(changeDataAction, &QAction::triggered,
|
||||
this, &LauncherMainWindow::onChangeDataDir);
|
||||
m_controller, &LauncherController::requestChangeDataPath);
|
||||
|
||||
QAction* viewCommandLineAction = toolsMenu->addAction(tr("View command-line"));
|
||||
connect(viewCommandLineAction, &QAction::triggered,
|
||||
|
@ -58,7 +55,7 @@ LauncherMainWindow::LauncherMainWindow() :
|
|||
|
||||
QAction* qa = new QAction(this);
|
||||
qa->setShortcut(QKeySequence("Ctrl+Q"));
|
||||
connect(qa, &QAction::triggered, this, &LauncherMainWindow::onQuit);
|
||||
connect(qa, &QAction::triggered, m_controller, &LauncherController::quit);
|
||||
|
||||
m_controller->restoreSettings();
|
||||
flightgear::launcherSetSceneryPaths();
|
||||
|
@ -88,6 +85,8 @@ LauncherMainWindow::LauncherMainWindow() :
|
|||
ctx->setContextProperty("_weatherScenarios", weatherScenariosModel);
|
||||
|
||||
setSource(QUrl("qrc:///qml/Launcher.qml"));
|
||||
|
||||
setMinimumSize(QSize(300, 400));
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -127,69 +126,3 @@ bool LauncherMainWindow::execInApp()
|
|||
return m_controller->inAppResult();
|
||||
}
|
||||
|
||||
void LauncherMainWindow::onQuit()
|
||||
{
|
||||
qApp->exit(-1);
|
||||
}
|
||||
|
||||
void LauncherMainWindow::onRestoreDefaults()
|
||||
{
|
||||
QMessageBox mbox;
|
||||
mbox.setText(tr("Restore all settings to defaults?"));
|
||||
mbox.setInformativeText(tr("Restoring settings to their defaults may affect available add-ons such as scenery or aircraft."));
|
||||
QPushButton* quitButton = mbox.addButton(tr("Restore and restart 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;
|
||||
settings.clear();
|
||||
settings.setValue("restore-defaults-on-run", true);
|
||||
}
|
||||
|
||||
flightgear::restartTheApp();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -48,19 +48,6 @@ public:
|
|||
bool wasRejected();
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
private slots:
|
||||
|
||||
|
||||
void onRestoreDefaults();
|
||||
|
||||
void onQuit();
|
||||
|
||||
// void onQuickStatusChanged(QQuickWidget::Status status);
|
||||
|
||||
void onChangeDataDir();
|
||||
|
||||
private:
|
||||
LauncherController* m_controller;
|
||||
};
|
||||
|
|
22
src/GUI/qml/BaseMenuItem.qml
Normal file
22
src/GUI/qml/BaseMenuItem.qml
Normal file
|
@ -0,0 +1,22 @@
|
|||
import QtQuick 2.4
|
||||
import "."
|
||||
|
||||
Item
|
||||
{
|
||||
property bool enabled: true
|
||||
|
||||
implicitHeight: Style.menuItemHeight
|
||||
width: parent.width // take width from our parent menu
|
||||
|
||||
function minWidth() { return 0; }
|
||||
|
||||
function closeMenu()
|
||||
{
|
||||
parent.requestClose();
|
||||
}
|
||||
|
||||
function menu()
|
||||
{
|
||||
return parent.getMenu();
|
||||
}
|
||||
}
|
|
@ -72,6 +72,8 @@ Item {
|
|||
pagesModel: pagesModel
|
||||
selectedPage: 0 // open on the summary page
|
||||
|
||||
onShowMenu: menu.show();
|
||||
|
||||
onSelectPage: {
|
||||
pageLoader.source = pageSource
|
||||
root.state = pagesModel.get(selectedPage).state
|
||||
|
@ -124,5 +126,21 @@ Item {
|
|||
onShowSelectedLocation: root.selectPage(2)
|
||||
}
|
||||
|
||||
Menu {
|
||||
id: menu
|
||||
z: 100
|
||||
|
||||
items: [
|
||||
MenuItem { text:qsTr("Open saved configuration..."); enabled: false },
|
||||
MenuItem { text:qsTr("Save configuration..."); enabled: false },
|
||||
MenuDivider {},
|
||||
MenuItem { text:qsTr("View command line"); onTriggered: _launcher.viewCommandLine(); },
|
||||
MenuItem { text:qsTr("Select data files location..."); onTriggered: _launcher.requestChangeDataPath(); },
|
||||
MenuItem { text:qsTr("Restore default settings..."); onTriggered: _launcher.requestRestoreDefaults(); },
|
||||
MenuDivider {},
|
||||
MenuItem { text:qsTr("Quit"); shortcut: "Ctrl+Q"; onTriggered: _launcher.quit(); }
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
78
src/GUI/qml/Menu.qml
Normal file
78
src/GUI/qml/Menu.qml
Normal file
|
@ -0,0 +1,78 @@
|
|||
import QtQuick 2.4
|
||||
import "."
|
||||
|
||||
Item {
|
||||
id: root
|
||||
visible: false
|
||||
|
||||
function show()
|
||||
{
|
||||
computeMenuWidth();
|
||||
visible = true;
|
||||
}
|
||||
|
||||
function close()
|
||||
{
|
||||
visible = false;
|
||||
}
|
||||
|
||||
function computeMenuWidth()
|
||||
{
|
||||
var minWidth = 0;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
minWidth = Math.max(minWidth, items[i].minWidth());
|
||||
}
|
||||
|
||||
menuFrame.width = minWidth;
|
||||
}
|
||||
|
||||
property alias items: contentBox.children
|
||||
|
||||
// underlying mouse area to close menu when clicking outside
|
||||
// this also eats hover events
|
||||
MouseArea {
|
||||
x: -1000
|
||||
y: -1000
|
||||
width: 2000
|
||||
height: 2000
|
||||
hoverEnabled: true
|
||||
onClicked: root.close()
|
||||
}
|
||||
|
||||
width: 1
|
||||
height: 1
|
||||
|
||||
Rectangle {
|
||||
id: menuFrame
|
||||
border.width: 1
|
||||
border.color: Style.themeColor
|
||||
height: contentBox.childrenRect.height + 2
|
||||
color: "white"
|
||||
|
||||
// width is computed during show(), but if we don't see a valid
|
||||
// value here, the Column doesn't position the items until
|
||||
// slightly late
|
||||
width: 100
|
||||
|
||||
|
||||
Column {
|
||||
id: contentBox
|
||||
x: 1
|
||||
y: 1
|
||||
width: parent.width - 2
|
||||
|
||||
// helper function called by BaseMenuItem on its parent, i.e,
|
||||
// us, to requestc closing the menu
|
||||
function requestClose()
|
||||
{
|
||||
root.close();
|
||||
}
|
||||
|
||||
function getMenu() {
|
||||
return root;
|
||||
}
|
||||
|
||||
// menu items get inserted here
|
||||
}
|
||||
}
|
||||
}
|
13
src/GUI/qml/MenuDivider.qml
Normal file
13
src/GUI/qml/MenuDivider.qml
Normal file
|
@ -0,0 +1,13 @@
|
|||
import QtQuick 2.4
|
||||
import "."
|
||||
|
||||
BaseMenuItem {
|
||||
height: 3
|
||||
Rectangle {
|
||||
x: Style.margin
|
||||
y: 1
|
||||
width: parent.width - (2 * Style.margin)
|
||||
height: 1
|
||||
color: Style.themeColor
|
||||
}
|
||||
}
|
60
src/GUI/qml/MenuItem.qml
Normal file
60
src/GUI/qml/MenuItem.qml
Normal file
|
@ -0,0 +1,60 @@
|
|||
import QtQuick 2.4
|
||||
import "."
|
||||
|
||||
BaseMenuItem {
|
||||
id: root
|
||||
|
||||
property alias text: itemText.text
|
||||
property alias shortcut: shortcutText.text
|
||||
|
||||
signal triggered();
|
||||
|
||||
function minWidth() {
|
||||
return itemText.width + shortcutText.width + (Style.inset * 2)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
height: parent.height
|
||||
width: parent.width
|
||||
visible: mouse.containsMouse
|
||||
color: "#cfcfcf"
|
||||
}
|
||||
|
||||
Text {
|
||||
id: itemText
|
||||
font.pixelSize: Style.baseFontPixelSize
|
||||
color: mouse.containsMouse ? Style.themeColor :
|
||||
(root.enabled ? Style.baseTextColor : Style.disabledTextColor);
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: Style.inset
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: shortcutText
|
||||
color: Style.disabledTextColor
|
||||
font.pixelSize: Style.baseFontPixelSize
|
||||
width: implicitWidth + Style.inset
|
||||
horizontalAlignment: Text.AlignRight
|
||||
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: Style.inset
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouse
|
||||
enabled: root.enabled
|
||||
anchors.fill: parent
|
||||
hoverEnabled: root.enabled
|
||||
onClicked: {
|
||||
root.closeMenu();
|
||||
root.triggered();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,9 +8,12 @@ Rectangle {
|
|||
|
||||
property alias pagesModel: buttonRepeater.model
|
||||
property int selectedPage: 0
|
||||
property alias showMenuIcon: menuIcon.visible
|
||||
|
||||
signal selectPage(var pageSource);
|
||||
|
||||
signal showMenu();
|
||||
|
||||
function setSelectedPage(index)
|
||||
{
|
||||
selectedPage = index
|
||||
|
@ -19,8 +22,28 @@ Rectangle {
|
|||
Column {
|
||||
width: parent.width
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Style.margin
|
||||
anchors.bottom: flyButton.top
|
||||
//spacing: Style.margin
|
||||
|
||||
Rectangle {
|
||||
id: menuIcon
|
||||
width: parent.width
|
||||
height:menuIconImage.sourceSize.height
|
||||
color: menuMouseArea.containsMouse ? Style.activeColor : "transparent"
|
||||
|
||||
Image {
|
||||
id: menuIconImage
|
||||
anchors.centerIn: parent
|
||||
source: "qrc:///ellipsis-icon"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: menuMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: root.showMenu()
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: buttonRepeater
|
||||
|
|
|
@ -30,5 +30,7 @@ QtObject
|
|||
readonly property string disabledTextColor: "#6f6f6f"
|
||||
|
||||
readonly property double panelOpacity: 0.7
|
||||
|
||||
readonly property int menuItemHeight: baseFontPixelSize + (margin * 2)
|
||||
}
|
||||
|
||||
|
|
|
@ -100,6 +100,10 @@
|
|||
<file>qml/SidebarButton.qml</file>
|
||||
<file>qml/ViewCommandLine.qml</file>
|
||||
<file>qml/AddOnsHeader.qml</file>
|
||||
<file>qml/Menu.qml</file>
|
||||
<file>qml/BaseMenuItem.qml</file>
|
||||
<file>qml/MenuItem.qml</file>
|
||||
<file>qml/MenuDivider.qml</file>
|
||||
</qresource>
|
||||
<qresource prefix="/preview">
|
||||
<file alias="close-icon">preview-close.png</file>
|
||||
|
|
Loading…
Add table
Reference in a new issue