diff --git a/NERODevelopment/CMakeLists.txt b/NERODevelopment/CMakeLists.txt index d2b68ea..1198ed2 100644 --- a/NERODevelopment/CMakeLists.txt +++ b/NERODevelopment/CMakeLists.txt @@ -61,7 +61,9 @@ set(PROJECT_SOURCES find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick Network Mqtt Protobuf) qt_add_executable(NEROApp ${PROJECT_SOURCES} - src/controllers/flappybirdcontroller.h src/controllers/flappybirdcontroller.cpp) + src/controllers/flappybirdcontroller.h src/controllers/flappybirdcontroller.cpp + src/controllers/keyboardcontroller.h src/controllers/keyboardcontroller.cpp + src/controllers/configurationcontroller.h src/controllers/configurationcontroller.cpp) qt_add_resources(NEROApp "configuration" PREFIX "/" diff --git a/NERODevelopment/content/Configuration.qml b/NERODevelopment/content/Configuration.qml index 37e8317..498c34d 100644 --- a/NERODevelopment/content/Configuration.qml +++ b/NERODevelopment/content/Configuration.qml @@ -1,5 +1,6 @@ import QtQuick 2.15 import QtQuick.Controls +import NERO Item { id: configuration @@ -8,56 +9,116 @@ Item { property string driverText: "" property string locationText: "" property string systemText: "" + property int selectedConfigurationIndex: configurationController.selectedConfigurationIndex + property bool isKeyboardSelected: configurationController.isKeyboardSelected + property int inputHeight: 70 + + Keys.onPressed: event => { + switch (event.key) { + case Qt.Key_Up: + configurationController.upButtonPressed() + break + case Qt.Key_Down: + configurationController.downButtonPressed() + break + case Qt.Key_Return: + configurationController.enterButtonPressed() + break + } + } ValueText { + id: title anchors.top: parent.top anchors.topMargin: 5 anchors.horizontalCenter: parent.horizontalCenter - id: title text: qsTr("Configuration") } Row { - id: driverRow + id: driverBackground anchors.top: title.bottom anchors.topMargin: 5 anchors.horizontalCenter: parent.horizontalCenter - LabelText { - text: "Driver" - } - KeyboardInput { - label: "joe mama" + id: driverKeyboard + label: "Enter Driver" onAccepted: { configuration.driverText = text + configuration.focus = true + configurationController.setDriverName(text) + configurationController.setIsKeyboardSelected(false) } + selected: configuration.isKeyboardSelected + && configuration.selectedConfigurationIndex === 0 + + border.width: configuration.selectedConfigurationIndex === 0 ? 2 : 0 + border.color: "blue" + height: configuration.inputHeight } } Row { - id: locationRow - anchors.top: driverRow.bottom + id: locationBackground + anchors.top: driverBackground.bottom anchors.topMargin: 5 - LabelText { - text: "Location" - } + anchors.horizontalCenter: parent.horizontalCenter + + KeyboardInput { + label: "Enter Location" + onAccepted: { + configuration.locationText = text + configuration.focus = true + configurationController.setLocationName(text) + configurationController.setIsKeyboardSelected(false) + } + selected: configuration.isKeyboardSelected + && configuration.selectedConfigurationIndex === 1 - ValueText { - text: configuration.locationText + border.width: configuration.selectedConfigurationIndex === 1 ? 2 : 0 + border.color: "blue" + height: configuration.inputHeight } } Row { - id: systemRow - anchors.top: locationRow.bottom + id: systemBackground + anchors.top: locationBackground.bottom anchors.topMargin: 5 - LabelText { - text: "System" + anchors.horizontalCenter: parent.horizontalCenter + KeyboardInput { + label: "Enter System" + onAccepted: { + configuration.systemText = text + configuration.focus = true + configurationController.setSystemName(text) + configurationController.setIsKeyboardSelected(false) + } + selected: configuration.isKeyboardSelected + && configuration.selectedConfigurationIndex === 2 + + border.width: configuration.selectedConfigurationIndex === 2 ? 2 : 0 + border.color: "blue" + height: configuration.inputHeight + } + } + + Button { + id: submitButton + anchors.top: systemBackground.bottom + anchors.topMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + + background: Rectangle { + border.color: "blue" + border.width: configuration.selectedConfigurationIndex === 3 ? 2 : 0 + radius: 10 } - ValueText { - text: configuration.systemText + contentItem: LabelText { + text: "Save" + color: "black" } } } diff --git a/NERODevelopment/content/Keyboard.qml b/NERODevelopment/content/Keyboard.qml index df48bf2..f035f06 100644 --- a/NERODevelopment/content/Keyboard.qml +++ b/NERODevelopment/content/Keyboard.qml @@ -1,5 +1,6 @@ import QtQuick 2.15 import QtQuick.Controls +import NERO Item { id: root @@ -22,24 +23,26 @@ Item { property bool symbols: false property double columns: 10 property double rows: 5 - property int selectedIndex: 0 + property int selectedIndex: keyboardViewController.selectedIndex + property bool isKeySelected: keyboardViewController.selectedKey property int numKeys: 44 Keys.onPressed: event => { - console.log(selectedIndex) switch (event.key) { case Qt.Key_Up: - selectedIndex = Math.max(0, selectedIndex - columns) + keyboardViewController.upButtonPressed() break case Qt.Key_Down: - selectedIndex = Math.min(numKeys, - selectedIndex + columns) + keyboardViewController.downButtonPressed() break case Qt.Key_Left: - selectedIndex = Math.max(0, selectedIndex - 1) + keyboardViewController.leftButtonPressed() break case Qt.Key_Right: - selectedIndex = Math.min(numKeys, selectedIndex + 1) + keyboardViewController.rightButtonPressed() + break + case Qt.Key_Return: + keyboardViewController.enterButtonPressed() break } } @@ -161,13 +164,15 @@ Item { width: modelData.width * keyboard.width / columns - rowSpacing height: keyboard.height / rows - columnSpacing highlighted: root.selectedIndex === index - focus: root.selectedIndex === index + property bool isKeySelected: root.isKeySelected onClicked: root.clicked(text) - Keys.onReturnPressed: { - clicked() - event.accepted = true + onIsKeySelectedChanged: { + if (root.isKeySelected && highlighted) { + clicked() + event.accepted = true + } } } } @@ -227,15 +232,16 @@ Item { ) : modelData.text width: modelData.width * keyboard.width / columns - rowSpacing height: keyboard.height / rows - columnSpacing - highlighted: root.selectedIndex === index + root.columns - focus: root.selectedIndex === index + root.columns - onClicked: root.clicked(text) - Keys.onReturnPressed: { - clicked() - event.accepted = true + property bool isKeySelected: root.isKeySelected + + onIsKeySelectedChanged: { + if (root.isKeySelected && highlighted) { + clicked() + event.accepted = true + } } } } @@ -298,13 +304,15 @@ Item { width: modelData.width * keyboard.width / columns - rowSpacing height: keyboard.height / rows - columnSpacing highlighted: root.selectedIndex === index + 2 * root.columns - focus: root.selectedIndex === index + 2 * root.columns + property bool isKeySelected: root.isKeySelected onClicked: root.clicked(text) - Keys.onReturnPressed: { - clicked() - event.accepted = true + onIsKeySelectedChanged: { + if (root.isKeySelected && highlighted) { + clicked() + event.accepted = true + } } } } @@ -361,13 +369,15 @@ Item { width: modelData.width * keyboard.width / columns - rowSpacing height: keyboard.height / rows - columnSpacing highlighted: root.selectedIndex === index + 3 * root.columns + 1 - focus: root.selectedIndex === index + 3 * root.columns + 1 + property bool isKeySelected: root.isKeySelected onClicked: root.clicked(text) - Keys.onReturnPressed: { - clicked() - event.accepted = true + onIsKeySelectedChanged: { + if (root.isKeySelected && highlighted) { + clicked() + event.accepted = true + } } } } @@ -402,13 +412,15 @@ Item { width: modelData.width * keyboard.width / columns - rowSpacing height: keyboard.height / rows - columnSpacing highlighted: root.selectedIndex === index + 4 * root.columns - focus: root.selectedIndex === index + 4 * root.columns + property bool isKeySelected: root.isKeySelected onClicked: root.clicked(text) - Keys.onReturnPressed: { - clicked() - event.accepted = true + onIsKeySelectedChanged: { + if (root.isKeySelected && highlighted) { + clicked() + event.accepted = true + } } } } @@ -418,33 +430,34 @@ Item { } signal clicked(string text) - onClicked: { - if (text == '\u2190') { - // LEFTWARDS ARROW (backspace) - var position = textInput.cursorPosition - textInput.text = textInput.text.substring( - 0, - textInput.cursorPosition - 1) + textInput.text.substring( - textInput.cursorPosition, textInput.text.length) - textInput.cursorPosition = position - 1 - } else if (text == '\u2191') - shift = !shift // UPWARDS ARROW (shift) - else if (text == '@#') - symbols = true - else if (text == 'AB') - symbols = false - else if (text == '\u21B5') - accepted(textInput.text) // DOWNWARDS ARROW WITH CORNER LEFTWARDS (enter) - else { - // insert text - var position = textInput.cursorPosition - textInput.text = textInput.text.substring( - 0, - textInput.cursorPosition) + text + textInput.text.substring( - textInput.cursorPosition, textInput.text.length) - textInput.cursorPosition = position + 1 - - shift = false // momentary - } - } + onClicked: text => { + if (text === '\u2190') { + // LEFTWARDS ARROW (backspace) + var position = textInput.cursorPosition + textInput.text = textInput.text.substring( + 0, + textInput.cursorPosition - 1) + textInput.text.substring( + textInput.cursorPosition, textInput.text.length) + textInput.cursorPosition = position - 1 + } else if (text === '\u2191') + shift = !shift // UPWARDS ARROW (shift) + else if (text === '@#') + symbols = true + else if (text === 'AB') + symbols = false + else if (text === '\u21B5') + accepted( + textInput.text) // DOWNWARDS ARROW WITH CORNER LEFTWARDS (enter) + else { + // insert text + var position = textInput.cursorPosition + textInput.text = textInput.text.substring( + 0, + textInput.cursorPosition) + text + textInput.text.substring( + textInput.cursorPosition, textInput.text.length) + textInput.cursorPosition = position + 1 + + shift = false // momentary + } + } } diff --git a/NERODevelopment/content/KeyboardInput.qml b/NERODevelopment/content/KeyboardInput.qml index 61cb510..15e8fc2 100644 --- a/NERODevelopment/content/KeyboardInput.qml +++ b/NERODevelopment/content/KeyboardInput.qml @@ -7,16 +7,23 @@ Rectangle { // public property string label: 'label' property bool password: false + property bool selected: false property alias text: textInput.text // in/out - signal accepted(string text) // onAccepted: print('onAccepted', text) + signal accepted(string text) + // onAccepted: print('onAccepted', text) // private width: 500 height: 100 // default size - border.width: 0.05 * root.height radius: 0.2 * height - opacity: enabled && !mouseArea.pressed ? 1 : 0.3 // disabled/pressed state + + onSelectedChanged: { + if (selected) { + textInput.focus = true + keyboardController.show() + } + } Text { // label @@ -45,15 +52,6 @@ Rectangle { echoMode: password ? TextInput.Password : TextInput.Normal } - MouseArea { - // comment out to input text via physical keyboard - id: mouseArea - - anchors.fill: parent - - onClicked: keyboardController.show() - } - KeyboardController { id: keyboardController diff --git a/NERODevelopment/src/controllers/configurationcontroller.cpp b/NERODevelopment/src/controllers/configurationcontroller.cpp new file mode 100644 index 0000000..69fc43d --- /dev/null +++ b/NERODevelopment/src/controllers/configurationcontroller.cpp @@ -0,0 +1,66 @@ +#include "configurationcontroller.h" + +ConfigurationController::ConfigurationController(Model *model, QObject *parent) + : ButtonController{model, parent} {} + +int ConfigurationController::selectedConfigurationIndex() const { + return this->m_selectedConfigurationIndex; +} +void ConfigurationController::setSelectedConfigurationIndex(int index) { + if (this->m_selectedConfigurationIndex != index) { + this->m_selectedConfigurationIndex = index; + emit this->selectedConfigurationIndexChanged(); + } +} + +bool ConfigurationController::isKeyboardSelected() const { + return this->m_isKeyboardSelected; +} +void ConfigurationController::setIsKeyboardSelected(bool selected) { + if (this->m_isKeyboardSelected != selected) { + this->m_isKeyboardSelected = selected; + emit this->isKeyboardSelectedChanged(); + } +} + +void ConfigurationController::setDriverName(QString driverName) { + if (this->m_driverName != driverName) { + this->m_driverName = driverName; + } +} + +void ConfigurationController::setSystemName(QString systemName) { + if (this->m_systemName != systemName) { + this->m_systemName = systemName; + } +} + +void ConfigurationController::setLocationName(QString locationName) { + if (this->m_locationName != locationName) { + this->m_locationName = locationName; + } +} + +void ConfigurationController::downButtonPressed() { + if (!this->m_isKeyboardSelected) { + this->setSelectedConfigurationIndex(std::min( + this->m_numConfigs - 1, this->m_selectedConfigurationIndex + 1)); + } +} + +void ConfigurationController::upButtonPressed() { + if (!this->m_isKeyboardSelected) { + this->setSelectedConfigurationIndex( + std::max(0, this->m_selectedConfigurationIndex - 1)); + } +} + +void ConfigurationController::enterButtonPressed() { + if (this->m_selectedConfigurationIndex == 3) { + this->m_model->sendMessage("/driver", this->m_driverName); + this->m_model->sendMessage("/system", this->m_systemName); + this->m_model->sendMessage("/location", this->m_locationName); + } else { + this->setIsKeyboardSelected(!this->m_isKeyboardSelected); + } +} diff --git a/NERODevelopment/src/controllers/configurationcontroller.h b/NERODevelopment/src/controllers/configurationcontroller.h new file mode 100644 index 0000000..61f8103 --- /dev/null +++ b/NERODevelopment/src/controllers/configurationcontroller.h @@ -0,0 +1,43 @@ +#ifndef CONFIGURATIONCONTROLLER_H +#define CONFIGURATIONCONTROLLER_H + +#include "buttoncontroller.h" + +class ConfigurationController : public ButtonController { + Q_OBJECT + Q_PROPERTY(int selectedConfigurationIndex READ selectedConfigurationIndex + WRITE setSelectedConfigurationIndex NOTIFY + selectedConfigurationIndexChanged FINAL) + Q_PROPERTY(bool isKeyboardSelected READ isKeyboardSelected WRITE + setIsKeyboardSelected NOTIFY isKeyboardSelectedChanged FINAL) + +public: + explicit ConfigurationController(Model *model, QObject *parent = nullptr); + int selectedConfigurationIndex() const; + bool isKeyboardSelected() const; + +signals: + void selectedConfigurationIndexChanged(); + void isKeyboardSelectedChanged(); + +public slots: + void setSelectedConfigurationIndex(int); + void setIsKeyboardSelected(bool); + void setDriverName(QString); + void setSystemName(QString); + void setLocationName(QString); + + void downButtonPressed() override; + void upButtonPressed() override; + void enterButtonPressed() override; + +private: + int m_selectedConfigurationIndex = 0; + bool m_isKeyboardSelected = false; + QString m_driverName; + QString m_systemName; + QString m_locationName; + int m_numConfigs = 4; +}; + +#endif // CONFIGURATIONCONTROLLER_H diff --git a/NERODevelopment/src/controllers/keyboardcontroller.cpp b/NERODevelopment/src/controllers/keyboardcontroller.cpp new file mode 100644 index 0000000..3b93539 --- /dev/null +++ b/NERODevelopment/src/controllers/keyboardcontroller.cpp @@ -0,0 +1,45 @@ +#include "keyboardcontroller.h" + +KeyboardController::KeyboardController(Model *model, QObject *parent) + : ButtonController{model, parent} {} + +int KeyboardController::selectedIndex() const { return this->m_selectedIndex; } + +bool KeyboardController::selectedKey() const { return this->m_selectedKey; } + +void KeyboardController::setSelectedIndex(int index) { + if (this->m_selectedIndex != index) { + this->m_selectedIndex = index; + emit selectedIndexChanged(); + } +} + +void KeyboardController::setSelectedKey(bool selected) { + if (this->m_selectedKey != selected) { + this->m_selectedKey = selected; + emit selectedKeyChanged(); + } +} + +void KeyboardController::downButtonPressed() { + this->setSelectedIndex( + std::min(this->m_numKeys - 1, this->m_selectedIndex + this->m_columns)); +} + +void KeyboardController::upButtonPressed() { + this->setSelectedIndex(std::max(0, this->m_selectedIndex - this->m_columns)); +} + +void KeyboardController::leftButtonPressed() { + this->setSelectedIndex(std::max(0, this->m_selectedIndex - 1)); +} + +void KeyboardController::rightButtonPressed() { + this->setSelectedIndex( + std::min(this->m_numKeys - 1, this->m_selectedIndex + 1)); +} + +void KeyboardController::enterButtonPressed() { + this->setSelectedKey(true); + this->setSelectedKey(false); +} diff --git a/NERODevelopment/src/controllers/keyboardcontroller.h b/NERODevelopment/src/controllers/keyboardcontroller.h new file mode 100644 index 0000000..a10fe5b --- /dev/null +++ b/NERODevelopment/src/controllers/keyboardcontroller.h @@ -0,0 +1,39 @@ +#ifndef KEYBOARDCONTROLLER_H +#define KEYBOARDCONTROLLER_H + +#include "buttoncontroller.h" + +class KeyboardController : public ButtonController { + Q_OBJECT + Q_PROPERTY(int selectedIndex READ selectedIndex WRITE setSelectedIndex NOTIFY + selectedIndexChanged FINAL) + Q_PROPERTY(bool selectedKey READ selectedKey WRITE setSelectedKey NOTIFY + selectedKeyChanged FINAL) +public: + explicit KeyboardController(Model *model, QObject *parent = nullptr); + + int selectedIndex() const; + bool selectedKey() const; + +signals: + void selectedIndexChanged(); + void selectedKeyChanged(); + +public slots: + void setSelectedIndex(int); + void setSelectedKey(bool); + + void downButtonPressed() override; + void upButtonPressed() override; + void leftButtonPressed() override; + void rightButtonPressed() override; + void enterButtonPressed() override; + +private: + int m_selectedIndex = 0; + bool m_selectedKey = false; + int m_numKeys = 45; + int m_columns = 10; +}; + +#endif // KEYBOARDCONTROLLER_H diff --git a/NERODevelopment/src/main.cpp b/NERODevelopment/src/main.cpp index ad54e8a..103a9fc 100644 --- a/NERODevelopment/src/main.cpp +++ b/NERODevelopment/src/main.cpp @@ -2,9 +2,13 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "app_environment.h" +#include "controllers/configurationcontroller.h" #include "controllers/debugtablecontroller.h" #include "controllers/flappybirdcontroller.h" #include "controllers/homecontroller.h" +#include "controllers/keyboardcontroller.h" +#include "controllers/navigationcontroller.h" +#include "controllers/offviewcontroller.h" #include "import_qml_components_plugins.h" #include "import_qml_plugins.h" #include "src/models/mock_model.h" @@ -14,10 +18,6 @@ #include #include -#include "controllers/homecontroller.h" -#include "controllers/navigationcontroller.h" -#include "controllers/offviewcontroller.h" - int main(int argc, char *argv[]) { set_qt_environment(); @@ -44,7 +44,9 @@ int main(int argc, char *argv[]) { OffViewController offViewController(model); DebugTableController tableController(model); NavigationController navigationController(model); - FlappyBirdController FlappyBirdController(model); + FlappyBirdController flappyBirdController(model); + ConfigurationController configurationController(model); + KeyboardController keyboardController(model); dataThread->start(); @@ -65,7 +67,11 @@ int main(int argc, char *argv[]) { engine.rootContext()->setContextProperty("navigationController", &navigationController); engine.rootContext()->setContextProperty("flappyBirdController", - &FlappyBirdController); + &flappyBirdController); + engine.rootContext()->setContextProperty("configurationController", + &configurationController); + engine.rootContext()->setContextProperty("keyboardViewController", + &keyboardController); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); diff --git a/NERODevelopment/src/models/mock_model.cpp b/NERODevelopment/src/models/mock_model.cpp index 6d07aec..0dcd637 100644 --- a/NERODevelopment/src/models/mock_model.cpp +++ b/NERODevelopment/src/models/mock_model.cpp @@ -355,6 +355,10 @@ std::optional MockModel::getNumberOfCriticalFaults() { return 0; } std::optional MockModel::getNumberOfNonCriticalFaults() { return 0; } +void MockModel::sendMessage(QString topic, QString message) { + qDebug() << "Sending Message: " << topic << " " << message; +} + QVector MockModel::convertNumberToDataInfoValue(float value) { // qDebug() << value; QVector val = {QString::number(value)}; diff --git a/NERODevelopment/src/models/mock_model.h b/NERODevelopment/src/models/mock_model.h index f811c39..502e029 100644 --- a/NERODevelopment/src/models/mock_model.h +++ b/NERODevelopment/src/models/mock_model.h @@ -73,6 +73,7 @@ class MockModel : public Model { std::optional getIsTalking() override; std::optional getNumberOfCriticalFaults() override; std::optional getNumberOfNonCriticalFaults() override; + void sendMessage(const QString topic, const QString message) override; private slots: void updateCurrentData() override; diff --git a/NERODevelopment/src/models/model.h b/NERODevelopment/src/models/model.h index 740107c..a6ed9d9 100644 --- a/NERODevelopment/src/models/model.h +++ b/NERODevelopment/src/models/model.h @@ -78,6 +78,7 @@ class Model : public QObject { virtual std::optional getIsTalking() = 0; virtual std::optional getNumberOfCriticalFaults() = 0; virtual std::optional getNumberOfNonCriticalFaults() = 0; + virtual void sendMessage(QString topic, QString message) = 0; QList getDebugTableValues(); void updatePackTempData(); diff --git a/NERODevelopment/src/models/raspberry_model.cpp b/NERODevelopment/src/models/raspberry_model.cpp index dcc75d5..63a8038 100644 --- a/NERODevelopment/src/models/raspberry_model.cpp +++ b/NERODevelopment/src/models/raspberry_model.cpp @@ -23,6 +23,11 @@ void RaspberryModel::connectToMQTT() { connect(client, &MqttClient::emitServerData, this, &RaspberryModel::receiveServerData); client->connectToHost(); + this->m_client = client; +} + +void RaspberryModel::sendMessage(const QString topic, const QString message) { + this->m_client->sendMessage(topic, message); } void RaspberryModel::receiveServerData(const serverdata::ServerData data, diff --git a/NERODevelopment/src/models/raspberry_model.h b/NERODevelopment/src/models/raspberry_model.h index 6069d2b..7ba48d6 100644 --- a/NERODevelopment/src/models/raspberry_model.h +++ b/NERODevelopment/src/models/raspberry_model.h @@ -3,8 +3,8 @@ #ifndef _WIN32 #include "model.h" +#include "mqtt_client.h" #include - /** * @brief The RaspberryModel class * The Production Model that is used when running on the car @@ -75,6 +75,7 @@ class RaspberryModel : public Model { std::optional getIsTalking() override; std::optional getNumberOfCriticalFaults() override; std::optional getNumberOfNonCriticalFaults() override; + void sendMessage(const QString topic, const QString message) override; private slots: void updateCurrentData() override; @@ -83,6 +84,7 @@ private slots: private: void processData(const std::string &data); int totalNumberOfOnesIn(float value); + MqttClient *m_client; }; #endif #endif // RASPBERRY_MODEL_H