diff --git a/app/app.pro b/app/app.pro index 24e051ae..d1378e08 100644 --- a/app/app.pro +++ b/app/app.pro @@ -57,7 +57,8 @@ SOURCES += \ streaming/input.cpp \ streaming/session.cpp \ streaming/audio.cpp \ - streaming/video.cpp + streaming/video.cpp \ + gui/computermodel.cpp HEADERS += \ utils.h \ @@ -68,7 +69,8 @@ HEADERS += \ backend/boxartmanager.h \ settings/streamingpreferences.h \ streaming/input.hpp \ - streaming/session.hpp + streaming/session.hpp \ + gui/computermodel.h RESOURCES += \ resources.qrc \ diff --git a/app/backend/computermanager.cpp b/app/backend/computermanager.cpp index 83fbbaf0..6157df23 100644 --- a/app/backend/computermanager.cpp +++ b/app/backend/computermanager.cpp @@ -199,7 +199,7 @@ QVector NvComputer::uniqueAddresses() } // We must have at least 1 address - Q_ASSERT(uniqueAddressList.count() != 0); + Q_ASSERT(!uniqueAddressList.isEmpty()); return uniqueAddressList; } diff --git a/app/gui/PcView.qml b/app/gui/PcView.qml new file mode 100644 index 00000000..114c0692 --- /dev/null +++ b/app/gui/PcView.qml @@ -0,0 +1,83 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 + +import ComputerModel 1.0 + +Frame { + GridView { + anchors.fill: parent + cellWidth: 200; cellHeight: 300; + focus: true + + model: ComputerModel {} + + delegate: Item { + width: 300; height: 300; + + Image { + id: pcIcon + y: 10; anchors.horizontalCenter: parent.horizontalCenter; + source: { + model.addPc ? "ic_add_to_queue_white_48px.svg" : "ic_tv_white_48px.svg" + } + sourceSize { + width: 200 + height: 200 + } + } + + Text { + id: pcNameText + text: model.name + color: "white" + + width: parent.width + anchors.top: pcIcon.bottom + minimumPointSize: 12 + font.pointSize: 36 + horizontalAlignment: Text.AlignHCenter + fontSizeMode: Text.HorizontalFit + } + + Text { + function getStatusText(model) + { + if (model.online) { + var text = "Online" + text += " - " + if (model.paired) { + text += "Paired" + } + else if (model.busy) { + text += "Busy" + } + else { + text += "Not Paired" + } + return text + } + else { + return "Offline"; + } + } + + id: pcPairedText + text: getStatusText(model) + + width: parent.width + anchors.top: pcNameText.bottom + minimumPointSize: 12 + font.pointSize: 36 + horizontalAlignment: Text.AlignHCenter + fontSizeMode: Text.HorizontalFit + } + + MouseArea { + anchors.fill: parent + onClicked: { + parent.GridView.view.currentIndex = index + } + } + } + } +} diff --git a/app/gui/computermodel.cpp b/app/gui/computermodel.cpp new file mode 100644 index 00000000..94cd53ff --- /dev/null +++ b/app/gui/computermodel.cpp @@ -0,0 +1,94 @@ +#include "computermodel.h" + +ComputerModel::ComputerModel(QObject* object) + : QAbstractListModel(object) +{ + connect(&m_ComputerManager, &ComputerManager::computerStateChanged, + this, &ComputerModel::handleComputerStateChanged); + + m_Computers = m_ComputerManager.getComputers(); + m_ComputerManager.startPolling(); +} + +QVariant ComputerModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + + if (index.row() == m_Computers.count()) { + // We insert a synthetic item at the end for the Add PC option + switch (role) { + case NameRole: + return "Add PC"; + case AddPcRole: + return true; + } + } + else if (index.row() > m_Computers.count()) { + qWarning() << "Index out of bounds: " << index.row(); + return QVariant(); + } + + NvComputer* computer = m_Computers[index.row()]; + QReadLocker lock(&computer->lock); + + switch (role) { + case NameRole: + return computer->name; + case OnlineRole: + return computer->state == NvComputer::CS_ONLINE; + case PairedRole: + return computer->state == NvComputer::PS_PAIRED; + case BusyRole: + return computer->currentGameId != 0; + case AddPcRole: + return false; + default: + return QVariant(); + } +} + +int ComputerModel::rowCount(const QModelIndex& parent) const +{ + // We should not return a count for valid index values, + // only the parent (which will not have a "valid" index). + if (parent.isValid()) { + return 0; + } + + // Add PC placeholder counts as 1 + return m_Computers.count() + 1; +} + +QHash ComputerModel::roleNames() const +{ + QHash names; + + names[NameRole] = "name"; + names[OnlineRole] = "online"; + names[PairedRole] = "paired"; + names[BusyRole] = "busy"; + + return names; +} + +void ComputerModel::handleComputerStateChanged(NvComputer* computer) +{ + // If this is an existing computer, we can report the data changed + int index = m_Computers.indexOf(computer); + if (index >= 0) { + // Let the view know that this specific computer changed + emit dataChanged(createIndex(index, 0), createIndex(index, 0)); + } + else { + // This is a new PC that will be inserted at the end + beginInsertRows(QModelIndex(), m_Computers.count(), m_Computers.count()); + m_Computers.append(computer); + endInsertRows(); + } + + // Our view of the world must be in sync with ComputerManager's + Q_ASSERT(m_Computers.count() == m_ComputerManager.getComputers().count()); +} + diff --git a/app/gui/computermodel.h b/app/gui/computermodel.h new file mode 100644 index 00000000..d60ddab2 --- /dev/null +++ b/app/gui/computermodel.h @@ -0,0 +1,31 @@ +#include "backend/computermanager.h" + +#include + +class ComputerModel : public QAbstractListModel +{ + enum Roles + { + NameRole = Qt::UserRole, + OnlineRole, + PairedRole, + BusyRole, + AddPcRole + }; + +public: + ComputerModel(QObject* object = nullptr); + + QVariant data(const QModelIndex &index, int role) const override; + + int rowCount(const QModelIndex &parent) const override; + + virtual QHash roleNames() const override; + +private slots: + void handleComputerStateChanged(NvComputer* computer); + +private: + QVector m_Computers; + ComputerManager m_ComputerManager; +}; diff --git a/app/res/ic_add_to_queue_white_48px.svg b/app/gui/ic_add_to_queue_white_48px.svg similarity index 100% rename from app/res/ic_add_to_queue_white_48px.svg rename to app/gui/ic_add_to_queue_white_48px.svg diff --git a/app/res/ic_tv_white_48px.svg b/app/gui/ic_tv_white_48px.svg similarity index 100% rename from app/res/ic_tv_white_48px.svg rename to app/gui/ic_tv_white_48px.svg diff --git a/app/gui/main.qml b/app/gui/main.qml index ba5e0bc9..3fafbef4 100644 --- a/app/gui/main.qml +++ b/app/gui/main.qml @@ -7,59 +7,8 @@ ApplicationWindow { width: 640 height: 480 title: qsTr("Stack") + color: "#333333" - 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 + PcView { } } diff --git a/app/gui/qtquickcontrols2.conf b/app/gui/qtquickcontrols2.conf index 08109fee..535b22ca 100644 --- a/app/gui/qtquickcontrols2.conf +++ b/app/gui/qtquickcontrols2.conf @@ -3,4 +3,4 @@ ; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html [Controls] -Style=Imagine +Style=Material diff --git a/app/main.cpp b/app/main.cpp index 1633be52..a087c0db 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -1,7 +1,7 @@ #include #include -#include "backend/nvhttp.h" +#include "gui/computermodel.h" // Don't let SDL hook our main function, since Qt is already // doing the same thing @@ -26,6 +26,9 @@ int main(int argc, char *argv[]) QGuiApplication app(argc, argv); + // Register our C++ types for QML + qmlRegisterType("ComputerModel", 1, 0, "ComputerModel"); + // Load the main.qml file QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/gui/main.qml"))); diff --git a/app/qml.qrc b/app/qml.qrc index 5851b4cb..e5008661 100644 --- a/app/qml.qrc +++ b/app/qml.qrc @@ -2,5 +2,8 @@ gui/main.qml gui/qtquickcontrols2.conf + gui/PcView.qml + gui/ic_tv_white_48px.svg + gui/ic_add_to_queue_white_48px.svg diff --git a/app/resources.qrc b/app/resources.qrc index 0fce81cc..a96cfa0a 100644 --- a/app/resources.qrc +++ b/app/resources.qrc @@ -1,10 +1,8 @@ res/icon128.png - res/ic_add_to_queue_white_48px.svg res/ic_remove_circle_outline_white_48px.svg res/ic_remove_from_queue_white_48px.svg - res/ic_tv_white_48px.svg res/ic_videogame_asset_white_48px.svg res/no_app_image.png