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.

165 lines
5.3 KiB

#include "tools/cabana/signaledit.h"
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QMessageBox>
#include <QVBoxLayout>
// SignalForm
SignalForm::SignalForm(const Signal &sig, QWidget *parent) : QWidget(parent) {
QFormLayout *form_layout = new QFormLayout(this);
name = new QLineEdit(sig.name.c_str());
form_layout->addRow(tr("Name"), name);
size = new QSpinBox();
size->setValue(sig.size);
form_layout->addRow(tr("Size"), size);
msb = new QSpinBox();
msb->setValue(sig.msb);
form_layout->addRow(tr("Most significant bit"), msb);
endianness = new QComboBox();
endianness->addItems({"Little", "Big"});
endianness->setCurrentIndex(sig.is_little_endian ? 0 : 1);
form_layout->addRow(tr("Endianness"), endianness);
sign = new QComboBox();
sign->addItems({"Signed", "Unsigned"});
sign->setCurrentIndex(sig.is_signed ? 0 : 1);
form_layout->addRow(tr("sign"), sign);
factor = new QSpinBox();
factor->setValue(sig.factor);
form_layout->addRow(tr("Factor"), factor);
offset = new QSpinBox();
offset->setValue(sig.offset);
form_layout->addRow(tr("Offset"), offset);
// TODO: parse the following parameters in opendbc
unit = new QLineEdit();
form_layout->addRow(tr("Unit"), unit);
comment = new QLineEdit();
form_layout->addRow(tr("Comment"), comment);
min_val = new QSpinBox();
form_layout->addRow(tr("Minimum value"), min_val);
max_val = new QSpinBox();
form_layout->addRow(tr("Maximum value"), max_val);
val_desc = new QLineEdit();
form_layout->addRow(tr("Value descriptions"), val_desc);
}
std::optional<Signal> SignalForm::getSignal() {
Signal sig = {};
sig.name = name->text().toStdString();
sig.size = size->text().toInt();
sig.offset = offset->text().toDouble();
sig.factor = factor->text().toDouble();
sig.msb = msb->text().toInt();
sig.is_signed = sign->currentIndex() == 0;
sig.is_little_endian = endianness->currentIndex() == 0;
if (sig.is_little_endian) {
sig.lsb = sig.start_bit;
sig.msb = sig.start_bit + sig.size - 1;
} else {
sig.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(sig.start_bit) + sig.size - 1);
sig.msb = sig.start_bit;
}
return (sig.name.empty() || sig.size <= 0) ? std::nullopt : std::optional(sig);
}
// SignalEdit
SignalEdit::SignalEdit(const QString &id, const Signal &sig, const QString &color, QWidget *parent) : id(id), name_(sig.name.c_str()), QWidget(parent) {
QVBoxLayout *main_layout = new QVBoxLayout(this);
main_layout->setContentsMargins(0, 0, 0, 0);
// title
QHBoxLayout *title_layout = new QHBoxLayout();
QLabel *icon = new QLabel(">");
icon->setStyleSheet("font-weight:bold");
title_layout->addWidget(icon);
title = new ElidedLabel(this);
title->setText(sig.name.c_str());
title->setStyleSheet(QString("font-weight:bold; color:%1").arg(color));
title_layout->addWidget(title);
title_layout->addStretch();
plot_btn = new QPushButton("📈");
plot_btn->setToolTip(tr("Show Plot"));
plot_btn->setFixedSize(30, 30);
QObject::connect(plot_btn, &QPushButton::clicked, [=]() { emit parser->showPlot(id, name_); });
title_layout->addWidget(plot_btn);
main_layout->addLayout(title_layout);
edit_container = new QWidget(this);
QVBoxLayout *v_layout = new QVBoxLayout(edit_container);
form = new SignalForm(sig, this);
v_layout->addWidget(form);
QHBoxLayout *h = new QHBoxLayout();
remove_btn = new QPushButton(tr("Remove Signal"));
h->addWidget(remove_btn);
h->addStretch();
QPushButton *save_btn = new QPushButton(tr("Save"));
h->addWidget(save_btn);
v_layout->addLayout(h);
edit_container->setVisible(false);
main_layout->addWidget(edit_container);
QObject::connect(remove_btn, &QPushButton::clicked, this, &SignalEdit::remove);
QObject::connect(save_btn, &QPushButton::clicked, this, &SignalEdit::save);
QObject::connect(title, &ElidedLabel::clicked, [=]() {
edit_container->isVisible() ? edit_container->hide() : edit_container->show();
icon->setText(edit_container->isVisible() ? "" : ">");
});
}
void SignalEdit::save() {
if (auto sig = const_cast<Signal *>(parser->getSig(id, name_))) {
if (auto s = form->getSignal()) {
*sig = *s;
// TODO: reset the chart for sig
}
}
}
void SignalEdit::remove() {
QMessageBox msgbox;
msgbox.setText(tr("Remove signal"));
msgbox.setInformativeText(tr("Are you sure you want to remove signal '%1'").arg(name_));
msgbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgbox.setDefaultButton(QMessageBox::Cancel);
if (msgbox.exec()) {
parser->removeSignal(id, name_);
deleteLater();
}
}
// AddSignalDialog
AddSignalDialog::AddSignalDialog(const QString &id, QWidget *parent) : QDialog(parent) {
setWindowTitle(tr("Add signal to %1").arg(parser->getMsg(id)->name.c_str()));
QVBoxLayout *main_layout = new QVBoxLayout(this);
Signal sig = {.name = "untitled"};
auto form = new SignalForm(sig, this);
main_layout->addWidget(form);
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
main_layout->addWidget(buttonBox);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
connect(buttonBox, &QDialogButtonBox::accepted, [=]() {
if (auto msg = const_cast<Msg *>(parser->getMsg(id))) {
if (auto signal = form->getSignal()) {
msg->sigs.push_back(*signal);
}
}
QDialog::accept();
});
}