From ce48d3c91eb66924ca20c0bcbd14a74e88207997 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 25 Dec 2020 01:02:47 -0800 Subject: [PATCH] offroad home style (#19593) * make drive stats look nicer * offroad alerts style * rest of alerts * move that * fix up colors Co-authored-by: Comma Device --- selfdrive/ui/qt/home.cc | 2 +- selfdrive/ui/qt/offroad/settings.cc | 2 +- selfdrive/ui/qt/widgets/drive_stats.cc | 91 ++++++------- selfdrive/ui/qt/widgets/drive_stats.hpp | 2 - selfdrive/ui/qt/widgets/offroad_alerts.cc | 148 +++++++++------------ selfdrive/ui/qt/widgets/offroad_alerts.hpp | 9 +- selfdrive/ui/sidebar.cc | 7 +- selfdrive/ui/tests/cycle_offroad_alerts.py | 5 +- selfdrive/ui/ui.hpp | 4 + 9 files changed, 122 insertions(+), 148 deletions(-) diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index b1ee784481..033ba115ce 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -44,7 +44,7 @@ OffroadHome::OffroadHome(QWidget *parent) : QWidget(parent) { main_layout->addWidget(alert_notification, 0, Qt::AlignTop | Qt::AlignRight); // main content - main_layout->addSpacing(100); + main_layout->addSpacing(25); center_layout = new QStackedLayout(); DriveStats *drive = new DriveStats; diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index f9886b7e20..feaf7c203c 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -64,7 +64,7 @@ QWidget * toggles_panel() { toggles_list->setSpacing(25); toggles_list->addWidget(new ParamsToggle("OpenpilotEnabledToggle", - "Enable Openpilot", + "Enable openpilot", "Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.", "../assets/offroad/icon_openpilot.png" )); diff --git a/selfdrive/ui/qt/widgets/drive_stats.cc b/selfdrive/ui/qt/widgets/drive_stats.cc index b5c72594d3..8e94415a70 100644 --- a/selfdrive/ui/qt/widgets/drive_stats.cc +++ b/selfdrive/ui/qt/widgets/drive_stats.cc @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -19,7 +18,9 @@ #include "drive_stats.hpp" #include "common/params.h" #include "common/utilpp.h" -double MILE_TO_KM = 1.60934; + + +constexpr double MILE_TO_KM = 1.60934; #if defined(QCOM) || defined(QCOM2) @@ -28,7 +29,8 @@ const std::string private_key_path = "/persist/comma/id_rsa"; const std::string private_key_path = util::getenv_default("HOME", "/.comma/persist/comma/id_rsa", "/persist/comma/id_rsa"); #endif -QByteArray rsa_sign(QByteArray data){ + +QByteArray rsa_sign(QByteArray data) { auto file = QFile(private_key_path.c_str()); bool r = file.open(QIODevice::ReadOnly); assert(r); @@ -56,7 +58,7 @@ QByteArray rsa_sign(QByteArray data){ return sig; } -QString create_jwt(QString dongle_id, int expiry=3600){ +QString create_jwt(QString dongle_id, int expiry=3600) { QJsonObject header; header.insert("alg", "RS256"); header.insert("typ", "JWT"); @@ -81,24 +83,27 @@ QString create_jwt(QString dongle_id, int expiry=3600){ return jwt; } -QString bold(QString s) { - return "" + s + ""; -} - -QWidget *widget(QLayout *l){ - QWidget *q = new QWidget(); - q->setLayout(l); - return q; -} - -QWidget *build_stat(QString name, int stat){ +QLayout *build_stat(QString name, int stat) { QVBoxLayout *layout = new QVBoxLayout; - layout->addWidget(new QLabel(bold(QString("%1").arg(stat))), 1, Qt::AlignCenter); - layout->addWidget(new QLabel(name),1, Qt::AlignCenter); - return widget(layout); + + QLabel *metric = new QLabel(QString("%1").arg(stat)); + metric->setStyleSheet(R"( + font-size: 72px; + font-weight: 700; + )"); + layout->addWidget(metric, 0, Qt::AlignLeft); + + QLabel *label = new QLabel(name); + label->setStyleSheet(R"( + font-size: 32px; + font-weight: 600; + )"); + layout->addWidget(label, 0, Qt::AlignLeft); + + return layout; } -void DriveStats::replyFinished(QNetworkReply *l){ +void DriveStats::replyFinished(QNetworkReply *l) { QString answer = l->readAll(); answer.chop(1); @@ -116,47 +121,27 @@ void DriveStats::replyFinished(QNetworkReply *l){ QGridLayout *gl = new QGridLayout(); int all_distance = all["distance"].toDouble()*(metric ? MILE_TO_KM : 1); - gl->addWidget(new QLabel(bold("ALL TIME")), 0, 0, 1, 3); - gl->addWidget(build_stat("DRIVES", all["routes"].toDouble()), 1, 0, 3, 1); - gl->addWidget(build_stat(metric ? "KM" : "MILES", all_distance), 1, 1, 3, 1); - gl->addWidget(build_stat("HOURS", all["minutes"].toDouble() / 60), 1, 2, 3, 1); - - QFrame *lineA = new QFrame; - lineA->setFrameShape(QFrame::HLine); - lineA->setFrameShadow(QFrame::Sunken); - lineA->setProperty("class", "line"); - gl->addWidget(lineA, 5, 0, 1, 3); + gl->addWidget(new QLabel("ALL TIME"), 0, 0, 1, 3); + gl->addLayout(build_stat("DRIVES", all["routes"].toDouble()), 1, 0, 3, 1); + gl->addLayout(build_stat(metric ? "KM" : "MILES", all_distance), 1, 1, 3, 1); + gl->addLayout(build_stat("HOURS", all["minutes"].toDouble() / 60), 1, 2, 3, 1); int week_distance = week["distance"].toDouble()*(metric ? MILE_TO_KM : 1); - gl->addWidget(new QLabel(bold("PAST WEEK")), 6, 0, 1, 3); - gl->addWidget(build_stat("DRIVES", week["routes"].toDouble()), 7, 0, 3, 1); - gl->addWidget(build_stat(metric ? "KM" : "MILES", week_distance), 7, 1, 3, 1); - gl->addWidget(build_stat("HOURS", week["minutes"].toDouble() / 60), 7, 2, 3, 1); - - f->setLayout(gl); - f->setStyleSheet(R"( - [class="line"] { - border: 2px solid white; - } - [class="outside"] { - border-radius: 20px; - border: 2px solid white; - padding: 10px; - } + gl->addWidget(new QLabel("PAST WEEK"), 6, 0, 1, 3); + gl->addLayout(build_stat("DRIVES", week["routes"].toDouble()), 7, 0, 3, 1); + gl->addLayout(build_stat(metric ? "KM" : "MILES", week_distance), 7, 1, 3, 1); + gl->addLayout(build_stat("HOURS", week["minutes"].toDouble() / 60), 7, 2, 3, 1); + + setLayout(gl); + setStyleSheet(R"( QLabel { - font-size: 70px; - font-weight: 200; + font-size: 48px; + font-weight: 600; } )"); - } -DriveStats::DriveStats(QWidget *parent) : QWidget(parent) { - f = new QFrame; - f->setProperty("class", "outside"); - QVBoxLayout *v = new QVBoxLayout; - v->addWidget(f); - setLayout(v); +DriveStats::DriveStats(QWidget *parent) : QWidget(parent) { QString dongle_id = QString::fromStdString(Params().get("DongleId")); QString token = create_jwt(dongle_id); diff --git a/selfdrive/ui/qt/widgets/drive_stats.hpp b/selfdrive/ui/qt/widgets/drive_stats.hpp index 3a9731ca88..991de7e2ce 100644 --- a/selfdrive/ui/qt/widgets/drive_stats.hpp +++ b/selfdrive/ui/qt/widgets/drive_stats.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -12,6 +11,5 @@ public: explicit DriveStats(QWidget *parent = 0); private: - QFrame *f; void replyFinished(QNetworkReply *l); }; diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.cc b/selfdrive/ui/qt/widgets/offroad_alerts.cc index 4fb0b9fdbc..5a31935f02 100644 --- a/selfdrive/ui/qt/widgets/offroad_alerts.cc +++ b/selfdrive/ui/qt/widgets/offroad_alerts.cc @@ -1,130 +1,110 @@ -#include #include +#include #include +#include #include #include #include #include "offroad_alerts.hpp" - #include "common/params.h" -void cleanLayout(QLayout* layout) { - while (QLayoutItem* item = layout->takeAt(0)) { - if (QWidget* widget = item->widget()) { - widget->deleteLater(); - } - if (QLayout* childLayout = item->layout()) { - cleanLayout(childLayout); - } - delete item; +void cleanStackedWidget(QStackedWidget* swidget) { + while(swidget->count() > 0) { + QWidget *w = swidget->widget(0); + swidget->removeWidget(w); + w->deleteLater(); } } -QString vectorToQString(std::vector v) { - return QString::fromStdString(std::string(v.begin(), v.end())); -} - OffroadAlert::OffroadAlert(QWidget* parent) { - vlayout = new QVBoxLayout; - refresh(); - setLayout(vlayout); + QVBoxLayout *main_layout = new QVBoxLayout(); + main_layout->setMargin(25); + + alerts_stack = new QStackedWidget(); + main_layout->addWidget(alerts_stack, 1); + + // bottom footer + QVBoxLayout *footer_layout = new QVBoxLayout(); + main_layout->addLayout(footer_layout); + + QPushButton *dismiss_btn = new QPushButton("Dismiss"); + dismiss_btn->setFixedSize(453, 125); + footer_layout->addWidget(dismiss_btn, 0, Qt::AlignLeft); + QObject::connect(dismiss_btn, SIGNAL(released()), this, SIGNAL(closeAlerts())); + + setLayout(main_layout); + setStyleSheet(R"( + * { + color: white; + } + QFrame { + border-radius: 30px; + background-color: #393939; + } + QPushButton { + color: black; + font-size: 40px; + font-weight: 600; + border-radius: 20px; + background-color: white; + } + )"); } void OffroadAlert::refresh() { - cleanLayout(vlayout); parse_alerts(); + cleanStackedWidget(alerts_stack); - updateAvailable = false; std::vector bytes = Params().read_db_bytes("UpdateAvailable"); - if (bytes.size() && bytes[0] == '1') { - updateAvailable = true; - } - - if (updateAvailable) { - // If there is an update available, don't show alerts - alerts.clear(); + updateAvailable = bytes.size() && bytes[0] == '1'; - QFrame *f = new QFrame(); + QVBoxLayout *layout = new QVBoxLayout; - QVBoxLayout *update_layout = new QVBoxLayout; - update_layout->setMargin(10); - update_layout->setSpacing(20); - - QLabel *title = new QLabel("Update available"); + if (updateAvailable) { + QLabel *title = new QLabel("Update Available"); title->setStyleSheet(R"( - font-size: 55px; - font-weight: bold; + font-size: 72px; + font-weight: 700; )"); - update_layout->addWidget(title, 0, Qt::AlignTop); + layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop); QString release_notes = QString::fromStdString(Params().get("ReleaseNotes")); - QLabel *notes_label = new QLabel(release_notes); - notes_label->setStyleSheet(R"(font-size: 40px;)"); - notes_label->setWordWrap(true); - update_layout->addWidget(notes_label, 1, Qt::AlignTop); - - QPushButton *update_button = new QPushButton("Reboot and Update"); - update_layout->addWidget(update_button); -#ifdef __aarch64__ - QObject::connect(update_button, &QPushButton::released, [=]() {std::system("sudo reboot");}); -#endif - - f->setLayout(update_layout); - f->setStyleSheet(R"( - .QFrame{ - border-radius: 20px; - border: 2px solid white; - background-color: #114267; - } - QPushButton { - padding: 20px; - font-size: 35px; - color: white; - background-color: blue; - } + QLabel *body = new QLabel(release_notes); + body->setStyleSheet(R"( + font-size: 48px; + font-weight: 600; )"); - - vlayout->addWidget(f); - vlayout->addSpacing(60); + layout->addWidget(body, 1, Qt::AlignLeft | Qt::AlignTop); } else { - vlayout->addSpacing(60); - + // TODO: paginate the alerts for (const auto &alert : alerts) { QLabel *l = new QLabel(alert.text); l->setWordWrap(true); l->setMargin(60); QString style = R"( - font-size: 40px; - font-weight: bold; - border-radius: 30px; - border: 2px solid; - border-color: white; + font-size: 48px; + font-weight: 600; )"; - style.append("background-color: " + QString(alert.severity ? "#971b1c" : "#114267")); - + style.append("background-color: " + QString(alert.severity ? "#E22C2C" : "#292929")); l->setStyleSheet(style); - vlayout->addWidget(l); - vlayout->addSpacing(20); + + layout->addWidget(l, 0, Qt::AlignTop); } + layout->setSpacing(20); } - QPushButton *hide_btn = new QPushButton(updateAvailable ? "Later" : "Hide alerts"); - hide_btn->setStyleSheet(R"( - padding: 20px; - font-size: 35px; - color: white; - background-color: blue; - )"); - vlayout->addWidget(hide_btn); - QObject::connect(hide_btn, SIGNAL(released()), this, SIGNAL(closeAlerts())); + QWidget *w = new QWidget(); + w->setLayout(layout); + alerts_stack->addWidget(w); } void OffroadAlert::parse_alerts() { alerts.clear(); - // We launch in selfdrive/ui + + // TODO: only read this once QFile inFile("../controls/lib/alerts_offroad.json"); inFile.open(QIODevice::ReadOnly | QIODevice::Text); QByteArray data = inFile.readAll(); diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.hpp b/selfdrive/ui/qt/widgets/offroad_alerts.hpp index 1e425158fd..f8ad3aba01 100644 --- a/selfdrive/ui/qt/widgets/offroad_alerts.hpp +++ b/selfdrive/ui/qt/widgets/offroad_alerts.hpp @@ -1,14 +1,14 @@ #pragma once -#include -#include +#include +#include struct Alert { QString text; int severity; }; -class OffroadAlert : public QWidget { +class OffroadAlert : public QFrame { Q_OBJECT public: @@ -17,8 +17,7 @@ public: bool updateAvailable; private: - QVBoxLayout *vlayout; - + QStackedWidget *alerts_stack; void parse_alerts(); signals: diff --git a/selfdrive/ui/sidebar.cc b/selfdrive/ui/sidebar.cc index 65b20bdac2..2d317c49a0 100644 --- a/selfdrive/ui/sidebar.cc +++ b/selfdrive/ui/sidebar.cc @@ -7,7 +7,12 @@ #include "sidebar.hpp" static void ui_draw_sidebar_background(UIState *s) { - ui_draw_rect(s->vg, 0, 0, sbr_w, s->fb_h, COLOR_BLACK_ALPHA(85)); +#ifdef QCOM + const NVGcolor color = COLOR_BLACK_ALPHA(85); +#else + const NVGcolor color = nvgRGBA(0x39, 0x39, 0x39, 0xff); +#endif + ui_draw_rect(s->vg, 0, 0, sbr_w, s->fb_h, color); } static void ui_draw_sidebar_settings_button(UIState *s) { diff --git a/selfdrive/ui/tests/cycle_offroad_alerts.py b/selfdrive/ui/tests/cycle_offroad_alerts.py index f15486662a..10614b95d4 100755 --- a/selfdrive/ui/tests/cycle_offroad_alerts.py +++ b/selfdrive/ui/tests/cycle_offroad_alerts.py @@ -18,7 +18,10 @@ if __name__ == "__main__": while True: print("setting alert update") params.put("UpdateAvailable", "1") - params.put("ReleaseNotes", "this is a new version") + r = open(os.path.join(BASEDIR, "RELEASES.md"), "r").read() + r = r[:r.find('\n\n')] # Slice latest release notes + params.put("ReleaseNotes", r + "\n") + time.sleep(t) params.put("UpdateAvailable", "0") diff --git a/selfdrive/ui/ui.hpp b/selfdrive/ui/ui.hpp index 6c326cec70..d989a501d4 100644 --- a/selfdrive/ui/ui.hpp +++ b/selfdrive/ui/ui.hpp @@ -74,7 +74,11 @@ typedef enum UIStatus { } UIStatus; static std::map bg_colors = { +#ifdef QCOM {STATUS_OFFROAD, nvgRGBA(0x07, 0x23, 0x39, 0xf1)}, +#else + {STATUS_OFFROAD, nvgRGBA(0x0, 0x0, 0x0, 0xff)}, +#endif {STATUS_DISENGAGED, nvgRGBA(0x17, 0x33, 0x49, 0xc8)}, {STATUS_ENGAGED, nvgRGBA(0x17, 0x86, 0x44, 0xf1)}, {STATUS_WARNING, nvgRGBA(0xDA, 0x6F, 0x25, 0xf1)},