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 <adeebshihadeh@gmail.com>
albatross
Dean Lee 2021-03-22 14:53:56 +08:00 committed by GitHub
parent 33500bf23f
commit 8be2e07f4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 166 additions and 141 deletions

View File

@ -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"]

View File

@ -3,128 +3,60 @@
#include <sstream>
#include <cassert>
#include <QString>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QPixmap>
#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<std::pair<std::string, std::string>> 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<std::pair<const char*, const char*>> 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();

View File

@ -8,24 +8,7 @@
#include <QButtonGroup>
#include <QStackedLayout>
#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<QLabel *> labels;
QList<LabelControl *> labels;
};
// *** settings window ***
class SettingsWindow : public QFrame {
Q_OBJECT

View File

@ -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);
}

View File

@ -0,0 +1,91 @@
#pragma once
#include <QFrame>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#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 <typename Functor>
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 &param, 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;
};