mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-05 13:32:05 +08:00
OffroadHome: separate the update and alert buttons (#21326)
* refactor * better loop * remove stretch * only refreshed by timer * fix wrong bg color * descending sort alert labels by severity * remove duplicate stylesheet * Update selfdrive/ui/qt/widgets/offroad_alerts.cc * rebase master * qt best pratice * split offroadAlerts * only show first time * short variable name * space * don't do refresh in every showEvent * Revert "don't do refresh in every showEvent" This reverts commit 2b0032fb0af7138e9d9df1ad052c589fd96d2e05. * cleanup rename name to key cleanup * add stretch back * hide alert widgets when not alerts * rebase master * fix flash on startup Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com> old-commit-hash: e836ed7f6e9fd53f386b8dd07bcb0aa39b8f571f
This commit is contained in:
+46
-60
@@ -6,9 +6,6 @@
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "selfdrive/common/params.h"
|
||||
#include "selfdrive/common/swaglog.h"
|
||||
#include "selfdrive/common/timing.h"
|
||||
#include "selfdrive/common/util.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/widgets/drive_stats.h"
|
||||
#include "selfdrive/ui/qt/widgets/setup.h"
|
||||
@@ -94,18 +91,24 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
|
||||
|
||||
// top header
|
||||
QHBoxLayout* header_layout = new QHBoxLayout();
|
||||
header_layout->setSpacing(16);
|
||||
|
||||
date = new QLabel();
|
||||
header_layout->addWidget(date, 0, Qt::AlignHCenter | Qt::AlignLeft);
|
||||
header_layout->addWidget(date, 1, Qt::AlignHCenter | Qt::AlignLeft);
|
||||
|
||||
alert_notification = new QPushButton();
|
||||
alert_notification->setObjectName("alert_notification");
|
||||
alert_notification->setVisible(false);
|
||||
QObject::connect(alert_notification, &QPushButton::released, this, &OffroadHome::openAlerts);
|
||||
header_layout->addWidget(alert_notification, 0, Qt::AlignHCenter | Qt::AlignRight);
|
||||
update_notif = new QPushButton("UPDATE");
|
||||
update_notif->setVisible(false);
|
||||
update_notif->setStyleSheet("background-color: #364DEF;");
|
||||
QObject::connect(update_notif, &QPushButton::released, [=]() { center_layout->setCurrentIndex(1); });
|
||||
header_layout->addWidget(update_notif, 0, Qt::AlignHCenter | Qt::AlignRight);
|
||||
|
||||
QLabel* version = new QLabel(getBrandVersion());
|
||||
header_layout->addWidget(version, 0, Qt::AlignHCenter | Qt::AlignRight);
|
||||
alert_notif = new QPushButton();
|
||||
alert_notif->setVisible(false);
|
||||
alert_notif->setStyleSheet("background-color: #E22C2C;");
|
||||
QObject::connect(alert_notif, &QPushButton::released, [=] { center_layout->setCurrentIndex(2); });
|
||||
header_layout->addWidget(alert_notif, 0, Qt::AlignHCenter | Qt::AlignRight);
|
||||
|
||||
header_layout->addWidget(new QLabel(getBrandVersion()), 0, Qt::AlignHCenter | Qt::AlignRight);
|
||||
|
||||
main_layout->addLayout(header_layout);
|
||||
|
||||
@@ -113,32 +116,29 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
|
||||
main_layout->addSpacing(25);
|
||||
center_layout = new QStackedLayout();
|
||||
|
||||
QHBoxLayout* statsAndSetup = new QHBoxLayout();
|
||||
QWidget* statsAndSetupWidget = new QWidget(this);
|
||||
QHBoxLayout* statsAndSetup = new QHBoxLayout(statsAndSetupWidget);
|
||||
statsAndSetup->setMargin(0);
|
||||
|
||||
DriveStats* drive = new DriveStats;
|
||||
DriveStats* drive = new DriveStats();
|
||||
drive->setFixedSize(800, 800);
|
||||
statsAndSetup->addWidget(drive);
|
||||
|
||||
SetupWidget* setup = new SetupWidget;
|
||||
statsAndSetup->addWidget(setup);
|
||||
|
||||
QWidget* statsAndSetupWidget = new QWidget();
|
||||
statsAndSetupWidget->setLayout(statsAndSetup);
|
||||
statsAndSetup->addWidget(new SetupWidget);
|
||||
|
||||
center_layout->addWidget(statsAndSetupWidget);
|
||||
|
||||
// add update & alerts widgets
|
||||
update_widget = new UpdateAlert();
|
||||
QObject::connect(update_widget, &UpdateAlert::dismiss, [=]() { center_layout->setCurrentIndex(0); });
|
||||
center_layout->addWidget(update_widget);
|
||||
alerts_widget = new OffroadAlert();
|
||||
QObject::connect(alerts_widget, &OffroadAlert::closeAlerts, this, &OffroadHome::closeAlerts);
|
||||
QObject::connect(alerts_widget, &OffroadAlert::dismiss, [=]() { center_layout->setCurrentIndex(0); });
|
||||
center_layout->addWidget(alerts_widget);
|
||||
center_layout->setAlignment(alerts_widget, Qt::AlignCenter);
|
||||
|
||||
main_layout->addLayout(center_layout, 1);
|
||||
|
||||
// set up refresh timer
|
||||
timer = new QTimer(this);
|
||||
QObject::connect(timer, &QTimer::timeout, this, &OffroadHome::refresh);
|
||||
timer->start(10 * 1000);
|
||||
timer->callOnTimeout(this, &OffroadHome::refresh);
|
||||
|
||||
setStyleSheet(R"(
|
||||
* {
|
||||
@@ -147,61 +147,47 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
|
||||
OffroadHome {
|
||||
background-color: black;
|
||||
}
|
||||
#alert_notification {
|
||||
padding: 15px;
|
||||
padding-left: 30px;
|
||||
padding-right: 30px;
|
||||
border: 1px solid;
|
||||
OffroadHome > QPushButton {
|
||||
padding: 15px 30px;
|
||||
border-radius: 5px;
|
||||
font-size: 40px;
|
||||
font-weight: 500;
|
||||
}
|
||||
OffroadHome>QLabel {
|
||||
OffroadHome > QLabel {
|
||||
font-size: 55px;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
void OffroadHome::showEvent(QShowEvent *event) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
void OffroadHome::openAlerts() {
|
||||
center_layout->setCurrentIndex(1);
|
||||
void OffroadHome::showEvent(QShowEvent *event) {
|
||||
timer->start(10 * 1000);
|
||||
}
|
||||
|
||||
void OffroadHome::closeAlerts() {
|
||||
center_layout->setCurrentIndex(0);
|
||||
void OffroadHome::hideEvent(QHideEvent *event) {
|
||||
timer->stop();
|
||||
}
|
||||
|
||||
void OffroadHome::refresh() {
|
||||
bool first_refresh = !date->text().size();
|
||||
if (!isVisible() && !first_refresh) {
|
||||
return;
|
||||
}
|
||||
|
||||
date->setText(QDateTime::currentDateTime().toString("dddd, MMMM d"));
|
||||
|
||||
// update alerts
|
||||
bool updateAvailable = update_widget->refresh();
|
||||
int alerts = alerts_widget->refresh();
|
||||
|
||||
alerts_widget->refresh();
|
||||
if (!alerts_widget->alertCount && !alerts_widget->updateAvailable) {
|
||||
closeAlerts();
|
||||
alert_notification->setVisible(false);
|
||||
return;
|
||||
// pop-up new notification
|
||||
int idx = center_layout->currentIndex();
|
||||
if (!updateAvailable && !alerts) {
|
||||
idx = 0;
|
||||
} else if (updateAvailable && (!update_notif->isVisible() || (!alerts && idx == 2))) {
|
||||
idx = 1;
|
||||
} else if (alerts && (!alert_notif->isVisible() || (!updateAvailable && idx == 1))) {
|
||||
idx = 2;
|
||||
}
|
||||
center_layout->setCurrentIndex(idx);
|
||||
|
||||
if (alerts_widget->updateAvailable) {
|
||||
alert_notification->setText("UPDATE");
|
||||
} else {
|
||||
int alerts = alerts_widget->alertCount;
|
||||
alert_notification->setText(QString::number(alerts) + " ALERT" + (alerts == 1 ? "" : "S"));
|
||||
update_notif->setVisible(updateAvailable);
|
||||
alert_notif->setVisible(alerts);
|
||||
if (alerts) {
|
||||
alert_notif->setText(QString::number(alerts) + " ALERT" + (alerts > 1 ? "S" : ""));
|
||||
}
|
||||
|
||||
if (!alert_notification->isVisible() && !first_refresh) {
|
||||
openAlerts();
|
||||
}
|
||||
alert_notification->setVisible(true);
|
||||
// Red background for alerts, blue for update available
|
||||
alert_notification->setStyleSheet(alerts_widget->updateAvailable ? "background-color: #364DEF" : "background-color: #E22C2C");
|
||||
}
|
||||
|
||||
+7
-10
@@ -19,21 +19,18 @@ class OffroadHome : public QFrame {
|
||||
public:
|
||||
explicit OffroadHome(QWidget* parent = 0);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
private:
|
||||
QTimer* timer;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
void refresh();
|
||||
|
||||
QTimer* timer;
|
||||
QLabel* date;
|
||||
QStackedLayout* center_layout;
|
||||
UpdateAlert *update_widget;
|
||||
OffroadAlert* alerts_widget;
|
||||
QPushButton* alert_notification;
|
||||
|
||||
public slots:
|
||||
void closeAlerts();
|
||||
void openAlerts();
|
||||
void refresh();
|
||||
QPushButton* alert_notif;
|
||||
QPushButton* update_notif;
|
||||
};
|
||||
|
||||
class HomeWindow : public QWidget {
|
||||
|
||||
@@ -3,33 +3,21 @@
|
||||
#include <QHBoxLayout>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "selfdrive/common/util.h"
|
||||
#include "selfdrive/hardware/hw.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
|
||||
OffroadAlert::OffroadAlert(QWidget* parent) : QFrame(parent) {
|
||||
AbstractAlert::AbstractAlert(bool hasRebootBtn, QWidget *parent) : QFrame(parent) {
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
||||
main_layout->setMargin(50);
|
||||
main_layout->setSpacing(30);
|
||||
|
||||
QWidget *alerts_widget = new QWidget(this);
|
||||
alerts_layout = new QVBoxLayout(alerts_widget);
|
||||
alerts_layout->setMargin(0);
|
||||
alerts_layout->setSpacing(30);
|
||||
alerts_widget->setStyleSheet("background-color: transparent;");
|
||||
|
||||
// release notes
|
||||
releaseNotes.setWordWrap(true);
|
||||
releaseNotes.setVisible(false);
|
||||
releaseNotes.setStyleSheet("font-size: 48px;");
|
||||
releaseNotes.setAlignment(Qt::AlignTop);
|
||||
|
||||
releaseNotesScroll = new ScrollView(&releaseNotes, this);
|
||||
main_layout->addWidget(releaseNotesScroll);
|
||||
|
||||
alertsScroll = new ScrollView(alerts_widget, this);
|
||||
main_layout->addWidget(alertsScroll);
|
||||
QWidget *widget = new QWidget;
|
||||
scrollable_layout = new QVBoxLayout(widget);
|
||||
widget->setStyleSheet("background-color: transparent;");
|
||||
main_layout->addWidget(new ScrollView(widget));
|
||||
|
||||
// bottom footer, dismiss + reboot buttons
|
||||
QHBoxLayout *footer_layout = new QHBoxLayout();
|
||||
@@ -38,14 +26,14 @@ OffroadAlert::OffroadAlert(QWidget* parent) : QFrame(parent) {
|
||||
QPushButton *dismiss_btn = new QPushButton("Dismiss");
|
||||
dismiss_btn->setFixedSize(400, 125);
|
||||
footer_layout->addWidget(dismiss_btn, 0, Qt::AlignBottom | Qt::AlignLeft);
|
||||
QObject::connect(dismiss_btn, &QPushButton::released, this, &OffroadAlert::closeAlerts);
|
||||
|
||||
rebootBtn.setText("Reboot and Update");
|
||||
rebootBtn.setFixedSize(600, 125);
|
||||
rebootBtn.setVisible(false);
|
||||
footer_layout->addWidget(&rebootBtn, 0, Qt::AlignBottom | Qt::AlignRight);
|
||||
QObject::connect(&rebootBtn, &QPushButton::released, [=]() { Hardware::reboot(); });
|
||||
QObject::connect(dismiss_btn, &QPushButton::released, this, &AbstractAlert::dismiss);
|
||||
|
||||
if (hasRebootBtn) {
|
||||
QPushButton *rebootBtn = new QPushButton("Reboot and Update");
|
||||
rebootBtn->setFixedSize(600, 125);
|
||||
footer_layout->addWidget(rebootBtn, 0, Qt::AlignBottom | Qt::AlignRight);
|
||||
QObject::connect(rebootBtn, &QPushButton::released, [=]() { Hardware::reboot(); });
|
||||
}
|
||||
setStyleSheet(R"(
|
||||
* {
|
||||
font-size: 48px;
|
||||
@@ -64,49 +52,55 @@ OffroadAlert::OffroadAlert(QWidget* parent) : QFrame(parent) {
|
||||
)");
|
||||
}
|
||||
|
||||
void OffroadAlert::refresh() {
|
||||
int OffroadAlert::refresh() {
|
||||
if (alerts.empty()) {
|
||||
// setup labels for each alert
|
||||
QString json = QString::fromStdString(util::read_file("../controls/lib/alerts_offroad.json"));
|
||||
QString json = util::read_file("../controls/lib/alerts_offroad.json").c_str();
|
||||
QJsonObject obj = QJsonDocument::fromJson(json.toUtf8()).object();
|
||||
for (auto &k : obj.keys()) {
|
||||
QLabel *l = new QLabel(this);
|
||||
alerts[k.toStdString()] = l;
|
||||
int severity = obj[k].toObject()["severity"].toInt();
|
||||
// descending sort labels by severity
|
||||
std::vector<std::pair<std::string, int>> sorted;
|
||||
for (auto it = obj.constBegin(); it != obj.constEnd(); ++it) {
|
||||
sorted.push_back({it.key().toStdString(), it.value()["severity"].toInt()});
|
||||
}
|
||||
std::sort(sorted.begin(), sorted.end(), [=](auto &l, auto &r) { return l.second > r.second; });
|
||||
|
||||
for (auto &[key, severity] : sorted) {
|
||||
QLabel *l = new QLabel(this);
|
||||
alerts[key] = l;
|
||||
l->setMargin(60);
|
||||
l->setWordWrap(true);
|
||||
l->setStyleSheet("background-color: " + QString(severity ? "#E22C2C" : "#292929"));
|
||||
l->setVisible(false);
|
||||
alerts_layout->addWidget(l);
|
||||
l->setStyleSheet(QString("background-color: %1").arg(severity ? "#E22C2C" : "#292929"));
|
||||
scrollable_layout->addWidget(l);
|
||||
}
|
||||
alerts_layout->addStretch(1);
|
||||
scrollable_layout->addStretch(1);
|
||||
}
|
||||
|
||||
updateAlerts();
|
||||
|
||||
rebootBtn.setVisible(updateAvailable);
|
||||
releaseNotesScroll->setVisible(updateAvailable);
|
||||
releaseNotes.setText(QString::fromStdString(params.get("ReleaseNotes")));
|
||||
|
||||
alertsScroll->setVisible(!updateAvailable);
|
||||
for (const auto& [k, label] : alerts) {
|
||||
label->setVisible(!label->text().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
void OffroadAlert::updateAlerts() {
|
||||
alertCount = 0;
|
||||
for (const auto& [key, label] : alerts) {
|
||||
auto bytes = params.get(key.c_str());
|
||||
int alertCount = 0;
|
||||
for (const auto &[key, label] : alerts) {
|
||||
QString text;
|
||||
std::string bytes = params.get(key);
|
||||
if (bytes.size()) {
|
||||
QJsonDocument doc_par = QJsonDocument::fromJson(QByteArray(bytes.data(), bytes.size()));
|
||||
QJsonObject obj = doc_par.object();
|
||||
label->setText(obj.value("text").toString());
|
||||
alertCount++;
|
||||
} else {
|
||||
label->setText("");
|
||||
auto doc_par = QJsonDocument::fromJson(bytes.c_str());
|
||||
text = doc_par["text"].toString();
|
||||
}
|
||||
label->setText(text);
|
||||
label->setVisible(!text.isEmpty());
|
||||
alertCount += !text.isEmpty();
|
||||
}
|
||||
updateAvailable = params.getBool("UpdateAvailable") && alertCount < 1;
|
||||
return alertCount;
|
||||
}
|
||||
|
||||
UpdateAlert::UpdateAlert(QWidget *parent) : AbstractAlert(true, parent) {
|
||||
releaseNotes = new QLabel(this);
|
||||
releaseNotes->setWordWrap(true);
|
||||
releaseNotes->setAlignment(Qt::AlignTop);
|
||||
scrollable_layout->addWidget(releaseNotes);
|
||||
}
|
||||
|
||||
bool UpdateAlert::refresh() {
|
||||
bool updateAvailable = params.getBool("UpdateAvailable");
|
||||
if (updateAvailable) {
|
||||
releaseNotes->setText(params.get("ReleaseNotes").c_str());
|
||||
}
|
||||
return updateAvailable;
|
||||
}
|
||||
|
||||
@@ -2,37 +2,41 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "selfdrive/common/params.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
|
||||
class OffroadAlert : public QFrame {
|
||||
class AbstractAlert : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
AbstractAlert(bool hasRebootBtn, QWidget *parent = nullptr);
|
||||
QVBoxLayout *scrollable_layout;
|
||||
Params params;
|
||||
|
||||
signals:
|
||||
void dismiss();
|
||||
};
|
||||
|
||||
class UpdateAlert : public AbstractAlert {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OffroadAlert(QWidget *parent = 0);
|
||||
int alertCount = 0;
|
||||
bool updateAvailable;
|
||||
UpdateAlert(QWidget *parent = 0);
|
||||
bool refresh();
|
||||
|
||||
private:
|
||||
void updateAlerts();
|
||||
|
||||
Params params;
|
||||
std::map<std::string, QLabel*> alerts;
|
||||
|
||||
QLabel releaseNotes;
|
||||
QPushButton rebootBtn;
|
||||
ScrollView *alertsScroll;
|
||||
ScrollView *releaseNotesScroll;
|
||||
QVBoxLayout *alerts_layout;
|
||||
|
||||
signals:
|
||||
void closeAlerts();
|
||||
|
||||
public slots:
|
||||
void refresh();
|
||||
QLabel *releaseNotes = nullptr;
|
||||
};
|
||||
|
||||
class OffroadAlert : public AbstractAlert {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OffroadAlert(QWidget *parent = 0) : AbstractAlert(false, parent) {}
|
||||
int refresh();
|
||||
|
||||
private:
|
||||
std::map<std::string, QLabel*> alerts;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user