From 4d0e9bc74f8b09c22ef3a860e3df8a857ec15fa5 Mon Sep 17 00:00:00 2001 From: Dorian Zedler Date: Sun, 11 Oct 2020 21:01:21 +0200 Subject: [PATCH] added some controls --- OmobiDisplayApp/OmobiDisplayApp.pro | 6 +- OmobiDisplayApp/QBluetoothLeUart | 2 +- OmobiDisplayApp/main.cpp | 2 + OmobiDisplayApp/omobidisplaybackend.cpp | 20 +- OmobiDisplayApp/omobidisplaybackend.h | 8 + OmobiDisplayApp/omobidisplaytextmodel.cpp | 117 ++++++++++ OmobiDisplayApp/omobidisplaytextmodel.h | 58 +++++ .../qml/CollapsableItemDelegate.qml | 93 ++++++++ .../ressources/qml/ConnectedPage.qml | 17 +- .../ressources/qml/DisplayTextDelegate.qml | 52 +++++ .../qml/DisplayTextModelListView.qml | 220 ++++++++++++++++++ OmobiDisplayApp/ressources/qml/main.qml | 6 +- OmobiDisplayApp/ressources/qml/qml.qrc | 3 + 13 files changed, 582 insertions(+), 22 deletions(-) create mode 100644 OmobiDisplayApp/omobidisplaytextmodel.cpp create mode 100644 OmobiDisplayApp/omobidisplaytextmodel.h create mode 100644 OmobiDisplayApp/ressources/qml/CollapsableItemDelegate.qml create mode 100644 OmobiDisplayApp/ressources/qml/DisplayTextDelegate.qml create mode 100644 OmobiDisplayApp/ressources/qml/DisplayTextModelListView.qml diff --git a/OmobiDisplayApp/OmobiDisplayApp.pro b/OmobiDisplayApp/OmobiDisplayApp.pro index 7570e3d..8936c66 100644 --- a/OmobiDisplayApp/OmobiDisplayApp.pro +++ b/OmobiDisplayApp/OmobiDisplayApp.pro @@ -11,10 +11,12 @@ TEMPLATE = app SOURCES += \ main.cpp \ - omobidisplaybackend.cpp + omobidisplaybackend.cpp \ + omobidisplaytextmodel.cpp HEADERS += \ - omobidisplaybackend.h + omobidisplaybackend.h \ + omobidisplaytextmodel.h RESOURCES += \ ressources/qml/qml.qrc \ diff --git a/OmobiDisplayApp/QBluetoothLeUart b/OmobiDisplayApp/QBluetoothLeUart index 60d10f0..0b053ea 160000 --- a/OmobiDisplayApp/QBluetoothLeUart +++ b/OmobiDisplayApp/QBluetoothLeUart @@ -1 +1 @@ -Subproject commit 60d10f056b53b1816bd97559ad2d7527bbc158a8 +Subproject commit 0b053eaa88ffdcc0b32e533904e5e266b8e62fb3 diff --git a/OmobiDisplayApp/main.cpp b/OmobiDisplayApp/main.cpp index c25f814..4d73779 100644 --- a/OmobiDisplayApp/main.cpp +++ b/OmobiDisplayApp/main.cpp @@ -4,6 +4,7 @@ #include #include "omobidisplaybackend.h" +#include "omobidisplaytextmodel.h" int main(int argc, char *argv[]) { @@ -12,6 +13,7 @@ int main(int argc, char *argv[]) QGuiApplication app(argc, argv); qmlRegisterType("de.itsblue.omobidisplayapp", 1, 0, "OmobiDisplayBackend"); + qmlRegisterUncreatableType("de.itsblue.omobidisplayapp", 1, 0, "OmobiDisplayTextModel", "OmobiDisplayTextModel cannot be created"); QBluetoothLeUart::init(); QQuickStyle::setStyle("Material"); diff --git a/OmobiDisplayApp/omobidisplaybackend.cpp b/OmobiDisplayApp/omobidisplaybackend.cpp index 26ca122..5a0681b 100644 --- a/OmobiDisplayApp/omobidisplaybackend.cpp +++ b/OmobiDisplayApp/omobidisplaybackend.cpp @@ -3,11 +3,13 @@ OmobiDisplayBackend::OmobiDisplayBackend(QObject *parent) : QObject(parent) { this->ble = new QBluetoothLeUart(); + this->displayTextModel = new OmobiDisplayTextModel(this); connect(this->ble, &QBluetoothLeUart::stateChanged, this, &OmobiDisplayBackend::handleBluetoothStateChange); connect(this->ble, &QBluetoothLeUart::foundNewDevice, this, &OmobiDisplayBackend::handleFoundNewDevice); connect(this->ble, &QBluetoothLeUart::dataReceived, this, &OmobiDisplayBackend::DataHandler); connect(this->ble, &QBluetoothLeUart::connectedToDevice, this, &OmobiDisplayBackend::handleBluetoothDeviceConected); + connect(this->displayTextModel, &OmobiDisplayTextModel::dataChanged, this, &OmobiDisplayBackend::handleDisplayTextModelDataChanged); this->setState(Idle); this->ble->startScanningForDevices(); @@ -46,7 +48,6 @@ void OmobiDisplayBackend::handleBluetoothStateChange(QBluetoothLeUart::Bluetooth } case QBluetoothLeUart::Connected: { - this->setState(Connected); break; } } @@ -54,6 +55,13 @@ void OmobiDisplayBackend::handleBluetoothStateChange(QBluetoothLeUart::Bluetooth void OmobiDisplayBackend::handleBluetoothDeviceConected() { this->ble->sendData("Hallihallo ich bin Julia Mueller"); + + // get the existing model data! + // TODO: implement some communication! + + QString currentDisplayText = "[[],[]]"; + + this->setState(Connected); } void OmobiDisplayBackend::handleFoundNewDevice(QBluetoothLeUartDevice* device) { @@ -66,10 +74,20 @@ void OmobiDisplayBackend::DataHandler(const QString &s){ } + +void OmobiDisplayBackend::handleDisplayTextModelDataChanged() { + qDebug() << "MODEL DATA CHANGED!"; +} + QBluetoothLeUart* OmobiDisplayBackend::getBleController() { return this->ble; } + +OmobiDisplayTextModel* OmobiDisplayBackend::getDisplayTextModel() { + return this->displayTextModel; +} + OmobiDisplayBackend::OmobiDisplayAppState OmobiDisplayBackend::getState() { return this->state; } diff --git a/OmobiDisplayApp/omobidisplaybackend.h b/OmobiDisplayApp/omobidisplaybackend.h index 4a2d0a2..e7762d7 100644 --- a/OmobiDisplayApp/omobidisplaybackend.h +++ b/OmobiDisplayApp/omobidisplaybackend.h @@ -3,12 +3,15 @@ #include #include +#include class OmobiDisplayBackend : public QObject { Q_OBJECT Q_PROPERTY(QBluetoothLeUart* bleController READ getBleController NOTIFY bleControllerChanged) Q_PROPERTY(OmobiDisplayAppState state READ getState WRITE setState NOTIFY stateChanged) + Q_PROPERTY(OmobiDisplayTextModel* displayTextModel READ getDisplayTextModel NOTIFY displayTextModelChanged) + public: explicit OmobiDisplayBackend(QObject *parent = nullptr); @@ -24,11 +27,13 @@ public: private: OmobiDisplayAppState state; QBluetoothLeUart *ble; + OmobiDisplayTextModel* displayTextModel; public slots: Q_INVOKABLE void startScanning(); Q_INVOKABLE QBluetoothLeUart* getBleController(); Q_INVOKABLE OmobiDisplayAppState getState(); + Q_INVOKABLE OmobiDisplayTextModel* getDisplayTextModel(); private slots: void handleBluetoothStateChange(QBluetoothLeUart::BluetoothLeUartState state); @@ -36,11 +41,14 @@ private slots: void DataHandler(const QString &s); void handleBluetoothDeviceConected(); + void handleDisplayTextModelDataChanged(); + void setState(OmobiDisplayAppState state); signals: void stateChanged(); void bleControllerChanged(); + void displayTextModelChanged(); }; diff --git a/OmobiDisplayApp/omobidisplaytextmodel.cpp b/OmobiDisplayApp/omobidisplaytextmodel.cpp new file mode 100644 index 0000000..76cb3e3 --- /dev/null +++ b/OmobiDisplayApp/omobidisplaytextmodel.cpp @@ -0,0 +1,117 @@ +#include "omobidisplaytextmodel.h" + +OmobiDisplayTextModel::OmobiDisplayTextModel(QObject* parent) : QAbstractListModel(parent) +{ + QMap sampleText1 = { + { TextRole, "itsblue.de" }, + { ActiveRole, true }, + { RuntimeRole, 20 }, + { ColorRole, "blue" }, + { AlignmentRole, "center" }, + { ScrollRole, true }, + { ScrollCountRole, 20 } + }; + + QMap sampleText2 = { + { TextRole, "Das ist ein tolles Display" }, + { ActiveRole, false }, + { RuntimeRole, 10 }, + { ColorRole, "green" }, + { AlignmentRole, "left" }, + { ScrollRole, true }, + { ScrollCountRole, 10 } + }; + + this->texts.append(sampleText1); + this->texts.append(sampleText2); +} + + +int OmobiDisplayTextModel::rowCount(const QModelIndex &) const +{ + return this->texts.length(); +} + +QVariant OmobiDisplayTextModel::data(const QModelIndex &index, int role) const +{ + if (index.row() < rowCount()) + if(this->texts[index.row()].contains(role)) + return this->texts[index.row()][role]; + return QVariant(); +} + +QHash OmobiDisplayTextModel::roleNames() const +{ + static const QHash roles { + { TextRole, "text" }, + { ActiveRole, "active" }, + { RuntimeRole, "runtime" }, + { ColorRole, "color" }, + { AlignmentRole, "alignment" }, + { ScrollRole, "scroll" }, + { ScrollCountRole, "scrollCount" } + }; + return roles; +} + +void OmobiDisplayTextModel::append( + QString text, + bool active, + unsigned int runtime, + QString color, + QString alignment, + bool scroll, + unsigned int scrollCount + ) { + QMap roles = { + { TextRole, text }, + { ActiveRole, active }, + { RuntimeRole, runtime }, + { ColorRole, color }, + { AlignmentRole, alignment }, + { ScrollRole, scroll }, + { ScrollCountRole, scrollCount } + }; + + this->append(roles); +} + +void OmobiDisplayTextModel::append(const QMap &roles) { + int row = this->texts.length(); + this->beginInsertRows(QModelIndex(), row, row); + this->texts.insert(row, roles); + this->endInsertRows(); +} + +bool OmobiDisplayTextModel::setData(const QModelIndex &index, const QVariant &value, int role) { + if (index.row() >= rowCount() || !this->texts[index.row()].contains(role)) + return false; + + if(this->texts[index.row()][role] == value) + return true; + + this->texts[index.row()][role] = value; + + emit dataChanged(index, index); + + return QAbstractItemModel::setData(index, value, role); +} + +void OmobiDisplayTextModel::remove(int row) +{ + if (row < 0 || row >= this->rowCount()) + return; + + beginRemoveRows(QModelIndex(), row, row); + this->texts.removeAt(row); + endRemoveRows(); +} + +void OmobiDisplayTextModel::clear() { + for(int i = 0; i < this->texts.length(); i++) + this->remove(i); +} + +QString OmobiDisplayTextModel::getAsJson() { + +} diff --git a/OmobiDisplayApp/omobidisplaytextmodel.h b/OmobiDisplayApp/omobidisplaytextmodel.h new file mode 100644 index 0000000..b9b0ca2 --- /dev/null +++ b/OmobiDisplayApp/omobidisplaytextmodel.h @@ -0,0 +1,58 @@ +#ifndef OMOBIDISPLAYTEXTMODEL_H +#define OMOBIDISPLAYTEXTMODEL_H + +#include +#include +#include +#include + + +class OmobiDisplayTextModel : public QAbstractListModel +{ + Q_OBJECT +public: + friend class OmobiDisplayBackend; + + enum QBluetoothLeUartDeviceModelRole { + TextRole = Qt::DisplayRole, + ActiveRole, + RuntimeRole, + ColorRole, + AlignmentRole, + ScrollRole, + ScrollCountRole + }; + Q_ENUM(QBluetoothLeUartDeviceModelRole) + + int rowCount(const QModelIndex & = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QHash roleNames() const; + + Q_INVOKABLE void append( + QString text, + bool active, + unsigned int runtime, + QString color, + QString alignment, + bool scroll, + unsigned int scrollCount + ); + void append(const QMap &roles); + + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + Q_INVOKABLE void remove(int row); + +protected: + OmobiDisplayTextModel(QObject* parent = nullptr); + + void reloadFromJson(QString json); + QString getAsJson(); + + void clear(); + +private: + QList> texts; +}; + +#endif // OMOBIDISPLAYTEXTMODEL_H diff --git a/OmobiDisplayApp/ressources/qml/CollapsableItemDelegate.qml b/OmobiDisplayApp/ressources/qml/CollapsableItemDelegate.qml new file mode 100644 index 0000000..36003f3 --- /dev/null +++ b/OmobiDisplayApp/ressources/qml/CollapsableItemDelegate.qml @@ -0,0 +1,93 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.0 + +ItemDelegate { + id: control + + property bool expanded: false + property Component expandedComponent: Component { + Rectangle { + implicitHeight: 100 + color: "red" + } + } + + height: 70 + expandedItemContainer.height + + contentItem: Item {} + + state: expanded ? "open":"closed" + + Item { + id: expandedItemContainer + + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + margins: 5 + } + + clip: true + + height: control.state === "open" && expandedItemLoader.status === Loader.Ready && expandedItemLoader.item !== undefined ? expandedItemLoader.item.implicitHeight:0 + + Behavior on height { + NumberAnimation { + duration: 200 + } + } + + Loader { + id: expandedItemLoader + + anchors.centerIn: parent + + width: parent.width + + onEnabledChanged: { + if(enabled){ + sourceComponent = control.expandedComponent + } + else { + hideDelayPa.start() + } + } + + anchors.fill: parent + + PauseAnimation { + id: hideDelayPa + + duration: 200 + + onRunningChanged: { + if(!running && !expandedItemLoader.enabled){ + expandedItemLoader.sourceComponent = undefined + } + } + } + } + + + } + + states: [ + State { + name: "closed" + + PropertyChanges { + target: expandedItemLoader + enabled: false + } + }, + State { + name: "opened" + + PropertyChanges { + target: expandedItemLoader + enabled: true + } + } + ] +} diff --git a/OmobiDisplayApp/ressources/qml/ConnectedPage.qml b/OmobiDisplayApp/ressources/qml/ConnectedPage.qml index 49396eb..e960972 100644 --- a/OmobiDisplayApp/ressources/qml/ConnectedPage.qml +++ b/OmobiDisplayApp/ressources/qml/ConnectedPage.qml @@ -7,22 +7,7 @@ import de.itsblue.bluetoothleuart 1.0 Page { id: root - ColumnLayout { + DisplayTextModelListView { anchors.fill: parent - anchors.margins: 10 - - TextField { - id: newTextInput - Layout.fillWidth: true - Layout.preferredHeight: 50 - } - - Button { - Layout.fillWidth: true - - onClicked: { - backend.bleController.sendData(newTextInput.text) - } - } } } diff --git a/OmobiDisplayApp/ressources/qml/DisplayTextDelegate.qml b/OmobiDisplayApp/ressources/qml/DisplayTextDelegate.qml new file mode 100644 index 0000000..177469f --- /dev/null +++ b/OmobiDisplayApp/ressources/qml/DisplayTextDelegate.qml @@ -0,0 +1,52 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.0 + +CollapsableItemDelegate { + id: control + + expandedComponent: Component { + Item { + implicitHeight: 200 + RowLayout { + anchors.fill: parent + + TextField { + id: textTextInput + Layout.preferredWidth: parent.width + Layout.preferredHeight: 50 + text: model.text + } + + Button { + Layout.preferredWidth: parent.width + Layout.preferredHeight: 50 + + text: "apply" + + onClicked: { + model.text = textTextInput.text + } + } + } + } + } + + Text { + id: labelText + + anchors { + top: parent.top + left: parent.left + right: parent.right + margins: 5 + } + + height: 70 - 2 * anchors.margins + + verticalAlignment: Text.AlignVCenter + + font.pixelSize: height * 0.4 + text: model.text + } +} diff --git a/OmobiDisplayApp/ressources/qml/DisplayTextModelListView.qml b/OmobiDisplayApp/ressources/qml/DisplayTextModelListView.qml new file mode 100644 index 0000000..757957b --- /dev/null +++ b/OmobiDisplayApp/ressources/qml/DisplayTextModelListView.qml @@ -0,0 +1,220 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.9 +import QtQuick.Layouts 1.0 +import de.itsblue.omobidisplayapp 1.0 +import QtQuick.Controls.Material 2.0 + +ListView { + id: control + + + + model: backend.displayTextModel + + delegate: DisplayTextDelegate { + id: delegate + width: control.width + + onClicked: { + popup.edit(model) + } + } + + RoundButton { + anchors { + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + bottomMargin: height * 0.25 + } + + height: parent.width * 0.15 + width: height + + text: "" + + onClicked: popup.add() + + Text { + anchors.fill: parent + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + font.pixelSize: height * 0.4 + + text: "+" + } + } + + Dialog { + id: popup + + property bool editing + property var editingModel + + parent: Overlay.overlay + + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + + width: parent.width * 0.6 + + title: editing ? "Edit item" : "New item" + + standardButtons: Dialog.Ok | Dialog.Cancel + + modal: true + + onAccepted: { + if(editing) { + editingModel.active = activeSwitch.checked + editingModel.text = textTextField.text + editingModel.runtime = runtimeSpinBox.value + editingModel.color = colorComboBox.currentText + editingModel.alignment = alignmentComboBox.currentText + editingModel.scroll = scrollSwitch.checked + editingModel.scrollCount = scrollCountSpinBox.value + } + else { + control.model.append(textTextField.text, + activeSwitch.checked, + runtimeSpinBox.value, + colorComboBox.currentText, + alignmentComboBox.currentText, + scrollSwitch.checked, + scrollCountSpinBox.value + ) + } + } + + contentItem: GridLayout { + + property int rowHeight: 50 + + columns: 2 + columnSpacing: 10 + + Label { + font.bold: true + text: "Active:" + } + + Switch { + id: activeSwitch + Layout.fillWidth: true + } + + Label { + font.bold: true + text: "Text:" + } + + TextField { + id: textTextField + Layout.fillWidth: true + } + + Label { + font.bold: true + text: "Runtime (in s):" + } + + SpinBox { + id: runtimeSpinBox + Layout.fillWidth: true + } + + Label { + font.bold: true + text: "Color:" + } + + ComboBox { + id: colorComboBox + Layout.fillWidth: true + model: ["white", "blue", "red", "green"] + } + + Label { + font.bold: true + text: "Alignment:" + } + + ComboBox { + id: alignmentComboBox + Layout.fillWidth: true + model: ["left", "center", "right"] + } + + Label { + font.bold: true + text: "Scroll:" + } + + Switch { + id: scrollSwitch + Layout.fillWidth: true + } + + Label { + font.bold: true + text: "Scroll count:" + } + + SpinBox { + id: scrollCountSpinBox + Layout.fillWidth: true + } + + Button { + visible: popup.editing + + Layout.preferredWidth: parent.width * 0.5 + Layout.alignment: Layout.Center + + Material.background: Material.Red + Material.foreground: "white" + + text: "delete" + + onClicked: { + control.model.remove(0) + popup.close() + } + } + } + + function edit(model) { + editingModel = model + editing = true + + reset() + + activeSwitch.checked = editingModel.active + textTextField.text = editingModel.text + runtimeSpinBox.value = editingModel.runtime + colorComboBox.currentIndex = colorComboBox.model.indexOf(editingModel.color) + alignmentComboBox.currentIndex = alignmentComboBox.model.indexOf(editingModel.alignment) + scrollSwitch.checked = editingModel.scroll + scrollCountSpinBox.value = editingModel.scrollCount + + open() + } + + function add() { + editing = false + reset() + open() + } + + function reset() { + activeSwitch.checked = false + textTextField.text = "" + runtimeSpinBox.value = 0 + colorComboBox.currentIndex = 0 + alignmentComboBox.currentIndex = 0 + scrollSwitch.checked = false + scrollCountSpinBox.value = 0 + } + } +} diff --git a/OmobiDisplayApp/ressources/qml/main.qml b/OmobiDisplayApp/ressources/qml/main.qml index 205af20..4a92d66 100644 --- a/OmobiDisplayApp/ressources/qml/main.qml +++ b/OmobiDisplayApp/ressources/qml/main.qml @@ -47,10 +47,12 @@ ApplicationWindow { property Component currentComponent onCurrentComponentChanged: { - if(currentComponent != currentItem) - mainStack.replace(currentComponent) + //if(currentComponent != currentItem) + //mainStack.replace(currentComponent) } + initialItem: connectedPageComp + Component { id: connectPageComp ConnectPage { diff --git a/OmobiDisplayApp/ressources/qml/qml.qrc b/OmobiDisplayApp/ressources/qml/qml.qrc index 4fd83c3..e89dc78 100644 --- a/OmobiDisplayApp/ressources/qml/qml.qrc +++ b/OmobiDisplayApp/ressources/qml/qml.qrc @@ -3,5 +3,8 @@ main.qml ConnectPage.qml ConnectedPage.qml + DisplayTextDelegate.qml + CollapsableItemDelegate.qml + DisplayTextModelListView.qml