From d7cf75fc64f6e6c11948cddff55cbd3c6fbb88ad Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 22 Mar 2021 14:53:56 +0800 Subject: [PATCH] Qt: use the AbstractControl for multiple types of controls (#20417) * class ClickableLabel * scrollable widget * rename to controls.cc * rename to AbstractControl * cleanup * remove useless stylesheets * change button stylesheet * cleanup * better margin * cleanup cleanup * remove bottom line from AbstractControl * no scrolling for now * add those back * style * clean up * don't need a function for that Co-authored-by: Adeeb Shihadeh old-commit-hash: 8be2e07f4f56bf784bd091d81df442b2718cff84 --- selfdrive/ui/SConscript | 2 +- selfdrive/ui/qt/offroad/settings.cc | 155 +++++++-------------------- selfdrive/ui/qt/offroad/settings.hpp | 23 +--- selfdrive/ui/qt/widgets/controls.cc | 36 +++++++ selfdrive/ui/qt/widgets/controls.hpp | 91 ++++++++++++++++ 5 files changed, 166 insertions(+), 141 deletions(-) create mode 100644 selfdrive/ui/qt/widgets/controls.cc create mode 100644 selfdrive/ui/qt/widgets/controls.hpp diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 83b5fe51f1..e09f168c77 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -25,7 +25,7 @@ else: qt_env['FRAMEWORKS'] += ['OpenCL'] widgets_src = ["qt/widgets/input.cc", "qt/widgets/drive_stats.cc", - "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/qt_sound.cc", + "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc", "qt/qt_sound.cc", "qt/widgets/offroad_alerts.cc", "qt/widgets/setup.cc", "qt/widgets/keyboard.cc", "#phonelibs/qrcode/QrCode.cc"] diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 8cb9c06552..d9cdf34ae9 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -3,128 +3,60 @@ #include #include -#include -#include -#include -#include -#include -#include - #ifndef QCOM #include "networking.hpp" #endif - #include "settings.hpp" #include "widgets/input.hpp" #include "widgets/toggle.hpp" #include "widgets/offroad_alerts.hpp" - -#include "selfdrive/common/params.h" -#include "selfdrive/common/util.h" +#include "widgets/controls.hpp" +#include "common/params.h" +#include "common/util.h" #include "selfdrive/hardware/hw.h" -QFrame* horizontal_line(QWidget* parent = 0){ - QFrame* line = new QFrame(parent); - line->setFrameShape(QFrame::StyledPanel); - line->setStyleSheet("margin-left: 40px; margin-right: 40px; border-width: 1px; border-bottom-style: solid; border-color: gray;"); - line->setFixedHeight(2); - return line; -} - -QWidget *labelWidget(QString labelName, QString labelContent, QLabel **label = nullptr) { - QHBoxLayout* labelLayout = new QHBoxLayout; - labelLayout->addWidget(new QLabel(labelName), 0, Qt::AlignLeft); - QLabel* paramContent = new QLabel(labelContent); - paramContent->setStyleSheet("color: #aaaaaa"); - labelLayout->addWidget(paramContent, 0, Qt::AlignRight); - QWidget* labelWidget = new QWidget; - labelWidget->setLayout(labelLayout); - if (label) *label = paramContent; - return labelWidget; -} - -ParamsToggle::ParamsToggle(QString param, QString title, QString description, QString icon_path, QWidget *parent): QFrame(parent) , param(param) { - QHBoxLayout *layout = new QHBoxLayout; - layout->setMargin(0); - layout->setSpacing(50); - - // Parameter image - const int img_size = 80; - if (icon_path.length()) { - QPixmap pix(icon_path); - QLabel *icon = new QLabel(); - icon->setPixmap(pix.scaledToWidth(img_size, Qt::SmoothTransformation)); - icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); - layout->addWidget(icon); - } else { - layout->addSpacing(img_size); - } - - // Name of the parameter - QLabel *label = new QLabel(title); - label->setStyleSheet(R"(font-size: 50px;)"); - layout->addWidget(label); - - // toggle switch - toggle = new Toggle(this); - toggle->setFixedSize(150, 100); - layout->addWidget(toggle); - QObject::connect(toggle, SIGNAL(stateChanged(int)), this, SLOT(checkboxClicked(int))); - - // set initial state from param - if (Params().read_db_bool(param.toStdString().c_str())) { - toggle->togglePosition(); - } - - setLayout(layout); -} - -void ParamsToggle::checkboxClicked(int state) { - char value = state ? '1': '0'; - Params().write_db_value(param.toStdString().c_str(), &value, 1); -} QWidget * toggles_panel() { QVBoxLayout *toggles_list = new QVBoxLayout(); - toggles_list->setMargin(50); - toggles_list->addWidget(new ParamsToggle("OpenpilotEnabledToggle", + toggles_list->setMargin(50); + toggles_list->addWidget(new ToggleControl("OpenpilotEnabledToggle", "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" )); toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ParamsToggle("LaneChangeEnabled", + toggles_list->addWidget(new ToggleControl("LaneChangeEnabled", "Enable Lane Change Assist", "Perform assisted lane changes with openpilot by checking your surroundings for safety, activating the turn signal and gently nudging the steering wheel towards your desired lane. openpilot is not capable of checking if a lane change is safe. You must continuously observe your surroundings to use this feature.", "../assets/offroad/icon_road.png" )); toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ParamsToggle("IsLdwEnabled", + toggles_list->addWidget(new ToggleControl("IsLdwEnabled", "Enable Lane Departure Warnings", "Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31mph (50kph).", "../assets/offroad/icon_warning.png" )); toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ParamsToggle("IsRHD", + toggles_list->addWidget(new ToggleControl("IsRHD", "Enable Right-Hand Drive", "Allow openpilot to obey left-hand traffic conventions and perform driver monitoring on right driver seat.", "../assets/offroad/icon_openpilot_mirrored.png" )); toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ParamsToggle("IsMetric", + toggles_list->addWidget(new ToggleControl("IsMetric", "Use Metric System", "Display speed in km/h instead of mp/h.", "../assets/offroad/icon_metric.png" )); toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ParamsToggle("CommunityFeaturesToggle", + toggles_list->addWidget(new ToggleControl("CommunityFeaturesToggle", "Enable Community Features", "Use features from the open source community that are not maintained or supported by comma.ai and have not been confirmed to meet the standard safety model. These features include community supported cars and community supported hardware. Be extra cautious when using these features", "../assets/offroad/icon_shell.png" )); - ParamsToggle *record_toggle = new ParamsToggle("RecordFront", + ToggleControl *record_toggle = new ToggleControl("RecordFront", "Record and Upload Driver Camera", "Upload data from the driver facing camera and help improve the driver monitoring algorithm.", "../assets/offroad/icon_network.png"); @@ -132,7 +64,7 @@ QWidget * toggles_panel() { toggles_list->addWidget(record_toggle); bool record_lock = Params().read_db_bool("RecordFrontLock"); - record_toggle->toggle->setEnabled(!record_lock); + record_toggle->setEnabled(!record_lock); QWidget *widget = new QWidget; widget->setLayout(toggles_list); @@ -140,10 +72,8 @@ QWidget * toggles_panel() { } QWidget * device_panel() { - QVBoxLayout *device_layout = new QVBoxLayout; device_layout->setMargin(100); - device_layout->setSpacing(30); Params params = Params(); std::vector> labels = { @@ -158,26 +88,26 @@ QWidget * device_panel() { //} for (auto &l : labels) { - device_layout->addWidget(labelWidget(QString::fromStdString(l.first), - QString::fromStdString(l.second)), 0, Qt::AlignTop); + device_layout->addWidget(new LabelControl(QString::fromStdString(l.first), + QString::fromStdString(l.second))); } - QPushButton* dcam_view = new QPushButton("Driver camera view"); - device_layout->addWidget(dcam_view, 0, Qt::AlignBottom); - device_layout->addWidget(horizontal_line(), Qt::AlignBottom); - QObject::connect(dcam_view, &QPushButton::released, [=]() { - Params().write_db_value("IsDriverViewEnabled", "1", 1); - }); + device_layout->addWidget(horizontal_line()); + + device_layout->addWidget(new ButtonControl("Driver camera view", "PREVIEW", + "Preview the driver facing camera to help optimize device mounting position for best driver monitoring experience. (vehicle must be off)", + [=]() { Params().write_db_value("IsDriverViewEnabled", "1", 1); })); + + device_layout->addWidget(horizontal_line()); // TODO: show current calibration values - QPushButton *clear_cal_btn = new QPushButton("Reset Calibration"); - device_layout->addWidget(clear_cal_btn, 0, Qt::AlignBottom); - device_layout->addWidget(horizontal_line(), Qt::AlignBottom); - QObject::connect(clear_cal_btn, &QPushButton::released, [=]() { - if (ConfirmationDialog::confirm("Are you sure you want to reset calibration?")) { - Params().delete_db_value("CalibrationParams"); - } - }); + device_layout->addWidget(new ButtonControl("Reset Calibration", "RESET", + "openpilot requires the device to be mounted within 4° left or right and within 5° up or down. openpilot is continuously calibrating, resetting is rarely required.", + [=]() { + if (ConfirmationDialog::confirm("Are you sure you want to reset calibration?")) { + Params().delete_db_value("CalibrationParams"); + } + })); // power buttons @@ -243,12 +173,11 @@ void DeveloperPanel::showEvent(QShowEvent *event) { if (labels.size() > i) { labels[i]->setText(QString::fromStdString(value)); } else { - QLabel *label = nullptr; - layout()->addWidget(labelWidget(name, QString::fromStdString(value), &label)); + labels.push_back(new LabelControl(name, QString::fromStdString(value))); + layout()->addWidget(labels[i]); if (i < (dev_params.size() - 1)) { layout()->addWidget(horizontal_line()); } - labels.push_back(label); } } } @@ -262,39 +191,27 @@ QWidget * network_panel(QWidget * parent) { // TODO: can probably use the ndk for this // simple wifi + tethering buttons std::vector> btns = { - {"Open WiFi Settings", "am start -n com.android.settings/.wifi.WifiPickerActivity \ - -a android.net.wifi.PICK_WIFI_NETWORK \ + {"WiFi Settings", "am start -n com.android.settings/.wifi.WifiPickerActivity \ + -a android.net.wifi.PICK_WIFI_NETWORK \ + --ez extra_prefs_show_button_bar true \ + --es extra_prefs_set_next_text ''"}, + {"Tethering Settings", "am start -n com.android.settings/.TetherSettings \ --ez extra_prefs_show_button_bar true \ --es extra_prefs_set_next_text ''"}, - {"Open Tethering Settings", "am start -n com.android.settings/.TetherSettings \ - --ez extra_prefs_show_button_bar true \ - --es extra_prefs_set_next_text ''"}, }; for (auto &b : btns) { - QPushButton *btn = new QPushButton(b.first); - layout->addWidget(btn, 0, Qt::AlignTop); - QObject::connect(btn, &QPushButton::released, [=]() { std::system(b.second); }); + layout->addWidget(new ButtonControl(b.first, "OPEN", "", [=]() { std::system(b.second); })); } layout->addStretch(1); QWidget *w = new QWidget; w->setLayout(layout); - w->setStyleSheet(R"( - QPushButton { - padding: 0; - height: 120px; - border-radius: 15px; - background-color: #393939; - } - )"); - #else Networking *w = new Networking(parent); #endif return w; } - SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { // setup two main layouts QVBoxLayout *sidebar_layout = new QVBoxLayout(); diff --git a/selfdrive/ui/qt/offroad/settings.hpp b/selfdrive/ui/qt/offroad/settings.hpp index 3ddfdfb91d..0555bfa58d 100644 --- a/selfdrive/ui/qt/offroad/settings.hpp +++ b/selfdrive/ui/qt/offroad/settings.hpp @@ -8,24 +8,7 @@ #include #include -#include "selfdrive/ui/qt/widgets/toggle.hpp" - -// *** settings widgets *** - -class ParamsToggle : public QFrame { - Q_OBJECT - -public: - explicit ParamsToggle(QString param, QString title, QString description, - QString icon, QWidget *parent = 0); - Toggle *toggle; - -private: - QString param; - -public slots: - void checkboxClicked(int state); -}; +#include "selfdrive/ui/qt/widgets/controls.hpp" class DeveloperPanel : public QFrame { Q_OBJECT @@ -34,11 +17,9 @@ public: protected: void showEvent(QShowEvent *event) override; - QList labels; + QList labels; }; -// *** settings window *** - class SettingsWindow : public QFrame { Q_OBJECT diff --git a/selfdrive/ui/qt/widgets/controls.cc b/selfdrive/ui/qt/widgets/controls.cc new file mode 100644 index 0000000000..811199626c --- /dev/null +++ b/selfdrive/ui/qt/widgets/controls.cc @@ -0,0 +1,36 @@ +#include "controls.hpp" + +QFrame *horizontal_line(QWidget *parent) { + QFrame *line = new QFrame(parent); + line->setFrameShape(QFrame::StyledPanel); + line->setStyleSheet(R"( + margin-left: 40px; + margin-right: 40px; + border-width: 1px; + border-bottom-style: solid; + border-color: gray; + )"); + line->setFixedHeight(2); + return line; +} + +AbstractControl::AbstractControl(const QString &title, const QString &desc, const QString &icon) : QFrame() { + hlayout = new QHBoxLayout; + hlayout->setSpacing(50); + + // left icon + if (!icon.isEmpty()) { + QPixmap pix(icon); + QLabel *icon = new QLabel(); + icon->setPixmap(pix.scaledToWidth(80, Qt::SmoothTransformation)); + icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + hlayout->addWidget(icon); + } + + // title + title_label = new QLabel(title); + title_label->setStyleSheet("font-size: 50px; font-weight: 400;"); + hlayout->addWidget(title_label); + + setLayout(hlayout); +} diff --git a/selfdrive/ui/qt/widgets/controls.hpp b/selfdrive/ui/qt/widgets/controls.hpp new file mode 100644 index 0000000000..82db77f480 --- /dev/null +++ b/selfdrive/ui/qt/widgets/controls.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "common/params.h" +#include "toggle.hpp" + +QFrame *horizontal_line(QWidget *parent = nullptr); + +class AbstractControl : public QFrame { + Q_OBJECT + +protected: + AbstractControl(const QString &title, const QString &desc = "", const QString &icon = ""); + + QSize minimumSizeHint() const override { + QSize size = QFrame::minimumSizeHint(); + size.setHeight(120); + return size; + }; + + QHBoxLayout *hlayout; + QLabel *title_label; +}; + +class LabelControl : public AbstractControl { + Q_OBJECT + +public: + LabelControl(const QString &title, const QString &text, const QString &desc = "") : AbstractControl(title, desc, "") { + label.setText(text); + label.setAlignment(Qt::AlignRight | Qt::AlignVCenter); + hlayout->addWidget(&label); + } + void setText(const QString &text) { label.setText(text); } + +private: + QLabel label; +}; + +class ButtonControl : public AbstractControl { + Q_OBJECT + +public: + template + ButtonControl(const QString &title, const QString &text, const QString &desc, Functor functor, const QString &icon = "") : AbstractControl(title, desc, icon) { + btn.setText(text); + btn.setStyleSheet(R"( + padding: 0; + border-radius: 40px; + font-size: 30px; + font-weight: 500; + color: #E4E4E4; + background-color: #393939; + )"); + btn.setFixedSize(200, 80); + QObject::connect(&btn, &QPushButton::released, functor); + hlayout->addWidget(&btn); + } + void setText(const QString &text) { btn.setText(text); } + +private: + QPushButton btn; +}; + +class ToggleControl : public AbstractControl { + Q_OBJECT + +public: + ToggleControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon) : AbstractControl(title, desc, icon) { + toggle.setFixedSize(150, 100); + // set initial state from param + if (Params().read_db_bool(param.toStdString().c_str())) { + toggle.togglePosition(); + } + QObject::connect(&toggle, &Toggle::stateChanged, [=](int state) { + char value = state ? '1' : '0'; + Params().write_db_value(param.toStdString().c_str(), &value, 1); + }); + hlayout->addWidget(&toggle); + } + + void setEnabled(bool enabled) { toggle.setEnabled(enabled); } + +private: + Toggle toggle; +};