Files
oscarpilot/selfdrive/frogpilot/ui/frogpilot_functions.h.org
Your Name 886ca6bde8 wip
2024-02-16 17:27:58 -06:00

662 lines
19 KiB
Org Mode

#pragma once
#include "selfdrive/ui/qt/widgets/controls.h"
class FrogPilotConfirmationDialog : public ConfirmationDialog {
Q_OBJECT
public:
explicit FrogPilotConfirmationDialog(const QString &prompt_text, const QString &confirm_text,
const QString &cancel_text, const bool rich, QWidget* parent);
static bool toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent);
static bool toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent);
static bool yesorno(const QString &prompt_text, QWidget *parent);
};
class FrogPilotListWidget : public QWidget {
Q_OBJECT
public:
explicit FrogPilotListWidget(QWidget *parent = 0) : QWidget(parent), outer_layout(this) {
outer_layout.setMargin(0);
outer_layout.setSpacing(0);
outer_layout.addLayout(&inner_layout);
inner_layout.setMargin(0);
inner_layout.setSpacing(25); // default spacing is 25
outer_layout.addStretch();
}
inline void addItem(QWidget *w) { inner_layout.addWidget(w); }
inline void addItem(QLayout *layout) { inner_layout.addLayout(layout); }
inline void setSpacing(int spacing) { inner_layout.setSpacing(spacing); }
private:
void paintEvent(QPaintEvent *) override {
QPainter p(this);
p.setPen(Qt::gray);
int visibleWidgetCount = 0;
std::vector<QRect> visibleRects;
for (int i = 0; i < inner_layout.count(); ++i) {
QWidget *widget = inner_layout.itemAt(i)->widget();
if (widget && widget->isVisible()) {
visibleWidgetCount++;
visibleRects.push_back(inner_layout.itemAt(i)->geometry());
}
}
for (int i = 0; i < visibleWidgetCount - 1; ++i) {
int bottom = visibleRects[i].bottom() + inner_layout.spacing() / 2;
p.drawLine(visibleRects[i].left() + 40, bottom, visibleRects[i].right() - 40, bottom);
}
}
QVBoxLayout outer_layout;
QVBoxLayout inner_layout;
};
class FrogPilotButtonIconControl : public AbstractControl {
Q_OBJECT
public:
FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr);
inline void setText(const QString &text) { btn.setText(text); }
inline QString text() const { return btn.text(); }
signals:
void clicked();
public slots:
void setEnabled(bool enabled) { btn.setEnabled(enabled); }
private:
QPushButton btn;
};
class FrogPilotButtonParamControl : public ParamControl {
Q_OBJECT
public:
FrogPilotButtonParamControl(const QString &param, const QString &title, const QString &desc, const QString &icon,
const std::vector<QString> &button_texts, const int minimum_button_width = 225)
: ParamControl(param, title, desc, icon) {
const QString style = R"(
QPushButton {
border-radius: 50px;
font-size: 40px;
font-weight: 500;
height:100px;
padding: 0 25 0 25;
color: #E4E4E4;
background-color: #393939;
}
QPushButton:pressed {
background-color: #4a4a4a;
}
QPushButton:checked:enabled {
background-color: #0048FF;
}
QPushButton:disabled {
color: #33E4E4E4;
}
)";
key = param.toStdString();
int value = atoi(params.get(key).c_str());
button_group = new QButtonGroup(this);
button_group->setExclusive(true);
for (size_t i = 0; i < button_texts.size(); i++) {
QPushButton *button = new QPushButton(button_texts[i], this);
button->setCheckable(true);
button->setChecked(i == value);
button->setStyleSheet(style);
button->setMinimumWidth(minimum_button_width);
hlayout->addWidget(button);
button_group->addButton(button, i);
}
QObject::connect(button_group, QOverload<int, bool>::of(&QButtonGroup::buttonToggled), [=](int id, bool checked) {
if (checked) {
params.put(key, std::to_string(id));
refresh();
emit buttonClicked(id);
}
});
toggle.hide();
}
void setEnabled(bool enable) {
for (auto btn : button_group->buttons()) {
btn->setEnabled(enable);
}
}
signals:
void buttonClicked(int id);
private:
std::string key;
Params params;
QButtonGroup *button_group;
};
class FrogPilotParamManageControl : public ParamControl {
Q_OBJECT
public:
FrogPilotParamManageControl(const QString &param, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr)
: ParamControl(param, title, desc, icon, parent),
key(param.toStdString()),
manageButton(new ButtonControl(tr(""), tr("MANAGE"), tr(""))) {
hlayout->insertWidget(hlayout->indexOf(&toggle) - 1, manageButton);
connect(this, &ToggleControl::toggleFlipped, this, [this](bool state) {
refresh();
});
connect(manageButton, &ButtonControl::clicked, this, &FrogPilotParamManageControl::manageButtonClicked);
}
void refresh() {
ParamControl::refresh();
manageButton->setVisible(params.getBool(key));
}
void showEvent(QShowEvent *event) override {
ParamControl::showEvent(event);
refresh();
}
signals:
void manageButtonClicked();
private:
std::string key;
Params params;
ButtonControl *manageButton;
};
class FrogPilotParamToggleControl : public ParamControl {
Q_OBJECT
public:
FrogPilotParamToggleControl(const QString &param, const QString &title, const QString &desc,
const QString &icon, const std::vector<QString> &button_params,
const std::vector<QString> &button_texts, QWidget *parent = nullptr,
const int minimum_button_width = 225)
: ParamControl(param, title, desc, icon, parent) {
connect(this, &ToggleControl::toggleFlipped, this, [this](bool state) {
refreshButtons(state);
});
const QString style = R"(
QPushButton {
border-radius: 50px;
font-size: 40px;
font-weight: 500;
height:100px;
padding: 0 25 0 25;
color: #E4E4E4;
background-color: #393939;
}
QPushButton:pressed {
background-color: #4a4a4a;
}
QPushButton:checked:enabled {
background-color: #0048FF;
}
QPushButton:disabled {
color: #33E4E4E4;
}
)";
button_group = new QButtonGroup(this);
button_group->setExclusive(false);
std::map<QString, bool> paramState;
for (const QString &button_param : button_params) {
paramState[button_param] = params.getBool(button_param.toStdString());
}
for (int i = 0; i < button_texts.size(); ++i) {
QPushButton *button = new QPushButton(button_texts[i], this);
button->setCheckable(true);
button->setChecked(paramState[button_params[i]]);
button->setStyleSheet(style);
button->setMinimumWidth(minimum_button_width);
button_group->addButton(button, i);
connect(button, &QPushButton::clicked, [this, button_params, i](bool checked) {
params.putBool(button_params[i].toStdString(), checked);
button_group->button(i)->setChecked(checked);
emit buttonClicked(checked);
});
hlayout->insertWidget(hlayout->indexOf(&toggle), button);
}
}
void refreshButtons(bool state) {
for (QAbstractButton *button : button_group->buttons()) {
button->setVisible(state);
}
}
signals:
void buttonClicked(const bool checked);
private:
Params params;
QButtonGroup *button_group;
};
class FrogPilotParamValueControl : public ParamControl {
Q_OBJECT
public:
FrogPilotParamValueControl(const QString &param, const QString &title, const QString &desc, const QString &icon,
const int &minValue, const int &maxValue, const std::map<int, QString> &valueLabels,
QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const int &division = 1)
: ParamControl(param, title, desc, icon, parent),
minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) {
key = param.toStdString();
valueLabel = new QLabel(this);
hlayout->addWidget(valueLabel);
QPushButton *decrementButton = createButton("-", this);
QPushButton *incrementButton = createButton("+", this);
hlayout->addWidget(decrementButton);
hlayout->addWidget(incrementButton);
connect(decrementButton, &QPushButton::clicked, this, [=]() {
updateValue(-1);
});
connect(incrementButton, &QPushButton::clicked, this, [=]() {
updateValue(1);
});
toggle.hide();
}
void updateValue(int increment) {
value = value + increment;
if (loop) {
if (value < minValue) value = maxValue;
else if (value > maxValue) value = minValue;
} else {
value = std::max(minValue, std::min(maxValue, value));
}
params.putInt(key, value);
refresh();
emit buttonPressed();
emit valueChanged(value);
}
void refresh() {
value = params.getInt(key);
QString text;
auto it = valueLabelMappings.find(value);
if (division > 1) {
text = QString::number(value / (division * 1.0), 'g');
} else {
text = it != valueLabelMappings.end() ? it->second : QString::number(value);
}
if (!labelText.isEmpty()) {
text += labelText;
}
valueLabel->setText(text);
valueLabel->setStyleSheet("QLabel { color: #E0E879; }");
}
void updateControl(int newMinValue, int newMaxValue, const QString &newLabel, int newDivision = 1) {
minValue = newMinValue;
maxValue = newMaxValue;
labelText = newLabel;
division = newDivision;
}
void showEvent(QShowEvent *event) override {
refresh();
}
signals:
void buttonPressed();
void valueChanged(int value);
private:
bool loop;
int division;
int maxValue;
int minValue;
int value;
QLabel *valueLabel;
QString labelText;
std::map<int, QString> valueLabelMappings;
std::string key;
Params params;
QPushButton *createButton(const QString &text, QWidget *parent) {
QPushButton *button = new QPushButton(text, parent);
button->setFixedSize(150, 100);
button->setAutoRepeat(true);
button->setAutoRepeatInterval(150);
button->setStyleSheet(R"(
QPushButton {
border-radius: 50px;
font-size: 50px;
font-weight: 500;
height: 100px;
padding: 0 25 0 25;
color: #E4E4E4;
background-color: #393939;
}
QPushButton:pressed {
background-color: #4a4a4a;
}
)");
return button;
}
};
class FrogPilotParamValueControlFloat : public ParamControl {
Q_OBJECT
public:
FrogPilotParamValueControlFloat(const QString &param, const QString &title, const QString &desc, const QString &icon,
const float &minValue, const float &maxValue, const std::map<int, QString> &valueLabels,
QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const float &division = 1.0f)
: ParamControl(param, title, desc, icon, parent),
minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) {
key = param.toStdString();
valueLabel = new QLabel(this);
hlayout->addWidget(valueLabel);
QPushButton *decrementButton = createButton("-", this);
QPushButton *incrementButton = createButton("+", this);
hlayout->addWidget(decrementButton);
hlayout->addWidget(incrementButton);
connect(decrementButton, &QPushButton::clicked, this, [=]() {
updateValue(-1.0f);
});
connect(incrementButton, &QPushButton::clicked, this, [=]() {
updateValue(1.0f);
});
toggle.hide();
}
void updateValue(float increment) {
value += increment * 0.1f;
if (loop) {
if (value < minValue) value = maxValue;
else if (value > maxValue) value = minValue;
} else {
value = std::max(minValue, std::min(maxValue, value));
}
params.putFloat(key, value);
refresh();
emit buttonPressed();
emit valueChanged(value);
}
void refresh() {
value = params.getFloat(key);
QString text;
auto it = valueLabelMappings.find(value);
if (division > 0.1f) {
text = QString::number(value, 'f', 1);
} else {
text = it != valueLabelMappings.end() ? it->second : QString::number(value, 'f', 1);
}
if (!labelText.isEmpty()) {
text += labelText;
}
valueLabel->setText(text);
valueLabel->setStyleSheet("QLabel { color: #E0E879; }");
}
void updateControl(float newMinValue, float newMaxValue, const QString &newLabel, float newDivision = 1.0f) {
minValue = newMinValue;
maxValue = newMaxValue;
labelText = newLabel;
division = newDivision;
}
void showEvent(QShowEvent *event) override {
refresh();
}
signals:
void buttonPressed();
void valueChanged(float value);
private:
bool loop;
float division;
float maxValue;
float minValue;
float value;
QLabel *valueLabel;
QString labelText;
std::map<int, QString> valueLabelMappings;
std::string key;
Params params;
QPushButton *createButton(const QString &text, QWidget *parent) {
QPushButton *button = new QPushButton(text, parent);
button->setFixedSize(150, 100);
button->setAutoRepeat(true);
button->setAutoRepeatInterval(150);
button->setStyleSheet(R"(
QPushButton {
border-radius: 50px;
font-size: 50px;
font-weight: 500;
height: 100px;
padding: 0 25 0 25;
color: #E4E4E4;
background-color: #393939;
}
QPushButton:pressed {
background-color: #4a4a4a;
}
)");
return button;
}
};
class FrogPilotDualParamControl : public QFrame {
Q_OBJECT
public:
FrogPilotDualParamControl(ParamControl *control1, ParamControl *control2, QWidget *parent = nullptr, bool split=false)
: QFrame(parent) {
QHBoxLayout *hlayout = new QHBoxLayout(this);
control1->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
control1->setMaximumWidth(split ? 800 : 700);
control2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
control2->setMaximumWidth(800);
hlayout->addWidget(control1);
hlayout->addWidget(control2);
}
};
class FrogPilotParamValueToggleControl : public ParamControl {
Q_OBJECT
public:
FrogPilotParamValueToggleControl(const QString &param, const QString &title, const QString &desc, const QString &icon,
const int &minValue, const int &maxValue, const std::map<int, QString> &valueLabels,
QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const int &division = 1,
const std::vector<QString> &button_params = std::vector<QString>(), const std::vector<QString> &button_texts = std::vector<QString>(),
const int minimum_button_width = 225)
: ParamControl(param, title, desc, icon, parent),
minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) {
key = param.toStdString();
const QString style = R"(
QPushButton {
border-radius: 50px;
font-size: 40px;
font-weight: 500;
height:100px;
padding: 0 25 0 25;
color: #E4E4E4;
background-color: #393939;
}
QPushButton:pressed {
background-color: #4a4a4a;
}
QPushButton:checked:enabled {
background-color: #0048FF;
}
QPushButton:disabled {
color: #33E4E4E4;
}
)";
button_group = new QButtonGroup(this);
button_group->setExclusive(false);
std::map<QString, bool> paramState;
for (const QString &button_param : button_params) {
paramState[button_param] = params.getBool(button_param.toStdString());
}
for (int i = 0; i < button_texts.size(); ++i) {
QPushButton *button = new QPushButton(button_texts[i], this);
button->setCheckable(true);
button->setChecked(paramState[button_params[i]]);
button->setStyleSheet(style);
button->setMinimumWidth(minimum_button_width);
button_group->addButton(button, i);
connect(button, &QPushButton::clicked, [this, button_params, i](bool checked) {
params.putBool(button_params[i].toStdString(), checked);
button_group->button(i)->setChecked(checked);
});
hlayout->addWidget(button);
}
valueLabel = new QLabel(this);
hlayout->addWidget(valueLabel);
QPushButton *decrementButton = createButton("-", this);
QPushButton *incrementButton = createButton("+", this);
hlayout->addWidget(decrementButton);
hlayout->addWidget(incrementButton);
connect(decrementButton, &QPushButton::clicked, this, [=]() {
updateValue(-1);
});
connect(incrementButton, &QPushButton::clicked, this, [=]() {
updateValue(1);
});
toggle.hide();
}
void updateValue(int increment) {
value = value + increment;
if (loop) {
if (value < minValue) value = maxValue;
else if (value > maxValue) value = minValue;
} else {
value = std::max(minValue, std::min(maxValue, value));
}
params.putInt(key, value);
refresh();
emit buttonPressed();
emit valueChanged(value);
}
void refresh() {
value = params.getInt(key);
QString text;
auto it = valueLabelMappings.find(value);
if (division > 1) {
text = QString::number(value / (division * 1.0), 'g');
} else {
text = it != valueLabelMappings.end() ? it->second : QString::number(value);
}
if (!labelText.isEmpty()) {
text += labelText;
}
valueLabel->setText(text);
valueLabel->setStyleSheet("QLabel { color: #E0E879; }");
}
void updateControl(int newMinValue, int newMaxValue, const QString &newLabel, int newDivision) {
minValue = newMinValue;
maxValue = newMaxValue;
labelText = newLabel;
division = newDivision;
}
void showEvent(QShowEvent *event) override {
refresh();
}
signals:
void buttonPressed();
void valueChanged(int value);
private:
bool loop;
int division;
int maxValue;
int minValue;
int value;
QButtonGroup *button_group;
QLabel *valueLabel;
QString labelText;
std::map<int, QString> valueLabelMappings;
std::string key;
Params params;
QPushButton *createButton(const QString &text, QWidget *parent) {
QPushButton *button = new QPushButton(text, parent);
button->setFixedSize(150, 100);
button->setAutoRepeat(true);
button->setAutoRepeatInterval(150);
button->setStyleSheet(R"(
QPushButton {
border-radius: 50px;
font-size: 50px;
font-weight: 500;
height: 100px;
padding: 0 25 0 25;
color: #E4E4E4;
background-color: #393939;
}
QPushButton:pressed {
background-color: #4a4a4a;
}
)");
return button;
}
};
void setDefaultParams();