diff --git a/newmenus b/newmenus index 4e20472..79cdbd3 100644 --- a/newmenus +++ b/newmenus @@ -1,9 +1,38 @@ Device -Network -Driving -Visuals -Services -Navigation +Network & Services +- Standard Wifi +- Metered Wifi +- SSH +- Web companion + - Route logging + - Dashcam upload + - Live driver monitoring / fleet mgr +- Weather + - Display alerts + - API key +- Random facts + - Get random fact about area driver is in (spoken, ai) +Basic +- Enable openpilot / Dashcam only +- Always on Lateral: True / False +- Longitudial Control scheme: Stock / Stock+SLC / OpenPilot +- Experimental Mode: never / on curves / always +- Longitudial Control scheme: Stock / Stock+SLC / Experimental +- Speed Limit offset customization: +- Lane Change Assist: Disabled / Nudge Wheel +- Driver Attention Monitoring: Strict / Relaxed +- Hands On Wheel: Always / At Dusk / 2+ hrs driving Advanced + Navigation +Customization +Extras + - Window down notification + - Set climate on drive mode +Fleet Mgr Notes: + - Seperate fork for fleet mgr + - Self drive preferences + - Distance traveled + - SLC + - Driver camera diff --git a/selfdrive/frogpilot/ui/control_settings.cc.org b/selfdrive/frogpilot/ui/control_settings.cc.org new file mode 100644 index 0000000..da081a6 --- /dev/null +++ b/selfdrive/frogpilot/ui/control_settings.cc.org @@ -0,0 +1,559 @@ +#include "selfdrive/frogpilot/ui/control_settings.h" +#include "selfdrive/ui/ui.h" + +FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) { + const std::vector> controlToggles { + {"AdjustablePersonalities", "Adjustable Personalities", "Use the 'Distance' button on the steering wheel or the onroad UI to switch between openpilot's driving personalities.\n\n1 bar = Aggressive\n2 bars = Standard\n3 bars = Relaxed", "../frogpilot/assets/toggle_icons/icon_distance.png"}, + {"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"}, + + {"ConditionalExperimental", "Conditional Experimental Mode", "Automatically switches to 'Experimental Mode' under predefined conditions.", "../frogpilot/assets/toggle_icons/icon_conditional.png"}, + {"CECurves", "Curve Detected Ahead", "Switch to 'Experimental Mode' when a curve is detected.", ""}, + {"CENavigation", "Navigation Based", "Switch to 'Experimental Mode' based on navigation data. (i.e. Intersections, stop signs, etc.)", ""}, + {"CESlowerLead", "Slower Lead Detected Ahead", "Switch to 'Experimental Mode' when a slower lead vehicle is detected ahead.", ""}, + // {"CEStopLights", "Stop Lights and Stop Signs", "Switch to 'Experimental Mode' when a stop light or stop sign is detected.", ""}, + {"CESignal", "Turn Signal When Below Highway Speeds", "Switch to 'Experimental Mode' when using turn signals below highway speeds to help assit with turns.", ""}, + {"CSLCEnabled", "Custom Stock Longitudinal Control", "Use cruise control button spamming to adjust cruise set speed based on MTSC, VTSC, and SLC", "../frogpilot/assets/toggle_icons/icon_custom.png"}, + {"CustomPersonalities", "Custom Driving Personalities", "Customize the driving personality profiles to your driving style.", "../frogpilot/assets/toggle_icons/icon_custom.png"}, + {"DeviceShutdown", "Device Shutdown Timer", "Configure the timer for automatic device shutdown when offroad conserving energy and preventing battery drain.", "../frogpilot/assets/toggle_icons/icon_time.png"}, + {"ExperimentalModeActivation", "Experimental Mode Via", "Toggle Experimental Mode by double-clicking the 'Lane Departure'/'LKAS' button or double tapping screen.\n\nOverrides 'Conditional Experimental Mode'.", "../assets/img_experimental_white.svg"}, + + {"FireTheBabysitter", "Fire the Babysitter", "Deactivate some of openpilot's 'Babysitter' protocols for more user autonomy.", "../frogpilot/assets/toggle_icons/icon_babysitter.png"}, + {"NoLogging", "Disable All Logging", "Turn off all data tracking to enhance privacy or reduce thermal load.\n\nWARNING: This action will prevent drive recording and data cannot be recovered!", ""}, + {"MuteDoor", "Mute Door Open Alert", "Disable alerts for open doors.", ""}, + {"MuteDM", "Mute Driver Monitoring", "Disable driver monitoring.", ""}, + {"MuteOverheated", "Mute Overheated System Alert", "Disable alerts for the device being overheated.", ""}, + {"MuteSeatbelt", "Mute Seatbelt Unlatched Alert", "Disable alerts for unlatched seatbelts.", ""}, + {"OfflineMode", "Offline Mode", "Allow the device to be offline indefinitely.", ""}, + + {"LateralTune", "Lateral Tuning", "Modify openpilot's steering behavior.", "../frogpilot/assets/toggle_icons/icon_lateral_tune.png"}, + {"AverageCurvature", "Average Desired Curvature", "Use Pfeiferj's distance-based curvature adjustment for improved curve handling.", ""}, + {"NNFF", "NNFF - Neural Network Feedforward", "Use Twilsonco's Neural Network Feedforward for enhanced precision in lateral control.", ""}, + {"SteerRatio", steerRatioStock != 0 ? QString("Steer Ratio (Default: %1)").arg(steerRatioStock, 0, 'f', 2) : "Steer Ratio", "Set a custom steer ratio for your vehicle controls.", ""}, + + {"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.", ""}, + {"AggressiveAcceleration", "Aggressive Acceleration With Lead", "Increase acceleration aggressiveness when following a lead vehicle from a stop.", ""}, + {"StoppingDistance", "Increased Stopping Distance", "Increase the stopping distance for a more comfortable stop.", ""}, + {"SmoothBraking", "Smoother Braking Behind Lead", "Smoothen out the braking behavior when approaching slower vehicles.", ""}, + + {"Model", "Model Selector", "Choose your preferred openpilot model.", "../assets/offroad/icon_calibration.png"}, + + {"MTSCEnabled", "Map Turn Speed Control", "Slow down for anticipated curves detected by your downloaded maps.", "../frogpilot/assets/toggle_icons/icon_speed_map.png"}, + + {"NudgelessLaneChange", "Nudgeless Lane Change", "Enable lane changes without manual steering input.", "../frogpilot/assets/toggle_icons/icon_lane.png"}, + {"LaneChangeTime", "Lane Change Timer", "Specify a delay before executing a nudgeless lane change.", ""}, + {"LaneDetection", "Lane Detection", "Block nudgeless lane changes when a lane isn't detected.", ""}, + {"OneLaneChange", "One Lane Change Per Signal", "Limit to one nudgeless lane change per turn signal activation.", ""}, + + {"QOLControls", "Quality of Life", "Miscellaneous quality of life changes to improve your overall openpilot experience.", "../frogpilot/assets/toggle_icons/quality_of_life.png"}, + {"DisableOnroadUploads", "Disable Onroad Uploads", "Prevent large data uploads when onroad.", ""}, + {"HigherBitrate", "Higher Bitrate Recording", "Increases the quality of the footage uploaded to comma connect.", ""}, + {"PauseLateralOnSignal", "Pause Lateral On Turn Signal Below", "Temporarily disable lateral control during turn signal use below the set speed.", ""}, + {"ReverseCruise", "Reverse Cruise Increase", "Reverses the 'long press' functionality when increasing the max set speed. Useful to increase the max speed quickly.", ""}, + {"SetSpeedOffset", "Set Speed Offset", "Set an offset for your desired set speed.", ""}, + + {"SpeedLimitController", "Speed Limit Controller", "Automatically adjust vehicle speed to match speed limits using 'Open Street Map's, 'Navigate On openpilot', or your car's dashboard (TSS2 Toyotas only).", "../assets/offroad/icon_speed_limit.png"}, + {"Offset1", "Speed Limit Offset (0-34 mph)", "Speed limit offset for speed limits between 0-34 mph.", ""}, + {"Offset2", "Speed Limit Offset (35-54 mph)", "Speed limit offset for speed limits between 35-54 mph.", ""}, + {"Offset3", "Speed Limit Offset (55-64 mph)", "Speed limit offset for speed limits between 55-64 mph.", ""}, + {"Offset4", "Speed Limit Offset (65-99 mph)", "Speed limit offset for speed limits between 65-99 mph.", ""}, + {"SLCFallback", "Fallback Method", "Choose your fallback method for when there are no speed limits currently being obtained from Navigation, OSM, and the car's dashboard.", ""}, + {"SLCOverride", "Override Method", "Choose your preferred method to override the current speed limit.", ""}, + {"SLCPriority", "Priority Order", "Determine the priority order for what speed limits to use.", ""}, + + {"TurnDesires", "Use Turn Desires", "Use turn desires for enhanced precision in turns below the minimum lane change speed.", "../assets/navigation/direction_continue_right.png"}, + + {"VisionTurnControl", "Vision Turn Speed Controller", "Slow down for detected road curvature for smoother curve handling.", "../frogpilot/assets/toggle_icons/icon_vtc.png"}, + {"CurveSensitivity", "Curve Detection Sensitivity", "Set curve detection sensitivity. Higher values prompt earlier responses, lower values lead to smoother but later reactions.", ""}, + {"TurnAggressiveness", "Turn Speed Aggressiveness", "Set turn speed aggressiveness. Higher values result in faster turns, lower values yield gentler turns.", ""}, + }; + + for (const auto &[param, title, desc, icon] : controlToggles) { + ParamControl *toggle; + + if (param == "AdjustablePersonalities") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 3, {{0, "None"}, {1, "Steering Wheel"}, {2, "Onroad UI Button"}, {3, "Wheel + Button"}}, this, true); + + } else 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 (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + + } else if (param == "ConditionalExperimental") { + FrogPilotParamManageControl *conditionalExperimentalToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(conditionalExperimentalToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + conditionalSpeedsImperial->setVisible(!isMetric); + conditionalSpeedsMetric->setVisible(isMetric); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(conditionalExperimentalKeys.find(key.c_str()) != conditionalExperimentalKeys.end()); + } + }); + toggle = conditionalExperimentalToggle; + } else if (param == "CECurves") { + FrogPilotParamValueControl *CESpeedImperial = new FrogPilotParamValueControl("CESpeed", "Below", "Switch to 'Experimental Mode' below this speed in absence of a lead vehicle.", "", 0, 99, + std::map(), this, false, " mph"); + FrogPilotParamValueControl *CESpeedLeadImperial = new FrogPilotParamValueControl("CESpeedLead", " w/Lead", "Switch to 'Experimental Mode' below this speed when following a lead vehicle.", "", 0, 99, + std::map(), this, false, " mph"); + conditionalSpeedsImperial = new FrogPilotDualParamControl(CESpeedImperial, CESpeedLeadImperial, this); + addItem(conditionalSpeedsImperial); + + FrogPilotParamValueControl *CESpeedMetric = new FrogPilotParamValueControl("CESpeed", "Below", "Switch to 'Experimental Mode' below this speed in absence of a lead vehicle.", "", 0, 150, + std::map(), this, false, " kph"); + FrogPilotParamValueControl *CESpeedLeadMetric = new FrogPilotParamValueControl("CESpeedLead", " w/Lead", "Switch to 'Experimental Mode' below this speed when following a lead vehicle.", "", 0, 150, + std::map(), this, false, " kph"); + conditionalSpeedsMetric = new FrogPilotDualParamControl(CESpeedMetric, CESpeedLeadMetric, this); + addItem(conditionalSpeedsMetric); + + std::vector curveToggles{"CECurvesLead"}; + std::vector curveToggleNames{tr("With Lead")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, curveToggles, curveToggleNames); + } else if (param == "CEStopLights") { + std::vector stopLightToggles{"CEStopLightsLead"}; + std::vector stopLightToggleNames{tr("With Lead")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, stopLightToggles, stopLightToggleNames); + + } else if (param == "CustomPersonalities") { + FrogPilotParamManageControl *customPersonalitiesToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(customPersonalitiesToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(false); + } + aggressiveProfile->setVisible(true); + standardProfile->setVisible(true); + relaxedProfile->setVisible(true); + }); + toggle = customPersonalitiesToggle; + + FrogPilotParamValueControl *aggressiveFollow = new FrogPilotParamValueControl("AggressiveFollow", "Follow", + "Set the 'Aggressive' personality' following distance. Represents seconds to follow behind the lead vehicle.\n\nStock: 1.25 seconds.", "../frogpilot/assets/other_images/aggressive.png", + 10, 50, std::map(), this, false, " sec", 10); + FrogPilotParamValueControl *aggressiveJerk = new FrogPilotParamValueControl("AggressiveJerk", " Jerk", + "Configure brake/gas pedal responsiveness for the 'Aggressive' personality. Higher values yield a more 'relaxed' response.\n\nStock: 0.5.", "", 1, 50, + std::map(), this, false, "", 10); + aggressiveProfile = new FrogPilotDualParamControl(aggressiveFollow, aggressiveJerk, this, true); + addItem(aggressiveProfile); + + FrogPilotParamValueControl *standardFollow = new FrogPilotParamValueControl("StandardFollow", "Follow", + "Set the 'Standard' personality following distance. Represents seconds to follow behind the lead vehicle.\n\nStock: 1.45 seconds.", "../frogpilot/assets/other_images/standard.png", + 10, 50, std::map(), this, false, " sec", 10); + FrogPilotParamValueControl *standardJerk = new FrogPilotParamValueControl("StandardJerk", " Jerk", + "Adjust brake/gas pedal responsiveness for the 'Standard' personality. Higher values yield a more 'relaxed' response.\n\nStock: 1.0.", "", 1, 50, + std::map(), this, false, "", 10); + standardProfile = new FrogPilotDualParamControl(standardFollow, standardJerk, this, true); + addItem(standardProfile); + + FrogPilotParamValueControl *relaxedFollow = new FrogPilotParamValueControl("RelaxedFollow", "Follow", + "Set the 'Relaxed' personality following distance. Represents seconds to follow behind the lead vehicle.\n\nStock: 1.75 seconds.", "../frogpilot/assets/other_images/relaxed.png", + 10, 50, std::map(), this, false, " sec", 10); + FrogPilotParamValueControl *relaxedJerk = new FrogPilotParamValueControl("RelaxedJerk", " Jerk", + "Set brake/gas pedal responsiveness for the 'Relaxed' personality. Higher values yield a more 'relaxed' response.\n\nStock: 1.0.", "", 1, 50, + std::map(), this, false, "", 10); + relaxedProfile = new FrogPilotDualParamControl(relaxedFollow, relaxedJerk, this, true); + addItem(relaxedProfile); + + } else if (param == "DeviceShutdown") { + std::map shutdownLabels; + for (int i = 0; i <= 33; ++i) { + shutdownLabels[i] = i == 0 ? "Instant" : i <= 3 ? QString::number(i * 15) + " mins" : QString::number(i - 3) + (i == 4 ? " hour" : " hours"); + } + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 33, shutdownLabels, this, false); + + } else if (param == "ExperimentalModeActivation") { + std::vector experimentalModeToggles{"ExperimentalModeViaLKAS", "ExperimentalModeViaScreen"}; + std::vector experimentalModeNames{tr("LKAS Button"), tr("Screen")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, experimentalModeToggles, experimentalModeNames); + + } else if (param == "FireTheBabysitter") { + FrogPilotParamManageControl *fireTheBabysitterToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(fireTheBabysitterToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(fireTheBabysitterKeys.find(key.c_str()) != fireTheBabysitterKeys.end()); + } + }); + toggle = fireTheBabysitterToggle; + + } 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 == "SteerRatio") { + toggle = new FrogPilotParamValueControlFloat(param, title, desc, icon, steerRatioStock * 0.75, steerRatioStock * 1.25, std::map(), this, false, "", 10.0); + + } 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 == "StoppingDistance") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, std::map(), this, false, " feet"); + + } else if (param == "Model") { + modelSelectorButton = new FrogPilotButtonIconControl(title, tr("SELECT"), desc, icon); + QStringList models = {"New Delhi (Default)", "Blue Diamond V1", "Blue Diamond V2", "Farmville", "New Lemon Pie"}; + QObject::connect(modelSelectorButton, &FrogPilotButtonIconControl::clicked, this, [this, models]() { + int currentModel = params.getInt("Model"); + QString currentModelLabel = models[currentModel]; + + QString selection = MultiOptionDialog::getSelection(tr("Select a driving model"), models, currentModelLabel, this); + if (!selection.isEmpty()) { + int selectedModel = models.indexOf(selection); + params.putInt("Model", selectedModel); + params.remove("CalibrationParams"); + params.remove("LiveTorqueParameters"); + modelSelectorButton->setValue(selection); + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + } + }); + modelSelectorButton->setValue(models[params.getInt("Model")]); + addItem(modelSelectorButton); + + } else if (param == "NudgelessLaneChange") { + FrogPilotParamManageControl *laneChangeToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(laneChangeToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(laneChangeKeys.find(key.c_str()) != laneChangeKeys.end()); + } + }); + toggle = laneChangeToggle; + } else if (param == "LaneChangeTime") { + std::map laneChangeTimeLabels; + for (int i = 0; i <= 10; ++i) { + laneChangeTimeLabels[i] = i == 0 ? "Instant" : QString::number(i / 2.0) + " seconds"; + } + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, laneChangeTimeLabels, this, false); + + } 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 if (param == "PauseLateralOnSignal") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, std::map(), this, false, " mph"); + } else if (param == "SetSpeedOffset") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, std::map(), this, false, " mph"); + + } else if (param == "SpeedLimitController") { + FrogPilotParamManageControl *speedLimitControllerToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(speedLimitControllerToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(speedLimitControllerKeys.find(key.c_str()) != speedLimitControllerKeys.end()); + } + slscPriorityButton->setVisible(true); + }); + toggle = speedLimitControllerToggle; + } else if (param == "Offset1" || param == "Offset2" || param == "Offset3" || param == "Offset4") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, std::map(), this, false, " mph"); + } else if (param == "SLCFallback") { + std::vector fallbackOptions{tr("None"), tr("Experimental Mode"), tr("Previous Limit")}; + FrogPilotButtonParamControl *fallbackSelection = new FrogPilotButtonParamControl(param, title, desc, icon, fallbackOptions); + toggle = fallbackSelection; + } else if (param == "SLCOverride") { + std::vector overrideOptions{tr("None"), tr("Manual Set Speed"), tr("Max Set Speed")}; + FrogPilotButtonParamControl *overrideSelection = new FrogPilotButtonParamControl(param, title, desc, icon, overrideOptions); + toggle = overrideSelection; + } else if (param == "SLCPriority") { + const QStringList priorities { + "Navigation, Dashboard, Offline Maps", + "Navigation, Offline Maps, Dashboard", + "Navigation, Offline Maps", + "Navigation, Dashboard", + "Navigation", + "Offline Maps, Dashboard, Navigation", + "Offline Maps, Navigation, Dashboard", + "Offline Maps, Navigation", + "Offline Maps, Dashboard", + "Offline Maps", + "Dashboard, Navigation, Offline Maps", + "Dashboard, Offline Maps, Navigation", + "Dashboard, Offline Maps", + "Dashboard, Navigation", + "Dashboard", + "Highest", + "Lowest", + "", + }; + + slscPriorityButton = new ButtonControl(title, tr("SELECT"), desc); + QObject::connect(slscPriorityButton, &ButtonControl::clicked, this, [this, priorities]() { + QStringList availablePriorities = {"Dashboard", "Navigation", "Offline Maps", "Highest", "Lowest", "None"}; + QStringList selectedPriorities; + int priorityValue = -1; + + QStringList priorityPrompts = {tr("Select your primary priority"), tr("Select your secondary priority"), tr("Select your tertiary priority")}; + + for (int i = 0; i < 3; ++i) { + QString selection = MultiOptionDialog::getSelection(priorityPrompts[i], availablePriorities, "", this); + if (selection.isEmpty()) break; + + if (selection == "None") { + priorityValue = 17; + break; + } else if (selection == "Highest") { + priorityValue = 15; + break; + } else if (selection == "Lowest") { + priorityValue = 16; + break; + } else { + selectedPriorities.append(selection); + availablePriorities.removeAll(selection); + availablePriorities.removeAll("Highest"); + availablePriorities.removeAll("Lowest"); + } + } + + if (priorityValue == -1 && !selectedPriorities.isEmpty()) { + QString priorityString = selectedPriorities.join(", "); + priorityValue = priorities.indexOf(priorityString); + } + + if (priorityValue != -1) { + slscPriorityButton->setValue(priorities[priorityValue]); + params.putInt("SLCPriority", priorityValue); + updateToggles(); + } + }); + slscPriorityButton->setValue(priorities[params.getInt("SLCPriority")]); + addItem(slscPriorityButton); + + } else if (param == "VisionTurnControl") { + FrogPilotParamManageControl *visionTurnControlToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(visionTurnControlToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(visionTurnControlKeys.find(key.c_str()) != visionTurnControlKeys.end()); + } + }); + toggle = visionTurnControlToggle; + } else if (param == "CurveSensitivity" || param == "TurnAggressiveness") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 200, std::map(), this, false, "%"); + + } 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), &FrogPilotParamValueControl::buttonPressed, [this]() { + updateToggles(); + }); + + QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() { + update(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + update(); + }); + } + + std::set rebootKeys = {"AlwaysOnLateral", "FireTheBabysitter", "HigherBitrate", "MuteDM", "NNFF"}; + for (const std::string &key : rebootKeys) { + QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() { + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + } + + conditionalExperimentalKeys = {"CECurves", "CECurvesLead", "CESlowerLead", "CENavigation", "CEStopLights", "CESignal"}; + fireTheBabysitterKeys = {"NoLogging", "MuteDM", "MuteDoor", "MuteOverheated", "MuteSeatbelt", "OfflineMode"}; + laneChangeKeys = {"LaneChangeTime", "LaneDetection", "OneLaneChange"}; + lateralTuneKeys = {"AverageCurvature", "NNFF", "SteerRatio"}; + longitudinalTuneKeys = {"AccelerationProfile", "AggressiveAcceleration", "SmoothBraking", "StoppingDistance"}; + mtscKeys = {"MTSCAggressiveness"}; + qolKeys = {"DisableOnroadUploads", "HigherBitrate", "PauseLateralOnSignal", "ReverseCruise", "SetSpeedOffset"}; + speedLimitControllerKeys = {"Offset1", "Offset2", "Offset3", "Offset4", "SLCFallback", "SLCOverride", "SLCPriority"}; + visionTurnControlKeys = {"CurveSensitivity", "TurnAggressiveness"}; + + QObject::connect(uiState(), &UIState::offroadTransition, this, [this](bool offroad) { + if (!offroad) { + updateCarToggles(); + } + }); + + QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotControlsPanel::hideSubToggles); + QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotControlsPanel::hideSubToggles); + QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotControlsPanel::updateMetric); + + hideSubToggles(); + updateMetric(); +} + +void FrogPilotControlsPanel::updateCarToggles() { + FrogPilotParamValueControlFloat *steerRatioToggle = static_cast(toggles["SteerRatio"]); + steerRatioStock = params.getFloat("SteerRatioStock"); + steerRatioToggle->setTitle(steerRatioStock != 0 ? QString("Steer Ratio (Default: %1)").arg(steerRatioStock, 0, 'f', 2) : QString("Steer Ratio")); + steerRatioToggle->updateControl(steerRatioStock * 0.75, steerRatioStock * 1.25, "", 10.0); + steerRatioToggle->refresh(); +} + +void FrogPilotControlsPanel::updateToggles() { + std::thread([this]() { + paramsMemory.putBool("FrogPilotTogglesUpdated", true); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + paramsMemory.putBool("FrogPilotTogglesUpdated", false); + }).detach(); +} + +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; + params.putInt("CESpeed", std::nearbyint(params.getInt("CESpeed") * speedConversion)); + params.putInt("CESpeedLead", std::nearbyint(params.getInt("CESpeedLead") * speedConversion)); + params.putInt("Offset1", std::nearbyint(params.getInt("Offset1") * speedConversion)); + params.putInt("Offset2", std::nearbyint(params.getInt("Offset2") * speedConversion)); + params.putInt("Offset3", std::nearbyint(params.getInt("Offset3") * speedConversion)); + params.putInt("Offset4", std::nearbyint(params.getInt("Offset4") * speedConversion)); + params.putInt("PauseLateralOnSignal", std::nearbyint(params.getInt("PauseLateralOnSignal") * speedConversion)); + params.putInt("SetSpeedOffset", std::nearbyint(params.getInt("SetSpeedOffset") * speedConversion)); + params.putInt("StoppingDistance", std::nearbyint(params.getInt("StoppingDistance") * distanceConversion)); + } + + FrogPilotParamValueControl *offset1Toggle = static_cast(toggles["Offset1"]); + FrogPilotParamValueControl *offset2Toggle = static_cast(toggles["Offset2"]); + FrogPilotParamValueControl *offset3Toggle = static_cast(toggles["Offset3"]); + FrogPilotParamValueControl *offset4Toggle = static_cast(toggles["Offset4"]); + FrogPilotParamValueControl *pauseLateralToggle = static_cast(toggles["PauseLateralOnSignal"]); + FrogPilotParamValueControl *setSpeedOffsetToggle = static_cast(toggles["SetSpeedOffset"]); + FrogPilotParamValueControl *stoppingDistanceToggle = static_cast(toggles["StoppingDistance"]); + + if (isMetric) { + offset1Toggle->setTitle("Speed Limit Offset (0-34 kph)"); + offset2Toggle->setTitle("Speed Limit Offset (35-54 kph)"); + offset3Toggle->setTitle("Speed Limit Offset (55-64 kph)"); + offset4Toggle->setTitle("Speed Limit Offset (65-99 kph)"); + + offset1Toggle->setDescription("Set speed limit offset for limits between 0-34 kph."); + offset2Toggle->setDescription("Set speed limit offset for limits between 35-54 kph."); + offset3Toggle->setDescription("Set speed limit offset for limits between 55-64 kph."); + offset4Toggle->setDescription("Set speed limit offset for limits between 65-99 kph."); + + offset1Toggle->updateControl(0, 150, " kph"); + offset2Toggle->updateControl(0, 150, " kph"); + offset3Toggle->updateControl(0, 150, " kph"); + offset4Toggle->updateControl(0, 150, " kph"); + pauseLateralToggle->updateControl(0, 150, " kph"); + setSpeedOffsetToggle->updateControl(0, 150, " kph"); + stoppingDistanceToggle->updateControl(0, 5, " meters"); + } else { + offset1Toggle->setTitle("Speed Limit Offset (0-34 mph)"); + offset2Toggle->setTitle("Speed Limit Offset (35-54 mph)"); + offset3Toggle->setTitle("Speed Limit Offset (55-64 mph)"); + offset4Toggle->setTitle("Speed Limit Offset (65-99 mph)"); + + offset1Toggle->setDescription("Set speed limit offset for limits between 0-34 mph."); + offset2Toggle->setDescription("Set speed limit offset for limits between 35-54 mph."); + offset3Toggle->setDescription("Set speed limit offset for limits between 55-64 mph."); + offset4Toggle->setDescription("Set speed limit offset for limits between 65-99 mph."); + + offset1Toggle->updateControl(0, 99, " mph"); + offset2Toggle->updateControl(0, 99, " mph"); + offset3Toggle->updateControl(0, 99, " mph"); + offset4Toggle->updateControl(0, 99, " mph"); + pauseLateralToggle->updateControl(0, 99, " mph"); + setSpeedOffsetToggle->updateControl(0, 99, " mph"); + stoppingDistanceToggle->updateControl(0, 10, " feet"); + } + + offset1Toggle->refresh(); + offset2Toggle->refresh(); + offset3Toggle->refresh(); + offset4Toggle->refresh(); + pauseLateralToggle->refresh(); + setSpeedOffsetToggle->refresh(); + stoppingDistanceToggle->refresh(); + + previousIsMetric = isMetric; +} + +void FrogPilotControlsPanel::parentToggleClicked() { + aggressiveProfile->setVisible(false); + conditionalSpeedsImperial->setVisible(false); + conditionalSpeedsMetric->setVisible(false); + modelSelectorButton->setVisible(false); + slscPriorityButton->setVisible(false); + standardProfile->setVisible(false); + relaxedProfile->setVisible(false); + + this->openParentToggle(); +} + +void FrogPilotControlsPanel::hideSubToggles() { + aggressiveProfile->setVisible(false); + conditionalSpeedsImperial->setVisible(false); + conditionalSpeedsMetric->setVisible(false); + modelSelectorButton->setVisible(true); + slscPriorityButton->setVisible(false); + standardProfile->setVisible(false); + relaxedProfile->setVisible(false); + + 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); + } + + this->closeParentToggle(); +} + +void FrogPilotControlsPanel::hideEvent(QHideEvent *event) { + hideSubToggles(); +} diff --git a/selfdrive/frogpilot/ui/control_settings.h.org b/selfdrive/frogpilot/ui/control_settings.h.org new file mode 100644 index 0000000..b029249 --- /dev/null +++ b/selfdrive/frogpilot/ui/control_settings.h.org @@ -0,0 +1,53 @@ +#pragma once + +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/qt/offroad/settings.h" + +class FrogPilotControlsPanel : public FrogPilotListWidget { + Q_OBJECT + +public: + explicit FrogPilotControlsPanel(SettingsWindow *parent); + +signals: + void closeParentToggle(); + void openParentToggle(); + +private: + void hideEvent(QHideEvent *event); + void hideSubToggles(); + void parentToggleClicked(); + void updateCarToggles(); + void updateMetric(); + void updateToggles(); + + ButtonControl *slscPriorityButton; + + FrogPilotButtonIconControl *modelSelectorButton; + + FrogPilotDualParamControl *aggressiveProfile; + FrogPilotDualParamControl *conditionalSpeedsImperial; + FrogPilotDualParamControl *conditionalSpeedsMetric; + FrogPilotDualParamControl *standardProfile; + FrogPilotDualParamControl *relaxedProfile; + + std::set conditionalExperimentalKeys; + std::set fireTheBabysitterKeys; + std::set laneChangeKeys; + std::set lateralTuneKeys; + std::set longitudinalTuneKeys; + std::set mtscKeys; + std::set qolKeys; + std::set speedLimitControllerKeys; + std::set visionTurnControlKeys; + + std::map toggles; + + Params params; + Params paramsMemory{"/dev/shm/params"}; + + bool isMetric = params.getBool("IsMetric"); + float steerRatioStock = params.getFloat("SteerRatioStock"); +}; diff --git a/selfdrive/frogpilot/ui/frogpilot_functions.cc b/selfdrive/frogpilot/ui/frogpilot_functions.cc index 135bd4d..3c09c61 100644 --- a/selfdrive/frogpilot/ui/frogpilot_functions.cc +++ b/selfdrive/frogpilot/ui/frogpilot_functions.cc @@ -43,35 +43,36 @@ FrogPilotButtonIconControl::FrogPilotButtonIconControl(const QString &title, con void setDefaultParams() { Params params = Params(); - bool FrogsGoMoo = params.get("DongleId").substr(0, 3) == "be6"; - bool brianbot = params.get("DongleId").substr(0, 6) == "90bb71"; + bool FrogsGoMoo = false; + + bool elite_mode = params.get("DongleId").substr(0, 6) == "90bb71"; std::map defaultValues { - {"AccelerationPath", brianbot ? "1" : "0"}, - {"AccelerationProfile", brianbot ? "2" : "2"}, - {"AdjacentPath", FrogsGoMoo ? "1" : "0"}, + {"AccelerationPath", "0"}, // NOTE: Should be one if using OPLong + {"AccelerationProfile", "2"}, + {"AdjacentPath", "0"}, // Test? {"AdjustablePersonalities", "0"}, {"AggressiveAcceleration", "1"}, - {"AggressiveFollow", FrogsGoMoo ? "10" : "12"}, - {"AggressiveJerk", FrogsGoMoo ? "6" : "5"}, + {"AggressiveFollow", "12"}, + {"AggressiveJerk", "5"}, {"AlwaysOnLateral", "1"}, - {"AlwaysOnLateralMain", brianbot ? "1" : "0"}, - {"AverageCurvature", brianbot ? "1" : "0"}, + {"AlwaysOnLateralMain", "1"}, + {"AverageCurvature", "1"}, {"BlindSpotPath", "1"}, - {"CameraView", FrogsGoMoo ? "1" : "0"}, + {"CameraView", "0"}, {"CECurves", "1"}, - {"CECurvesLead", "0"}, + {"CECurvesLead", "1"}, {"CENavigation", "1"}, - {"CESignal", "1"}, + {"CESignal", "0"}, {"CESlowerLead", "0"}, {"CESpeed", "0"}, {"CESpeedLead", "0"}, {"CEStopLights", "0"}, - {"CEStopLightsLead", FrogsGoMoo ? "0" : "0"}, - {"Compass", FrogsGoMoo ? "1" : "0"}, + {"CEStopLightsLead", "0"}, + {"Compass", "0"}, {"ConditionalExperimental", "1"}, - {"CurveSensitivity", FrogsGoMoo ? "125" : "100"}, + {"CurveSensitivity", "125"}, // was 100 {"CustomColors", "1"}, {"CustomIcons", "1"}, {"CustomPersonalities", "0"}, @@ -84,10 +85,10 @@ void setDefaultParams() { {"DriverCamera", "0"}, {"DriveStats", "1"}, {"EVTable", FrogsGoMoo ? "0" : "1"}, - {"ExperimentalModeActivation", "1"}, + {"ExperimentalModeActivation", "0"}, {"ExperimentalModeViaLKAS", "0"}, - {"ExperimentalModeViaScreen", FrogsGoMoo ? "0" : "1"}, - {"Fahrenheit", "0"}, + {"ExperimentalModeViaScreen", "0"}, + {"Fahrenheit", "1"}, {"FireTheBabysitter", FrogsGoMoo ? "1" : "0"}, {"FullMap", "0"}, {"GasRegenCmd", "0"}, @@ -107,11 +108,11 @@ void setDefaultParams() { {"Model", "3"}, {"ModelUI", "1"}, {"MTSCEnabled", "1"}, - {"MuteDM", FrogsGoMoo ? "1" : "1"}, - {"MuteDoor", FrogsGoMoo ? "1" : "1"}, - {"MuteOverheated", FrogsGoMoo ? "1" : "0"}, - {"MuteSeatbelt", FrogsGoMoo ? "1" : "0"}, - {"NNFF", FrogsGoMoo ? "1" : "1"}, + {"MuteDM", "1"}, + {"MuteDoor", "1"}, + {"MuteOverheated", "0"}, + {"MuteSeatbelt", "1"}, + {"NNFF", "1"}, {"NoLogging", "1"}, {"NudgelessLaneChange", "0"}, {"NumericalTemp", FrogsGoMoo ? "1" : "0"}, @@ -126,7 +127,7 @@ void setDefaultParams() { {"PreferredSchedule", "0"}, {"QOLControls", "1"}, {"QOLVisuals", "1"}, - {"RandomEvents", FrogsGoMoo ? "1" : "0"}, + {"RandomEvents", "0"}, {"RelaxedFollow", "30"}, {"RelaxedJerk", "50"}, {"ReverseCruise", "0"}, @@ -135,11 +136,11 @@ void setDefaultParams() { {"RotatingWheel", "1"}, {"ScreenBrightness", "101"}, {"SearchInput", "0"}, - {"ShowCPU", FrogsGoMoo ? "1" : "0"}, - {"ShowFPS", FrogsGoMoo ? "1" : "0"}, + {"ShowCPU", "0"}, + {"ShowFPS", "0"}, {"ShowGPU", "0"}, - {"ShowMemoryUsage", FrogsGoMoo ? "1" : "0"}, - {"Sidebar", FrogsGoMoo ? "1" : "0"}, + {"ShowMemoryUsage", "0"}, + {"Sidebar", "0"}, {"SilentMode", "0"}, {"SLCFallback", "2"}, {"SLCOverride", FrogsGoMoo ? "2" : "1"}, @@ -157,7 +158,9 @@ void setDefaultParams() { {"UseSI", FrogsGoMoo ? "1" : "0"}, {"UseVienna", "0"}, {"VisionTurnControl", "1"}, - {"WheelIcon", FrogsGoMoo ? "1" : "0"} + {"WheelIcon", "0"}, + {"IsLdwEnabled", "1"}, + {"RecordFront", "0"} }; bool rebootRequired = false; diff --git a/selfdrive/frogpilot/ui/frogpilot_functions.cc.org b/selfdrive/frogpilot/ui/frogpilot_functions.cc.org new file mode 100644 index 0000000..135bd4d --- /dev/null +++ b/selfdrive/frogpilot/ui/frogpilot_functions.cc.org @@ -0,0 +1,177 @@ +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/ui.h" + +bool FrogPilotConfirmationDialog::toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, confirm_text, tr("Reboot Later"), false, parent); + return d.exec(); +} + +bool FrogPilotConfirmationDialog::toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, button_text, "", false, parent); + return d.exec(); +} + +bool FrogPilotConfirmationDialog::yesorno(const QString &prompt_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Yes"), tr("No"), false, parent); + return d.exec(); +} + +FrogPilotButtonIconControl::FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc, const QString &icon, QWidget *parent) : AbstractControl(title, desc, icon, parent) { + btn.setText(text); + btn.setStyleSheet(R"( + QPushButton { + padding: 0; + border-radius: 50px; + font-size: 35px; + font-weight: 500; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:disabled { + color: #33E4E4E4; + } + )"); + btn.setFixedSize(250, 100); + QObject::connect(&btn, &QPushButton::clicked, this, &FrogPilotButtonIconControl::clicked); + hlayout->addWidget(&btn); +} + +void setDefaultParams() { + Params params = Params(); + bool FrogsGoMoo = params.get("DongleId").substr(0, 3) == "be6"; + + bool brianbot = params.get("DongleId").substr(0, 6) == "90bb71"; + + std::map defaultValues { + {"AccelerationPath", brianbot ? "1" : "0"}, + {"AccelerationProfile", brianbot ? "2" : "2"}, + {"AdjacentPath", FrogsGoMoo ? "1" : "0"}, + {"AdjustablePersonalities", "0"}, + {"AggressiveAcceleration", "1"}, + {"AggressiveFollow", FrogsGoMoo ? "10" : "12"}, + {"AggressiveJerk", FrogsGoMoo ? "6" : "5"}, + {"AlwaysOnLateral", "1"}, + {"AlwaysOnLateralMain", brianbot ? "1" : "0"}, + {"AverageCurvature", brianbot ? "1" : "0"}, + {"BlindSpotPath", "1"}, + {"CameraView", FrogsGoMoo ? "1" : "0"}, + {"CECurves", "1"}, + {"CECurvesLead", "0"}, + {"CENavigation", "1"}, + {"CESignal", "1"}, + {"CESlowerLead", "0"}, + {"CESpeed", "0"}, + {"CESpeedLead", "0"}, + {"CEStopLights", "0"}, + {"CEStopLightsLead", FrogsGoMoo ? "0" : "0"}, + {"Compass", FrogsGoMoo ? "1" : "0"}, + {"ConditionalExperimental", "1"}, + {"CurveSensitivity", FrogsGoMoo ? "125" : "100"}, + {"CustomColors", "1"}, + {"CustomIcons", "1"}, + {"CustomPersonalities", "0"}, + {"CustomSignals", "0"}, + {"CustomSounds", "1"}, + {"CustomTheme", "1"}, + {"CustomUI", "0"}, + {"DeviceShutdown", "1"}, + {"DisableOnroadUploads", "1"}, + {"DriverCamera", "0"}, + {"DriveStats", "1"}, + {"EVTable", FrogsGoMoo ? "0" : "1"}, + {"ExperimentalModeActivation", "1"}, + {"ExperimentalModeViaLKAS", "0"}, + {"ExperimentalModeViaScreen", FrogsGoMoo ? "0" : "1"}, + {"Fahrenheit", "0"}, + {"FireTheBabysitter", FrogsGoMoo ? "1" : "0"}, + {"FullMap", "0"}, + {"GasRegenCmd", "0"}, + {"GoatScream", "0"}, + {"GreenLightAlert", "0"}, + {"HideSpeed", "0"}, + {"HigherBitrate", "0"}, + {"LaneChangeTime", "0"}, + {"LaneDetection", "1"}, + {"LaneLinesWidth", "4"}, + {"LateralTune", "1"}, + {"LeadInfo", FrogsGoMoo ? "1" : "0"}, + {"LockDoors", "0"}, + {"LongitudinalTune", "1"}, + {"LongPitch", FrogsGoMoo ? "0" : "1"}, + {"LowerVolt", FrogsGoMoo ? "0" : "1"}, + {"Model", "3"}, + {"ModelUI", "1"}, + {"MTSCEnabled", "1"}, + {"MuteDM", FrogsGoMoo ? "1" : "1"}, + {"MuteDoor", FrogsGoMoo ? "1" : "1"}, + {"MuteOverheated", FrogsGoMoo ? "1" : "0"}, + {"MuteSeatbelt", FrogsGoMoo ? "1" : "0"}, + {"NNFF", FrogsGoMoo ? "1" : "1"}, + {"NoLogging", "1"}, + {"NudgelessLaneChange", "0"}, + {"NumericalTemp", FrogsGoMoo ? "1" : "0"}, + {"Offset1", "3"}, + {"Offset2", FrogsGoMoo ? "7" : "5"}, + {"Offset3", "7"}, + {"Offset4", FrogsGoMoo ? "20" : "7"}, + {"OneLaneChange", "1"}, + {"PathEdgeWidth", "20"}, + {"PathWidth", "61"}, + {"PauseLateralOnSignal", "20"}, + {"PreferredSchedule", "0"}, + {"QOLControls", "1"}, + {"QOLVisuals", "1"}, + {"RandomEvents", FrogsGoMoo ? "1" : "0"}, + {"RelaxedFollow", "30"}, + {"RelaxedJerk", "50"}, + {"ReverseCruise", "0"}, + {"RoadEdgesWidth", "2"}, + {"RoadNameUI", "1"}, + {"RotatingWheel", "1"}, + {"ScreenBrightness", "101"}, + {"SearchInput", "0"}, + {"ShowCPU", FrogsGoMoo ? "1" : "0"}, + {"ShowFPS", FrogsGoMoo ? "1" : "0"}, + {"ShowGPU", "0"}, + {"ShowMemoryUsage", FrogsGoMoo ? "1" : "0"}, + {"Sidebar", FrogsGoMoo ? "1" : "0"}, + {"SilentMode", "0"}, + {"SLCFallback", "2"}, + {"SLCOverride", FrogsGoMoo ? "2" : "1"}, + {"SLCPriority", "1"}, + {"SmoothBraking", "1"}, + {"SNGHack", FrogsGoMoo ? "0" : "1"}, + {"SpeedLimitController", "1"}, + {"StandardFollow", "15"}, + {"StandardJerk", "10"}, + {"StoppingDistance", FrogsGoMoo ? "6" : "0"}, + {"TSS2Tune", "1"}, + {"TurnAggressiveness", FrogsGoMoo ? "150" : "100"}, // Test 90? + {"TurnDesires", "0"}, + {"UnlimitedLength", "1"}, + {"UseSI", FrogsGoMoo ? "1" : "0"}, + {"UseVienna", "0"}, + {"VisionTurnControl", "1"}, + {"WheelIcon", FrogsGoMoo ? "1" : "0"} + }; + + bool rebootRequired = false; + for (const auto &[key, value] : defaultValues) { + if (params.get(key).empty()) { + params.put(key, value); + rebootRequired = true; + } + } + + if (rebootRequired) { + while (!std::filesystem::exists("/data/openpilot/prebuilt")) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + Hardware::reboot(); + } +} diff --git a/selfdrive/frogpilot/ui/frogpilot_functions.h.org b/selfdrive/frogpilot/ui/frogpilot_functions.h.org new file mode 100644 index 0000000..26bb046 --- /dev/null +++ b/selfdrive/frogpilot/ui/frogpilot_functions.h.org @@ -0,0 +1,661 @@ +#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 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 ¶m, const QString &title, const QString &desc, const QString &icon, + const std::vector &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::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 ¶m, 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 ¶m, const QString &title, const QString &desc, + const QString &icon, const std::vector &button_params, + const std::vector &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 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 ¶m, const QString &title, const QString &desc, const QString &icon, + const int &minValue, const int &maxValue, const std::map &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 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 ¶m, const QString &title, const QString &desc, const QString &icon, + const float &minValue, const float &maxValue, const std::map &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 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 ¶m, const QString &title, const QString &desc, const QString &icon, + const int &minValue, const int &maxValue, const std::map &valueLabels, + QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const int &division = 1, + const std::vector &button_params = std::vector(), const std::vector &button_texts = std::vector(), + 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 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 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(); diff --git a/selfdrive/frogpilot/ui/vehicle_settings.cc.org b/selfdrive/frogpilot/ui/vehicle_settings.cc.org new file mode 100644 index 0000000..b658218 --- /dev/null +++ b/selfdrive/frogpilot/ui/vehicle_settings.cc.org @@ -0,0 +1,185 @@ +#include +#include +#include + +#include "selfdrive/frogpilot/ui/vehicle_settings.h" +#include "selfdrive/ui/ui.h" + +QStringList getCarNames(const QString &carMake) { + QMap makeMap; + makeMap["acura"] = "honda"; + makeMap["audi"] = "volkswagen"; + makeMap["buick"] = "gm"; + makeMap["cadillac"] = "gm"; + makeMap["chevrolet"] = "gm"; + makeMap["chrysler"] = "chrysler"; + makeMap["dodge"] = "chrysler"; + makeMap["ford"] = "ford"; + makeMap["gm"] = "gm"; + makeMap["gmc"] = "gm"; + makeMap["genesis"] = "hyundai"; + makeMap["honda"] = "honda"; + makeMap["hyundai"] = "hyundai"; + makeMap["infiniti"] = "nissan"; + makeMap["jeep"] = "chrysler"; + makeMap["kia"] = "hyundai"; + makeMap["lexus"] = "toyota"; + makeMap["lincoln"] = "ford"; + makeMap["man"] = "volkswagen"; + makeMap["mazda"] = "mazda"; + makeMap["nissan"] = "nissan"; + makeMap["ram"] = "chrysler"; + makeMap["seat"] = "volkswagen"; + makeMap["subaru"] = "subaru"; + makeMap["tesla"] = "tesla"; + makeMap["toyota"] = "toyota"; + makeMap["volkswagen"] = "volkswagen"; + makeMap["skoda"] = "volkswagen"; + + QString dirPath = "../../selfdrive/car"; + QDir dir(dirPath); + QString targetFolder = makeMap.value(carMake, carMake); + QStringList names; + + foreach (const QString &folder, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { + if (folder == targetFolder) { + QFile file(dirPath + "/" + folder + "/values.py"); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QRegularExpression regex("class CAR\\(StrEnum\\):([\\s\\S]*?)(?=^\\w)", QRegularExpression::MultilineOption); + QRegularExpressionMatch match = regex.match(QTextStream(&file).readAll()); + file.close(); + + if (match.hasMatch()) { + QRegularExpression nameRegex("=\\s*\"([^\"]+)\""); + QRegularExpressionMatchIterator it = nameRegex.globalMatch(match.captured(1)); + while (it.hasNext()) { + names << it.next().captured(1); + } + } + } + } + } + + std::sort(names.begin(), names.end()); + return names; +} + +FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) { + selectMakeButton = new ButtonControl(tr("Select Make"), tr("SELECT")); + QObject::connect(selectMakeButton, &ButtonControl::clicked, [this]() { + std::string currentMake = params.get("CarMake"); + QStringList makes = { + "Acura", "Audi", "BMW", "Buick", "Cadillac", "Chevrolet", "Chrysler", "Dodge", "Ford", "GM", "GMC", + "Genesis", "Honda", "Hyundai", "Infiniti", "Jeep", "Kia", "Lexus", "Lincoln", "MAN", "Mazda", + "Mercedes", "Nissan", "Ram", "SEAT", "Subaru", "Tesla", "Toyota", "Volkswagen", "Volvo", "Škoda", + }; + + QString newMakeSelection = MultiOptionDialog::getSelection(tr("Select a Make"), makes, QString::fromStdString(currentMake), this); + if (!newMakeSelection.isEmpty()) { + carMake = newMakeSelection; + params.put("CarMake", carMake.toStdString()); + selectMakeButton->setValue(newMakeSelection); + setModels(); + } + }); + addItem(selectMakeButton); + + selectModelButton = new ButtonControl(tr("Select Model"), tr("SELECT")); + QString modelSelection = QString::fromStdString(params.get("CarModel")); + QObject::connect(selectModelButton, &ButtonControl::clicked, [this]() { + std::string currentModel = params.get("CarModel"); + QString newModelSelection = MultiOptionDialog::getSelection(tr("Select a Model"), models, QString::fromStdString(currentModel), this); + if (!newModelSelection.isEmpty()) { + params.put("CarModel", newModelSelection.toStdString()); + selectModelButton->setValue(newModelSelection); + } + }); + selectModelButton->setValue(modelSelection); + addItem(selectModelButton); + selectModelButton->setVisible(false); + + std::vector> vehicleToggles { + {"EVTable", "EV Lookup Tables", "Smoothen out the gas and brake controls for EV vehicles.", ""}, + {"GasRegenCmd", "Gas Regen Cmd", "", ""}, + {"LongPitch", "Long Pitch Compensation", "Reduce speed and acceleration error for greater passenger comfort and improved vehicle efficiency.", ""}, + {"LowerVolt", "Lower Volt Enable Speed", "Lower the Volt's minimum enable speed to enable openpilot at any speed.", ""}, + + {"LockDoors", "Lock Doors In Drive", "Automatically lock the doors when in drive and unlock when in park.", ""}, + {"SNGHack", "Stop and Go Hack", "Enable the 'Stop and Go' hack for vehicles without stock stop and go functionality.", ""}, + {"TSS2Tune", "TSS2 Tune", "Tuning profile based on the tuning profile from DragonPilot for TSS2 vehicles.", ""} + }; + + for (auto &[param, title, desc, icon] : vehicleToggles) { + ParamControl *toggle = new ParamControl(param, title, desc, icon, this); + + addItem(toggle); + toggle->setVisible(false); + toggles[param.toStdString()] = toggle; + + QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() { + updateToggles(); + }); + } + + gmKeys = {"EVTable", "GasRegenCmd", "LongPitch", "LowerVolt"}; + toyotaKeys = {"LockDoors", "SNGHack", "TSS2Tune"}; + + std::set rebootKeys = {"EVTable", "GasRegenCmd", "LongPitch", "LowerVolt", "TSS2Tune"}; + for (const std::string &key : rebootKeys) { + QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() { + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + } + + QObject::connect(uiState(), &UIState::offroadTransition, this, [this](bool offroad) { + if (!offroad) { + std::thread([this]() { + while (carMake.isEmpty()) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + carMake = QString::fromStdString(params.get("CarMake")); + } + setModels(); + }).detach(); + } + }); + + carMake = QString::fromStdString(params.get("CarMake")); + if (!carMake.isEmpty()) { + setModels(); + } +} + +void FrogPilotVehiclesPanel::updateToggles() { + std::thread([this]() { + paramsMemory.putBool("FrogPilotTogglesUpdated", true); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + paramsMemory.putBool("FrogPilotTogglesUpdated", false); + }).detach(); +} + +void FrogPilotVehiclesPanel::setModels() { + models = getCarNames(carMake.toLower()); + setToggles(); +} + +void FrogPilotVehiclesPanel::setToggles() { + selectMakeButton->setValue(carMake); + selectModelButton->setVisible(!carMake.isEmpty()); + + bool gm = carMake == "Buick" || carMake == "Cadillac" || carMake == "Chevrolet" || carMake == "GM" || carMake == "GMC"; + bool toyota = carMake == "Lexus" || carMake == "Toyota"; + + for (auto &[key, toggle] : toggles) { + toggle->setVisible(false); + + if (gm) { + toggle->setVisible(gmKeys.find(key.c_str()) != gmKeys.end()); + } else if (toyota) { + toggle->setVisible(toyotaKeys.find(key.c_str()) != toyotaKeys.end()); + } + } + + update(); +} diff --git a/selfdrive/frogpilot/ui/vehicle_settings.h.org b/selfdrive/frogpilot/ui/vehicle_settings.h.org new file mode 100644 index 0000000..d8d8a32 --- /dev/null +++ b/selfdrive/frogpilot/ui/vehicle_settings.h.org @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/qt/offroad/settings.h" + +class FrogPilotVehiclesPanel : public FrogPilotListWidget { + Q_OBJECT + +public: + explicit FrogPilotVehiclesPanel(SettingsWindow *parent); + +private: + void setModels(); + void setToggles(); + void updateToggles(); + + ButtonControl *selectMakeButton; + ButtonControl *selectModelButton; + + QString carMake; + QStringList models; + + std::map toggles; + + std::set gmKeys; + std::set toyotaKeys; + + Params params; + Params paramsMemory{"/dev/shm/params"}; +}; diff --git a/selfdrive/frogpilot/ui/visual_settings.cc.org b/selfdrive/frogpilot/ui/visual_settings.cc.org new file mode 100644 index 0000000..3bad476 --- /dev/null +++ b/selfdrive/frogpilot/ui/visual_settings.cc.org @@ -0,0 +1,242 @@ +#include "selfdrive/frogpilot/ui/visual_settings.h" +#include "selfdrive/ui/ui.h" + +FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) { + const std::vector> visualToggles { + {"CustomTheme", "Custom Themes", "Enable the ability to use custom themes.", "../frogpilot/assets/wheel_images/frog.png"}, + {"CustomColors", "Color Theme", "Switch out the standard openpilot color scheme with a custom color scheme.\n\nWant to submit your own color scheme? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + {"CustomIcons", "Icon Pack", "Switch out the standard openpilot icons with a set of custom icons.\n\nWant to submit your own icon pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + {"CustomSignals", "Turn Signals", "Add custom animations for your turn signals for a personal touch!\n\nWant to submit your own turn signal animation? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + {"CustomSounds", "Sound Pack", "Switch out the standard openpilot sounds with a set of custom sounds.\n\nWant to submit your own sound pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + + {"CameraView", "Camera View", "Choose your preferred camera view for the onroad UI. This is a visual change only and doesn't impact openpilot.", "../frogpilot/assets/toggle_icons/icon_camera.png"}, + {"Compass", "Compass", "Add a compass to your onroad UI.", "../frogpilot/assets/toggle_icons/icon_compass.png"}, + + {"CustomUI", "Custom Onroad UI", "Customize the Onroad UI with some additional visual functions.", "../assets/offroad/icon_road.png"}, + {"AdjacentPath", "Adjacent Paths", "Display paths to the left and right of your car, visualizing where the model detects lanes.", ""}, + {"BlindSpotPath", "Blind Spot Path", "Visualize your blind spots with a red path when another vehicle is detected nearby.", ""}, + {"ShowFPS", "FPS Counter", "Display the Frames Per Second (FPS) of your onroad UI for monitoring system performance.", ""}, + {"LeadInfo", "Lead Info and Logics", "Get detailed information about the vehicle ahead, including speed and distance, and the logic behind your following distance.", ""}, + {"RoadNameUI", "Road Name", "See the name of the road you're on at the bottom of your screen. Sourced from OpenStreetMap.", ""}, + {"UseVienna", "Use Vienna Speed Limit Signs", "Use the Vienna (EU) speed limit style signs as opposed to MUTCD (US).", ""}, + + {"DriverCamera", "Driver Camera On Reverse", "Show the driver's camera feed when you shift to reverse.", "../assets/img_driver_face_static.png"}, + {"GreenLightAlert", "Green Light Alert", "Get an alert when a traffic light changes from red to green.", "../frogpilot/assets/toggle_icons/icon_green_light.png"}, + + {"ModelUI", "Model UI", "Personalize how the model's visualizations appear on your screen.", "../assets/offroad/icon_calibration.png"}, + {"AccelerationPath", "Acceleration Path", "Visualize the car's intended acceleration or deceleration with a color-coded path.", ""}, + {"LaneLinesWidth", "Lane Lines", "Adjust the visual thickness of lane lines on your display.\n\nDefault matches the MUTCD average of 4 inches.", ""}, + {"PathEdgeWidth", "Path Edges", "Adjust the width of the path edges shown on your UI to represent different driving modes and statuses.\n\nDefault is 20% of the total path.\n\nBlue = Navigation\nLight Blue = Always On Lateral\nGreen = Default with 'FrogPilot Colors'\nLight Green = Default with stock colors\nOrange = Experimental Mode Active\nYellow = Conditional Overriden", ""}, + {"PathWidth", "Path Width", "Customize the width of the driving path shown on your UI.\n\nDefault matches the width of a 2019 Lexus ES 350.", ""}, + {"RoadEdgesWidth", "Road Edges", "Adjust the visual thickness of road edges on your display.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches.", ""}, + {"UnlimitedLength", "'Unlimited' Road UI Length", "Extend the display of the path, lane lines, and road edges as far as the system can detect, providing a more expansive view of the road ahead.", ""}, + + {"QOLVisuals", "Quality of Life", "Miscellaneous quality of life changes to improve your overall openpilot experience.", "../frogpilot/assets/toggle_icons/quality_of_life.png"}, + {"DriveStats", "Drive Stats In Home Screen", "Display your device's drive stats in the home screen.", ""}, + {"HideSpeed", "Hide Speed", "Hide the speed indicator in the onroad UI.", ""}, + {"ShowSLCOffset", "Show Speed Limit Offset", "Show the speed limit offset seperated from the speed limit in the onroad UI when using 'Speed Limit Controller'.", ""}, + + {"RandomEvents", "Random Events", "Enjoy a bit of unpredictability with random events that can occur during certain driving conditions.", "../frogpilot/assets/toggle_icons/icon_random.png"}, + {"ScreenBrightness", "Screen Brightness", "Customize your screen brightness.", "../frogpilot/assets/toggle_icons/icon_light.png"}, + {"SilentMode", "Silent Mode", "Mute openpilot sounds for a quieter driving experience.", "../frogpilot/assets/toggle_icons/icon_mute.png"}, + {"WheelIcon", "Steering Wheel Icon", "Replace the default steering wheel icon with a custom design, adding a unique touch to your interface.", "../assets/offroad/icon_openpilot.png"}, + }; + + for (const auto &[param, title, desc, icon] : visualToggles) { + ParamControl *toggle; + + if (param == "CameraView") { + std::vector cameraOptions{tr("Auto"), tr("Standard"), tr("Wide"), tr("Driver")}; + FrogPilotButtonParamControl *preferredCamera = new FrogPilotButtonParamControl(param, title, desc, icon, cameraOptions); + toggle = preferredCamera; + + } else if (param == "CustomTheme") { + FrogPilotParamManageControl *customThemeToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(customThemeToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(customThemeKeys.find(key.c_str()) != customThemeKeys.end()); + } + }); + toggle = customThemeToggle; + } else if (param == "CustomColors" || param == "CustomIcons" || param == "CustomSignals" || param == "CustomSounds") { + std::vector themeOptions{tr("Stock"), tr("Frog"), tr("Tesla"), tr("Stalin")}; + FrogPilotButtonParamControl *themeSelection = new FrogPilotButtonParamControl(param, title, desc, icon, themeOptions); + toggle = themeSelection; + + if (param == "CustomSounds") { + QObject::connect(static_cast(toggle), &FrogPilotButtonParamControl::buttonClicked, [this](int id) { + if (id == 1) { + if (FrogPilotConfirmationDialog::yesorno("Do you want to enable the bonus 'Goat' sound effect?", this)) { + params.putBool("GoatScream", true); + } else { + params.putBool("GoatScream", false); + } + } + }); + } + + } else if (param == "CustomUI") { + FrogPilotParamManageControl *customUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(customUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end()); + } + }); + toggle = customUIToggle; + } else if (param == "LeadInfo") { + std::vector leadInfoToggles{tr("UseSI")}; + std::vector leadInfoToggleNames{tr("Use SI Values")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, leadInfoToggles, leadInfoToggleNames); + + } else if (param == "ModelUI") { + FrogPilotParamManageControl *modelUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(modelUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(modelUIKeys.find(key.c_str()) != modelUIKeys.end()); + } + }); + toggle = modelUIToggle; + } else if (param == "LaneLinesWidth" || param == "RoadEdgesWidth") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 24, std::map(), this, false, " inches"); + } else if (param == "PathEdgeWidth") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, std::map(), this, false, "%"); + } else if (param == "PathWidth") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, std::map(), this, false, " feet", 10); + + } else if (param == "QOLVisuals") { + 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 if (param == "ScreenBrightness") { + std::map brightnessLabels; + for (int i = 0; i <= 101; ++i) { + brightnessLabels[i] = i == 0 ? "Screen Off" : i == 101 ? "Auto" : QString::number(i) + "%"; + } + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 101, brightnessLabels, this, false); + + } else if (param == "WheelIcon") { + std::vector wheelToggles{"RotatingWheel"}; + std::vector wheelToggleNames{tr("Rotating")}; + std::map steeringWheelLabels = {{0, "Stock"}, {1, "Lexus"}, {2, "Toyota"}, {3, "Frog"}, {4, "Rocket"}, {5, "Hyundai"}, {6, "Stalin"}}; + toggle = new FrogPilotParamValueToggleControl(param, title, desc, icon, 0, 6, steeringWheelLabels, this, true, "", 1, wheelToggles, wheelToggleNames); + + } 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), &FrogPilotParamValueControl::buttonPressed, [this]() { + updateToggles(); + }); + + QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() { + update(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamManageControl::manageButtonClicked, [this]() { + update(); + }); + } + + std::set rebootKeys = {"DriveStats"}; + for (const std::string &key : rebootKeys) { + QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() { + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + } + + customOnroadUIKeys = {"AdjacentPath", "BlindSpotPath", "ShowFPS", "LeadInfo", "RoadNameUI", "UseVienna"}; + customThemeKeys = {"CustomColors", "CustomIcons", "CustomSignals", "CustomSounds"}; + modelUIKeys = {"AccelerationPath", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"}; + qolKeys = {"DriveStats", "HideSpeed", "ShowSLCOffset"}; + + QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotVisualsPanel::hideSubToggles); + QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotVisualsPanel::hideSubToggles); + QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotVisualsPanel::updateMetric); + + hideSubToggles(); + updateMetric(); +} + +void FrogPilotVisualsPanel::updateToggles() { + std::thread([this]() { + paramsMemory.putBool("FrogPilotTogglesUpdated", true); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + paramsMemory.putBool("FrogPilotTogglesUpdated", false); + }).detach(); +} + +void FrogPilotVisualsPanel::updateMetric() { + bool previousIsMetric = isMetric; + isMetric = params.getBool("IsMetric"); + + if (isMetric != previousIsMetric) { + double distanceConversion = isMetric ? INCH_TO_CM : CM_TO_INCH; + double speedConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT; + params.putInt("LaneLinesWidth", std::nearbyint(params.getInt("LaneLinesWidth") * distanceConversion)); + params.putInt("RoadEdgesWidth", std::nearbyint(params.getInt("RoadEdgesWidth") * distanceConversion)); + params.putInt("PathWidth", std::nearbyint(params.getInt("PathWidth") * speedConversion)); + } + + FrogPilotParamValueControl *laneLinesWidthToggle = static_cast(toggles["LaneLinesWidth"]); + FrogPilotParamValueControl *roadEdgesWidthToggle = static_cast(toggles["RoadEdgesWidth"]); + FrogPilotParamValueControl *pathWidthToggle = static_cast(toggles["PathWidth"]); + + if (isMetric) { + laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the Vienna average of 10 centimeters."); + roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the Vienna average lane line width of 10 centimeters."); + + laneLinesWidthToggle->updateControl(0, 60, " centimeters"); + roadEdgesWidthToggle->updateControl(0, 60, " centimeters"); + pathWidthToggle->updateControl(0, 30, " meters"); + } else { + laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the MUTCD average of 4 inches."); + roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches."); + + laneLinesWidthToggle->updateControl(0, 24, " inches"); + roadEdgesWidthToggle->updateControl(0, 24, " inches"); + pathWidthToggle->updateControl(0, 100, " feet"); + } + + laneLinesWidthToggle->refresh(); + roadEdgesWidthToggle->refresh(); + + previousIsMetric = isMetric; +} + +void FrogPilotVisualsPanel::parentToggleClicked() { + this->openParentToggle(); +} + +void FrogPilotVisualsPanel::hideSubToggles() { + for (auto &[key, toggle] : toggles) { + bool subToggles = modelUIKeys.find(key.c_str()) != modelUIKeys.end() || + customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end() || + customThemeKeys.find(key.c_str()) != customThemeKeys.end() || + qolKeys.find(key.c_str()) != qolKeys.end(); + toggle->setVisible(!subToggles); + } + + this->closeParentToggle(); +} + +void FrogPilotVisualsPanel::hideEvent(QHideEvent *event) { + hideSubToggles(); +} diff --git a/selfdrive/frogpilot/ui/visual_settings.h.org b/selfdrive/frogpilot/ui/visual_settings.h.org new file mode 100644 index 0000000..f30cda7 --- /dev/null +++ b/selfdrive/frogpilot/ui/visual_settings.h.org @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/qt/offroad/settings.h" + +class FrogPilotVisualsPanel : public FrogPilotListWidget { + Q_OBJECT + +public: + explicit FrogPilotVisualsPanel(SettingsWindow *parent); + +signals: + void closeParentToggle(); + void openParentToggle(); + +private: + void hideEvent(QHideEvent *event); + void hideSubToggles(); + void parentToggleClicked(); + void updateMetric(); + void updateToggles(); + + std::set customOnroadUIKeys; + std::set customThemeKeys; + std::set modelUIKeys; + std::set qolKeys; + + std::map toggles; + + Params params; + Params paramsMemory{"/dev/shm/params"}; + + bool isMetric = params.getBool("IsMetric"); +}; diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 42b4c9e..da91ca3 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -35,12 +35,12 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { // param, title, desc, icon std::vector> toggle_defs{ - { - "OpenpilotEnabledToggle", - tr("Enable openpilot"), - tr("Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off."), - "../assets/offroad/icon_openpilot.png", - }, + // { + // "OpenpilotEnabledToggle", + // tr("Enable openpilot"), + // tr("Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off."), + // "../assets/offroad/icon_openpilot.png", + // }, { "ExperimentalLongitudinalEnabled", tr("openpilot Longitudinal Control (Alpha)"), @@ -50,30 +50,30 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { "Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.")), "../assets/offroad/icon_speed_limit.png", }, - { - "ExperimentalMode", - tr("Experimental Mode"), - "", - "../assets/img_experimental_white.svg", - }, - { - "DisengageOnAccelerator", - tr("Disengage on Accelerator Pedal"), - tr("When enabled, pressing the accelerator pedal will disengage openpilot."), - "../assets/offroad/icon_disengage_on_accelerator.svg", - }, + // { + // "ExperimentalMode", + // tr("Experimental Mode"), + // "", + // "../assets/img_experimental_white.svg", + // }, + // { + // "DisengageOnAccelerator", + // tr("Disengage on Accelerator Pedal"), + // tr("When enabled, pressing the accelerator pedal will disengage openpilot."), + // "../assets/offroad/icon_disengage_on_accelerator.svg", + // }, { "IsLdwEnabled", tr("Enable Lane Departure Warnings"), tr("Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h)."), "../assets/offroad/icon_warning.png", }, - { - "RecordFront", - tr("Record and Upload Driver Camera"), - tr("Upload data from the driver facing camera and help improve the driver monitoring algorithm."), - "../assets/offroad/icon_monitoring.png", - }, + // { + // "RecordFront", + // tr("Record and Upload Driver Camera"), + // tr("Upload data from the driver facing camera and help improve the driver monitoring algorithm."), + // "../assets/offroad/icon_monitoring.png", + // }, { "IsMetric", tr("Use Metric System"), @@ -98,11 +98,11 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { std::vector longi_button_texts{tr("Aggressive"), tr("Standard"), tr("Relaxed")}; - long_personality_setting = new ButtonParamControl("LongitudinalPersonality", tr("Driving Personality"), - tr("Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. " - "In relaxed mode openpilot will stay further away from lead cars."), - "../assets/offroad/icon_speed_limit.png", - longi_button_texts); + // long_personality_setting = new ButtonParamControl("LongitudinalPersonality", tr("Driving Personality"), + // tr("Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. " + // "In relaxed mode openpilot will stay further away from lead cars."), + // "../assets/offroad/icon_speed_limit.png", + // longi_button_texts); for (auto &[param, title, desc, icon] : toggle_defs) { auto toggle = new ParamControl(param, title, desc, icon, this); @@ -447,14 +447,15 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { QObject::connect(frogpilotVisuals, &FrogPilotVisualsPanel::openParentToggle, this, [this]() {frogPilotTogglesOpen = true;}); QList> panels = { - {tr("Device"), device}, - {tr("Network"), new Networking(this)}, - {tr("Toggles"), toggles}, - {tr("Software"), new SoftwarePanel(this)}, - {tr("Controls"), frogpilotControls}, - {tr("Navigation"), new FrogPilotNavigationPanel(this)}, - {tr("Vehicles"), new FrogPilotVehiclesPanel(this)}, - {tr("Visuals"), frogpilotVisuals}, + {tr("Basic"), toggles}, + {tr("Customization"), frogpilotVisuals}, + {tr("Advanced"), frogpilotControls}, + {tr("System"), new Networking(this)}, + {tr("Extras"), device}, + // {tr("Navigation"), new FrogPilotNavigationPanel(this)}, + // {tr("Vehicles"), new FrogPilotVehiclesPanel(this)}, + // {tr("Visuals"), frogpilotVisuals}, + // {tr("Device"), device}, }; nav_btns = new QButtonGroup(this);