openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

186 lines
6.0 KiB

#include "tools/cabana/detailwidget.h"
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QMessageBox>
#include <QTimer>
#include "tools/cabana/canmessages.h"
#include "tools/cabana/dbcmanager.h"
// DetailWidget
DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) {
QVBoxLayout *main_layout = new QVBoxLayout(this);
// title
QHBoxLayout *title_layout = new QHBoxLayout();
title_layout->addWidget(new QLabel("time:"));
time_label = new QLabel(this);
title_layout->addWidget(time_label);
time_label->setStyleSheet("font-weight:bold");
title_layout->addStretch();
name_label = new QLabel(this);
name_label->setStyleSheet("font-weight:bold;");
title_layout->addWidget(name_label);
title_layout->addStretch();
edit_btn = new QPushButton(tr("Edit"), this);
edit_btn->setVisible(false);
title_layout->addWidget(edit_btn);
main_layout->addLayout(title_layout);
// binary view
binary_view = new BinaryView(this);
main_layout->addWidget(binary_view, 0, Qt::AlignTop);
// signals
signals_container = new QWidget(this);
signals_container->setLayout(new QVBoxLayout);
signals_container->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
scroll = new ScrollArea(this);
scroll->setWidget(signals_container);
scroll->setWidgetResizable(true);
scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
main_layout->addWidget(scroll);
// history log
history_log = new HistoryLog(this);
main_layout->addWidget(history_log);
QObject::connect(edit_btn, &QPushButton::clicked, this, &DetailWidget::editMsg);
QObject::connect(binary_view, &BinaryView::cellsSelected, this, &DetailWidget::addSignal);
QObject::connect(can, &CANMessages::updated, this, &DetailWidget::updateState);
QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &DetailWidget::dbcMsgChanged);
}
void DetailWidget::setMessage(const QString &message_id) {
if (msg_id != message_id) {
msg_id = message_id;
dbcMsgChanged();
}
}
void DetailWidget::dbcMsgChanged() {
if (msg_id.isEmpty()) return;
qDeleteAll(signals_container->findChildren<SignalEdit *>());
QString msg_name = tr("untitled");
if (auto msg = dbc()->msg(msg_id)) {
for (int i = 0; i < msg->sigs.size(); ++i) {
auto form = new SignalEdit(i, msg_id, msg->sigs[i]);
signals_container->layout()->addWidget(form);
QObject::connect(form, &SignalEdit::showChart, [this, sig = &msg->sigs[i]]() { emit showChart(msg_id, sig); });
QObject::connect(form, &SignalEdit::showFormClicked, this, &DetailWidget::showForm);
QObject::connect(form, &SignalEdit::remove, this, &DetailWidget::removeSignal);
QObject::connect(form, &SignalEdit::save, this, &DetailWidget::saveSignal);
}
msg_name = msg->name.c_str();
}
edit_btn->setVisible(true);
name_label->setText(msg_name);
binary_view->setMessage(msg_id);
history_log->setMessage(msg_id);
}
void DetailWidget::updateState() {
time_label->setText(QString::number(can->currentSec(), 'f', 3));
if (msg_id.isEmpty()) return;
binary_view->updateState();
history_log->updateState();
}
void DetailWidget::showForm() {
SignalEdit *sender = qobject_cast<SignalEdit *>(QObject::sender());
for (auto f : signals_container->findChildren<SignalEdit *>()) {
f->setFormVisible(f == sender && !f->isFormVisible());
if (f == sender) {
QTimer::singleShot(0, [=]() { scroll->ensureWidgetVisible(f); });
}
}
}
void DetailWidget::editMsg() {
auto msg = dbc()->msg(msg_id);
QString name = msg ? msg->name.c_str() : "untitled";
int size = msg ? msg->size : can->lastMessage(msg_id).dat.size();
EditMessageDialog dlg(msg_id, name, size, this);
if (dlg.exec()) {
dbc()->updateMsg(msg_id, dlg.name_edit->text(), dlg.size_spin->value());
dbcMsgChanged();
}
}
void DetailWidget::addSignal(int start_bit, int size) {
if (dbc()->msg(msg_id)) {
AddSignalDialog dlg(msg_id, start_bit, size, this);
if (dlg.exec()) {
dbc()->addSignal(msg_id, dlg.form->getSignal());
dbcMsgChanged();
}
}
}
void DetailWidget::saveSignal() {
SignalEdit *sig_form = qobject_cast<SignalEdit *>(QObject::sender());
auto s = sig_form->form->getSignal();
dbc()->updateSignal(msg_id, sig_form->sig_name, s);
// update binary view and history log
binary_view->setMessage(msg_id);
history_log->setMessage(msg_id);
}
void DetailWidget::removeSignal() {
SignalEdit *sig_form = qobject_cast<SignalEdit *>(QObject::sender());
QString text = tr("Are you sure you want to remove signal '%1'").arg(sig_form->sig_name);
if (QMessageBox::Yes == QMessageBox::question(this, tr("Remove signal"), text)) {
dbc()->removeSignal(msg_id, sig_form->sig_name);
dbcMsgChanged();
}
}
// EditMessageDialog
EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title, int size, QWidget *parent) : QDialog(parent) {
setWindowTitle(tr("Edit message"));
QVBoxLayout *main_layout = new QVBoxLayout(this);
QFormLayout *form_layout = new QFormLayout();
form_layout->addRow("ID", new QLabel(msg_id));
name_edit = new QLineEdit(title, this);
form_layout->addRow(tr("Name"), name_edit);
size_spin = new QSpinBox(this);
// TODO: limit the maximum?
size_spin->setMinimum(1);
size_spin->setValue(size);
form_layout->addRow(tr("Size"), size_spin);
main_layout->addLayout(form_layout);
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
main_layout->addWidget(buttonBox);
setFixedWidth(parent->width() * 0.9);
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
// ScrollArea
bool ScrollArea::eventFilter(QObject *obj, QEvent *ev) {
if (obj == widget() && ev->type() == QEvent::Resize) {
int height = widget()->height() + 4;
setMinimumHeight(height > 480 ? 480 : height);
setMaximumHeight(height);
}
return QScrollArea::eventFilter(obj, ev);
}
void ScrollArea::setWidget(QWidget *w) {
QScrollArea::setWidget(w);
w->installEventFilter(this);
}