Files
MoreTore/frogpilot/ui/qt/offroad/vehicle_settings.cc
T
2026-02-13 00:20:57 -07:00

282 lines
12 KiB
C++

#include "frogpilot/ui/qt/offroad/vehicle_settings.h"
FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent, bool forceOpen) : FrogPilotListWidget(parent), parent(parent) {
forceOpenDescriptions = forceOpen;
QStackedLayout *vehiclesLayout = new QStackedLayout();
addItem(vehiclesLayout);
FrogPilotListWidget *settingsList = new FrogPilotListWidget(this);
ScrollView *vehiclesPanel = new ScrollView(settingsList, this);
vehiclesLayout->addWidget(vehiclesPanel);
FrogPilotListWidget *gmList = new FrogPilotListWidget(this);
FrogPilotListWidget *hkgList = new FrogPilotListWidget(this);
FrogPilotListWidget *subaruList = new FrogPilotListWidget(this);
FrogPilotListWidget *toyotaList = new FrogPilotListWidget(this);
FrogPilotListWidget *vehicleInfoList = new FrogPilotListWidget(this);
ScrollView *gmPanel = new ScrollView(gmList, this);
ScrollView *hkgPanel = new ScrollView(hkgList, this);
ScrollView *subaruPanel = new ScrollView(subaruList, this);
ScrollView *toyotaPanel = new ScrollView(toyotaList, this);
ScrollView *vehicleInfoPanel = new ScrollView(vehicleInfoList, this);
vehiclesLayout->addWidget(gmPanel);
vehiclesLayout->addWidget(hkgPanel);
vehiclesLayout->addWidget(subaruPanel);
vehiclesLayout->addWidget(toyotaPanel);
vehiclesLayout->addWidget(vehicleInfoPanel);
std::vector<std::tuple<QString, QString, QString, QString>> vehicleToggles {
{"GMToggles", tr("General Motors Settings"), tr("<b>FrogPilot features for General Motors vehicles.</b>"), ""},
{"VoltSNG", tr("Stop-and-Go Hack"), tr("<b>Force stop-and-go</b> on the 2017 Chevy Volt."), ""},
{"HKGToggles", tr("Hyundai/Kia/Genesis Settings"), tr("<b>FrogPilot features for Genesis, Hyundai, and Kia vehicles.</b>"), ""},
{"TacoTuneHacks", tr("\"Taco Bell Run\" Torque Hack"), tr("<b>The steering torque hack from comma's 2022 \"Taco Bell Run\".</b> Designed to increase steering torque at low speeds for left and right turns."), ""},
{"SubaruToggles", tr("Subaru Settings"), tr("<b>FrogPilot features for Subaru vehicles.</b>"), ""},
{"SubaruSNG", tr("Stop and Go"), tr("Stop and go for supported Subaru vehicles."), ""},
{"ToyotaToggles", tr("Toyota/Lexus Settings"), tr("<b>FrogPilot features for Lexus and Toyota vehicles.</b>"), ""},
{"ToyotaDoors", tr("Automatically Lock/Unlock Doors"), tr("<b>Automatically lock/unlock doors</b> when shifting in and out of drive."), ""},
{"ClusterOffset", tr("Dashboard Speed Offset"), tr("<b>The speed offset openpilot uses to match the speed on the dashboard display.</b>"), ""},
{"FrogsGoMoosTweak", tr("FrogsGoMoo's Personal Tweaks"), tr("<b>Personal tweaks by FrogsGoMoo for quicker acceleration and smoother braking.</b>"), ""},
{"LockDoorsTimer", tr("Lock Doors On Ignition Off After"), tr("<b>Automatically lock the doors on ignition off</b> when no one is detected in the front seats."), ""},
{"SNGHack", tr("Stop-and-Go Hack"), tr("<b>Force stop-and-go</b> on Lexus/Toyota vehicles without stock stop-and-go functionality."), ""},
{"VehicleInfo", tr("Vehicle Info"), tr("<b>Information about your vehicle in regards to openpilot support and functionality.</b>"), ""},
{"HardwareDetected", tr("3rd Party Hardware Detected"), tr("<b>Detected 3rd party hardware.</b>"), ""},
{"BlindSpotSupport", tr("Blind Spot Support"), tr("<b>Does openpilot use the vehicle's blind spot data?</b>"), ""},
{"PedalSupport", tr("comma Pedal Support"), tr("<b>Does your vehicle support the \"comma pedal\"?</b>"), ""},
{"OpenpilotLongitudinal", tr("openpilot Longitudinal Support"), tr("<b>Can openpilot control the vehicle's acceleration and braking?</b>"), ""},
{"RadarSupport", tr("Radar Support"), tr("<b>Does openpilot use the vehicle's radar data</b> alongside the device's camera for tracking lead vehicles?"), ""},
{"SDSUSupport", tr("SDSU Support"), tr("<b>Does your vehicle support \"SDSUs\"?</b>"), ""},
{"SNGSupport", tr("Stop-and-Go Support"), tr("<b>Does your vehicle support stop-and-go driving?</b>"), ""}
};
for (const auto &[param, title, desc, icon] : vehicleToggles) {
AbstractControl *vehicleToggle;
if (param == "GMToggles") {
ButtonControl *gmButton = new ButtonControl(title, tr("MANAGE"), desc);
QObject::connect(gmButton, &ButtonControl::clicked, [vehiclesLayout, gmPanel, this]() {
openDescriptions(forceOpenDescriptions, toggles);
vehiclesLayout->setCurrentWidget(gmPanel);
});
vehicleToggle = gmButton;
} else if (param == "HKGToggles") {
ButtonControl *hkgButton = new ButtonControl(title, tr("MANAGE"), desc);
QObject::connect(hkgButton, &ButtonControl::clicked, [vehiclesLayout, hkgPanel, this]() {
openDescriptions(forceOpenDescriptions, toggles);
vehiclesLayout->setCurrentWidget(hkgPanel);
});
vehicleToggle = hkgButton;
} else if (param == "SubaruToggles") {
ButtonControl *subaruButton = new ButtonControl(title, tr("MANAGE"), desc);
QObject::connect(subaruButton, &ButtonControl::clicked, [vehiclesLayout, subaruPanel, this]() {
openDescriptions(forceOpenDescriptions, toggles);
vehiclesLayout->setCurrentWidget(subaruPanel);
});
vehicleToggle = subaruButton;
} else if (param == "ToyotaToggles") {
ButtonControl *toyotaButton = new ButtonControl(title, tr("MANAGE"), desc);
QObject::connect(toyotaButton, &ButtonControl::clicked, [vehiclesLayout, toyotaPanel, this]() {
openDescriptions(forceOpenDescriptions, toggles);
vehiclesLayout->setCurrentWidget(toyotaPanel);
});
vehicleToggle = toyotaButton;
} else if (param == "ToyotaDoors") {
std::vector<QString> lockToggles{"LockDoors", "UnlockDoors"};
std::vector<QString> lockToggleNames{tr("Lock"), tr("Unlock")};
vehicleToggle = new FrogPilotButtonToggleControl(param, title, desc, icon, lockToggles, lockToggleNames);
} else if (param == "LockDoorsTimer") {
std::map<float, QString> autoLockLabels;
for (int i = 0; i <= 300; ++i) {
autoLockLabels[i] = i == 0 ? tr("Never") : QString::number(i) + tr(" seconds");
}
vehicleToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 300, QString(), autoLockLabels, 5);
} else if (param == "ClusterOffset") {
std::vector<QString> clusterOffsetButton{"Reset"};
FrogPilotParamValueButtonControl *clusterOffsetToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 1.000, 1.050, "x", std::map<float, QString>(), 0.001, false, {}, clusterOffsetButton, false, false);
QObject::connect(clusterOffsetToggle, &FrogPilotParamValueButtonControl::buttonClicked, [clusterOffsetToggle, this]() {
params.putFloat("ClusterOffset", std::stof(params.getKeyDefaultValue("ClusterOffset").value()));
clusterOffsetToggle->refresh();
});
vehicleToggle = clusterOffsetToggle;
} else if (param == "VehicleInfo") {
ButtonControl *VehicleInfoButton = new ButtonControl(title, tr("VIEW"), desc);
QObject::connect(VehicleInfoButton, &ButtonControl::clicked, [vehiclesLayout, vehicleInfoPanel, this]() {
openDescriptions(forceOpenDescriptions, toggles);
vehiclesLayout->setCurrentWidget(vehicleInfoPanel);
});
vehicleToggle = VehicleInfoButton;
} else if (vehicleInfoKeys.contains(param)) {
vehicleToggle = new LabelControl(title, "", desc);
} else {
vehicleToggle = new ParamControl(param, title, desc, icon);
}
toggles[param] = vehicleToggle;
if (gmKeys.contains(param)) {
gmList->addItem(vehicleToggle);
} else if (hkgKeys.contains(param)) {
hkgList->addItem(vehicleToggle);
} else if (subaruKeys.contains(param)) {
subaruList->addItem(vehicleToggle);
} else if (toyotaKeys.contains(param)) {
toyotaList->addItem(vehicleToggle);
} else if (vehicleInfoKeys.contains(param)) {
vehicleInfoList->addItem(vehicleToggle);
} else {
settingsList->addItem(vehicleToggle);
parentKeys.insert(param);
}
if (ButtonControl *buttonControl = qobject_cast<ButtonControl*>(vehicleToggle)) {
QObject::connect(buttonControl, &ButtonControl::clicked, this, &FrogPilotVehiclesPanel::openSubPanel);
}
QObject::connect(vehicleToggle, &AbstractControl::hideDescriptionEvent, [this]() {
update();
});
QObject::connect(vehicleToggle, &AbstractControl::showDescriptionEvent, [this]() {
update();
});
}
static_cast<FrogPilotParamValueControl*>(toggles["LockDoorsTimer"])->setWarning("<b>Warning:</b> openpilot can't detect if keys are still inside the car, so ensure you have a spare key to prevent accidental lockouts!");
QSet<QString> rebootKeys = {"TacoTuneHacks"};
for (const QString &key : rebootKeys) {
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, [key, this](bool state) {
if (started) {
if (key == "TacoTuneHacks" && state) {
if (FrogPilotConfirmationDialog::toggleReboot(this)) {
Hardware::reboot();
}
} else if (key != "TacoTuneHacks") {
if (FrogPilotConfirmationDialog::toggleReboot(this)) {
Hardware::reboot();
}
}
}
});
}
openDescriptions(forceOpenDescriptions, toggles);
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [vehiclesLayout, vehiclesPanel, this] {
if (forceOpenDescriptions) {
openDescriptions(forceOpenDescriptions, toggles);
}
vehiclesLayout->setCurrentWidget(vehiclesPanel);
});
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotVehiclesPanel::updateState);
}
void FrogPilotVehiclesPanel::showEvent(QShowEvent *event) {
if (forceOpenDescriptions) {
}
QStringList detected;
if (parent->hasPedal) detected << "comma Pedal";
if (parent->hasSDSU) detected << "SDSU";
if (parent->hasZSS) detected << "ZSS";
static_cast<LabelControl*>(toggles["HardwareDetected"])->setText(detected.isEmpty() ? tr("None") : detected.join(", "));
static_cast<LabelControl*>(toggles["BlindSpotSupport"])->setText(parent->hasBSM ? tr("Yes") : tr("No"));
static_cast<LabelControl*>(toggles["OpenpilotLongitudinal"])->setText(parent->hasOpenpilotLongitudinal ? tr("Yes") : tr("No"));
static_cast<LabelControl*>(toggles["PedalSupport"])->setText(parent->canUsePedal ? tr("Yes") : tr("No"));
static_cast<LabelControl*>(toggles["RadarSupport"])->setText(parent->hasRadar ? tr("Yes") : tr("No"));
static_cast<LabelControl*>(toggles["SDSUSupport"])->setText(parent->canUseSDSU ? tr("Yes") : tr("No"));
static_cast<LabelControl*>(toggles["SNGSupport"])->setText(parent->hasSNG ? tr("Yes") : tr("No"));
updateToggles();
}
void FrogPilotVehiclesPanel::updateState(const UIState &s) {
if (!isVisible()) {
return;
}
started = s.scene.started;
}
void FrogPilotVehiclesPanel::updateToggles() {
for (auto &[key, toggle] : toggles) {
if (parentKeys.contains(key)) {
toggle->setVisible(false);
}
}
for (auto &[key, toggle] : toggles) {
if (parentKeys.contains(key)) {
continue;
}
bool setVisible = parent->tuningLevel >= parent->frogpilotToggleLevels[key].toDouble();
if (gmKeys.contains(key)) {
setVisible &= parent->isGM;
} else if (hkgKeys.contains(key)) {
setVisible &= parent->isHKG;
} else if (subaruKeys.contains(key)) {
setVisible &= parent->isSubaru;
} else if (toyotaKeys.contains(key)) {
setVisible &= parent->isToyota;
} else if (vehicleInfoKeys.contains(key)) {
setVisible = true;
}
if (longitudinalKeys.contains(key)) {
setVisible &= parent->hasOpenpilotLongitudinal;
}
if (key == "SNGHack") {
setVisible &= !parent->hasSNG;
}
else if (key == "SubaruSNG") {
setVisible &= parent->hasSNG;
}
else if (key == "TacoTuneHacks") {
setVisible &= parent->isHKGCanFd;
}
else if (key == "VoltSNG") {
setVisible &= parent->isVolt && !parent->hasSNG;
}
toggle->setVisible(setVisible);
if (setVisible) {
if (gmKeys.contains(key)) {
toggles["GMToggles"]->setVisible(true);
} else if (hkgKeys.contains(key)) {
toggles["HKGToggles"]->setVisible(true);
} else if (subaruKeys.contains(key)) {
toggles["SubaruToggles"]->setVisible(true);
} else if (toyotaKeys.contains(key)) {
toggles["ToyotaToggles"]->setVisible(true);
} else if (vehicleInfoKeys.contains(key)) {
toggles["VehicleInfo"]->setVisible(true);
}
}
}
openDescriptions(forceOpenDescriptions, toggles);
update();
}