diff --git a/app/app.pro b/app/app.pro index 9914681a..24e051ae 100644 --- a/app/app.pro +++ b/app/app.pro @@ -1,12 +1,8 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2018-04-28T14:01:01 -# -#------------------------------------------------- +QT += core quick network +CONFIG += c++11 -QT += core gui network - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +# TODO: Rid ourselves of QtWidgets +QT += widgets TARGET = moonlight-qt TEMPLATE = app @@ -52,8 +48,6 @@ win32 { SOURCES += \ main.cpp \ - gui/mainwindow.cpp \ - gui/popupmanager.cpp \ backend/identitymanager.cpp \ backend/nvhttp.cpp \ backend/nvpairingmanager.cpp \ @@ -67,8 +61,6 @@ SOURCES += \ HEADERS += \ utils.h \ - gui/mainwindow.h \ - gui/popupmanager.h \ backend/identitymanager.h \ backend/nvhttp.h \ backend/nvpairingmanager.h \ @@ -78,11 +70,15 @@ HEADERS += \ streaming/input.hpp \ streaming/session.hpp -FORMS += \ - gui/mainwindow.ui - RESOURCES += \ - resources.qrc + resources.qrc \ + qml.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../moonlight-common-c/release/ -lmoonlight-common-c else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../moonlight-common-c/debug/ -lmoonlight-common-c @@ -104,3 +100,8 @@ else:unix: LIBS += -L$$OUT_PWD/../qmdnsengine/ -lqmdnsengine INCLUDEPATH += $$PWD/../qmdnsengine/qmdnsengine/src/include $$PWD/../qmdnsengine DEPENDPATH += $$PWD/../qmdnsengine/qmdnsengine/src/include $$PWD/../qmdnsengine + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/app/gui/main.qml b/app/gui/main.qml new file mode 100644 index 00000000..ba5e0bc9 --- /dev/null +++ b/app/gui/main.qml @@ -0,0 +1,65 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 + +ApplicationWindow { + id: window + visible: true + width: 640 + height: 480 + title: qsTr("Stack") + + header: ToolBar { + contentHeight: toolButton.implicitHeight + + ToolButton { + id: toolButton + text: stackView.depth > 1 ? "\u25C0" : "\u2630" + font.pixelSize: Qt.application.font.pixelSize * 1.6 + onClicked: { + if (stackView.depth > 1) { + stackView.pop() + } else { + drawer.open() + } + } + } + + Label { + text: stackView.currentItem.title + anchors.centerIn: parent + } + } + + Drawer { + id: drawer + width: window.width * 0.66 + height: window.height + + Column { + anchors.fill: parent + + ItemDelegate { + text: qsTr("Page 1") + width: parent.width + onClicked: { + stackView.push("Page1Form.ui.qml") + drawer.close() + } + } + ItemDelegate { + text: qsTr("Page 2") + width: parent.width + onClicked: { + stackView.push("Page2Form.ui.qml") + drawer.close() + } + } + } + } + + StackView { + id: stackView + initialItem: "HomeForm.ui.qml" + anchors.fill: parent + } +} diff --git a/app/gui/mainwindow.cpp b/app/gui/mainwindow.cpp deleted file mode 100644 index d336f83d..00000000 --- a/app/gui/mainwindow.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "gui/mainwindow.h" -#include "ui_mainwindow.h" -#include "gui/popupmanager.h" -#include "backend/identitymanager.h" -#include "backend/nvpairingmanager.h" -#include "streaming/session.hpp" -#include "backend/computermanager.h" -#include "backend/boxartmanager.h" -#include "settings/streamingpreferences.h" - -MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::MainWindow), - m_BoxArtManager(this), - m_ComputerManager(this) -{ - ui->setupUi(this); - connect(&m_BoxArtManager, SIGNAL(boxArtLoadComplete(NvComputer*,NvApp,QImage)), - this, SLOT(boxArtLoadComplete(NvComputer*,NvApp,QImage))); - connect(&m_ComputerManager, SIGNAL(computerStateChanged(NvComputer*)), - this, SLOT(computerStateChanged(NvComputer*))); - m_ComputerManager.startPolling(); - qDebug() << "Cached computers: " << m_ComputerManager.getComputers().count(); -} - -MainWindow::~MainWindow() -{ - delete ui; -} - -void MainWindow::boxArtLoadComplete(NvComputer* computer, NvApp app, QImage image) -{ - qDebug() << "Loaded image"; -} - -void MainWindow::on_actionExit_triggered() -{ - exit(EXIT_SUCCESS); -} - -void MainWindow::computerStateChanged(NvComputer* computer) -{ - QReadLocker lock(&computer->lock); - - NvHTTP http(computer->activeAddress); - - if (computer->pairState == NvComputer::PS_NOT_PAIRED) { - NvPairingManager pm(computer->activeAddress); - QString pin = pm.generatePinString(); - pm.pair(http.getServerInfo(), pin); - } - else if (!computer->appList.isEmpty()) { - QImage im = m_BoxArtManager.loadBoxArt(computer, computer->appList[0]); - - // Stop polling before launching a game - m_ComputerManager.stopPollingAsync(); - - Session session(computer, computer->appList.last()); - QStringList warnings; - QString errorMessage; - - // First check for a fatal configuration error - errorMessage = session.checkForFatalValidationError(); - if (!errorMessage.isEmpty()) { - // TODO: display error dialog - goto AfterStreaming; - } - - // Check for any informational messages to display - warnings = session.checkForAdvisoryValidationError(); - if (!warnings.isEmpty()) { - // TODO: display toast or something before we start - } - - // Run the streaming session until termination - session.exec(); - - AfterStreaming: - m_ComputerManager.startPolling(); - } -} - -void MainWindow::on_newHostBtn_clicked() -{ - QString hostname = popupmanager::getHostnameDialog(this); - if (!hostname.isEmpty()) { - m_ComputerManager.addNewHost(hostname, false); - } -} - -void MainWindow::addHostToDisplay(QMap hostMdnsMap) { - - QMapIterator i(hostMdnsMap); - while (i.hasNext()) { - i.next(); - ui->hostSelectCombo->addItem(i.key()); - // we can ignore the mdns for now, it's only useful for displaying unpairing options - } -} - -void MainWindow::on_selectHostComboBox_activated(const QString &selectedHostname) -{ - // TODO: get all the applications that "selectedHostname" has listed - // probably populate another combobox of applications for the time being -} diff --git a/app/gui/mainwindow.h b/app/gui/mainwindow.h deleted file mode 100644 index dfdba4db..00000000 --- a/app/gui/mainwindow.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include "backend/computermanager.h" -#include "backend/boxartmanager.h" - -#include -#include - -namespace Ui { -class MainWindow; -} - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = 0); - ~MainWindow(); - -private slots: - void on_actionExit_triggered(); - void on_newHostBtn_clicked(); - void addHostToDisplay(QMap); - void on_selectHostComboBox_activated(const QString &); - void computerStateChanged(NvComputer* computer); - void boxArtLoadComplete(NvComputer* computer, NvApp app, QImage image); - -private: - Ui::MainWindow *ui; - BoxArtManager m_BoxArtManager; - ComputerManager m_ComputerManager; -}; - -#endif // MAINWINDOW_H diff --git a/app/gui/mainwindow.ui b/app/gui/mainwindow.ui deleted file mode 100644 index bb2092ec..00000000 --- a/app/gui/mainwindow.ui +++ /dev/null @@ -1,102 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 400 - 483 - - - - MainWindow - - - - - - 50 - 30 - 306 - 191 - - - - - QLayout::SetDefaultConstraint - - - 10 - - - 10 - - - 10 - - - 10 - - - - - PointingHandCursor - - - Add New Host - - - - :/res/icon128.png:/res/icon128.png - - - - - - - - - - - - - 0 - 0 - 400 - 22 - - - - - File - - - - - - - - - - Settings - - - - - Gamepad Mapping - - - - - Exit - - - - - - - - - diff --git a/app/gui/popupmanager.cpp b/app/gui/popupmanager.cpp deleted file mode 100644 index 83a17aec..00000000 --- a/app/gui/popupmanager.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "popupmanager.h" - -QMessageBox *popupmanager::pinMsgBox = nullptr; - -popupmanager::popupmanager(){} - -// this opens a non-blocking informative message telling the user to enter the given pin -// it is open-loop: if the user cancels, nothing happens -// it is expected that upon pairing completion, the ::closePinDialog function will be called. -void popupmanager::displayPinDialog(QString pin, QWidget* parent) { - - popupmanager::pinMsgBox = new QMessageBox( parent ); - popupmanager::pinMsgBox->setAttribute( Qt::WA_DeleteOnClose ); //makes sure the msgbox is deleted automatically when closed - popupmanager::pinMsgBox->setStandardButtons( QMessageBox::Ok ); - popupmanager::pinMsgBox->setText("Please enter the number " + pin + " on the GFE dialog on the computer."); - popupmanager::pinMsgBox->setInformativeText("This dialog will be dismissed once complete."); - popupmanager::pinMsgBox->open(); -} - -// to be called when the pairing is complete -void popupmanager::closePinDialog() { - pinMsgBox->close(); - delete pinMsgBox; -} - -QString popupmanager::getHostnameDialog(QWidget* parent) { - bool ok; - QString responseHost - = QInputDialog::getText(parent, QObject::tr("Add Host Manually"), - QObject::tr("IP Address or Hostname of GeForce PC"), - QLineEdit::Normal, - QObject::tr("default string"), - &ok); - if (ok && !responseHost.isEmpty()) { - return responseHost; - } else { - return QObject::tr(""); - } -} - - diff --git a/app/gui/popupmanager.h b/app/gui/popupmanager.h deleted file mode 100644 index 934ba79d..00000000 --- a/app/gui/popupmanager.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef POPUPMANAGER_H -#define POPUPMANAGER_H - -#include - -class popupmanager -{ -public: - popupmanager(); - static void displayPinDialog(QString pin, QWidget* parent); - static void closePinDialog(); - static QString getHostnameDialog(QWidget* parent); - -private: - static QMessageBox *pinMsgBox; -}; - -#endif // POPUPMANAGER_H diff --git a/app/gui/qtquickcontrols2.conf b/app/gui/qtquickcontrols2.conf new file mode 100644 index 00000000..08109fee --- /dev/null +++ b/app/gui/qtquickcontrols2.conf @@ -0,0 +1,6 @@ +; This file can be edited to change the style of the application +; Read "Qt Quick Controls 2 Configuration File" for details: +; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html + +[Controls] +Style=Imagine diff --git a/app/main.cpp b/app/main.cpp index 2099c2b9..1633be52 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -1,5 +1,5 @@ -#include "gui/mainwindow.h" -#include +#include +#include #include "backend/nvhttp.h" @@ -10,6 +10,8 @@ int main(int argc, char *argv[]) { + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + // This avoids using the default keychain for SSL, which may cause // password prompts on macOS. qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); @@ -22,9 +24,13 @@ int main(int argc, char *argv[]) // Register custom metatypes for use in signals qRegisterMetaType("NvApp"); - QApplication a(argc, argv); - MainWindow w; - w.show(); + QGuiApplication app(argc, argv); + + // Load the main.qml file + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/gui/main.qml"))); + if (engine.rootObjects().isEmpty()) + return -1; // Ensure that SDL is always initialized since we may need to use it // for non-streaming purposes (like checking on audio devices) @@ -37,7 +43,7 @@ int main(int argc, char *argv[]) SDL_GetError()); } - int err = a.exec(); + int err = app.exec(); SDL_Quit(); diff --git a/app/qml.qrc b/app/qml.qrc new file mode 100644 index 00000000..5851b4cb --- /dev/null +++ b/app/qml.qrc @@ -0,0 +1,6 @@ + + + gui/main.qml + gui/qtquickcontrols2.conf + + diff --git a/app/streaming/session.hpp b/app/streaming/session.hpp index e510ed80..e35bb96d 100644 --- a/app/streaming/session.hpp +++ b/app/streaming/session.hpp @@ -7,7 +7,6 @@ #include - class Session { public: