#include "selfdrive/frogpilot/ui/control_settings.h" FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) { const std::vector> controlToggles { {"AlwaysOnLateral", "Always on Lateral", "Maintain openpilot lateral control when the brake or gas pedals are used.\n\nDeactivation occurs only through the 'Cruise Control' button.", "../frogpilot/assets/toggle_icons/icon_always_on_lateral.png"}, {"LateralTune", "Lateral Tuning", "Modify openpilot's steering behavior.", "../frogpilot/assets/toggle_icons/icon_lateral_tune.png"}, {"LongitudinalTune", "Longitudinal Tuning", "Modify openpilot's acceleration and braking behavior.", "../frogpilot/assets/toggle_icons/icon_longitudinal_tune.png"}, {"AccelerationProfile", "Acceleration Profile", "Change the acceleration rate to be either sporty or eco-friendly.", ""}, {"DecelerationProfile", "Deceleration Profile", "Change the deceleration rate to be either sporty or eco-friendly.", ""}, {"AggressiveAcceleration", "Aggressive Acceleration With Lead", "Increase acceleration aggressiveness when following a lead vehicle from a stop.", ""}, {"QOLControls", "Quality of Life", "Miscellaneous quality of life changes to improve your overall openpilot experience.", "../frogpilot/assets/toggle_icons/quality_of_life.png"}, }; for (const auto &[param, title, desc, icon] : controlToggles) { ParamControl *toggle; if (param == "AlwaysOnLateral") { std::vector aolToggles{"AlwaysOnLateralMain"}; std::vector aolToggleNames{tr("Enable On Cruise Main")}; toggle = new FrogPilotParamToggleControl(param, title, desc, icon, aolToggles, aolToggleNames); QObject::connect(static_cast(toggle), &FrogPilotParamToggleControl::buttonClicked, [this](const bool checked) { if (checked) { FrogPilotConfirmationDialog::toggleAlert("WARNING: This is very experimental and isn't guaranteed to work. If you run into any issues, please report it in the FrogPilot Discord!", "I understand the risks.", this); } if (started) { if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { Hardware::soft_reboot(); } } }); } else if (param == "LateralTune") { FrogPilotParamManageControl *lateralTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); QObject::connect(lateralTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { parentToggleClicked(); for (auto &[key, toggle] : toggles) { toggle->setVisible(lateralTuneKeys.find(key.c_str()) != lateralTuneKeys.end()); } }); toggle = lateralTuneToggle; } else if (param == "LongitudinalTune") { FrogPilotParamManageControl *longitudinalTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); QObject::connect(longitudinalTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { parentToggleClicked(); for (auto &[key, toggle] : toggles) { toggle->setVisible(longitudinalTuneKeys.find(key.c_str()) != longitudinalTuneKeys.end()); } }); toggle = longitudinalTuneToggle; } else if (param == "AccelerationProfile") { std::vector profileOptions{tr("Standard"), tr("Eco"), tr("Sport"), tr("Sport+")}; FrogPilotButtonParamControl *profileSelection = new FrogPilotButtonParamControl(param, title, desc, icon, profileOptions); toggle = profileSelection; QObject::connect(static_cast(toggle), &FrogPilotButtonParamControl::buttonClicked, [this](int id) { if (id == 3) { FrogPilotConfirmationDialog::toggleAlert("WARNING: This maxes out openpilot's acceleration from 2.0 m/s to 4.0 m/s and may cause oscillations when accelerating!", "I understand the risks.", this); } }); } else if (param == "DecelerationProfile") { std::vector profileOptions{tr("Standard"), tr("Eco"), tr("Sport")}; FrogPilotButtonParamControl *profileSelection = new FrogPilotButtonParamControl(param, title, desc, icon, profileOptions); toggle = profileSelection; } else if (param == "QOLControls") { FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { parentToggleClicked(); for (auto &[key, toggle] : toggles) { toggle->setVisible(qolKeys.find(key.c_str()) != qolKeys.end()); } }); toggle = qolToggle; } else { toggle = new ParamControl(param, title, desc, icon, this); } addItem(toggle); toggles[param.toStdString()] = toggle; QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() { updateToggles(); }); QObject::connect(static_cast(toggle), &FrogPilotButtonParamControl::buttonClicked, [this]() { updateToggles(); }); QObject::connect(static_cast(toggle), &FrogPilotParamValueControl::valueChanged, [this]() { updateToggles(); }); QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() { update(); }); QObject::connect(static_cast(toggle), &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { update(); }); } std::set rebootKeys = {"AlwaysOnLateral"}; for (const std::string &key : rebootKeys) { QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this, key]() { if (started) { if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { Hardware::soft_reboot(); } } }); } QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotControlsPanel::hideSubToggles); QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotControlsPanel::hideSubToggles); QObject::connect(parent, &SettingsWindow::closeSubParentToggle, this, &FrogPilotControlsPanel::hideSubSubToggles); QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotControlsPanel::updateMetric); QObject::connect(uiState(), &UIState::offroadTransition, this, &FrogPilotControlsPanel::updateCarToggles); QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotControlsPanel::updateState); hideSubToggles(); updateMetric(); } void FrogPilotControlsPanel::updateState(const UIState &s) { started = s.scene.started; } void FrogPilotControlsPanel::updateToggles() { std::thread([this]() { paramsMemory.putBool("FrogPilotTogglesUpdated", true); std::this_thread::sleep_for(std::chrono::seconds(1)); paramsMemory.putBool("FrogPilotTogglesUpdated", false); }).detach(); } void FrogPilotControlsPanel::updateCarToggles() { } void FrogPilotControlsPanel::updateMetric() { bool previousIsMetric = isMetric; isMetric = params.getBool("IsMetric"); if (isMetric != previousIsMetric) { double distanceConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT; double speedConversion = isMetric ? MILE_TO_KM : KM_TO_MILE; } if (isMetric) { } else { } previousIsMetric = isMetric; } void FrogPilotControlsPanel::parentToggleClicked() { openParentToggle(); } void FrogPilotControlsPanel::subParentToggleClicked() { openSubParentToggle(); } void FrogPilotControlsPanel::hideSubToggles() { for (auto &[key, toggle] : toggles) { bool subToggles = conditionalExperimentalKeys.find(key.c_str()) != conditionalExperimentalKeys.end() || fireTheBabysitterKeys.find(key.c_str()) != fireTheBabysitterKeys.end() || laneChangeKeys.find(key.c_str()) != laneChangeKeys.end() || lateralTuneKeys.find(key.c_str()) != lateralTuneKeys.end() || longitudinalTuneKeys.find(key.c_str()) != longitudinalTuneKeys.end() || mtscKeys.find(key.c_str()) != mtscKeys.end() || qolKeys.find(key.c_str()) != qolKeys.end() || speedLimitControllerKeys.find(key.c_str()) != speedLimitControllerKeys.end() || visionTurnControlKeys.find(key.c_str()) != visionTurnControlKeys.end(); toggle->setVisible(!subToggles); } closeParentToggle(); } void FrogPilotControlsPanel::hideSubSubToggles() { for (auto &[key, toggle] : toggles) { bool isVisible = false; toggle->setVisible(isVisible); } closeSubParentToggle(); update(); } void FrogPilotControlsPanel::hideEvent(QHideEvent *event) { hideSubToggles(); }