MainWindow: use new PowerStatusLED and a combobox for power

- Set power with combobox
- Feedback with PowerStatusLED
- Make connections inside MainWindow::setupConnections()
This commit is contained in:
Filippo Gentile 2023-04-11 18:41:55 +02:00
parent e30b9c6937
commit 33048e5bca
7 changed files with 250 additions and 158 deletions

View File

@ -24,6 +24,9 @@ set(PROJECT_SOURCES
z21server.h
z21server_constants.h
widgets/powerstatusled.h
widgets/powerstatusled.cpp
arduino_compat/WProgram.h
arduino_compat/EEPROM.h
arduino_compat/arduinocompat.h

View File

@ -4,12 +4,6 @@
#include "z21server.h"
//TODO: move to common utils header
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
@ -17,23 +11,7 @@ int main(int argc, char *argv[])
w.show();
Z21Server server;
QObject::connect(&server, &Z21Server::powerStateChanged,
&w, &MainWindow::setPowerStateLed);
QObject::connect(&w, &MainWindow::setShortCircuit,
&server, [&server]()
{
server.setPower(Z21::PowerState::ShortCircuit);
});
QObject::connect(&w, &MainWindow::s88_state,
&server, [&server](int module, int port, bool value)
{
uint8_t state = server.getS88State(module);
state = bitWrite(state, port, value);
server.setS88ModuleState(module, state);
});
w.setupConnections(&server);
server.startServer();

View File

@ -1,9 +1,16 @@
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QTimerEvent>
#include "z21server.h"
#include "z21server_constants.h"
#include "widgets/powerstatusled.h"
#include <QComboBox>
//TODO: move to common utils header
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
@ -11,7 +18,25 @@ MainWindow::MainWindow(QWidget *parent)
{
ui->setupUi(this);
connect(ui->shortCircuitBut, &QPushButton::clicked, this, &MainWindow::setShortCircuit);
m_powerStatusLed = new PowerStatusLED(this);
m_powerCombo = new QComboBox(this);
m_powerCombo->addItem(Z21::getPowerStateName(Z21::PowerState::Normal),
int(Z21::PowerState::Normal));
m_powerCombo->addItem(Z21::getPowerStateName(Z21::PowerState::EmergencyStop),
int(Z21::PowerState::EmergencyStop));
m_powerCombo->addItem(Z21::getPowerStateName(Z21::PowerState::TrackVoltageOff),
int(Z21::PowerState::TrackVoltageOff));
m_powerCombo->addItem(Z21::getPowerStateName(Z21::PowerState::ShortCircuit),
int(Z21::PowerState::ShortCircuit));
m_powerCombo->addItem(Z21::getPowerStateName(Z21::PowerState::ServiceMode),
int(Z21::PowerState::ServiceMode));
QHBoxLayout *powerLay = new QHBoxLayout;
powerLay->addWidget(m_powerStatusLed);
powerLay->addWidget(m_powerCombo);
ui->verticalLayout->addLayout(powerLay);
connect(ui->s88_first, &QCheckBox::toggled, this, [this](bool val)
{
emit s88_state(0, 0, val);
@ -27,70 +52,41 @@ MainWindow::~MainWindow()
delete ui;
}
void MainWindow::timerEvent(QTimerEvent *e)
void MainWindow::setupConnections(Z21Server *z21)
{
if(e->timerId() == m_blinkTimerId)
{
blinkState = !blinkState;
m_server = z21;
QPixmap pix(QSize(16, 16));
pix.fill(blinkState ? textColor : Qt::transparent);
ui->powerLabelIcon->setPixmap(pix);
}
connect(m_server, &Z21Server::powerStateChanged,
m_powerStatusLed, &PowerStatusLED::setPowerState_slot);
m_powerStatusLed->setPowerState(m_server->getPower());
connect(m_powerCombo, qOverload<int>(&QComboBox::currentIndexChanged),
this, &MainWindow::onPowerComboIndexChanged);
connect(m_server, &Z21Server::powerStateChanged,
this, &MainWindow::onPowerStateChanged);
onPowerStateChanged(int(m_server->getPower()));
connect(this, &MainWindow::s88_state, m_server, [this](int module, int port, bool value) {
uint8_t state = m_server->getS88State(module);
state = bitWrite(state, port, value);
m_server->setS88ModuleState(module, state);
});
connect(m_server, &QObject::destroyed, this, [this](){ m_server = nullptr; });
}
void MainWindow::setPowerStateLed(int state)
void MainWindow::onPowerStateChanged(int state)
{
Z21::PowerState powerState = Z21::PowerState(state);
QString text;
bool blink = false;
switch (powerState)
{
case Z21::PowerState::Normal:
text = tr("Normal");
textColor = Qt::cyan;
break;
case Z21::PowerState::ServiceMode:
text = tr("Service Mode");
textColor = Qt::green;
break;
case Z21::PowerState::EmergencyStop:
text = tr("Emergency Stop");
textColor = Qt::cyan;
blink = true;
break;
case Z21::PowerState::ShortCircuit:
text = tr("Short Circuit");
textColor = Qt::red;
blink = true;
break;
case Z21::PowerState::TrackVoltageOff:
text = tr("Power Off");
textColor = Qt::black;
break;
default:
text = tr("Error");
textColor = Qt::black;
break;
}
ui->powerLabel->setText(text);
QPixmap pix(QSize(16, 16));
pix.fill(textColor);
ui->powerLabelIcon->setPixmap(pix);
blinkState = true;
if(blink && !m_blinkTimerId)
{
m_blinkTimerId = startTimer(1000);
}
else if(!blink && m_blinkTimerId)
{
killTimer(m_blinkTimerId);
m_blinkTimerId = 0;
}
int idx = m_powerCombo->findData(state);
m_powerCombo->setCurrentIndex(idx);
}
void MainWindow::onPowerComboIndexChanged()
{
QVariant val = m_powerCombo->currentData();
Z21::PowerState state = Z21::PowerState(val.toInt());
if(!m_server || state == m_server->getPower())
return;
m_server->setPower(state);
}

View File

@ -7,6 +7,10 @@ QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class Z21Server;
class PowerStatusLED;
class QComboBox;
class MainWindow : public QMainWindow
{
Q_OBJECT
@ -15,20 +19,21 @@ public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void timerEvent(QTimerEvent *e) override;
void setupConnections(Z21Server *z21);
private slots:
void onPowerStateChanged(int state);
void onPowerComboIndexChanged();
signals:
void setShortCircuit();
void s88_state(int module, int port, bool value);
public slots:
void setPowerStateLed(int state);
private:
Ui::MainWindow *ui;
int m_blinkTimerId = 0;
bool blinkState = true;
QColor textColor;
PowerStatusLED *m_powerStatusLed;
QComboBox *m_powerCombo;
Z21Server *m_server = nullptr;
};
#endif // MAINWINDOW_H

View File

@ -15,56 +15,6 @@
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Power:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="powerLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="powerLabelIcon">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="shortCircuitBut">
<property name="text">
<string>Short</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="s88_first">
<property name="text">
@ -79,19 +29,6 @@
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">

136
widgets/powerstatusled.cpp Normal file
View File

@ -0,0 +1,136 @@
#include "powerstatusled.h"
#include <QTimerEvent>
#include <QPaintEvent>
#include <QPainter>
QRgb getZ21PowerStateColor(Z21::PowerState state)
{
switch (state)
{
case Z21::PowerState::Normal:
case Z21::PowerState::EmergencyStop:
return qRgb( 33, 128, 252);
case Z21::PowerState::TrackVoltageOff:
return qRgb( 0, 0, 0);
case Z21::PowerState::ShortCircuit:
return qRgb(251, 42, 29);
case Z21::PowerState::ServiceMode:
return qRgb(125, 248, 108);
default:
break;
}
return qRgb(128, 128, 128); //Gray for Unknown value
}
PowerStatusLED::PowerStatusLED(QWidget *parent) :
QWidget{parent}
{
setMinimumSize(50, 100);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
}
PowerStatusLED::~PowerStatusLED()
{
stopBlinkTimer();
}
QSize PowerStatusLED::sizeHint() const
{
return QSize(50, 100);
}
Z21::PowerState PowerStatusLED::powerState() const
{
return m_powerState;
}
void PowerStatusLED::setPowerState(Z21::PowerState newPowerState)
{
m_powerState = newPowerState;
switch (m_powerState)
{
case Z21::PowerState::EmergencyStop:
case Z21::PowerState::ShortCircuit:
startBlinkTimer();
break;
default:
stopBlinkTimer();
break;
}
update();
}
void PowerStatusLED::setPowerState_slot(int state)
{
setPowerState(Z21::PowerState(state));
}
void PowerStatusLED::timerEvent(QTimerEvent *e)
{
if(e->timerId() == m_blinkTimerId)
{
m_blinkState = !m_blinkState;
update();
}
}
void PowerStatusLED::paintEvent(QPaintEvent *e)
{
QPainter painter(this);
//White background
painter.fillRect(e->rect(), Qt::white);
QRectF ledRect = rect();
ledRect.setRight(qMin(ledRect.height(), ledRect.center().x()));
QRectF textRect = rect();
textRect.setLeft(ledRect.right());
if(m_blinkState)
{
//Draw LED circe
QColor color(getZ21PowerStateColor(m_powerState));
painter.setBrush(color);
qreal radius = qMin(ledRect.width(), ledRect.height()) / 2 * 0.9;
painter.drawEllipse(ledRect.center(), radius, radius);
}
painter.setBrush(Qt::NoBrush);
const QString label = Z21::getPowerStateName(m_powerState);
QTextOption opt;
opt.setAlignment(Qt::AlignCenter);
opt.setWrapMode(QTextOption::WordWrap);
QFont f;
f.setBold(true);
f.setPointSizeF(textRect.height() / 5);
painter.setFont(f);
painter.drawText(textRect, label, opt);
}
void PowerStatusLED::startBlinkTimer()
{
if(m_blinkTimerId)
return;
m_blinkTimerId = startTimer(1000, Qt::CoarseTimer);
m_blinkState = true;
}
void PowerStatusLED::stopBlinkTimer()
{
if(m_blinkTimerId)
{
killTimer(m_blinkTimerId);
m_blinkTimerId = 0;
m_blinkState = true;
}
}

37
widgets/powerstatusled.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef POWERSTATUSLED_H
#define POWERSTATUSLED_H
#include <QWidget>
#include "../z21server_constants.h"
class PowerStatusLED : public QWidget
{
Q_OBJECT
public:
explicit PowerStatusLED(QWidget *parent = nullptr);
~PowerStatusLED();
QSize sizeHint() const override;
Z21::PowerState powerState() const;
void setPowerState(Z21::PowerState newPowerState);
public slots:
void setPowerState_slot(int state);
protected:
void timerEvent(QTimerEvent *e) override;
void paintEvent(QPaintEvent *e) override;
private:
void startBlinkTimer();
void stopBlinkTimer();
private:
int m_blinkTimerId = 0;
bool m_blinkState = true;
Z21::PowerState m_powerState = Z21::PowerState::TrackVoltageOff;
};
#endif // POWERSTATUSLED_H