- finished implementing protocol
- added Initializing and Loading states - added color picker
This commit is contained in:
parent
6fbae42867
commit
ce6d436c85
13 changed files with 518 additions and 116 deletions
|
@ -4,12 +4,17 @@ OmobiDisplayBackend::OmobiDisplayBackend(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
this->ble = new QBluetoothLeUart();
|
this->ble = new QBluetoothLeUart();
|
||||||
this->displayTextModel = new OmobiDisplayTextModel(this);
|
this->displayTextModel = new OmobiDisplayTextModel(this);
|
||||||
|
this->textSetsBuffer.clear();
|
||||||
|
this->displayBrightness = -1;
|
||||||
|
this->waitingCommands = 0;
|
||||||
|
|
||||||
connect(this->ble, &QBluetoothLeUart::stateChanged, this, &OmobiDisplayBackend::handleBluetoothStateChange);
|
connect(this->ble, &QBluetoothLeUart::stateChanged, this, &OmobiDisplayBackend::handleBluetoothStateChange);
|
||||||
connect(this->ble, &QBluetoothLeUart::foundNewDevice, this, &OmobiDisplayBackend::handleFoundNewDevice);
|
connect(this->ble, &QBluetoothLeUart::foundNewDevice, this, &OmobiDisplayBackend::handleFoundNewDevice);
|
||||||
connect(this->ble, &QBluetoothLeUart::dataReceived, this, &OmobiDisplayBackend::DataHandler);
|
connect(this->ble, &QBluetoothLeUart::dataReceived, this, &OmobiDisplayBackend::handleBluetoothDataReceived);
|
||||||
connect(this->ble, &QBluetoothLeUart::connectedToDevice, this, &OmobiDisplayBackend::handleBluetoothDeviceConected);
|
connect(this->ble, &QBluetoothLeUart::connectedToDevice, this, &OmobiDisplayBackend::handleBluetoothDeviceConected);
|
||||||
connect(this->displayTextModel, &OmobiDisplayTextModel::dataChanged, this, &OmobiDisplayBackend::handleDisplayTextModelDataChanged);
|
connect(this->displayTextModel, &OmobiDisplayTextModel::dataChanged, this, &OmobiDisplayBackend::handleDisplayTextModelDataChanged);
|
||||||
|
connect(this->displayTextModel, &OmobiDisplayTextModel::rowsInserted, this, &OmobiDisplayBackend::handleDisplayTextModelRowsInserted);
|
||||||
|
connect(this->displayTextModel, &OmobiDisplayTextModel::rowsRemoved, this, &OmobiDisplayBackend::handleDisplayTextModelRowsRemoved);
|
||||||
|
|
||||||
this->setState(Idle);
|
this->setState(Idle);
|
||||||
this->ble->startScanningForDevices();
|
this->ble->startScanningForDevices();
|
||||||
|
@ -54,96 +59,145 @@ void OmobiDisplayBackend::handleBluetoothStateChange(QBluetoothLeUart::Bluetooth
|
||||||
}
|
}
|
||||||
|
|
||||||
void OmobiDisplayBackend::handleBluetoothDeviceConected() {
|
void OmobiDisplayBackend::handleBluetoothDeviceConected() {
|
||||||
this->ble->sendData("GET_TEXTS");
|
this->setState(Initing);
|
||||||
this->ble->sendData("GET_BRIGHTNESS");
|
|
||||||
|
|
||||||
// get the existing model data!
|
// tell display to send over existing model data
|
||||||
// TODO: implement some communication!
|
this->sendBluetoothCommand(GetAllTextSetsCommand);
|
||||||
|
this->sendBluetoothCommand(GetDisplayBrightnessCommand);
|
||||||
QString currentDisplayText = "[[],[]]";
|
|
||||||
|
|
||||||
this->setState(Connected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OmobiDisplayBackend::handleFoundNewDevice(QBluetoothLeUartDevice* device) {
|
void OmobiDisplayBackend::handleFoundNewDevice(QBluetoothLeUartDevice* device) {
|
||||||
qDebug() << "Found a device: name: " << device->getName() << " address: " << device->getAddress();
|
qDebug() << "Found a device: name: " << device->getName() << " address: " << device->getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OmobiDisplayBackend::DataHandler(QString s){
|
void OmobiDisplayBackend::handleDisplayTextModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) {
|
||||||
qDebug() << "New data: " << s;
|
|
||||||
if(s.startsWith("GET_TEXTS:")) {
|
qDebug() << "Data changed: topLeft: " << topLeft << " bottomRight: " << bottomRight << " roles: " << roles;
|
||||||
|
|
||||||
|
for(int role : roles)
|
||||||
|
this->updateDisplayTextSetParameter(topLeft.row(), role);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OmobiDisplayBackend::handleDisplayTextModelRowsInserted(const QModelIndex &parent, int first, int last) {
|
||||||
|
qDebug() << "Rows inserted: parent: " << parent << " first: " << first << " last " << last;
|
||||||
|
for(int i = 0; i < OmobiDisplayTextModel::OmobiDisplayTextModelRoleCount; i++) {
|
||||||
|
this->updateDisplayTextSetParameter(first, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OmobiDisplayBackend::handleDisplayTextModelRowsRemoved(const QModelIndex &parent, int first, int last) {
|
||||||
|
qDebug() << "Rows removed: parent: " << parent << " first: " << first << " last " << last;
|
||||||
|
// Setting Text to "" will delete the item
|
||||||
|
this->updateDisplayTextSetParameter(first, OmobiDisplayTextModel::TextRole, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void OmobiDisplayBackend::sendBluetoothCommand(OmobiDisplayCommand command, QVariant data) {
|
||||||
|
QVariantMap commandMap = {
|
||||||
|
{"header", command},
|
||||||
|
{"data", data}
|
||||||
|
};
|
||||||
|
|
||||||
|
QJsonDocument doc = QJsonDocument::fromVariant(commandMap);
|
||||||
|
|
||||||
|
qDebug() << "Sending command: \n" << qPrintable(doc.toJson(QJsonDocument::Indented));
|
||||||
|
|
||||||
|
this->waitingCommands ++;
|
||||||
|
|
||||||
|
if(this->state == Connected)
|
||||||
|
this->setState(Loading);
|
||||||
|
|
||||||
|
this->ble->sendData(doc.toJson(QJsonDocument::Compact));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OmobiDisplayBackend::handleBluetoothDataReceived(QString s){
|
||||||
|
qDebug() << "New data: \n" << qPrintable(s);
|
||||||
|
|
||||||
QJsonParseError parseError;
|
QJsonParseError parseError;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(s.replace("GET_TEXTS:", "").toUtf8(), &parseError);
|
QJsonDocument doc = QJsonDocument::fromJson(s.toUtf8(), &parseError);
|
||||||
|
|
||||||
if(parseError.error != QJsonParseError::NoError)
|
if(parseError.error != QJsonParseError::NoError)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QList<QMap<int, QVariant>> texts;
|
OmobiDisplayCommand header = OmobiDisplayCommand(doc.toVariant().toMap()["header"].toInt());
|
||||||
|
QVariantMap data = doc.toVariant().toMap()["data"].toMap();
|
||||||
|
OmobiDisplayStatusCode status = OmobiDisplayStatusCode(doc.toVariant().toMap()["status"].toInt());
|
||||||
|
|
||||||
for(QVariant textMap : doc.toVariant().toList()) {
|
switch (header) {
|
||||||
QMap<int, QVariant> text;
|
case GetAllTextSetsCommand: {
|
||||||
|
// indicates that all existing txt sets have been sent over after GetAllTextSetsCommand was called
|
||||||
|
if(status != Success)
|
||||||
|
// TODO: handle error
|
||||||
|
break;
|
||||||
|
|
||||||
static const QMap<QString, int> keyTranslations {
|
this->displayTextModel->maximumTextLength = data["maximumTextLength"].toInt();
|
||||||
{ "text", OmobiDisplayTextModel::TextRole },
|
this->displayTextModel->maximumTextSets = data["maximumTextSets"].toInt();
|
||||||
{ "active", OmobiDisplayTextModel::ActiveRole },
|
|
||||||
{ "runtime", OmobiDisplayTextModel::RuntimeRole },
|
this->displayTextModel->setTexts(this->textSetsBuffer);
|
||||||
{ "color", OmobiDisplayTextModel::ColorRole },
|
this->textSetsBuffer.clear();
|
||||||
{ "alignment", OmobiDisplayTextModel::AlignmentRole },
|
|
||||||
{ "scroll", OmobiDisplayTextModel::ScrollRole },
|
this->refreshLoadingState();
|
||||||
{ "scrollSpeed", OmobiDisplayTextModel::ScrollSpeedRole },
|
|
||||||
{ "scrollCount", OmobiDisplayTextModel::ScrollCountRole },
|
break;
|
||||||
{ "index", OmobiDisplayTextModel::IndexRole }
|
}
|
||||||
|
case GetTextSetParameterCommand: {
|
||||||
|
|
||||||
|
int index = data["index"].toInt();
|
||||||
|
|
||||||
|
if(index < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(this->textSetsBuffer.length() <= index)
|
||||||
|
this->textSetsBuffer.append(QMap<int, QVariant>());
|
||||||
|
|
||||||
|
int parameter = data["parameter"].toInt();
|
||||||
|
|
||||||
|
if(!this->textSetsBuffer[index].contains(parameter))
|
||||||
|
this->textSetsBuffer[index].insert(parameter, QVariant());
|
||||||
|
|
||||||
|
this->textSetsBuffer[index][parameter] = data["value"].toString();
|
||||||
|
|
||||||
|
if(this->state != Initing)
|
||||||
|
this->refreshLoadingState();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GetDisplayBrightnessCommand: {
|
||||||
|
this->setDisplayBrightness(data["displayBrightness"].toInt());
|
||||||
|
this->refreshLoadingState();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SetTextSetParameterCommand: {
|
||||||
|
// TODO: Error handling
|
||||||
|
this->refreshLoadingState();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SetDisplayBrightnessCommand: {
|
||||||
|
// TODO: Error handling
|
||||||
|
this->refreshLoadingState();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void OmobiDisplayBackend::updateDisplayTextSetParameter(int index, int parameter) {
|
||||||
|
this->updateDisplayTextSetParameter(index, parameter, this->displayTextModel->data(index, parameter).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void OmobiDisplayBackend::updateDisplayTextSetParameter(int index, int parameter, QString value) {
|
||||||
|
if(this->state == Initing)
|
||||||
|
return;
|
||||||
|
qDebug() << "Updating data at index: " << index << " parameter: " << parameter << " and value: " << value;
|
||||||
|
|
||||||
|
QVariantMap dataMap = {
|
||||||
|
{"index", index},
|
||||||
|
{"parameter", parameter},
|
||||||
|
{"value", value}
|
||||||
};
|
};
|
||||||
|
|
||||||
for(QString key : textMap.toMap().keys()) {
|
this->sendBluetoothCommand(SetTextSetParameterCommand, dataMap);
|
||||||
if(keyTranslations.contains(key)) {
|
|
||||||
if(key == "color") {
|
|
||||||
QVariantMap colorMap = textMap.toMap()[key].toMap();
|
|
||||||
QColor color(colorMap["r"].toInt(), colorMap["g"].toInt(), colorMap["b"].toInt());
|
|
||||||
text.insert(keyTranslations[key], color.name());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
text.insert(keyTranslations[key], textMap.toMap()[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
texts.append(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->displayTextModel->setTexts(texts);
|
|
||||||
}
|
|
||||||
else if(s.startsWith("GET_BRIGHTNESS:")) {
|
|
||||||
this->displayBrightness = s.replace("GET_BRIGHTNESS:", "").toInt();
|
|
||||||
emit this->displayBrightnessChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void OmobiDisplayBackend::handleDisplayTextModelDataChanged() {
|
|
||||||
|
|
||||||
QVariantList textList;
|
|
||||||
|
|
||||||
for(QMap<int, QVariant> text : this->displayTextModel->getTexts()) {
|
|
||||||
QVariantHash textMap;
|
|
||||||
|
|
||||||
for(int key : text.keys()) {
|
|
||||||
if(key == OmobiDisplayTextModel::ColorRole) {
|
|
||||||
QColor color = QColor(text[key].toString());
|
|
||||||
color = color.toRgb();
|
|
||||||
QVariantMap colorMap = {{"r", color.red()}, {"g", color.green()}, {"b", color.blue()}};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
textMap.insert(this->displayTextModel->roleNames()[key], text[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
textList.append(textMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonDocument doc = QJsonDocument::fromVariant(textList);
|
|
||||||
|
|
||||||
qDebug() << doc.toJson(QJsonDocument::Indented);
|
|
||||||
|
|
||||||
this->ble->sendData("SET_TEXTS:" + doc.toJson(QJsonDocument::Compact));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QBluetoothLeUart* OmobiDisplayBackend::getBleController() {
|
QBluetoothLeUart* OmobiDisplayBackend::getBleController() {
|
||||||
|
@ -159,6 +213,20 @@ OmobiDisplayBackend::OmobiDisplayAppState OmobiDisplayBackend::getState() {
|
||||||
return this->state;
|
return this->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OmobiDisplayBackend::refreshLoadingState() {
|
||||||
|
if(this->state != Initing && this->state != Loading)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qDebug() << "Refreshing loading state! Waiting: " << this->waitingCommands;
|
||||||
|
|
||||||
|
if(this->waitingCommands <= 1) {
|
||||||
|
this->waitingCommands = 0;
|
||||||
|
this->setState(Connected);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this->waitingCommands--;
|
||||||
|
}
|
||||||
|
|
||||||
void OmobiDisplayBackend::setState(OmobiDisplayAppState state) {
|
void OmobiDisplayBackend::setState(OmobiDisplayAppState state) {
|
||||||
if(state == this->state)
|
if(state == this->state)
|
||||||
return;
|
return;
|
||||||
|
@ -166,6 +234,8 @@ void OmobiDisplayBackend::setState(OmobiDisplayAppState state) {
|
||||||
this->state = state;
|
this->state = state;
|
||||||
emit this->stateChanged();
|
emit this->stateChanged();
|
||||||
|
|
||||||
|
qDebug() << "Now in " << state << " state";
|
||||||
|
|
||||||
if(this->state == Idle)
|
if(this->state == Idle)
|
||||||
this->ble->startScanningForDevices();
|
this->ble->startScanningForDevices();
|
||||||
}
|
}
|
||||||
|
@ -180,7 +250,7 @@ void OmobiDisplayBackend::setDisplayBrightness(int brightness) {
|
||||||
|
|
||||||
this->displayBrightness = brightness;
|
this->displayBrightness = brightness;
|
||||||
|
|
||||||
this->ble->sendData("SET_BRIGHTNESS:" + QString::number(this->displayBrightness));
|
this->sendBluetoothCommand(SetDisplayBrightnessCommand, this->displayBrightness);
|
||||||
|
|
||||||
emit this->displayBrightnessChanged();
|
emit this->displayBrightnessChanged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,24 +23,31 @@ public:
|
||||||
Scanning,
|
Scanning,
|
||||||
ReadyToConnect,
|
ReadyToConnect,
|
||||||
Connecting,
|
Connecting,
|
||||||
Connected
|
Initing,
|
||||||
|
Connected,
|
||||||
|
Loading
|
||||||
};
|
};
|
||||||
Q_ENUM(OmobiDisplayAppState)
|
Q_ENUM(OmobiDisplayAppState)
|
||||||
|
|
||||||
typedef struct text_set_t
|
|
||||||
{
|
|
||||||
const char text[5];
|
|
||||||
uint time_ms;
|
|
||||||
uint color;
|
|
||||||
bool text_scroll;
|
|
||||||
uint text_scroll_pass;
|
|
||||||
bool active;
|
|
||||||
} text_set_t;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum OmobiDisplayCommand {
|
||||||
|
GetAllTextSetsCommand = 10,
|
||||||
|
GetTextSetParameterCommand = 11,
|
||||||
|
GetDisplayBrightnessCommand = 12,
|
||||||
|
SetTextSetParameterCommand = 20,
|
||||||
|
SetDisplayBrightnessCommand = 21
|
||||||
|
};
|
||||||
|
|
||||||
|
enum OmobiDisplayStatusCode {
|
||||||
|
Success = 200,
|
||||||
|
DisplayControllerError = 501
|
||||||
|
};
|
||||||
|
|
||||||
OmobiDisplayAppState state;
|
OmobiDisplayAppState state;
|
||||||
QBluetoothLeUart *ble;
|
QBluetoothLeUart *ble;
|
||||||
OmobiDisplayTextModel* displayTextModel;
|
OmobiDisplayTextModel* displayTextModel;
|
||||||
|
int waitingCommands;
|
||||||
|
QList<QMap<int, QVariant>> textSetsBuffer;
|
||||||
int displayBrightness;
|
int displayBrightness;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -54,11 +61,18 @@ public slots:
|
||||||
private slots:
|
private slots:
|
||||||
void handleBluetoothStateChange(QBluetoothLeUart::BluetoothLeUartState state);
|
void handleBluetoothStateChange(QBluetoothLeUart::BluetoothLeUartState state);
|
||||||
void handleFoundNewDevice(QBluetoothLeUartDevice* device);
|
void handleFoundNewDevice(QBluetoothLeUartDevice* device);
|
||||||
void DataHandler(QString s);
|
|
||||||
void handleBluetoothDeviceConected();
|
void handleBluetoothDeviceConected();
|
||||||
|
|
||||||
void handleDisplayTextModelDataChanged();
|
void handleDisplayTextModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
|
||||||
|
void handleDisplayTextModelRowsInserted(const QModelIndex &parent, int first, int last);
|
||||||
|
void handleDisplayTextModelRowsRemoved(const QModelIndex &parent, int first, int last);
|
||||||
|
|
||||||
|
void sendBluetoothCommand(OmobiDisplayCommand command, QVariant data = QVariant());
|
||||||
|
void handleBluetoothDataReceived(QString s);
|
||||||
|
void updateDisplayTextSetParameter(int index, int parameter);
|
||||||
|
void updateDisplayTextSetParameter(int index, int parameter, QString value);
|
||||||
|
|
||||||
|
void refreshLoadingState();
|
||||||
void setState(OmobiDisplayAppState state);
|
void setState(OmobiDisplayAppState state);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
OmobiDisplayTextModel::OmobiDisplayTextModel(QObject* parent) : QAbstractListModel(parent)
|
OmobiDisplayTextModel::OmobiDisplayTextModel(QObject* parent) : QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
|
this->maximumTextSets = 0;
|
||||||
|
this->maximumTextLength = 0;
|
||||||
|
|
||||||
|
connect(this, &OmobiDisplayTextModel::rowsInserted, this, &OmobiDisplayTextModel::rowCountChanged);
|
||||||
|
connect(this, &OmobiDisplayTextModel::rowsRemoved, this, &OmobiDisplayTextModel::rowCountChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,11 +17,19 @@ int OmobiDisplayTextModel::rowCount(const QModelIndex &) const
|
||||||
|
|
||||||
QVariant OmobiDisplayTextModel::data(const QModelIndex &index, int role) const
|
QVariant OmobiDisplayTextModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (index.row() < rowCount()) {
|
return this->data(index.row(), role);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant OmobiDisplayTextModel::data(int row, int role) const {
|
||||||
|
if (row < rowCount()) {
|
||||||
|
if(this->texts[row].contains(role)) {
|
||||||
if(role == IndexRole)
|
if(role == IndexRole)
|
||||||
return index.row();
|
return row;
|
||||||
else if(this->texts[index.row()].contains(role))
|
|
||||||
return this->texts[index.row()][role];
|
QVariant value = this->texts[row][role];
|
||||||
|
value.convert(this->roleDataTypes[OmobiDisplayTextModelRole(role)]);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
@ -48,10 +61,13 @@ void OmobiDisplayTextModel::append(
|
||||||
unsigned int scrollCount
|
unsigned int scrollCount
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// the current Maximum is 5
|
// check length maximums
|
||||||
if(this->texts.length() >= 5)
|
if(this->texts.length() >= this->maximumTextSets)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if(text.length() > this->maximumTextLength)
|
||||||
|
text = text.left(this->maximumTextLength);
|
||||||
|
|
||||||
QMap<int, QVariant> roles = {
|
QMap<int, QVariant> roles = {
|
||||||
{ TextRole, text },
|
{ TextRole, text },
|
||||||
{ ActiveRole, active },
|
{ ActiveRole, active },
|
||||||
|
@ -80,11 +96,16 @@ bool OmobiDisplayTextModel::setData(const QModelIndex &index, const QVariant &va
|
||||||
if(this->texts[index.row()][role] == value)
|
if(this->texts[index.row()][role] == value)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if(role == TextRole && value.toString().length() > this->maximumTextLength)
|
||||||
|
this->texts[index.row()][role] = value.toString().left(this->maximumTextLength);
|
||||||
|
else
|
||||||
this->texts[index.row()][role] = value;
|
this->texts[index.row()][role] = value;
|
||||||
|
|
||||||
emit dataChanged(index, index);
|
qDebug() << "setting index: " << index << " role: " << role << " value " << value;
|
||||||
|
|
||||||
return QAbstractItemModel::setData(index, value, role);
|
emit dataChanged(index, index, QVector<int>({role}));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OmobiDisplayTextModel::remove(int row)
|
void OmobiDisplayTextModel::remove(int row)
|
||||||
|
@ -117,3 +138,15 @@ bool OmobiDisplayTextModel::setTexts(QList<QMap<int, QVariant>> texts) {
|
||||||
QList<QMap<int, QVariant>> OmobiDisplayTextModel::getTexts() {
|
QList<QMap<int, QVariant>> OmobiDisplayTextModel::getTexts() {
|
||||||
return this->texts;
|
return this->texts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMap<int, QVariant> OmobiDisplayTextModel::getText(const QModelIndex &index) {
|
||||||
|
if (index.row() < this->rowCount())
|
||||||
|
return this->texts[index.row()];
|
||||||
|
|
||||||
|
return QMap<int, QVariant>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int OmobiDisplayTextModel::getMaximumTextSets() {
|
||||||
|
return this->maximumTextSets;
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
class OmobiDisplayTextModel : public QAbstractListModel
|
class OmobiDisplayTextModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
|
||||||
|
Q_PROPERTY(int maximumTextSets READ getMaximumTextSets NOTIFY maximumTextSetsChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
friend class OmobiDisplayBackend;
|
friend class OmobiDisplayBackend;
|
||||||
|
|
||||||
|
@ -21,21 +24,21 @@ public:
|
||||||
ScrollRole,
|
ScrollRole,
|
||||||
ScrollSpeedRole,
|
ScrollSpeedRole,
|
||||||
ScrollCountRole,
|
ScrollCountRole,
|
||||||
IndexRole
|
IndexRole,
|
||||||
|
OmobiDisplayTextModelRoleCount
|
||||||
};
|
};
|
||||||
Q_ENUM(OmobiDisplayTextModelRole)
|
Q_ENUM(OmobiDisplayTextModelRole)
|
||||||
|
|
||||||
|
enum OmobiDisplayTextAlignment
|
||||||
enum text_align_t
|
|
||||||
{
|
{
|
||||||
AlignLeft,
|
AlignLeft,
|
||||||
AlignCenter,
|
AlignCenter,
|
||||||
AlignRignt
|
AlignRignt
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Q_INVOKABLE int rowCount(const QModelIndex & = QModelIndex()) const;
|
||||||
int rowCount(const QModelIndex & = QModelIndex()) const;
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||||
|
QVariant data(int i, int role = Qt::DisplayRole) const;
|
||||||
QHash<int, QByteArray> roleNames() const;
|
QHash<int, QByteArray> roleNames() const;
|
||||||
|
|
||||||
Q_INVOKABLE void append(
|
Q_INVOKABLE void append(
|
||||||
|
@ -54,16 +57,38 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void remove(int row);
|
Q_INVOKABLE void remove(int row);
|
||||||
|
|
||||||
|
Q_INVOKABLE int getMaximumTextSets();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
OmobiDisplayTextModel(QObject* parent = nullptr);
|
OmobiDisplayTextModel(QObject* parent = nullptr);
|
||||||
|
|
||||||
bool setTexts(QList<QMap<int, QVariant>> json);
|
bool setTexts(QList<QMap<int, QVariant>> json);
|
||||||
QList<QMap<int, QVariant>> getTexts();
|
QList<QMap<int, QVariant>> getTexts();
|
||||||
|
QMap<int, QVariant> getText(const QModelIndex &index);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<QMap<int, QVariant>> texts;
|
QList<QMap<int, QVariant>> texts;
|
||||||
|
|
||||||
|
int maximumTextSets;
|
||||||
|
int maximumTextLength;
|
||||||
|
|
||||||
|
const QMap<OmobiDisplayTextModelRole, QVariant::Type> roleDataTypes = {
|
||||||
|
{TextRole, QVariant::String},
|
||||||
|
{ActiveRole, QVariant::Bool},
|
||||||
|
{RuntimeRole, QVariant::Int},
|
||||||
|
{ColorRole, QVariant::String},
|
||||||
|
{AlignmentRole, QVariant::Int},
|
||||||
|
{ScrollRole, QVariant::Bool},
|
||||||
|
{ScrollSpeedRole, QVariant::Int},
|
||||||
|
{ScrollCountRole, QVariant::Int},
|
||||||
|
{IndexRole, QVariant::Int}
|
||||||
|
};
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void rowCountChanged();
|
||||||
|
void maximumTextSetsChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // OMOBIDISPLAYTEXTMODEL_H
|
#endif // OMOBIDISPLAYTEXTMODEL_H
|
||||||
|
|
92
OmobiDisplayApp/ressources/qml/ColorPicker.qml
Normal file
92
OmobiDisplayApp/ressources/qml/ColorPicker.qml
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 2.0
|
||||||
|
import QtQuick.Layouts 1.0
|
||||||
|
import QtQuick.Controls.Material 2.0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
property string value: ""
|
||||||
|
property string currentColor: rgbToHex(redSlider.value, greenSlider.value, blueSlider.value)
|
||||||
|
property bool isDarkColor: control.checkIsDarkColor(value)
|
||||||
|
|
||||||
|
implicitHeight: width
|
||||||
|
|
||||||
|
onValueChanged: {
|
||||||
|
var rgb = hexToRgb(value)
|
||||||
|
|
||||||
|
redSlider.value = rgb.r
|
||||||
|
greenSlider.value = rgb.g
|
||||||
|
blueSlider.value = rgb.b
|
||||||
|
}
|
||||||
|
|
||||||
|
onCurrentColorChanged: {
|
||||||
|
value = currentColor
|
||||||
|
}
|
||||||
|
|
||||||
|
function rgbToHex(r, g, b) {
|
||||||
|
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hexToRgb(hex) {
|
||||||
|
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||||
|
return result ? {
|
||||||
|
r: parseInt(result[1], 16),
|
||||||
|
g: parseInt(result[2], 16),
|
||||||
|
b: parseInt(result[3], 16)
|
||||||
|
} : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkIsDarkColor(color) {
|
||||||
|
var temp = Qt.darker(color, 1) //Force conversion to color QML type object
|
||||||
|
var a = 1 - ( 0.299 * temp.r + 0.587 * temp.g + 0.114 * temp.b);
|
||||||
|
return temp.a > 0 && a >= 0.3
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: parent.height * 0.5
|
||||||
|
color: control.currentColor
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider {
|
||||||
|
id: redSlider
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
from: 0
|
||||||
|
to: 255
|
||||||
|
stepSize: 1
|
||||||
|
|
||||||
|
Material.accent: Material.Red
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider {
|
||||||
|
id: greenSlider
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
from: 0
|
||||||
|
to: 255
|
||||||
|
stepSize: 1
|
||||||
|
|
||||||
|
Material.accent: Material.Green
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider {
|
||||||
|
id: blueSlider
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
from: 0
|
||||||
|
to: 255
|
||||||
|
stepSize: 1
|
||||||
|
|
||||||
|
Material.accent: Material.Blue
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
89
OmobiDisplayApp/ressources/qml/ColorPickerDelegate.qml
Normal file
89
OmobiDisplayApp/ressources/qml/ColorPickerDelegate.qml
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 2.9
|
||||||
|
import QtQuick.Controls.Material 2.0
|
||||||
|
|
||||||
|
ItemDelegate {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
property string value: ""
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
colorPicker.value = value
|
||||||
|
textEditDialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors {
|
||||||
|
right: nextPageIconText.left
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
rightMargin: control.padding
|
||||||
|
}
|
||||||
|
|
||||||
|
width: parent.width * 0.15
|
||||||
|
height: parent.height * 0.6
|
||||||
|
radius: height * 0.1
|
||||||
|
|
||||||
|
color: control.value === "" ? "transparent":control.value
|
||||||
|
|
||||||
|
border.width: 2
|
||||||
|
border.color: control.value === "" ? "lightgrey":control.value
|
||||||
|
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: parent.height * 0.1
|
||||||
|
|
||||||
|
font.pixelSize: height * 0.5
|
||||||
|
fontSizeMode: Text.Fit
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
|
||||||
|
color: colorPicker.isDarkColor && control.value !== "" ? "white":"black"
|
||||||
|
|
||||||
|
text: value === "" ? "Not set": value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: nextPageIconText
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
rightMargin: control.padding
|
||||||
|
}
|
||||||
|
|
||||||
|
font.pixelSize: parent.height * 0.5
|
||||||
|
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
|
||||||
|
text: ">"
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: textEditDialog
|
||||||
|
parent: Overlay.overlay
|
||||||
|
|
||||||
|
x: (parent.width - width) / 2
|
||||||
|
y: (parent.height - height) / 2
|
||||||
|
|
||||||
|
width: parent.width * 0.9
|
||||||
|
|
||||||
|
Material.theme: control.Material.theme
|
||||||
|
Material.accent: control.Material.accent
|
||||||
|
modal: true
|
||||||
|
|
||||||
|
title: control.text
|
||||||
|
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
|
||||||
|
contentItem: ColorPicker {
|
||||||
|
id: colorPicker
|
||||||
|
value: control.value
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
control.value = colorPicker.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,6 +77,10 @@ ItemDelegate {
|
||||||
checked: index === control.currentIndex
|
checked: index === control.currentIndex
|
||||||
ButtonGroup.group: buttonGroup
|
ButtonGroup.group: buttonGroup
|
||||||
text: modelData
|
text: modelData
|
||||||
|
onClicked: {
|
||||||
|
control.currentIndex = index
|
||||||
|
textEditDialog.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,10 +89,6 @@ ItemDelegate {
|
||||||
listView.model = control.model
|
listView.model = control.model
|
||||||
}
|
}
|
||||||
|
|
||||||
onAccepted: {
|
|
||||||
control.currentText = buttonGroup.checkedButton.text
|
|
||||||
}
|
|
||||||
|
|
||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
id: buttonGroup
|
id: buttonGroup
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,6 +166,20 @@ Page {
|
||||||
statusText: "trying to connect..."
|
statusText: "trying to connect..."
|
||||||
working: true
|
working: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: OmobiDisplayBackend.Initing
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: availableDevicesListView
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
statusText: "loading data..."
|
||||||
|
working: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,4 +64,50 @@ Page {
|
||||||
clip: true
|
clip: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: loadingDialog
|
||||||
|
|
||||||
|
property bool shouldBeOpen: false
|
||||||
|
|
||||||
|
onShouldBeOpenChanged: {
|
||||||
|
if(shouldBeOpen)
|
||||||
|
open()
|
||||||
|
else
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
parent: Overlay.overlay
|
||||||
|
|
||||||
|
x: (parent.width - width) / 2
|
||||||
|
y: (parent.height - height) / 2
|
||||||
|
|
||||||
|
closePolicy: Popup.NoAutoClose
|
||||||
|
modal: true
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
BusyIndicator {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.alignment: Layout.Center
|
||||||
|
text: qsTr("loading...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: OmobiDisplayBackend.Connected
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: OmobiDisplayBackend.Loading
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: loadingDialog
|
||||||
|
shouldBeOpen: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,8 @@ ListView {
|
||||||
height: implicitHeight * 1.3
|
height: implicitHeight * 1.3
|
||||||
width: height
|
width: height
|
||||||
|
|
||||||
|
enabled: control.model.rowCount < control.model.maximumTextSets
|
||||||
|
|
||||||
Material.background: Material.accent
|
Material.background: Material.accent
|
||||||
|
|
||||||
text: ""
|
text: ""
|
||||||
|
|
|
@ -28,8 +28,8 @@ Dialog {
|
||||||
editingModel.active = activeSwitch.checked
|
editingModel.active = activeSwitch.checked
|
||||||
editingModel.text = textTextField.value
|
editingModel.text = textTextField.value
|
||||||
editingModel.runtime = runtimeSpinBox.value
|
editingModel.runtime = runtimeSpinBox.value
|
||||||
editingModel.color = colorComboBox.currentText
|
editingModel.color = colorColorPicker.value
|
||||||
editingModel.alignment = alignmentComboBox.currentText
|
editingModel.alignment = alignmentComboBox.currentIndex
|
||||||
editingModel.scroll = scrollSwitch.checked
|
editingModel.scroll = scrollSwitch.checked
|
||||||
editingModel.scrollSpeed = scrollSpeedSpinBox.value
|
editingModel.scrollSpeed = scrollSpeedSpinBox.value
|
||||||
editingModel.scrollCount = scrollCountSpinBox.value
|
editingModel.scrollCount = scrollCountSpinBox.value
|
||||||
|
@ -38,7 +38,7 @@ Dialog {
|
||||||
editingModel.append(textTextField.value,
|
editingModel.append(textTextField.value,
|
||||||
activeSwitch.checked,
|
activeSwitch.checked,
|
||||||
runtimeSpinBox.value,
|
runtimeSpinBox.value,
|
||||||
colorComboBox.currentText,
|
colorColorPicker.value,
|
||||||
alignmentComboBox.currentText,
|
alignmentComboBox.currentText,
|
||||||
scrollSwitch.checked,
|
scrollSwitch.checked,
|
||||||
scrollSpeedSpinBox.value,
|
scrollSpeedSpinBox.value,
|
||||||
|
@ -88,10 +88,9 @@ Dialog {
|
||||||
text: qsTr("Runtime (in s)")
|
text: qsTr("Runtime (in s)")
|
||||||
}
|
}
|
||||||
|
|
||||||
ComboBoxDelegate {
|
ColorPickerDelegate {
|
||||||
id: colorComboBox
|
id: colorColorPicker
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
model: ["white", "blue", "red", "green"]
|
|
||||||
text: qsTr("Color")
|
text: qsTr("Color")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,8 +162,8 @@ Dialog {
|
||||||
activeSwitch.checked = editingModel.active
|
activeSwitch.checked = editingModel.active
|
||||||
textTextField.value = editingModel.text
|
textTextField.value = editingModel.text
|
||||||
runtimeSpinBox.value = editingModel.runtime
|
runtimeSpinBox.value = editingModel.runtime
|
||||||
colorComboBox.currentIndex = colorComboBox.model.indexOf(editingModel.color)
|
colorColorPicker.value = editingModel.color
|
||||||
alignmentComboBox.currentIndex = alignmentComboBox.model.indexOf(editingModel.alignment)
|
alignmentComboBox.currentIndex = editingModel.alignment
|
||||||
scrollSwitch.checked = editingModel.scroll
|
scrollSwitch.checked = editingModel.scroll
|
||||||
scrollSpeedSpinBox.value = editingModel.scrollSpeed
|
scrollSpeedSpinBox.value = editingModel.scrollSpeed
|
||||||
scrollCountSpinBox.value = editingModel.scrollCount
|
scrollCountSpinBox.value = editingModel.scrollCount
|
||||||
|
@ -183,7 +182,7 @@ Dialog {
|
||||||
activeSwitch.checked = true
|
activeSwitch.checked = true
|
||||||
textTextField.value = ""
|
textTextField.value = ""
|
||||||
runtimeSpinBox.value = 0
|
runtimeSpinBox.value = 0
|
||||||
colorComboBox.currentIndex = 0
|
colorColorPicker.value = ""
|
||||||
alignmentComboBox.currentIndex = 0
|
alignmentComboBox.currentIndex = 0
|
||||||
scrollSwitch.checked = false
|
scrollSwitch.checked = false
|
||||||
scrollSpeedSpinBox.value = 5
|
scrollSpeedSpinBox.value = 5
|
||||||
|
|
|
@ -54,7 +54,7 @@ ApplicationWindow {
|
||||||
mainStack.replace(currentComponent)
|
mainStack.replace(currentComponent)
|
||||||
}
|
}
|
||||||
|
|
||||||
//initialItem: connectedPageComp
|
initialItem: connectedPageComp
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: connectPageComp
|
id: connectPageComp
|
||||||
|
@ -104,12 +104,28 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
State {
|
||||||
|
name: OmobiDisplayBackend.Initing
|
||||||
|
PropertyChanges {
|
||||||
|
target: mainStack
|
||||||
|
currentComponent: connectPageComp
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
State {
|
State {
|
||||||
name: OmobiDisplayBackend.Connected
|
name: OmobiDisplayBackend.Connected
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: mainStack
|
target: mainStack
|
||||||
currentComponent: connectedPageComp
|
currentComponent: connectedPageComp
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
State {
|
||||||
|
name: OmobiDisplayBackend.Loading
|
||||||
|
PropertyChanges {
|
||||||
|
target: mainStack
|
||||||
|
currentComponent: connectedPageComp
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,5 +11,7 @@
|
||||||
<file>NextPageDelegate.qml</file>
|
<file>NextPageDelegate.qml</file>
|
||||||
<file>SpinBoxDelegate.qml</file>
|
<file>SpinBoxDelegate.qml</file>
|
||||||
<file>ComboBoxDelegate.qml</file>
|
<file>ComboBoxDelegate.qml</file>
|
||||||
|
<file>ColorPickerDelegate.qml</file>
|
||||||
|
<file>ColorPicker.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
Loading…
Reference in a new issue