mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-21 08:14:00 +08:00
September 27th, 2025 Update
This commit is contained in:
@@ -35,6 +35,8 @@ static void update_state(FrogPilotUIState *fs) {
|
||||
update_theme(fs);
|
||||
|
||||
emit fs->themeUpdated();
|
||||
|
||||
fs->params_memory.remove("UseActiveTheme");
|
||||
}
|
||||
if (frogpilotPlan.getTogglesUpdated()) {
|
||||
frogpilot_scene.frogpilot_toggles = QJsonDocument::fromJson(fs->params_memory.get("FrogPilotToggles").c_str()).object();
|
||||
@@ -62,9 +64,9 @@ void update_theme(FrogPilotUIState *fs) {
|
||||
|
||||
FrogPilotUIState::FrogPilotUIState(QObject *parent) : QObject(parent) {
|
||||
sm = std::make_unique<SubMaster, const std::initializer_list<const char *>>({
|
||||
"carControl", "carState", "controlsState", "deviceState", "frogpilotCarState", "frogpilotDeviceState",
|
||||
"frogpilotNavigation", "frogpilotPlan", "liveDelay", "liveParameters", "liveTorqueParameters", "liveTracks",
|
||||
"navInstruction"
|
||||
"carControl", "carState", "controlsState", "deviceState", "frogpilotCarState", "frogpilotControlsState",
|
||||
"frogpilotDeviceState", "frogpilotNavigation", "frogpilotPlan", "frogpilotRadarState", "liveDelay",
|
||||
"liveParameters", "liveTorqueParameters", "liveTracks", "navInstruction"
|
||||
});
|
||||
|
||||
wifi = new WifiManager(this);
|
||||
|
||||
@@ -49,6 +49,8 @@ struct FrogPilotUIScene {
|
||||
|
||||
QJsonObject frogpilot_toggles;
|
||||
|
||||
QPointF lead_vertices[2];
|
||||
|
||||
QPolygonF track_adjacent_vertices[2];
|
||||
QPolygonF track_edge_vertices;
|
||||
};
|
||||
|
||||
@@ -3,18 +3,35 @@
|
||||
#include "frogpilot/ui/qt/offroad/data_settings.h"
|
||||
|
||||
FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
ButtonControl *deleteDrivingDataBtn = new ButtonControl(tr("Delete Driving Footage and Data"), tr("DELETE"), tr("Deletes all stored driving footage and data from your device. Ideal for maintaining privacy or for simply freeing up space."));
|
||||
QObject::connect(deleteDrivingDataBtn, &ButtonControl::clicked, [=]() {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
bool forceOpenDescriptions = false;
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
QStackedLayout *dataLayout = new QStackedLayout();
|
||||
addItem(dataLayout);
|
||||
|
||||
FrogPilotListWidget *dataMainList = new FrogPilotListWidget(this);
|
||||
ScrollView *dataMainPanel = new ScrollView(dataMainList, this);
|
||||
dataLayout->addWidget(dataMainPanel);
|
||||
|
||||
ButtonControl *deleteDrivingDataButton = new ButtonControl(tr("Delete Driving Data"), tr("DELETE"), tr("<b>Delete all stored driving footage and data</b> to free up space and clear private information."));
|
||||
QObject::connect(deleteDrivingDataButton, &ButtonControl::clicked, [=]() {
|
||||
QDir hdDataDir("/data/media/0/realdata_HD/");
|
||||
QDir konikDataDir("/data/media/0/realdata_konik/");
|
||||
QDir realDataDir("/data/media/0/realdata/");
|
||||
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to delete all of your driving footage and data?"), tr("Delete"), this)) {
|
||||
if (ConfirmationDialog::confirm(tr("Delete all driving data and footage?"), tr("Delete"), this)) {
|
||||
std::thread([=]() mutable {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
deleteDrivingDataBtn->setEnabled(false);
|
||||
deleteDrivingDataBtn->setValue(tr("Deleting..."));
|
||||
deleteDrivingDataButton->setEnabled(false);
|
||||
deleteDrivingDataButton->setValue(tr("Deleting..."));
|
||||
|
||||
QList<QDir> footageDirs = {hdDataDir, konikDataDir, realDataDir};
|
||||
for (const QDir &footageDir : footageDirs) {
|
||||
@@ -31,48 +48,54 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
}
|
||||
}
|
||||
|
||||
deleteDrivingDataBtn->setValue(tr("Deleted!"));
|
||||
deleteDrivingDataButton->setValue(tr("Deleted!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
deleteDrivingDataBtn->setEnabled(true);
|
||||
deleteDrivingDataBtn->setValue("");
|
||||
deleteDrivingDataButton->setEnabled(true);
|
||||
deleteDrivingDataButton->setValue("");
|
||||
|
||||
parent->keepScreenOn = false;
|
||||
}).detach();
|
||||
}
|
||||
});
|
||||
addItem(deleteDrivingDataBtn);
|
||||
if (forceOpenDescriptions) {
|
||||
deleteDrivingDataButton->showDescription();
|
||||
}
|
||||
dataMainList->addItem(deleteDrivingDataButton);
|
||||
|
||||
ButtonControl *deleteErrorLogsBtn = new ButtonControl(tr("Delete Error Logs"), tr("DELETE"), tr("Deletes all stored error logs from your device. Ideal for freeing up space."));
|
||||
QObject::connect(deleteErrorLogsBtn, &ButtonControl::clicked, [=]() {
|
||||
ButtonControl *deleteErrorLogsButton = new ButtonControl(tr("Delete Error Logs"), tr("DELETE"), tr("<b>Delete collected error logs</b> to free up space and clear old crash records."));
|
||||
QObject::connect(deleteErrorLogsButton, &ButtonControl::clicked, [=]() {
|
||||
QDir errorLogsDir("/data/error_logs");
|
||||
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to delete all of the error logs?"), tr("Delete"), this)) {
|
||||
if (ConfirmationDialog::confirm(tr("Delete all error logs?"), tr("Delete"), this)) {
|
||||
std::thread([=]() mutable {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
deleteErrorLogsBtn->setEnabled(false);
|
||||
deleteErrorLogsBtn->setValue(tr("Deleting..."));
|
||||
deleteErrorLogsButton->setEnabled(false);
|
||||
deleteErrorLogsButton->setValue(tr("Deleting..."));
|
||||
|
||||
errorLogsDir.removeRecursively();
|
||||
errorLogsDir.mkpath(".");
|
||||
|
||||
deleteErrorLogsBtn->setValue(tr("Deleted!"));
|
||||
deleteErrorLogsButton->setValue(tr("Deleted!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
deleteErrorLogsBtn->setEnabled(true);
|
||||
deleteErrorLogsBtn->setValue("");
|
||||
deleteErrorLogsButton->setEnabled(true);
|
||||
deleteErrorLogsButton->setValue("");
|
||||
|
||||
parent->keepScreenOn = false;
|
||||
}).detach();
|
||||
}
|
||||
});
|
||||
addItem(deleteErrorLogsBtn);
|
||||
if (forceOpenDescriptions) {
|
||||
deleteErrorLogsButton->showDescription();
|
||||
}
|
||||
dataMainList->addItem(deleteErrorLogsButton);
|
||||
|
||||
FrogPilotButtonsControl *screenRecordingsBtn = new FrogPilotButtonsControl(tr("Screen Recordings"), tr("Manage your screen recordings."), "", {tr("DELETE"), tr("DELETE ALL"), tr("RENAME")});
|
||||
QObject::connect(screenRecordingsBtn, &FrogPilotButtonsControl::buttonClicked, [=](int id) {
|
||||
FrogPilotButtonsControl *screenRecordingsButton = new FrogPilotButtonsControl(tr("Screen Recordings"), tr("<b>Delete or rename screen recordings.</b>"), "", {tr("DELETE"), tr("DELETE ALL"), tr("RENAME")});
|
||||
QObject::connect(screenRecordingsButton, &FrogPilotButtonsControl::buttonClicked, [=](int id) {
|
||||
QDir recordingsDir("/data/media/screen_recordings");
|
||||
QStringList recordingsNames = recordingsDir.entryList(QDir::Files | QDir::NoDotAndDotDot);
|
||||
|
||||
@@ -84,29 +107,29 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
}
|
||||
|
||||
if (id == 0) {
|
||||
QString selection = MultiOptionDialog::getSelection(tr("Select a recording to delete"), mp4Recordings, "", this);
|
||||
QString selection = MultiOptionDialog::getSelection(tr("Choose a screen recording to delete"), mp4Recordings, "", this);
|
||||
if (!selection.isEmpty()) {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to delete this recording?"), tr("Delete"), this)) {
|
||||
if (ConfirmationDialog::confirm(tr("Delete this screen recording?"), tr("Delete"), this)) {
|
||||
std::thread([=]() {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
screenRecordingsBtn->setEnabled(false);
|
||||
screenRecordingsBtn->setValue(tr("Deleting..."));
|
||||
screenRecordingsButton->setEnabled(false);
|
||||
screenRecordingsButton->setValue(tr("Deleting..."));
|
||||
|
||||
screenRecordingsBtn->setVisibleButton(1, false);
|
||||
screenRecordingsBtn->setVisibleButton(2, false);
|
||||
screenRecordingsButton->setVisibleButton(1, false);
|
||||
screenRecordingsButton->setVisibleButton(2, false);
|
||||
|
||||
QFile::remove(recordingsDir.absoluteFilePath(selection));
|
||||
|
||||
screenRecordingsBtn->setValue(tr("Deleted!"));
|
||||
screenRecordingsButton->setValue(tr("Deleted!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
screenRecordingsBtn->setEnabled(true);
|
||||
screenRecordingsBtn->setValue("");
|
||||
screenRecordingsButton->setEnabled(true);
|
||||
screenRecordingsButton->setValue("");
|
||||
|
||||
screenRecordingsBtn->setVisibleButton(1, true);
|
||||
screenRecordingsBtn->setVisibleButton(2, true);
|
||||
screenRecordingsButton->setVisibleButton(1, true);
|
||||
screenRecordingsButton->setVisibleButton(2, true);
|
||||
|
||||
parent->keepScreenOn = false;
|
||||
}).detach();
|
||||
@@ -114,64 +137,65 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
}
|
||||
|
||||
} else if (id == 1) {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to delete all screen recordings?"), tr("Delete All"), this)) {
|
||||
if (ConfirmationDialog::confirm(tr("Delete all screen recordings?"), tr("Delete All"), this)) {
|
||||
std::thread([=]() mutable {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
screenRecordingsBtn->setEnabled(false);
|
||||
screenRecordingsBtn->setValue(tr("Deleting..."));
|
||||
screenRecordingsButton->setEnabled(false);
|
||||
screenRecordingsButton->setValue(tr("Deleting..."));
|
||||
|
||||
screenRecordingsBtn->setVisibleButton(0, false);
|
||||
screenRecordingsBtn->setVisibleButton(2, false);
|
||||
screenRecordingsButton->setVisibleButton(0, false);
|
||||
screenRecordingsButton->setVisibleButton(2, false);
|
||||
|
||||
recordingsDir.removeRecursively();
|
||||
recordingsDir.mkpath(".");
|
||||
|
||||
screenRecordingsBtn->setValue(tr("Deleted!"));
|
||||
screenRecordingsButton->setValue(tr("Deleted!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
screenRecordingsBtn->setEnabled(true);
|
||||
screenRecordingsBtn->setValue("");
|
||||
screenRecordingsButton->setEnabled(true);
|
||||
screenRecordingsButton->setValue("");
|
||||
|
||||
screenRecordingsBtn->setVisibleButton(0, true);
|
||||
screenRecordingsBtn->setVisibleButton(2, true);
|
||||
screenRecordingsButton->setVisibleButton(0, true);
|
||||
screenRecordingsButton->setVisibleButton(2, true);
|
||||
|
||||
parent->keepScreenOn = false;
|
||||
}).detach();
|
||||
}
|
||||
|
||||
} else if (id == 2) {
|
||||
QString selection = MultiOptionDialog::getSelection(tr("Select a recording to rename"), mp4Recordings, "", this);
|
||||
QString selection = MultiOptionDialog::getSelection(tr("Choose a screen recording to rename"), mp4Recordings, "", this);
|
||||
if (!selection.isEmpty()) {
|
||||
QString newName = InputDialog::getText(tr("Enter a new name"), this, tr("Rename Recording")).trimmed().replace(" ", "_");
|
||||
if (!newName.isEmpty()) {
|
||||
QString newBase = InputDialog::getText(tr("Enter a new name"), this, tr("Rename Screen Recording")).trimmed().replace(" ", "_");
|
||||
if (!newBase.isEmpty()) {
|
||||
QString newName = newBase + ".mp4";
|
||||
if (recordingsNames.contains(newName)) {
|
||||
ConfirmationDialog::alert(tr("A recording with this name already exists. Please choose a different name."), this);
|
||||
ConfirmationDialog::alert(tr("Name already in use. Please choose a different name."), this);
|
||||
return;
|
||||
}
|
||||
std::thread([=]() {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
screenRecordingsBtn->setEnabled(false);
|
||||
screenRecordingsBtn->setValue(tr("Renaming..."));
|
||||
screenRecordingsButton->setEnabled(false);
|
||||
screenRecordingsButton->setValue(tr("Renaming..."));
|
||||
|
||||
screenRecordingsBtn->setVisibleButton(0, false);
|
||||
screenRecordingsBtn->setVisibleButton(1, false);
|
||||
screenRecordingsButton->setVisibleButton(0, false);
|
||||
screenRecordingsButton->setVisibleButton(1, false);
|
||||
|
||||
QString newPath = recordingsDir.absoluteFilePath(newName);
|
||||
QString oldPath = recordingsDir.absoluteFilePath(selection);
|
||||
QFile::rename(oldPath, newPath);
|
||||
|
||||
screenRecordingsBtn->setValue(tr("Renamed!"));
|
||||
screenRecordingsButton->setValue(tr("Renamed!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
screenRecordingsBtn->setEnabled(true);
|
||||
screenRecordingsBtn->setValue("");
|
||||
screenRecordingsButton->setEnabled(true);
|
||||
screenRecordingsButton->setValue("");
|
||||
|
||||
screenRecordingsBtn->setVisibleButton(0, true);
|
||||
screenRecordingsBtn->setVisibleButton(1, true);
|
||||
screenRecordingsButton->setVisibleButton(0, true);
|
||||
screenRecordingsButton->setVisibleButton(1, true);
|
||||
|
||||
parent->keepScreenOn = false;
|
||||
}).detach();
|
||||
@@ -179,10 +203,13 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
}
|
||||
}
|
||||
});
|
||||
addItem(screenRecordingsBtn);
|
||||
if (forceOpenDescriptions) {
|
||||
screenRecordingsButton->showDescription();
|
||||
}
|
||||
dataMainList->addItem(screenRecordingsButton);
|
||||
|
||||
FrogPilotButtonsControl *frogpilotBackupBtn = new FrogPilotButtonsControl(tr("FrogPilot Backups"), tr("Manage your FrogPilot backups."), "", {tr("BACKUP"), tr("DELETE"), tr("DELETE ALL"), tr("RESTORE")});
|
||||
QObject::connect(frogpilotBackupBtn, &FrogPilotButtonsControl::buttonClicked, [=](int id) {
|
||||
FrogPilotButtonsControl *frogpilotBackupButton = new FrogPilotButtonsControl(tr("FrogPilot Backups"), tr("<b>Create, delete, or restore FrogPilot backups.</b>"), "", {tr("BACKUP"), tr("DELETE"), tr("DELETE ALL"), tr("RESTORE")});
|
||||
QObject::connect(frogpilotBackupButton, &FrogPilotButtonsControl::buttonClicked, [=](int id) {
|
||||
QDir backupDir("/data/backups");
|
||||
QStringList backupNames = backupDir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::Name).filter(QRegularExpression("^(?!.*_in_progress(?:\\..*)?$).*$"));
|
||||
|
||||
@@ -201,22 +228,22 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
}
|
||||
|
||||
if (id == 0) {
|
||||
QString nameSelection = InputDialog::getText(tr("Name your backup"), this, "", false, 1).trimmed().replace(" ", "_");
|
||||
QString nameSelection = InputDialog::getText(tr("Enter a name for this backup"), this, "", false, 1).trimmed().replace(" ", "_");
|
||||
if (!nameSelection.isEmpty()) {
|
||||
if (backupNames.contains(nameSelection)) {
|
||||
ConfirmationDialog::alert(tr("A backup with this name already exists. Please choose a different name."), this);
|
||||
ConfirmationDialog::alert(tr("Name already in use. Please choose a different name."), this);
|
||||
return;
|
||||
}
|
||||
bool compressed = FrogPilotConfirmationDialog::yesorno(tr("Do you want to compress this backup? This will take a few minutes, but the final result will be smaller and run in the background."), this);
|
||||
bool compressed = FrogPilotConfirmationDialog::yesorno(tr("Compress this backup? This will save space and run in the background but take a bit longer."), this);
|
||||
std::thread([=]() {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
frogpilotBackupBtn->setEnabled(false);
|
||||
frogpilotBackupBtn->setValue(tr("Backing up..."));
|
||||
frogpilotBackupButton->setEnabled(false);
|
||||
frogpilotBackupButton->setValue(tr("Backing up..."));
|
||||
|
||||
frogpilotBackupBtn->setVisibleButton(1, false);
|
||||
frogpilotBackupBtn->setVisibleButton(2, false);
|
||||
frogpilotBackupBtn->setVisibleButton(3, false);
|
||||
frogpilotBackupButton->setVisibleButton(1, false);
|
||||
frogpilotBackupButton->setVisibleButton(2, false);
|
||||
frogpilotBackupButton->setVisibleButton(3, false);
|
||||
|
||||
QString fullBackupPath = backupDir.filePath(nameSelection);
|
||||
QString inProgressBackupPath = fullBackupPath + "_in_progress";
|
||||
@@ -225,7 +252,7 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
std::system(qPrintable("rsync -av /data/openpilot/ " + inProgressBackupPath + "/"));
|
||||
|
||||
if (compressed) {
|
||||
frogpilotBackupBtn->setValue(tr("Compressing..."));
|
||||
frogpilotBackupButton->setValue(tr("Compressing..."));
|
||||
|
||||
std::system(qPrintable("tar -cf - -C " + inProgressBackupPath + " . | zstd -2 -T0 -o " + fullBackupPath + "_in_progress.tar.zst"));
|
||||
|
||||
@@ -238,53 +265,52 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
QDir().rename(inProgressBackupPath, fullBackupPath);
|
||||
}
|
||||
|
||||
frogpilotBackupBtn->setValue(tr("Backup created!"));
|
||||
frogpilotBackupButton->setValue(tr("Backup created!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
frogpilotBackupBtn->setEnabled(true);
|
||||
frogpilotBackupBtn->setValue("");
|
||||
frogpilotBackupButton->setEnabled(true);
|
||||
frogpilotBackupButton->setValue("");
|
||||
|
||||
frogpilotBackupBtn->setVisibleButton(1, true);
|
||||
frogpilotBackupBtn->setVisibleButton(2, true);
|
||||
frogpilotBackupBtn->setVisibleButton(3, true);
|
||||
frogpilotBackupButton->setVisibleButton(1, true);
|
||||
frogpilotBackupButton->setVisibleButton(2, true);
|
||||
frogpilotBackupButton->setVisibleButton(3, true);
|
||||
|
||||
parent->keepScreenOn = false;
|
||||
}).detach();
|
||||
}
|
||||
|
||||
} else if (id == 1) {
|
||||
QString selectionFriendly = MultiOptionDialog::getSelection(tr("Select a backup to delete"), backupFriendlyMap.keys(), "", this);
|
||||
QString selectionFriendly = MultiOptionDialog::getSelection(tr("Choose a FrogPilot backup to delete"), backupFriendlyMap.keys(), "", this);
|
||||
if (!selectionFriendly.isEmpty()) {
|
||||
QString selection = backupFriendlyMap.value(selectionFriendly);
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to delete this backup?"), tr("Delete"), this)) {
|
||||
if (ConfirmationDialog::confirm(tr("Delete this backup?"), tr("Delete"), this)) {
|
||||
std::thread([=]() {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
frogpilotBackupBtn->setEnabled(false);
|
||||
frogpilotBackupBtn->setValue(tr("Deleting..."));
|
||||
frogpilotBackupButton->setEnabled(false);
|
||||
frogpilotBackupButton->setValue(tr("Deleting..."));
|
||||
|
||||
frogpilotBackupBtn->setVisibleButton(0, false);
|
||||
frogpilotBackupBtn->setVisibleButton(2, false);
|
||||
frogpilotBackupBtn->setVisibleButton(3, false);
|
||||
frogpilotBackupButton->setVisibleButton(0, false);
|
||||
frogpilotBackupButton->setVisibleButton(2, false);
|
||||
frogpilotBackupButton->setVisibleButton(3, false);
|
||||
|
||||
QDir dirToDelete(backupDir.filePath(selection));
|
||||
if (selection.endsWith(".tar.gz") || selection.endsWith(".tar.zst")) {
|
||||
QFile::remove(dirToDelete.absolutePath());
|
||||
QFile::remove(backupDir.filePath(selection));
|
||||
} else {
|
||||
dirToDelete.removeRecursively();
|
||||
QDir(backupDir.filePath(selection)).removeRecursively();
|
||||
}
|
||||
|
||||
frogpilotBackupBtn->setValue(tr("Deleted!"));
|
||||
frogpilotBackupButton->setValue(tr("Deleted!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
frogpilotBackupBtn->setEnabled(true);
|
||||
frogpilotBackupBtn->setValue("");
|
||||
frogpilotBackupButton->setEnabled(true);
|
||||
frogpilotBackupButton->setValue("");
|
||||
|
||||
frogpilotBackupBtn->setVisibleButton(0, true);
|
||||
frogpilotBackupBtn->setVisibleButton(2, true);
|
||||
frogpilotBackupBtn->setVisibleButton(3, true);
|
||||
frogpilotBackupButton->setVisibleButton(0, true);
|
||||
frogpilotBackupButton->setVisibleButton(2, true);
|
||||
frogpilotBackupButton->setVisibleButton(3, true);
|
||||
|
||||
parent->keepScreenOn = false;
|
||||
}).detach();
|
||||
@@ -292,49 +318,49 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
}
|
||||
|
||||
} else if (id == 2) {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to delete all FrogPilot backups?"), tr("Delete All"), this)) {
|
||||
if (ConfirmationDialog::confirm(tr("Delete all backups?"), tr("Delete All"), this)) {
|
||||
std::thread([=]() mutable {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
frogpilotBackupBtn->setEnabled(false);
|
||||
frogpilotBackupBtn->setValue(tr("Deleting..."));
|
||||
frogpilotBackupButton->setEnabled(false);
|
||||
frogpilotBackupButton->setValue(tr("Deleting..."));
|
||||
|
||||
frogpilotBackupBtn->setVisibleButton(0, false);
|
||||
frogpilotBackupBtn->setVisibleButton(1, false);
|
||||
frogpilotBackupBtn->setVisibleButton(3, false);
|
||||
frogpilotBackupButton->setVisibleButton(0, false);
|
||||
frogpilotBackupButton->setVisibleButton(1, false);
|
||||
frogpilotBackupButton->setVisibleButton(3, false);
|
||||
|
||||
backupDir.removeRecursively();
|
||||
backupDir.mkpath(".");
|
||||
|
||||
frogpilotBackupBtn->setValue(tr("Deleted!"));
|
||||
frogpilotBackupButton->setValue(tr("Deleted!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
frogpilotBackupBtn->setEnabled(true);
|
||||
frogpilotBackupBtn->setValue("");
|
||||
frogpilotBackupButton->setEnabled(true);
|
||||
frogpilotBackupButton->setValue("");
|
||||
|
||||
frogpilotBackupBtn->setVisibleButton(0, true);
|
||||
frogpilotBackupBtn->setVisibleButton(1, true);
|
||||
frogpilotBackupBtn->setVisibleButton(3, true);
|
||||
frogpilotBackupButton->setVisibleButton(0, true);
|
||||
frogpilotBackupButton->setVisibleButton(1, true);
|
||||
frogpilotBackupButton->setVisibleButton(3, true);
|
||||
|
||||
parent->keepScreenOn = false;
|
||||
}).detach();
|
||||
}
|
||||
|
||||
} else if (id == 3) {
|
||||
QString selectionFriendly = MultiOptionDialog::getSelection(tr("Select a restore point"), backupFriendlyMap.keys(), "", this);
|
||||
QString selectionFriendly = MultiOptionDialog::getSelection(tr("Choose a backup to restore"), backupFriendlyMap.keys(), "", this);
|
||||
if (!selectionFriendly.isEmpty()) {
|
||||
QString selection = backupFriendlyMap.value(selectionFriendly);
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to restore this version of FrogPilot?"), tr("Restore"), this)) {
|
||||
if (ConfirmationDialog::confirm(tr("Restore this backup?"), tr("Restore"), this)) {
|
||||
std::thread([=]() {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
frogpilotBackupBtn->setEnabled(false);
|
||||
frogpilotBackupBtn->setValue(tr("Restoring..."));
|
||||
frogpilotBackupButton->setEnabled(false);
|
||||
frogpilotBackupButton->setValue(tr("Restoring..."));
|
||||
|
||||
frogpilotBackupBtn->setVisibleButton(0, false);
|
||||
frogpilotBackupBtn->setVisibleButton(1, false);
|
||||
frogpilotBackupBtn->setVisibleButton(2, false);
|
||||
frogpilotBackupButton->setVisibleButton(0, false);
|
||||
frogpilotBackupButton->setVisibleButton(1, false);
|
||||
frogpilotBackupButton->setVisibleButton(2, false);
|
||||
|
||||
QString extractDirectory = "/data/restore_temp";
|
||||
QString sourcePath = backupDir.filePath(selection);
|
||||
@@ -342,17 +368,19 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
|
||||
QDir().mkpath(extractDirectory);
|
||||
|
||||
std::system(qPrintable("tar --strip-components=1 -xzf " + sourcePath + " -C " + extractDirectory));
|
||||
if (selection.endsWith(".tar.gz")) {
|
||||
frogpilotBackupButton->setValue(tr("Extracting..."));
|
||||
|
||||
if (selection.endsWith(".tar.zst")) {
|
||||
frogpilotBackupBtn->setValue(tr("Extracting..."));
|
||||
|
||||
QDir().mkpath(extractDirectory);
|
||||
std::system(qPrintable("tar --strip-components=1 -xzf " + sourcePath + " -C " + extractDirectory));
|
||||
} else if (selection.endsWith(".tar.zst")) {
|
||||
frogpilotBackupButton->setValue(tr("Extracting..."));
|
||||
|
||||
std::system(qPrintable("zstd -d " + sourcePath + " -o " + extractDirectory + "/backup.tar"));
|
||||
std::system(qPrintable("tar --strip-components=1 -xf " + extractDirectory + "/backup.tar -C " + extractDirectory));
|
||||
|
||||
QFile::remove(extractDirectory + "/backup.tar");
|
||||
} else {
|
||||
std::system(qPrintable("rsync -av " + sourcePath + "/ " + extractDirectory + "/"));
|
||||
}
|
||||
|
||||
QDir().mkpath(targetPath);
|
||||
@@ -369,11 +397,11 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
|
||||
QFile("/cache/on_backup").open(QIODevice::WriteOnly);
|
||||
|
||||
frogpilotBackupBtn->setValue(tr("Restored!"));
|
||||
frogpilotBackupButton->setValue(tr("Restored!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
frogpilotBackupBtn->setValue(tr("Rebooting..."));
|
||||
frogpilotBackupButton->setValue(tr("Rebooting..."));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
@@ -383,10 +411,13 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
}
|
||||
}
|
||||
});
|
||||
addItem(frogpilotBackupBtn);
|
||||
if (forceOpenDescriptions) {
|
||||
frogpilotBackupButton->showDescription();
|
||||
}
|
||||
dataMainList->addItem(frogpilotBackupButton);
|
||||
|
||||
FrogPilotButtonsControl *toggleBackupBtn = new FrogPilotButtonsControl(tr("Toggle Backups"), tr("Manage your toggle backups."), "", {tr("BACKUP"), tr("DELETE"), tr("DELETE ALL"), tr("RESTORE")});
|
||||
QObject::connect(toggleBackupBtn, &FrogPilotButtonsControl::buttonClicked, [=](int id) {
|
||||
FrogPilotButtonsControl *toggleBackupButton = new FrogPilotButtonsControl(tr("Toggle Backups"), tr("<b>Create, delete, or restore toggle backups.</b>"), "", {tr("BACKUP"), tr("DELETE"), tr("DELETE ALL"), tr("RESTORE")});
|
||||
QObject::connect(toggleBackupButton, &FrogPilotButtonsControl::buttonClicked, [=](int id) {
|
||||
QDir backupDir("/data/toggle_backups");
|
||||
QStringList backupNames = backupDir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::Name).filter(QRegularExpression("^(?!.*_in_progress$).*$"));
|
||||
|
||||
@@ -414,21 +445,21 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
}
|
||||
|
||||
if (id == 0) {
|
||||
QString nameSelection = InputDialog::getText(tr("Name your toggle backup"), this, "", false, 1).trimmed().replace(" ", "_");
|
||||
QString nameSelection = InputDialog::getText(tr("Enter a name for this backup"), this, "", false, 1).trimmed().replace(" ", "_");
|
||||
if (!nameSelection.isEmpty()) {
|
||||
if (backupNames.contains(nameSelection)) {
|
||||
ConfirmationDialog::alert(tr("A toggle backup with this name already exists. Please choose a different name."), this);
|
||||
ConfirmationDialog::alert(tr("Name already in use. Please choose a different name."), this);
|
||||
return;
|
||||
}
|
||||
std::thread([=]() {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
toggleBackupBtn->setEnabled(false);
|
||||
toggleBackupBtn->setValue(tr("Backing up..."));
|
||||
toggleBackupButton->setEnabled(false);
|
||||
toggleBackupButton->setValue(tr("Backing up..."));
|
||||
|
||||
toggleBackupBtn->setVisibleButton(1, false);
|
||||
toggleBackupBtn->setVisibleButton(2, false);
|
||||
toggleBackupBtn->setVisibleButton(3, false);
|
||||
toggleBackupButton->setVisibleButton(1, false);
|
||||
toggleBackupButton->setVisibleButton(2, false);
|
||||
toggleBackupButton->setVisibleButton(3, false);
|
||||
|
||||
QString fullBackupPath = backupDir.filePath(nameSelection);
|
||||
QString inProgressBackupPath = fullBackupPath + "_in_progress";
|
||||
@@ -439,49 +470,49 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
|
||||
QDir().rename(inProgressBackupPath, fullBackupPath);
|
||||
|
||||
toggleBackupBtn->setValue(tr("Backup created!"));
|
||||
toggleBackupButton->setValue(tr("Backup created!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
toggleBackupBtn->setEnabled(true);
|
||||
toggleBackupBtn->setValue("");
|
||||
toggleBackupButton->setEnabled(true);
|
||||
toggleBackupButton->setValue("");
|
||||
|
||||
toggleBackupBtn->setVisibleButton(1, true);
|
||||
toggleBackupBtn->setVisibleButton(2, true);
|
||||
toggleBackupBtn->setVisibleButton(3, true);
|
||||
toggleBackupButton->setVisibleButton(1, true);
|
||||
toggleBackupButton->setVisibleButton(2, true);
|
||||
toggleBackupButton->setVisibleButton(3, true);
|
||||
|
||||
parent->keepScreenOn = false;
|
||||
}).detach();
|
||||
}
|
||||
|
||||
} else if (id == 1) {
|
||||
QString selectionFriendly = MultiOptionDialog::getSelection(tr("Select a toggle backup to delete"), backupFriendlyMap.keys(), "", this);
|
||||
QString selectionFriendly = MultiOptionDialog::getSelection(tr("Choose a backup to delete"), backupFriendlyMap.keys(), "", this);
|
||||
if (!selectionFriendly.isEmpty()) {
|
||||
QString selection = backupFriendlyMap.value(selectionFriendly);
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to delete this toggle backup?"), tr("Delete"), this)) {
|
||||
if (ConfirmationDialog::confirm(tr("Delete this backup?"), tr("Delete"), this)) {
|
||||
std::thread([=]() {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
toggleBackupBtn->setEnabled(false);
|
||||
toggleBackupBtn->setValue(tr("Deleting..."));
|
||||
toggleBackupButton->setEnabled(false);
|
||||
toggleBackupButton->setValue(tr("Deleting..."));
|
||||
|
||||
toggleBackupBtn->setVisibleButton(0, false);
|
||||
toggleBackupBtn->setVisibleButton(2, false);
|
||||
toggleBackupBtn->setVisibleButton(3, false);
|
||||
toggleBackupButton->setVisibleButton(0, false);
|
||||
toggleBackupButton->setVisibleButton(2, false);
|
||||
toggleBackupButton->setVisibleButton(3, false);
|
||||
|
||||
QDir dirToDelete(backupDir.filePath(selection));
|
||||
dirToDelete.removeRecursively();
|
||||
|
||||
toggleBackupBtn->setValue(tr("Deleted!"));
|
||||
toggleBackupButton->setValue(tr("Deleted!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
toggleBackupBtn->setEnabled(true);
|
||||
toggleBackupBtn->setValue("");
|
||||
toggleBackupButton->setEnabled(true);
|
||||
toggleBackupButton->setValue("");
|
||||
|
||||
toggleBackupBtn->setVisibleButton(0, true);
|
||||
toggleBackupBtn->setVisibleButton(2, true);
|
||||
toggleBackupBtn->setVisibleButton(3, true);
|
||||
toggleBackupButton->setVisibleButton(0, true);
|
||||
toggleBackupButton->setVisibleButton(2, true);
|
||||
toggleBackupButton->setVisibleButton(3, true);
|
||||
|
||||
parent->keepScreenOn = false;
|
||||
}).detach();
|
||||
@@ -489,49 +520,49 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
}
|
||||
|
||||
} else if (id == 2) {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to delete all toggle backups?"), tr("Delete All"), this)) {
|
||||
if (ConfirmationDialog::confirm(tr("Delete all backups?"), tr("Delete All"), this)) {
|
||||
std::thread([=]() mutable {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
toggleBackupBtn->setEnabled(false);
|
||||
toggleBackupBtn->setValue(tr("Deleting..."));
|
||||
toggleBackupButton->setEnabled(false);
|
||||
toggleBackupButton->setValue(tr("Deleting..."));
|
||||
|
||||
toggleBackupBtn->setVisibleButton(0, false);
|
||||
toggleBackupBtn->setVisibleButton(1, false);
|
||||
toggleBackupBtn->setVisibleButton(3, false);
|
||||
toggleBackupButton->setVisibleButton(0, false);
|
||||
toggleBackupButton->setVisibleButton(1, false);
|
||||
toggleBackupButton->setVisibleButton(3, false);
|
||||
|
||||
backupDir.removeRecursively();
|
||||
backupDir.mkpath(".");
|
||||
|
||||
toggleBackupBtn->setValue(tr("Deleted!"));
|
||||
toggleBackupButton->setValue(tr("Deleted!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
toggleBackupBtn->setEnabled(true);
|
||||
toggleBackupBtn->setValue("");
|
||||
toggleBackupButton->setEnabled(true);
|
||||
toggleBackupButton->setValue("");
|
||||
|
||||
toggleBackupBtn->setVisibleButton(0, true);
|
||||
toggleBackupBtn->setVisibleButton(1, true);
|
||||
toggleBackupBtn->setVisibleButton(3, true);
|
||||
toggleBackupButton->setVisibleButton(0, true);
|
||||
toggleBackupButton->setVisibleButton(1, true);
|
||||
toggleBackupButton->setVisibleButton(3, true);
|
||||
|
||||
parent->keepScreenOn = false;
|
||||
}).detach();
|
||||
}
|
||||
|
||||
} else if (id == 3) {
|
||||
QString selectionFriendly = MultiOptionDialog::getSelection(tr("Select a toggle restore point"), backupFriendlyMap.keys(), "", this);
|
||||
QString selectionFriendly = MultiOptionDialog::getSelection(tr("Choose a backup to restore"), backupFriendlyMap.keys(), "", this);
|
||||
if (!selectionFriendly.isEmpty()) {
|
||||
QString selection = backupFriendlyMap.value(selectionFriendly);
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to restore this toggle backup?"), tr("Restore"), this)) {
|
||||
if (ConfirmationDialog::confirm(tr("Restore this backup?"), tr("Restore"), this)) {
|
||||
std::thread([=]() {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
toggleBackupBtn->setEnabled(false);
|
||||
toggleBackupBtn->setValue(tr("Restoring..."));
|
||||
toggleBackupButton->setEnabled(false);
|
||||
toggleBackupButton->setValue(tr("Restoring..."));
|
||||
|
||||
toggleBackupBtn->setVisibleButton(0, false);
|
||||
toggleBackupBtn->setVisibleButton(1, false);
|
||||
toggleBackupBtn->setVisibleButton(2, false);
|
||||
toggleBackupButton->setVisibleButton(0, false);
|
||||
toggleBackupButton->setVisibleButton(1, false);
|
||||
toggleBackupButton->setVisibleButton(2, false);
|
||||
|
||||
QString sourcePath = backupDir.filePath(selection);
|
||||
QString targetPath = "/data/params/d";
|
||||
@@ -542,16 +573,16 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
|
||||
updateFrogPilotToggles();
|
||||
|
||||
toggleBackupBtn->setValue(tr("Restored!"));
|
||||
toggleBackupButton->setValue(tr("Restored!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
toggleBackupBtn->setEnabled(true);
|
||||
toggleBackupBtn->setValue("");
|
||||
toggleBackupButton->setEnabled(true);
|
||||
toggleBackupButton->setValue("");
|
||||
|
||||
toggleBackupBtn->setVisibleButton(0, true);
|
||||
toggleBackupBtn->setVisibleButton(1, true);
|
||||
toggleBackupBtn->setVisibleButton(2, true);
|
||||
toggleBackupButton->setVisibleButton(0, true);
|
||||
toggleBackupButton->setVisibleButton(1, true);
|
||||
toggleBackupButton->setVisibleButton(2, true);
|
||||
|
||||
parent->keepScreenOn = false;
|
||||
}).detach();
|
||||
@@ -559,5 +590,8 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
}
|
||||
}
|
||||
});
|
||||
addItem(toggleBackupBtn);
|
||||
if (forceOpenDescriptions) {
|
||||
toggleBackupButton->showDescription();
|
||||
}
|
||||
dataMainList->addItem(toggleBackupButton);
|
||||
}
|
||||
|
||||
@@ -10,4 +10,6 @@ public:
|
||||
|
||||
private:
|
||||
FrogPilotSettingsWindow *parent;
|
||||
|
||||
Params params;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
#include "frogpilot/ui/qt/offroad/device_settings.h"
|
||||
|
||||
FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
ScreenRecorder *screenRecorder = new ScreenRecorder(this);
|
||||
screenRecorder->setVisible(false);
|
||||
|
||||
@@ -24,21 +33,22 @@ FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
deviceLayout->addWidget(screenPanel);
|
||||
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> deviceToggles {
|
||||
{"DeviceManagement", tr("Device Settings"), tr("Settings that control device behavior."), "../../frogpilot/assets/toggle_icons/icon_device.png"},
|
||||
{"LowVoltageShutdown", tr("Battery Shutdown Threshold"), tr("Automatically shut down the device when the vehicle's battery voltage reaches the set threshold preventing excessive battery drain to protect the battery."), ""},
|
||||
{"DeviceShutdown", tr("Device Shutdown Timer"), tr("How long the device stays on for after you go offroad."), ""},
|
||||
{"NoLogging", tr("Disable Data Logging"), QString("<b>%1</b><br><br>%2").arg(tr("WARNING: This will prevent your drives from being recorded and all data will be unobtainable!")).arg(tr("Disable all data logging to improve privacy.")), ""},
|
||||
{"NoUploads", tr("Disable Data Uploads"), QString("<b>%1</b><br><br>%2").arg(tr("WARNING: This will prevent your drives from appearing on <b>comma connect</b> which may impact debugging and support!")).arg(tr("Prevent the device from sending any data to <b>comma</b>'s servers.")), ""},
|
||||
{"HigherBitrate", tr("High Bitrate Recording"), tr("Record driving footage at double the standard bitrate for improved video quality in driving logs."), ""},
|
||||
{"IncreaseThermalLimits", tr("Increase Thermal Safety Limit"), QString("<b>%1</b><br><br>%2").arg(tr("WARNING: This can damage your device by exceeding safe temperature limits!")).arg(tr("Allow the device to run hotter than comma recommended limit.")), ""},
|
||||
{"UseKonikServer", tr("Use Konik's Server Instead of comma's"), tr("Upload your driving data to <b>connect.konik.ai</b> instead of <b>connect.comma.ai</b>."), ""},
|
||||
{"DeviceManagement", tr("Device Settings"), tr("<b>Settings that control how the device runs, powers off, and manages driving data.</b>"), "../../frogpilot/assets/toggle_icons/icon_device.png"},
|
||||
{"DeviceShutdown", tr("Device Shutdown Timer"), tr("<b>Keep the device on for the set amount of time after a drive</b> before it shuts down automatically."), ""},
|
||||
{"NoLogging", tr("Disable Logging"), QString("<b>%1</b><br><br>%2").arg(tr("WARNING: This will prevent your drives from being recorded and all data will be unobtainable!")).arg(tr("<b>Prevent the device from saving driving data.</b>")), ""},
|
||||
{"NoUploads", tr("Disable Uploads"), QString("<b>%1</b><br><br>%2").arg(tr("WARNING: This will prevent your drives from being uploaded to <b>comma connect</b> which will impact debugging and official support from comma!")).arg(tr("<b>Prevent the device from uploading driving data.</b>")), ""},
|
||||
{"HigherBitrate", tr("High-Quality Recording"), tr("<b>Save drive footage in higher video quality.</b>"), ""},
|
||||
{"LowVoltageShutdown", tr("Low-Voltage Cutoff"), tr("<b>While parked, if the battery voltage falls below the set level, the device shuts down</b> to prevent excessive battery drain."), ""},
|
||||
{"IncreaseThermalLimits", tr("Raise Temperature Limits"), QString("<b>%1</b><br><br>%2").arg(tr("WARNING: Running at higher temperatures may damage your device!")).arg(tr("<b>Allow the device to run at higher temperatures</b> before throttling or shutting down. Use only if you understand the risks!")), ""},
|
||||
{"UseKonikServer", tr("Use Konik Server"), tr("<b>Upload driving data to \"connect.konik.ai\" instead of \"connect.comma.ai\".</b>"), ""},
|
||||
|
||||
{"ScreenManagement", tr("Screen Settings"), tr("Settings that control screen behavior."), "../../frogpilot/assets/toggle_icons/icon_light.png"},
|
||||
{"ScreenBrightness", tr("Screen Brightness (Offroad)"), tr("The screen brightness when not driving."), ""},
|
||||
{"ScreenBrightnessOnroad", tr("Screen Brightness (Onroad)"), tr("The screen brightness while driving."), ""},
|
||||
{"ScreenRecorder", tr("Screen Recorder"), tr("Enable a button in the driving screen to record the screen."), ""},
|
||||
{"ScreenTimeout", tr("Screen Timeout (Offroad)"), tr("How long it takes for the screen to turn off when not driving."), ""},
|
||||
{"ScreenTimeoutOnroad", tr("Screen Timeout (Onroad)"), tr("How long it takes for the screen to turn off while driving."), ""},
|
||||
{"ScreenManagement", tr("Screen Settings"), tr("<b>Settings that control screen brightness, screen recording, and timeout duration.</b>"), "../../frogpilot/assets/toggle_icons/icon_light.png"},
|
||||
{"ScreenBrightness", tr("Screen Brightness (Offroad)"), tr("<b>The screen brightness while not driving.</b>"), ""},
|
||||
{"ScreenBrightnessOnroad", tr("Screen Brightness (Onroad)"), tr("<b>The screen brightness while driving.</b>"), ""},
|
||||
{"ScreenRecorder", tr("Screen Recorder"), tr("<b>Add a button to the driving screen to record the display.</b>"), ""},
|
||||
{"ScreenTimeout", tr("Screen Timeout (Offroad)"), tr("<b>How long the screen stays on after being tapped while not driving.</b>"), ""},
|
||||
{"ScreenTimeoutOnroad", tr("Screen Timeout (Onroad)"), tr("<b>How long the screen stays on after being tapped while driving.</b>"), ""},
|
||||
{"StandbyMode", tr("Standby Mode"), tr("<b>Turn the screen off while driving and automatically wake it up for alerts or engagement state changes.</b>"), ""},
|
||||
|
||||
{"IgnoreMe", "Ignore Me", "This is simply used to fix the layout when the user opens the descriptions and the menu gets wonky. No idea why it happens, but I can't be asked to properly fix it so whatever. Sue me.", ""},
|
||||
{"IgnoreMe2", "Ignore Me", "This is simply used to fix the layout when the user opens the descriptions and the menu gets wonky. No idea why it happens, but I can't be asked to properly fix it so whatever. Sue me.", ""},
|
||||
@@ -64,7 +74,7 @@ FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
deviceToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 33, QString(), shutdownLabels, 1, true);
|
||||
} else if (param == "NoUploads") {
|
||||
std::vector<QString> uploadsToggles{"DisableOnroadUploads"};
|
||||
std::vector<QString> uploadsToggleNames{tr("Only Disable While Onroad")};
|
||||
std::vector<QString> uploadsToggleNames{tr("Disable Onroad Only")};
|
||||
deviceToggle = new FrogPilotButtonToggleControl(param, title, desc, icon, uploadsToggles, uploadsToggleNames);
|
||||
} else if (param == "LowVoltageShutdown") {
|
||||
deviceToggle = new FrogPilotParamValueControl(param, title, desc, icon, 11.8, 12.5, tr(" volts"), std::map<float, QString>(), 0.1);
|
||||
@@ -113,9 +123,9 @@ FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
toggles[param] = deviceToggle;
|
||||
|
||||
if (deviceManagementKeys.find(param) != deviceManagementKeys.end()) {
|
||||
if (deviceManagementKeys.contains(param)) {
|
||||
deviceManagementList->addItem(deviceToggle);
|
||||
} else if (screenKeys.find(param) != screenKeys.end()) {
|
||||
} else if (screenKeys.contains(param)) {
|
||||
screenList->addItem(deviceToggle);
|
||||
} else {
|
||||
deviceList->addItem(deviceToggle);
|
||||
@@ -124,9 +134,15 @@ FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
}
|
||||
|
||||
if (FrogPilotManageControl *frogPilotManageToggle = qobject_cast<FrogPilotManageControl*>(deviceToggle)) {
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, this, &FrogPilotDevicePanel::openSubPanel);
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, [this]() {
|
||||
emit openSubPanel();
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(deviceToggle, &AbstractControl::hideDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
QObject::connect(deviceToggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
@@ -136,10 +152,10 @@ FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
static_cast<ParamControl*>(toggles["NoLogging"])->setConfirmation(true, false);
|
||||
static_cast<ParamControl*>(toggles["NoUploads"])->setConfirmation(true, false);
|
||||
|
||||
std::set<QString> brightnessKeys = {"ScreenBrightness", "ScreenBrightnessOnroad"};
|
||||
QSet<QString> brightnessKeys = {"ScreenBrightness", "ScreenBrightnessOnroad"};
|
||||
for (const QString &key : brightnessKeys) {
|
||||
FrogPilotParamValueControl *paramControl = static_cast<FrogPilotParamValueControl*>(toggles[key]);
|
||||
QObject::connect(paramControl, &FrogPilotParamValueControl::valueChanged, [this, key](int value) {
|
||||
QObject::connect(paramControl, &FrogPilotParamValueControl::valueChanged, [key, this](int value) {
|
||||
if (!started && key == "ScreenBrightness") {
|
||||
Hardware::set_brightness(value);
|
||||
} else if (started && key == "ScreenBrightnessOnroad") {
|
||||
@@ -148,15 +164,15 @@ FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
});
|
||||
}
|
||||
|
||||
std::set<QString> forceUpdateKeys = {"NoUploads"};
|
||||
QSet<QString> forceUpdateKeys = {"NoUploads"};
|
||||
for (const QString &key : forceUpdateKeys) {
|
||||
QObject::connect(static_cast<FrogPilotButtonToggleControl*>(toggles[key]), &FrogPilotButtonToggleControl::buttonClicked, this, &FrogPilotDevicePanel::updateToggles);
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, this, &FrogPilotDevicePanel::updateToggles);
|
||||
}
|
||||
|
||||
std::set<QString> rebootKeys = {"HigherBitrate", "UseKonikServer"};
|
||||
QSet<QString> rebootKeys = {"HigherBitrate", "UseKonikServer"};
|
||||
for (const QString &key : rebootKeys) {
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, [this, key](bool state) {
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, [key, this](bool state) {
|
||||
QString filePath;
|
||||
if (key == "HigherBitrate") {
|
||||
filePath = "/cache/use_HD";
|
||||
@@ -184,7 +200,12 @@ FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [deviceLayout, devicePanel] {deviceLayout->setCurrentWidget(devicePanel);});
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [deviceLayout, devicePanel, this] {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
deviceLayout->setCurrentWidget(devicePanel);
|
||||
});
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotDevicePanel::updateState);
|
||||
}
|
||||
|
||||
@@ -205,13 +226,13 @@ void FrogPilotDevicePanel::updateState(const UIState &s) {
|
||||
|
||||
void FrogPilotDevicePanel::updateToggles() {
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
toggle->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -228,13 +249,15 @@ void FrogPilotDevicePanel::updateToggles() {
|
||||
toggle->setVisible(setVisible);
|
||||
|
||||
if (setVisible) {
|
||||
if (deviceManagementKeys.find(key) != deviceManagementKeys.end()) {
|
||||
if (deviceManagementKeys.contains(key)) {
|
||||
toggles["DeviceManagement"]->setVisible(true);
|
||||
} else if (screenKeys.find(key) != screenKeys.end()) {
|
||||
} else if (screenKeys.contains(key)) {
|
||||
toggles["ScreenManagement"]->setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "frogpilot/ui/qt/offroad/frogpilot_settings.h"
|
||||
|
||||
class FrogPilotDevicePanel : public FrogPilotListWidget {
|
||||
@@ -20,16 +18,17 @@ private:
|
||||
void updateState(const UIState &s);
|
||||
void updateToggles();
|
||||
|
||||
bool forceOpenDescriptions;
|
||||
bool started;
|
||||
|
||||
int tuningLevel;
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
std::set<QString> deviceManagementKeys = {"DeviceShutdown", "HigherBitrate", "IncreaseThermalLimits", "LowVoltageShutdown", "NoLogging", "NoUploads", "UseKonikServer"};
|
||||
std::set<QString> screenKeys = {"ScreenBrightness", "ScreenBrightnessOnroad", "ScreenRecorder", "ScreenTimeout", "ScreenTimeoutOnroad"};
|
||||
QSet<QString> deviceManagementKeys = {"DeviceShutdown", "HigherBitrate", "IncreaseThermalLimits", "LowVoltageShutdown", "NoLogging", "NoUploads", "UseKonikServer"};
|
||||
QSet<QString> screenKeys = {"ScreenBrightness", "ScreenBrightnessOnroad", "ScreenRecorder", "ScreenTimeout", "ScreenTimeoutOnroad", "StandbyMode"};
|
||||
|
||||
std::set<QString> parentKeys;
|
||||
QSet<QString> parentKeys;
|
||||
|
||||
FrogPilotSettingsWindow *parent;
|
||||
|
||||
|
||||
@@ -55,12 +55,12 @@ void FrogPilotSettingsWindow::createPanelButtons(FrogPilotListWidget *list) {
|
||||
};
|
||||
|
||||
std::vector<std::tuple<QString, QString, QString>> panelInfo = {
|
||||
{tr("Alerts and Sounds"), tr("FrogPilot settings for alert volumes and custom notifications to stay informed about important driving events."), "../../frogpilot/assets/toggle_icons/icon_sound.png"},
|
||||
{tr("Driving Controls"), tr("FrogPilot settings for acceleration, braking, and steering."), "../../frogpilot/assets/toggle_icons/icon_steering.png"},
|
||||
{tr("Navigation"), tr("Download map data for <b>Curve Speed Control</b>, <b>Speed Limit Controller</b>, and set up <b>Navigate on openpilot (NOO)</b>."), "../../frogpilot/assets/toggle_icons/icon_map.png"},
|
||||
{tr("System Management"), tr("Data storage management, debugging tools, device settings, screen behavior settings, system backups, and utilities to maintain, optimize, and troubleshoot FrogPilot."), "../../frogpilot/assets/toggle_icons/icon_system.png"},
|
||||
{tr("Theme and Appearance"), tr("FrogPilot settings for the current theme, driving-screen, and the overall user interface."), "../../frogpilot/assets/toggle_icons/icon_display.png"},
|
||||
{tr("Vehicle Controls"), tr("Options unique to supported manufacturers and vehicle fingerprint management."), "../../frogpilot/assets/toggle_icons/icon_vehicle.png"}
|
||||
{tr("Alerts and Sounds"), tr("<b>Adjust alert volumes and enable custom notifications.</b>"), "../../frogpilot/assets/toggle_icons/icon_sound.png"},
|
||||
{tr("Driving Controls"), tr("<b>Fine-tune custom FrogPilot acceleration, braking, and steering controls.</b>"), "../../frogpilot/assets/toggle_icons/icon_steering.png"},
|
||||
{tr("Navigation"), tr("<b>Download map data for the \"Speed Limit Controller\" and configure \"Navigate on openpilot\" (NOO).</b>"), "../../frogpilot/assets/toggle_icons/icon_map.png"},
|
||||
{tr("System Settings"), tr("<b>Manage backups, device settings, screen options, storage, and tools to keep FrogPilot running smoothly.</b>"), "../../frogpilot/assets/toggle_icons/icon_system.png"},
|
||||
{tr("Theme and Appearance"), tr("<b>Customize the look of the driving screen and interface, including themes!</b>"), "../../frogpilot/assets/toggle_icons/icon_display.png"},
|
||||
{tr("Vehicle Settings"), tr("<b>Configure car-specific options and steering wheel button mappings.</b>"), "../../frogpilot/assets/toggle_icons/icon_vehicle.png"}
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < panelInfo.size(); ++i) {
|
||||
@@ -85,11 +85,18 @@ void FrogPilotSettingsWindow::createPanelButtons(FrogPilotListWidget *list) {
|
||||
}
|
||||
|
||||
FrogPilotButtonsControl *panelButton = new FrogPilotButtonsControl(title, description, icon, labels);
|
||||
if (title == tr("Alerts and Sounds")) soundPanelButtons = panelButton;
|
||||
if (title == tr("Driving Controls")) drivingPanelButtons = panelButton;
|
||||
if (title == tr("System Management")) systemPanelButtons = panelButton;
|
||||
if (title == tr("Vehicle Controls")) vehiclePanelButtons = panelButton;
|
||||
if (title == tr("Navigation")) navigationPanelButtons = panelButton;
|
||||
if (title == tr("System Settings")) systemPanelButtons = panelButton;
|
||||
if (title == tr("Theme and Appearance")) themePanelButtons = panelButton;
|
||||
if (title == tr("Vehicle Settings")) vehiclePanelButtons = panelButton;
|
||||
|
||||
QObject::connect(panelButton, &FrogPilotButtonsControl::buttonClicked, [this, widgets](int id) {
|
||||
if (forceOpenDescriptions) {
|
||||
panelButton->showDescription();
|
||||
}
|
||||
|
||||
QObject::connect(panelButton, &FrogPilotButtonsControl::buttonClicked, [widgets, this](int id) {
|
||||
mainLayout->setCurrentWidget(widgets[id]);
|
||||
|
||||
panelOpen = true;
|
||||
@@ -106,8 +113,8 @@ void FrogPilotSettingsWindow::createPanelButtons(FrogPilotListWidget *list) {
|
||||
QObject::connect(frogpilotLongitudinalPanel, &FrogPilotLongitudinalPanel::openSubSubPanel, this, &FrogPilotSettingsWindow::openSubSubPanel);
|
||||
QObject::connect(frogpilotMapsPanel, &FrogPilotMapsPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
||||
QObject::connect(frogpilotModelPanel, &FrogPilotModelPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
||||
QObject::connect(frogpilotNavigationPanel, &FrogPilotNavigationPanel::closeSubSubPanel, this, &FrogPilotSettingsWindow::closeSubSubPanel);
|
||||
QObject::connect(frogpilotNavigationPanel, &FrogPilotNavigationPanel::openSubSubPanel, this, &FrogPilotSettingsWindow::openSubSubPanel);
|
||||
QObject::connect(frogpilotNavigationPanel, &FrogPilotNavigationPanel::closeSubPanel, this, &FrogPilotSettingsWindow::closeSubPanel);
|
||||
QObject::connect(frogpilotNavigationPanel, &FrogPilotNavigationPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
||||
QObject::connect(frogpilotSoundsPanel, &FrogPilotSoundsPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
||||
QObject::connect(frogpilotThemesPanel, &FrogPilotThemesPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
||||
QObject::connect(frogpilotVehiclesPanel, &FrogPilotVehiclesPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
||||
@@ -116,6 +123,15 @@ void FrogPilotSettingsWindow::createPanelButtons(FrogPilotListWidget *list) {
|
||||
}
|
||||
|
||||
FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFrame(parent) {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
mainLayout = new QStackedLayout(this);
|
||||
|
||||
QWidget *frogpilotWidget = new QWidget(this);
|
||||
@@ -132,13 +148,12 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram
|
||||
|
||||
std::vector<QString> togglePresets{tr("Minimal"), tr("Standard"), tr("Advanced"), tr("Developer")};
|
||||
togglePreset = new FrogPilotButtonsControl(tr("Tuning Level"),
|
||||
tr("The visibility and complexity of tuning settings. Lower levels simplify the interface by hiding advanced options, while higher levels unlock detailed customization.\n\n"
|
||||
"Minimal - Ideal for those who prefer simplicity or ease of use\n"
|
||||
"Standard - Recommended for most users for a balanced experience\n"
|
||||
"Advanced - Unlocks fine-tuning controls for more experienced users\n"
|
||||
"Developer - Unlocks highly customizable settings for seasoned enthusiasts"),
|
||||
"../../frogpilot/assets/toggle_icons/icon_customization.png",
|
||||
togglePresets, true);
|
||||
tr("Choose your tuning level. Lower levels keep it simple; higher levels unlock more toggles for finer control.\n\n"
|
||||
"Minimal - Ideal for those who prefer simplicity or ease of use\n"
|
||||
"Standard - Recommended for most users for a balanced experience\n"
|
||||
"Advanced - Fine-tuning for experienced users\n"
|
||||
"Developer - Highly customizable settings for seasoned enthusiasts"),
|
||||
"../../frogpilot/assets/toggle_icons/icon_customization.png", togglePresets, true);
|
||||
QObject::connect(togglePreset, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
tuningLevel = id;
|
||||
|
||||
@@ -147,10 +162,13 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram
|
||||
updateVariables();
|
||||
|
||||
if (id == 3) {
|
||||
ConfirmationDialog::alert(tr("WARNING: This unlocks some potentially dangerous settings that can DRASTICALLY alter your driving experience!"), this);
|
||||
ConfirmationDialog::alert(tr("WARNING: These settings are risky and can drastically change how openpilot drives. Only change if you fully understand what they do!"), this);
|
||||
}
|
||||
});
|
||||
togglePreset->setCheckedButton(params.getInt("TuningLevel"));
|
||||
if (forceOpenDescriptions) {
|
||||
togglePreset->showDescription();
|
||||
}
|
||||
list->addItem(togglePreset, true);
|
||||
|
||||
createPanelButtons(list);
|
||||
@@ -178,11 +196,42 @@ void FrogPilotSettingsWindow::updateTuningLevel() {
|
||||
updateVariables();
|
||||
}
|
||||
|
||||
void FrogPilotSettingsWindow::showEvent(QShowEvent *event) {
|
||||
static bool alertShown = false;
|
||||
|
||||
if (forceOpenDescriptions) {
|
||||
togglePreset->showDescription();
|
||||
|
||||
drivingPanelButtons->showDescription();
|
||||
navigationPanelButtons->showDescription();
|
||||
soundPanelButtons->showDescription();
|
||||
systemPanelButtons->showDescription();
|
||||
themePanelButtons->showDescription();
|
||||
vehiclePanelButtons->showDescription();
|
||||
|
||||
if (!alertShown) {
|
||||
ConfirmationDialog::alert(tr("All toggle descriptions are currently expanded. You can tap a toggle's name to open or close its description at any time!"), this);
|
||||
alertShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FrogPilotSettingsWindow::hideEvent(QHideEvent *event) {
|
||||
closePanel();
|
||||
}
|
||||
|
||||
void FrogPilotSettingsWindow::closePanel() {
|
||||
if (forceOpenDescriptions) {
|
||||
togglePreset->showDescription();
|
||||
|
||||
drivingPanelButtons->showDescription();
|
||||
navigationPanelButtons->showDescription();
|
||||
soundPanelButtons->showDescription();
|
||||
systemPanelButtons->showDescription();
|
||||
themePanelButtons->showDescription();
|
||||
vehiclePanelButtons->showDescription();
|
||||
}
|
||||
|
||||
mainLayout->setCurrentWidget(frogpilotPanel);
|
||||
|
||||
panelOpen = false;
|
||||
@@ -198,6 +247,9 @@ void FrogPilotSettingsWindow::updateState() {
|
||||
}
|
||||
|
||||
void FrogPilotSettingsWindow::updateVariables() {
|
||||
FrogPilotUIState &fs = *frogpilotUIState();
|
||||
QJsonObject &frogpilot_toggles = fs.frogpilot_toggles;
|
||||
|
||||
std::string carParams = params.get("CarParamsPersistent");
|
||||
if (!carParams.empty()) {
|
||||
AlignedBuffer aligned_buf;
|
||||
@@ -206,10 +258,8 @@ void FrogPilotSettingsWindow::updateVariables() {
|
||||
cereal::CarParams::SafetyModel safetyModel = CP.getSafetyConfigs()[0].getSafetyModel();
|
||||
|
||||
std::string carFingerprint = CP.getCarFingerprint();
|
||||
std::string carMake = CP.getCarName();
|
||||
carMake = CP.getCarName();
|
||||
|
||||
friction = CP.getLateralTuning().getTorque().getFriction();
|
||||
hasAutoTune = (carMake == "hyundai" || carMake == "toyota") && CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::TORQUE;
|
||||
hasBSM = CP.getEnableBsm();
|
||||
hasDashSpeedLimits = carMake == "ford" || carMake == "hyundai" || carMake == "toyota";
|
||||
hasExperimentalOpenpilotLongitudinal = CP.getExperimentalLongitudinalAvailable();
|
||||
@@ -218,22 +268,21 @@ void FrogPilotSettingsWindow::updateVariables() {
|
||||
hasPCMCruise = CP.getPcmCruise();
|
||||
hasPedal = CP.getEnableGasInterceptor();
|
||||
hasRadar = !CP.getRadarUnavailable();
|
||||
hasSNG = CP.getAutoResumeSng();
|
||||
hasSDSU = frogpilot_toggles.value("has_sdsu").toBool();
|
||||
hasSNG = hasOpenpilotLongitudinal && CP.getAutoResumeSng();
|
||||
hasZSS = frogpilot_toggles.value("has_zss").toBool();
|
||||
isAngleCar = CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE;
|
||||
isBolt = carFingerprint == "CHEVROLET_BOLT_CC" || carFingerprint == "CHEVROLET_BOLT_EUV";
|
||||
isGM = carMake == "gm";
|
||||
isHKG = carMake == "hyundai";
|
||||
isHKGCanFd = isHKG && safetyModel == cereal::CarParams::SafetyModel::HYUNDAI_CANFD;
|
||||
isSubaru = carMake == "subaru";
|
||||
isTorqueCar = CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::TORQUE;
|
||||
isToyota = carMake == "toyota";
|
||||
isTSK = CP.getSecOcRequired();
|
||||
isVolt = carFingerprint == "CHEVROLET_VOLT";
|
||||
latAccelFactor = CP.getLateralTuning().getTorque().getLatAccelFactor();
|
||||
longitudinalActuatorDelay = CP.getLongitudinalActuatorDelay();
|
||||
startAccel = CP.getStartAccel();
|
||||
steerActuatorDelay = CP.getSteerActuatorDelay();
|
||||
steerKp = CP.getLateralTuning().getTorque().getKp();
|
||||
steerRatio = CP.getSteerRatio();
|
||||
stopAccel = CP.getStopAccel();
|
||||
stoppingDecelRate = CP.getStoppingDecelRate();
|
||||
@@ -336,7 +385,14 @@ void FrogPilotSettingsWindow::updateVariables() {
|
||||
capnp::FlatArrayMessageReader fpcmsg(aligned_buf.align(frogpilotCarParams.data(), frogpilotCarParams.size()));
|
||||
cereal::FrogPilotCarParams::Reader FPCP = fpcmsg.getRoot<cereal::FrogPilotCarParams>();
|
||||
|
||||
canUsePedal = FPCP.getCanUsePedal();
|
||||
canUseSDSU = FPCP.getCanUseSDSU();
|
||||
friction = FPCP.getLateralTuning().getTorque().getFriction();
|
||||
hasAutoTune = (carMake == "hyundai" || carMake == "toyota") && FPCP.getLateralTuning().which() == cereal::FrogPilotCarParams::LateralTuning::TORQUE;
|
||||
isTorqueCar = FPCP.getLateralTuning().which() == cereal::FrogPilotCarParams::LateralTuning::TORQUE;
|
||||
latAccelFactor = FPCP.getLateralTuning().getTorque().getLatAccelFactor();
|
||||
openpilotLongitudinalControlDisabled = FPCP.getOpenpilotLongitudinalControlDisabled();
|
||||
steerKp = FPCP.getLateralTuning().getTorque().getKp();
|
||||
}
|
||||
|
||||
isC3 = util::read_file("/sys/firmware/devicetree/base/model").find("tici") != std::string::npos;
|
||||
|
||||
@@ -11,6 +11,9 @@ public:
|
||||
|
||||
void updateVariables();
|
||||
|
||||
bool canUsePedal = false;
|
||||
bool canUseSDSU = false;
|
||||
bool forceOpenDescriptions = false;
|
||||
bool hasAutoTune = true;
|
||||
bool hasBSM = true;
|
||||
bool hasDashSpeedLimits = true;
|
||||
@@ -20,7 +23,9 @@ public:
|
||||
bool hasPCMCruise = false;
|
||||
bool hasPedal = false;
|
||||
bool hasRadar = true;
|
||||
bool hasSDSU = false;
|
||||
bool hasSNG = false;
|
||||
bool hasZSS = false;
|
||||
bool isAngleCar = false;
|
||||
bool isBolt = false;
|
||||
bool isC3 = false;
|
||||
@@ -63,19 +68,24 @@ private:
|
||||
void closePanel();
|
||||
void createPanelButtons(FrogPilotListWidget *list);
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void updateState();
|
||||
void updateTuningLevel();
|
||||
|
||||
bool panelOpen;
|
||||
|
||||
std::string carMake;
|
||||
|
||||
FrogPilotButtonsControl *drivingPanelButtons;
|
||||
FrogPilotButtonsControl *navigationPanelButtons;
|
||||
FrogPilotButtonsControl *soundPanelButtons;
|
||||
FrogPilotButtonsControl *systemPanelButtons;
|
||||
FrogPilotButtonsControl *themePanelButtons;
|
||||
FrogPilotButtonsControl *togglePreset;
|
||||
FrogPilotButtonsControl *vehiclePanelButtons;
|
||||
|
||||
Params params;
|
||||
Params params_memory{"/dev/shm/params"};
|
||||
Params params_tracking{"/cache/tracking"};
|
||||
|
||||
QStackedLayout *mainLayout;
|
||||
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
#include "frogpilot/ui/qt/offroad/lateral_settings.h"
|
||||
|
||||
FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
QStackedLayout *lateralLayout = new QStackedLayout();
|
||||
addItem(lateralLayout);
|
||||
|
||||
@@ -29,34 +38,35 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
lateralLayout->addWidget(qolPanel);
|
||||
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> lateralToggles {
|
||||
{"AdvancedLateralTune", tr("Advanced Lateral Tuning"), tr("Advanced settings for fine-tuning openpilot's lateral controls."), "../../frogpilot/assets/toggle_icons/icon_advanced_lateral_tune.png"},
|
||||
{"SteerDelay", steerActuatorDelay != 0 ? QString(tr("Actuator Delay (Default: %1)")).arg(QString::number(steerActuatorDelay, 'f', 2)) : tr("Actuator Delay"), tr("How long the steering wheel takes to respond to commands. Higher values account for slower steering; lower values for quicker response."), ""},
|
||||
{"SteerFriction", friction != 0 ? QString(tr("Friction (Default: %1)")).arg(QString::number(friction, 'f', 2)) : tr("Friction"), tr("Adjust steering resistance. Higher values feel more stable but heavier; lower values feel lighter but more sensitive."), ""},
|
||||
{"SteerKP", steerKp != 0 ? QString(tr("Kp Factor (Default: %1)")).arg(QString::number(steerKp, 'f', 2)) : tr("Kp Factor"), tr("How aggressively openpilot corrects steering. Higher values respond faster but may feel jerky; lower values are smoother but slower."), ""},
|
||||
{"SteerLatAccel", latAccelFactor != 0 ? QString(tr("Lateral Accel (Default: %1)")).arg(QString::number(latAccelFactor, 'f', 2)) : tr("Lateral Accel"), tr("How quickly openpilot makes lateral adjustments. Higher values allow sharper turns; lower values provide smoother steering."), ""},
|
||||
{"SteerRatio", steerRatio != 0 ? QString(tr("Steer Ratio (Default: %1)")).arg(QString::number(steerRatio, 'f', 2)) : tr("Steer Ratio"), tr("How much the steering wheel turns in response to commands. Higher values feel more stable; lower values feel quicker."), ""},
|
||||
{"ForceAutoTune", tr("Force Auto Tune On"), tr("Force-enable comma’s auto lateral tuning."), ""},
|
||||
{"ForceAutoTuneOff", tr("Force Auto Tune Off"), tr("Force-disable comma’s auto lateral tuning."), ""},
|
||||
{"AdvancedLateralTune", tr("Advanced Lateral Tuning"), tr("<b>Advanced steering control changes to fine-tune how openpilot drives.</b>"), "../../frogpilot/assets/toggle_icons/icon_advanced_lateral_tune.png"},
|
||||
{"SteerDelay", steerActuatorDelay != 0 ? QString(tr("Actuator Delay (Default: %1)")).arg(QString::number(steerActuatorDelay, 'f', 2)) : tr("Actuator Delay"), tr("<b>The time between openpilot's steering command and the vehicle's response.</b> Increase if the vehicle reacts late; decrease if it feels jumpy. Auto-learned by default."), ""},
|
||||
{"SteerFriction", friction != 0 ? QString(tr("Friction (Default: %1)")).arg(QString::number(friction, 'f', 2)) : tr("Friction"), tr("<b>Compensates for steering friction.</b> Increase if the wheel sticks near center; decrease if it jitters. Auto-learned by default."), ""},
|
||||
{"SteerKP", steerKp != 0 ? QString(tr("Kp Factor (Default: %1)")).arg(QString::number(steerKp, 'f', 2)) : tr("Kp Factor"), tr("<b>How strongly openpilot corrects lane position.</b> Higher is tighter but twitchier; lower is smoother but slower. Auto-learned by default."), ""},
|
||||
{"SteerLatAccel", latAccelFactor != 0 ? QString(tr("Lateral Acceleration (Default: %1)")).arg(QString::number(latAccelFactor, 'f', 2)) : tr("Lateral Acceleration"), tr("<b>Maps steering torque to turning response.</b> Increase for sharper turns; decrease for gentler steering. Auto-learned by default."), ""},
|
||||
{"SteerRatio", steerRatio != 0 ? QString(tr("Steer Ratio (Default: %1)")).arg(QString::number(steerRatio, 'f', 2)) : tr("Steer Ratio"), tr("<b>The relationship between steering wheel rotation and road wheel angle.</b> Increase if steering feels too quick or twitchy; decrease if it feels too slow or weak. Auto-learned by default."), ""},
|
||||
{"ForceAutoTune", tr("Force Auto-Tune On"), tr("<b>Force-enable openpilot's live auto-tuning for \"Friction\" and \"Lateral Acceleration\".</b>"), ""},
|
||||
{"ForceAutoTuneOff", tr("Force Auto-Tune Off"), tr("<b>Force-disable openpilot's live auto-tuning for \"Friction\" and \"Lateral Acceleration\" and use the set value instead.</b>"), ""},
|
||||
{"ForceTorqueController", tr("Force Torque Controller"), tr("<b>Use torque-based steering control instead of angle-based control for smoother lane keeping, especially in curves.</b>"), ""},
|
||||
|
||||
{"AlwaysOnLateral", tr("Always on Lateral"), tr("openpilot's steering control stays active even when the brake or gas pedals are pressed.<br><br>Deactivation only occurs with the <b>Cruise Control</b> button."), "../../frogpilot/assets/toggle_icons/icon_always_on_lateral.png"},
|
||||
{"AlwaysOnLateralMain", tr("Enable With Cruise Control"), tr("Allow <b>Always on Lateral</b> to be active whenever <b>Cruise Control</b> is active, bypassing the need to enable openpilot first."), ""},
|
||||
{"AlwaysOnLateralLKAS", tr("Enable With LKAS Button"), tr("Allow <b>Always on Lateral</b> to be active whenever <b>LKAS</b> is active, bypassing the need to enable openpilot first."), ""},
|
||||
{"PauseAOLOnBrake", tr("Pause on Brake Below"), tr("Temporarily pause <b>Always on Lateral</b> below the set speed when braking."), ""},
|
||||
{"AlwaysOnLateral", tr("Always On Lateral"), tr("<b>openpilot's steering remains active even when the accelerator or brake pedals are pressed.</b>"), "../../frogpilot/assets/toggle_icons/icon_always_on_lateral.png"},
|
||||
{"AlwaysOnLateralMain", tr("Enable With Cruise Control"), tr("<b>Enable \"Always On Lateral\" whenever \"Cruise Control\" is on, even when openpilot is not engaged.</b>"), ""},
|
||||
{"AlwaysOnLateralLKAS", tr("Enable With LKAS"), tr("<b>Enable \"Always On Lateral\" whenever \"LKAS\" is on, even when openpilot is not engaged.</b>"), ""},
|
||||
{"PauseAOLOnBrake", tr("Pause on Brake Press Below"), tr("<b>Pause \"Always On Lateral\" below the set speed while the brake pedal is pressed.</b>"), ""},
|
||||
|
||||
{"LaneChangeCustomizations", tr("Lane Changes"), tr("Customize how openpilot performs lane changes."), "../../frogpilot/assets/toggle_icons/icon_lane.png"},
|
||||
{"NudgelessLaneChange", tr("Automatic Lane Changes"), tr("Change lanes automatically when the turn signal is on. No steering input needed!"), ""},
|
||||
{"LaneChangeTime", tr("Lane Change Delay"), tr("Delay automatic lane changes by the set amount of time."), ""},
|
||||
{"MinimumLaneChangeSpeed", tr("Minimum Lane Change Speed"), tr("Minimum speed required for openpilot to perform a lane change."), ""},
|
||||
{"LaneDetectionWidth", tr("Minimum Lane Width"), tr("openpilot won't initiate a lane change into a lane narrower than this width."), ""},
|
||||
{"OneLaneChange", tr("One Lane Change Per Signal"), tr("Limit lane changes to one per turn signal activation."), ""},
|
||||
{"LaneChanges", tr("Lane Changes"), tr("<b>Allow openpilot to change lanes.</b>"), "../../frogpilot/assets/toggle_icons/icon_lane.png"},
|
||||
{"NudgelessLaneChange", tr("Automatic Lane Changes"), tr("<b>When the turn signal is on, openpilot will automatically change lanes.</b> No steering-wheel nudge required!"), ""},
|
||||
{"LaneChangeTime", tr("Lane Change Delay"), tr("<b>Delay between turn signal activation and the start of an automatic lane change.</b>"), ""},
|
||||
{"MinimumLaneChangeSpeed", tr("Minimum Lane Change Speed"), tr("<b>Lowest speed at which openpilot will change lanes.</b>"), ""},
|
||||
{"LaneDetectionWidth", tr("Minimum Lane Width"), tr("<b>Prevent automatic lane changes into lanes narrower than the set width.</b>"), ""},
|
||||
{"OneLaneChange", tr("One Lane Change Per Signal"), tr("<b>Limit automatic lane changes to one per turn-signal activation.</b>"), ""},
|
||||
|
||||
{"LateralTune", tr("Lateral Tuning"), tr("Settings for fine-tuning openpilot's lateral controls."), "../../frogpilot/assets/toggle_icons/icon_lateral_tune.png"},
|
||||
{"TurnDesires", tr("Force Turn Desires Below Lane Change Speed"), tr("Force turn desires below the minimum lane change speed to improve turning accuracy."), ""},
|
||||
{"NNFF", tr("Neural Network Feedforward (NNFF)"), tr("Use <b>Twilsonco’s</b> <b>Neural Network FeedForward</b> model for smoother, model-based steering trained on your vehicle's data."), ""},
|
||||
{"NNFFLite", tr("Smooth Curve Handling"), tr("Use <b>Twilsonco’s</b> torque-based adjustments to smooth out steering during curves."), ""},
|
||||
{"LateralTune", tr("Lateral Tuning"), tr("<b>Miscellaneous steering control changes</b> to fine-tune how openpilot drives."), "../../frogpilot/assets/toggle_icons/icon_lateral_tune.png"},
|
||||
{"TurnDesires", tr("Force Turn Desires Below Lane Change Speed"), tr("<b>While driving below the minimum lane change speed with an active turn signal, instruct openpilot to turn left/right.</b>"), ""},
|
||||
{"NNFF", tr("Neural Network Feedforward (NNFF)"), tr("<b>Twilsonco's \"Neural Network FeedForward\" model controller for smoother, model-based steering trained on your vehicle's data.</b>"), ""},
|
||||
{"NNFFLite", tr("Smooth Curve Handling"), tr("<b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b>"), ""},
|
||||
|
||||
{"QOLLateral", tr("Quality of Life"), tr("Miscellaneous features to improve the steering experience."), "../../frogpilot/assets/toggle_icons/icon_quality_of_life.png"},
|
||||
{"PauseLateralSpeed", tr("Pause Steering Below"), tr("Temporarily pause steering control below the set speed."), ""},
|
||||
{"QOLLateral", tr("Quality of Life"), tr("<b>Steering control changes to fine-tune how openpilot drives.</b>"), "../../frogpilot/assets/toggle_icons/icon_quality_of_life.png"},
|
||||
{"PauseLateralSpeed", tr("Pause Steering Below"), tr("<b>Pause steering below the set speed.</b>"), ""},
|
||||
|
||||
{"IgnoreMe", "Ignore Me", "This is simply used to fix the layout when the user opens the descriptions and the menu gets wonky. No idea why it happens, but I can't be asked to properly fix it so whatever. Sue me.", ""},
|
||||
{"IgnoreMe2", "Ignore Me", "This is simply used to fix the layout when the user opens the descriptions and the menu gets wonky. No idea why it happens, but I can't be asked to properly fix it so whatever. Sue me.", ""}
|
||||
@@ -96,7 +106,7 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
} else if (param == "PauseAOLOnBrake") {
|
||||
lateralToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, QString(), std::map<float, QString>(), 1, true);
|
||||
|
||||
} else if (param == "LaneChangeCustomizations") {
|
||||
} else if (param == "LaneChanges") {
|
||||
FrogPilotManageControl *laneChangeToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||
QObject::connect(laneChangeToggle, &FrogPilotManageControl::manageButtonClicked, [lateralLayout, laneChangePanel]() {
|
||||
lateralLayout->setCurrentWidget(laneChangePanel);
|
||||
@@ -137,15 +147,15 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
|
||||
toggles[param] = lateralToggle;
|
||||
|
||||
if (advancedLateralTuneKeys.find(param) != advancedLateralTuneKeys.end()) {
|
||||
if (advancedLateralTuneKeys.contains(param)) {
|
||||
advancedLateralTuneList->addItem(lateralToggle);
|
||||
} else if (aolKeys.find(param) != aolKeys.end()) {
|
||||
} else if (aolKeys.contains(param)) {
|
||||
aolList->addItem(lateralToggle);
|
||||
} else if (laneChangeKeys.find(param) != laneChangeKeys.end()) {
|
||||
} else if (laneChangeKeys.contains(param)) {
|
||||
laneChangeList->addItem(lateralToggle);
|
||||
} else if (lateralTuneKeys.find(param) != lateralTuneKeys.end()) {
|
||||
} else if (lateralTuneKeys.contains(param)) {
|
||||
lateralTuneList->addItem(lateralToggle);
|
||||
} else if (qolKeys.find(param) != qolKeys.end()) {
|
||||
} else if (qolKeys.contains(param)) {
|
||||
qolList ->addItem(lateralToggle);
|
||||
} else {
|
||||
lateralList->addItem(lateralToggle);
|
||||
@@ -154,22 +164,28 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
}
|
||||
|
||||
if (FrogPilotManageControl *frogPilotManageToggle = qobject_cast<FrogPilotManageControl*>(lateralToggle)) {
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, this, &FrogPilotLateralPanel::openSubPanel);
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, [this]() {
|
||||
emit openSubPanel();
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(lateralToggle, &AbstractControl::hideDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
QObject::connect(lateralToggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
std::set<QString> forceUpdateKeys = {"ForceAutoTune", "ForceAutoTuneOff", "LateralTune", "NNFF", "NudgelessLaneChange"};
|
||||
QSet<QString> forceUpdateKeys = {"ForceAutoTune", "ForceAutoTuneOff", "LateralTune", "NNFF", "NudgelessLaneChange"};
|
||||
for (const QString &key : forceUpdateKeys) {
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, this, &FrogPilotLateralPanel::updateToggles);
|
||||
}
|
||||
|
||||
std::set<QString> rebootKeys = {"AlwaysOnLateral", "NNFF", "NNFFLite"};
|
||||
QSet<QString> rebootKeys = {"AlwaysOnLateral", "ForceTorqueController", "NNFF", "NNFFLite"};
|
||||
for (const QString &key : rebootKeys) {
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, [this, key](bool state) {
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, [key, this](bool state) {
|
||||
if (started) {
|
||||
if (key == "AlwaysOnLateral" && state) {
|
||||
if (FrogPilotConfirmationDialog::toggleReboot(this)) {
|
||||
@@ -192,7 +208,7 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
|
||||
steerDelayToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerDelay"]);
|
||||
QObject::connect(steerDelayToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your <b>Actuator Delay</b>?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Actuator Delay</b> to its default value?"), this)) {
|
||||
params.putFloat("SteerDelay", steerActuatorDelay);
|
||||
steerDelayToggle->refresh();
|
||||
}
|
||||
@@ -200,7 +216,7 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
|
||||
steerFrictionToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerFriction"]);
|
||||
QObject::connect(steerFrictionToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your <b>Friction</b>?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Friction</b> to its default value?"), this)) {
|
||||
params.putFloat("SteerFriction", friction);
|
||||
steerFrictionToggle->refresh();
|
||||
}
|
||||
@@ -208,7 +224,7 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
|
||||
steerKPToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerKP"]);
|
||||
QObject::connect(steerKPToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your <b>Kp Factor</b>?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Kp Factor</b> to its default value?"), this)) {
|
||||
params.putFloat("SteerKP", steerKp);
|
||||
steerKPToggle->refresh();
|
||||
}
|
||||
@@ -216,7 +232,7 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
|
||||
steerLatAccelToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerLatAccel"]);
|
||||
QObject::connect(steerLatAccelToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your <b>Lateral Accel</b>?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Lateral Accel</b> to its default value?"), this)) {
|
||||
params.putFloat("SteerLatAccel", latAccelFactor);
|
||||
steerLatAccelToggle->refresh();
|
||||
}
|
||||
@@ -224,13 +240,18 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
|
||||
steerRatioToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerRatio"]);
|
||||
QObject::connect(steerRatioToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your <b>Steer Ratio</b>?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Steer Ratio</b> to its default value?"), this)) {
|
||||
params.putFloat("SteerRatio", steerRatio);
|
||||
steerRatioToggle->refresh();
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [lateralLayout, lateralPanel] {lateralLayout->setCurrentWidget(lateralPanel);});
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [lateralLayout, lateralPanel, this] {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
lateralLayout->setCurrentWidget(lateralPanel);
|
||||
});
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::updateMetric, this, &FrogPilotLateralPanel::updateMetric);
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotLateralPanel::updateState);
|
||||
}
|
||||
@@ -332,20 +353,21 @@ void FrogPilotLateralPanel::updateMetric(bool metric, bool bootRun) {
|
||||
|
||||
void FrogPilotLateralPanel::updateToggles() {
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
toggle->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool forcingAutoTune = !hasAutoTune && params.getBool("ForceAutoTune");
|
||||
bool forcingAutoTuneOff = hasAutoTune && params.getBool("ForceAutoTuneOff");
|
||||
bool forcingTorqueController = !isAngleCar && params.getBool("ForceTorqueController");
|
||||
bool usingNNFF = hasNNFFLog && params.getBool("LateralTune") && params.getBool("NNFF");
|
||||
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool forcingAutoTune = !hasAutoTune && params.getBool("ForceAutoTune");
|
||||
bool forcingAutoTuneOff = hasAutoTune && params.getBool("ForceAutoTuneOff");
|
||||
bool usingNNFF = hasNNFFLog && params.getBool("LateralTune") && params.getBool("NNFF");
|
||||
|
||||
bool setVisible = tuningLevel >= frogpilotToggleLevels[key].toDouble();
|
||||
|
||||
if (key == "AlwaysOnLateralLKAS") {
|
||||
@@ -361,15 +383,24 @@ void FrogPilotLateralPanel::updateToggles() {
|
||||
else if (key == "ForceAutoTune") {
|
||||
setVisible &= !hasAutoTune;
|
||||
setVisible &= !isAngleCar;
|
||||
setVisible &= isTorqueCar;
|
||||
setVisible &= isTorqueCar || forcingTorqueController;
|
||||
}
|
||||
|
||||
else if (key == "ForceAutoTuneOff") {
|
||||
setVisible &= hasAutoTune;
|
||||
}
|
||||
|
||||
else if (key == "ForceTorqueController") {
|
||||
setVisible &= !isAngleCar;
|
||||
setVisible &= !isTorqueCar;
|
||||
}
|
||||
|
||||
else if (key == "LaneChangeTime") {
|
||||
setVisible &= params.getBool("LaneChangeCustomizations") && params.getBool("NudgelessLaneChange");
|
||||
setVisible &= params.getBool("LaneChanges") && params.getBool("NudgelessLaneChange");
|
||||
}
|
||||
|
||||
else if (key == "LaneDetectionWidth") {
|
||||
setVisible &= params.getBool("LaneChanges") && params.getBool("NudgelessLaneChange");
|
||||
}
|
||||
|
||||
else if (key == "NNFF") {
|
||||
@@ -389,20 +420,20 @@ void FrogPilotLateralPanel::updateToggles() {
|
||||
else if (key == "SteerFriction") {
|
||||
setVisible &= friction != 0;
|
||||
setVisible &= hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
|
||||
setVisible &= isTorqueCar;
|
||||
setVisible &= isTorqueCar || forcingTorqueController;
|
||||
setVisible &= !usingNNFF;
|
||||
}
|
||||
|
||||
else if (key == "SteerKP") {
|
||||
setVisible &= steerKp != 0;
|
||||
setVisible &= hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
|
||||
setVisible &= isTorqueCar;
|
||||
setVisible &= isTorqueCar || forcingTorqueController;
|
||||
}
|
||||
|
||||
else if (key == "SteerLatAccel") {
|
||||
setVisible &= latAccelFactor != 0;
|
||||
setVisible &= hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
|
||||
setVisible &= isTorqueCar;
|
||||
setVisible &= isTorqueCar || forcingTorqueController;
|
||||
setVisible &= !usingNNFF;
|
||||
}
|
||||
|
||||
@@ -414,19 +445,21 @@ void FrogPilotLateralPanel::updateToggles() {
|
||||
toggle->setVisible(setVisible);
|
||||
|
||||
if (setVisible) {
|
||||
if (advancedLateralTuneKeys.find(key) != advancedLateralTuneKeys.end()) {
|
||||
if (advancedLateralTuneKeys.contains(key)) {
|
||||
toggles["AdvancedLateralTune"]->setVisible(true);
|
||||
} else if (aolKeys.find(key) != aolKeys.end()) {
|
||||
} else if (aolKeys.contains(key)) {
|
||||
toggles["AlwaysOnLateral"]->setVisible(true);
|
||||
} else if (laneChangeKeys.find(key) != laneChangeKeys.end()) {
|
||||
toggles["LaneChangeCustomizations"]->setVisible(true);
|
||||
} else if (lateralTuneKeys.find(key) != lateralTuneKeys.end()) {
|
||||
} else if (laneChangeKeys.contains(key)) {
|
||||
toggles["LaneChanges"]->setVisible(true);
|
||||
} else if (lateralTuneKeys.contains(key)) {
|
||||
toggles["LateralTune"]->setVisible(true);
|
||||
} else if (qolKeys.find(key) != qolKeys.end()) {
|
||||
} else if (qolKeys.contains(key)) {
|
||||
toggles["QOLLateral"]->setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "frogpilot/ui/qt/offroad/frogpilot_settings.h"
|
||||
|
||||
class FrogPilotLateralPanel : public FrogPilotListWidget {
|
||||
@@ -21,6 +19,7 @@ private:
|
||||
void updateState(const UIState &s);
|
||||
void updateToggles();
|
||||
|
||||
bool forceOpenDescriptions;
|
||||
bool hasAutoTune;
|
||||
bool hasNNFFLog;
|
||||
bool hasOpenpilotLongitudinal;
|
||||
@@ -39,13 +38,13 @@ private:
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
std::set<QString> advancedLateralTuneKeys = {"ForceAutoTune", "ForceAutoTuneOff", "SteerDelay", "SteerFriction", "SteerLatAccel", "SteerKP", "SteerRatio"};
|
||||
std::set<QString> aolKeys = {"AlwaysOnLateralLKAS", "AlwaysOnLateralMain", "PauseAOLOnBrake"};
|
||||
std::set<QString> laneChangeKeys = {"LaneChangeTime", "LaneDetectionWidth", "MinimumLaneChangeSpeed", "NudgelessLaneChange", "OneLaneChange"};
|
||||
std::set<QString> lateralTuneKeys = {"NNFF", "NNFFLite", "TurnDesires"};
|
||||
std::set<QString> qolKeys = {"PauseLateralSpeed"};
|
||||
QSet<QString> advancedLateralTuneKeys = {"ForceAutoTune", "ForceAutoTuneOff", "ForceTorqueController", "SteerDelay", "SteerFriction", "SteerLatAccel", "SteerKP", "SteerRatio"};
|
||||
QSet<QString> aolKeys = {"AlwaysOnLateralLKAS", "AlwaysOnLateralMain", "PauseAOLOnBrake"};
|
||||
QSet<QString> laneChangeKeys = {"LaneChangeTime", "LaneDetectionWidth", "MinimumLaneChangeSpeed", "NudgelessLaneChange", "OneLaneChange"};
|
||||
QSet<QString> lateralTuneKeys = {"NNFF", "NNFFLite", "TurnDesires"};
|
||||
QSet<QString> qolKeys = {"PauseLateralSpeed"};
|
||||
|
||||
std::set<QString> parentKeys;
|
||||
QSet<QString> parentKeys;
|
||||
|
||||
FrogPilotParamValueButtonControl *steerDelayToggle;
|
||||
FrogPilotParamValueButtonControl *steerFrictionToggle;
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
#include "frogpilot/ui/qt/offroad/longitudinal_settings.h"
|
||||
|
||||
FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
QStackedLayout *longitudinalLayout = new QStackedLayout();
|
||||
addItem(longitudinalLayout);
|
||||
|
||||
@@ -56,109 +65,113 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
longitudinalLayout->addWidget(trafficPersonalityPanel);
|
||||
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> longitudinalToggles {
|
||||
{"AdvancedLongitudinalTune", tr("Advanced Longitudinal Tuning"), tr("Advanced settings for customizing how openpilot handles acceleration and braking."), "../../frogpilot/assets/toggle_icons/icon_advanced_longitudinal_tune.png"},
|
||||
{"LongitudinalActuatorDelay", longitudinalActuatorDelay != 0 ? QString(tr("Actuator Delay (Default: %1)")).arg(QString::number(longitudinalActuatorDelay, 'f', 2)) : tr("Actuator Delay"), tr("Delay before throttle or brake takes effect. Higher values smooth slow actuators but can feel laggy; lower values react quicker but may overshoot."), ""},
|
||||
{"StartAccel", startAccel != 0 ? QString(tr("Start Acceleration (Default: %1)")).arg(QString::number(startAccel, 'f', 2)) : tr("Start Acceleration"), tr("Extra acceleration applied when pulling away from a stop. Increase for snappier launches at the cost of smoothness; decrease for gentler starts."), ""},
|
||||
{"VEgoStarting", vEgoStarting != 0 ? QString(tr("Start Speed (Default: %1)")).arg(QString::number(vEgoStarting, 'f', 2)) : tr("Start Speed"), tr("Speed where openpilot begins to exit the stopped state. Higher values avoid creeping but may feel sluggish; lower values move sooner but risk creeping."), ""},
|
||||
{"StopAccel", stopAccel != 0 ? QString(tr("Stop Acceleration (Default: %1)")).arg(QString::number(stopAccel, 'f', 2)) : tr("Stop Acceleration"), tr("Brake force applied to hold the vehicle still. Larger values prevent creeping on hills but might jerk to a stop. Smaller values can feel smoother but may allow rolling."), ""},
|
||||
{"StoppingDecelRate", stoppingDecelRate != 0 ? QString(tr("Stopping Rate (Default: %1)")).arg(QString::number(stoppingDecelRate, 'f', 2)) : tr("Stopping Rate"), tr("How quickly braking ramps up when stopping. Faster rates shorten stopping distance but can be harsh; slower rates are smoother but need more room."), ""},
|
||||
{"VEgoStopping", vEgoStopping != 0 ? QString(tr("Stop Speed (Default: %1)")).arg(QString::number(vEgoStopping, 'f', 2)) : tr("Stop Speed"), tr("Speed where openpilot beings to enter the stopped state. Higher values brake earlier for smoother stops but might stop too soon; lower values wait longer and can overshoot."), ""},
|
||||
{"AdvancedLongitudinalTune", tr("Advanced Longitudinal Tuning"), tr("<b>Advanced acceleration and braking control changes</b> to fine-tune how openpilot drives."), "../../frogpilot/assets/toggle_icons/icon_advanced_longitudinal_tune.png"},
|
||||
{"LongitudinalActuatorDelay", longitudinalActuatorDelay != 0 ? QString(tr("Actuator Delay (Default: %1)")).arg(QString::number(longitudinalActuatorDelay, 'f', 2)) : tr("Actuator Delay"), tr("<b>The time between openpilot's throttle or brake command and the vehicle's response.</b> Increase if the vehicle feels slow to react; decrease if it feels too eager or overshoots."), ""},
|
||||
{"StartAccel", startAccel != 0 ? QString(tr("Start Acceleration (Default: %1)")).arg(QString::number(startAccel, 'f', 2)) : tr("Start Acceleration"), tr("<b>Extra acceleration applied when starting from a stop.</b> Increase for quicker takeoffs; decrease for smoother, gentler starts."), ""},
|
||||
{"VEgoStarting", vEgoStarting != 0 ? QString(tr("Start Speed (Default: %1)")).arg(QString::number(vEgoStarting, 'f', 2)) : tr("Start Speed"), tr("<b>The speed at which openpilot exits the stopped state.</b> Increase to reduce creeping; decrease to move sooner after stopping."), ""},
|
||||
{"StopAccel", stopAccel != 0 ? QString(tr("Stop Acceleration (Default: %1)")).arg(QString::number(stopAccel, 'f', 2)) : tr("Stop Acceleration"), tr("<b>Brake force applied to hold the vehicle at a standstill.</b> Increase to prevent rolling on hills; decrease for smoother, softer stops."), ""},
|
||||
{"StoppingDecelRate", stoppingDecelRate != 0 ? QString(tr("Stopping Rate (Default: %1)")).arg(QString::number(stoppingDecelRate, 'f', 2)) : tr("Stopping Rate"), tr("<b>How quickly braking ramps up when stopping.</b> Increase for shorter, firmer stops; decrease for smoother, longer stops."), ""},
|
||||
{"VEgoStopping", vEgoStopping != 0 ? QString(tr("Stop Speed (Default: %1)")).arg(QString::number(vEgoStopping, 'f', 2)) : tr("Stop Speed"), tr("<b>The speed at which openpilot considers the vehicle stopped.</b> Increase to brake earlier and stop smoothly; decrease to wait longer but risk overshooting."), ""},
|
||||
|
||||
{"ConditionalExperimental", tr("Conditional Experimental Mode"), tr("Automatically switch to <b>Experimental Mode</b> when set conditions are met."), "../../frogpilot/assets/toggle_icons/icon_conditional.png"},
|
||||
{"CESpeed", tr("Below"), tr("Switch to <b>Experimental Mode</b> when driving below this speed."), ""},
|
||||
{"CECurves", tr("Curve Detected Ahead"), tr("Switch to <b>Experimental Mode</b> when a curve is detected ahead. Useful for letting the model choose the appropriate speed for the curve."), ""},
|
||||
{"CELead", tr("Lead Detected Ahead"), tr("Switch to <b>Experimental Mode</b> when a slower or stopped vehicle is detected ahead. Can improve braking smoothness and reliability on some vehicles."), ""},
|
||||
{"CENavigation", tr("Navigation Data"), tr("Switch to <b>Experimental Mode</b> when approaching intersections or turns on the active route while using <b>Navigate on openpilot (NOO)</b>. Useful for letting the model choose the appropriate speed for upcoming navigation maneuvers."), ""},
|
||||
{"CEModelStopTime", tr("openpilot Wants to Stop In"), tr("Switch to <b>Experimental Mode</b> when openpilot wants to stop within the set amount of time. This is typically triggered by the driving model \"detecting\" a red light or stop sign."), ""},
|
||||
{"CESignalSpeed", tr("Turn Signal Below"), tr("Switch to <b>Experimental Mode</b> when using a turn signal below the set speed. Useful for letting the model choose the appropriate speed for upcoming left or right turns."), ""},
|
||||
{"ShowCEMStatus", tr("Status Widget"), tr("Show the <b>Conditional Experimental Mode</b> status on the driving screen."), ""},
|
||||
{"ConditionalExperimental", tr("Conditional Experimental Mode"), tr("<b>Automatically switch to \"Experimental Mode\" when set conditions are met.</b> Allows the model to handle challenging situations with smarter decision making."), "../../frogpilot/assets/toggle_icons/icon_conditional.png"},
|
||||
{"CESpeed", tr("Below"), tr("<b>Switch to \"Experimental Mode\" when driving below this speed without a lead</b> to help openpilot handle low-speed situations more smoothly."), ""},
|
||||
{"CECurves", tr("Curve Detected Ahead"), tr("<b>Switch to \"Experimental Mode\" when a curve is detected</b> to allow the model to set an appropriate speed for the curve."), ""},
|
||||
{"CELead", tr("Lead Detected Ahead"), tr("<b>Switch to \"Experimental Mode\" when a slower or stopped vehicle is detected.</b> Can make braking smoother and more reliable on some vehicles."), ""},
|
||||
{"CENavigation", tr("Navigation-Based"), tr("<b>Switch to \"Experimental Mode\" when approaching intersections or turns on the active route</b> while using \"Navigate on openpilot\" (NOO) to allow the model to set an appropriate speed for upcoming maneuvers."), ""},
|
||||
{"CEModelStopTime", tr("Predicted Stop In"), tr("<b>Switch to \"Experimental Mode\" when openpilot predicts a stop within the set time.</b> This is usually triggered when the model \"sees\" a red light or stop sign ahead.<br><br><i><b>Disclaimer</b>: openpilot does not explicitly detect traffic lights or stop signs. In \"Experimental Mode\", openpilot makes end-to-end driving decisions from camera input, which means it may stop even when there's no clear reason.</i>"), ""},
|
||||
{"CESignalSpeed", tr("Turn Signal Below"), tr("<b>Switch to \"Experimental Mode\" when using a turn signal below the set speed</b> to allow the model to choose an appropriate speed for smoother left and right turns."), ""},
|
||||
{"ShowCEMStatus", tr("Status Widget"), tr("<b>Show which condition triggered \"Experimental Mode\"</b> on the driving screen."), ""},
|
||||
|
||||
{"CurveSpeedControl", tr("Curve Speed Control"), tr("Automatically slow down for upcoming curves using downloaded maps or the driving model."), "../../frogpilot/assets/toggle_icons/icon_speed_map.png"},
|
||||
{"CurveDetectionMethod", tr("Curve Detection Method"), tr("How curves are detected. <b>Map-Based</b> uses downloaded map data to identify curves and determine the appropriate speed in which to handle them at, while <b>Vision</b> relies solely on the driving model."), ""},
|
||||
{"MTSCCurvatureCheck", tr("Curve Detection Failsafe"), tr("Only trigger <b>Curve Speed Control</b> if a curve is detected with the model while using the <b>Map-Based</b> method. Useful to help prevent false positives."), ""},
|
||||
{"CurveSensitivity", tr("Curve Detection Sensitivity"), tr("How sensitive openpilot is when detecting curves. Higher values trigger earlier responses at the risk of triggering too often, while lower values increase confidence at the risk of triggering too infrequently."), ""},
|
||||
{"TurnAggressiveness", tr("Curve Speed Aggressiveness"), tr("How aggressive openpilot is when navigating through curves. Higher values result in faster turns but may reduce comfort or stability, while lower values result in slower, smoother turns at the risk of being overly cautious."), ""},
|
||||
{"ShowCSCStatus", tr("Status Widget"), tr("Show <b>Curve Speed Control</b>'s desired speed on the driving screen."), ""},
|
||||
{"CurveSpeedController", tr("Curve Speed Controller"), tr("<b>Automatically slow down for upcoming curves</b> using data learned from your driving style, adapting to curves as you would."), "../../frogpilot/assets/toggle_icons/icon_speed_map.png"},
|
||||
{"CalibratedLateralAcceleration", tr("Calibrated Lateral Acceleration"), tr("<b>The learned lateral acceleration from collected driving data.</b> This sets how fast openpilot will take curves. Higher values allow faster cornering; lower values slow the vehicle for gentler turns."), ""},
|
||||
{"CalibrationProgress", tr("Calibration Progress"), tr("<b>How much curve data has been collected.</b> This is a progress meter; it is normal for the value to stay low and rarely reach 100%."), ""},
|
||||
{"ResetCurveData", tr("Reset Curve Data"), tr("<b>Reset collected user data for \"Curve Speed Controller\".</b>"), ""},
|
||||
{"ShowCSCStatus", tr("Status Widget"), tr("<b>Show the \"Curve Speed Controller\" target speed on the driving screen.</b>"), ""},
|
||||
|
||||
{"CustomPersonalities", tr("Customize Driving Personalities"), tr("Customize the personality profiles to your driving style."), "../../frogpilot/assets/toggle_icons/icon_personality.png"},
|
||||
{"CustomPersonalities", tr("Driving Personalities"), tr("<b>Customize the \"Driving Personalities\"</b> to better match your driving style."), "../../frogpilot/assets/toggle_icons/icon_personality.png"},
|
||||
|
||||
{"TrafficPersonalityProfile", tr("Traffic Personality"), tr("Customize the <b>Traffic</b> personality profile. Tailored for navigating through traffic."), "../../frogpilot/assets/stock_theme/distance_icons/traffic.png"},
|
||||
{"TrafficFollow", tr("Following Distance"), tr("The minimum following distance while in <b>Traffic Mode</b>. openpilot will dynamically adjust between this value and the value in the <b>Aggressive</b> profile based on your current speed."), ""},
|
||||
{"TrafficJerkAcceleration", tr("Acceleration Sensitivity"), tr("How sensitive openpilot is to changes in acceleration while in <b>Traffic Mode</b>. Higher values result in smoother, more gradual acceleration, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"TrafficJerkDeceleration", tr("Deceleration Sensitivity"), tr("How sensitive openpilot is to changes in deceleration while in <b>Traffic Mode</b>. Higher values result in smoother, more gradual deceleration, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"TrafficJerkDanger", tr("Safety Distance Sensitivity"), tr("How cautious openpilot is around other vehicles or obstacles while in <b>Traffic Mode</b>. Higher values increase following distances and prioritize safety, leading to more cautious driving, while lower values allow for closer following but may reduce reaction time."), ""},
|
||||
{"TrafficJerkSpeedDecrease", tr("Speed Decrease Response"), tr("How quickly openpilot decreases speed while in <b>Traffic Mode</b>. Higher values ensure smoother, more gradual speed changes when slowing down, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"TrafficJerkSpeed", tr("Speed Increase Response"), tr("How quickly openpilot increases speed while in <b>Traffic Mode</b>. Higher values ensure smoother, more gradual speed changes when accelerating, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"ResetTrafficPersonality", tr("Reset Settings"), tr("Reset <b>Traffic Mode</b> settings to default values."), ""},
|
||||
{"TrafficPersonalityProfile", tr("Traffic Mode"), tr("<b>Customize the \"Traffic Mode\" personality profile.</b> Designed for stop-and-go driving."), "../../frogpilot/assets/stock_theme/distance_icons/traffic.png"},
|
||||
{"TrafficFollow", tr("Following Distance"), tr("<b>The minimum following distance to the lead vehicle in \"Traffic Mode\".</b> openpilot blends between this value and the \"Aggressive\" profile as speed increases. Increase for more space; decrease for tighter gaps."), ""},
|
||||
{"TrafficJerkAcceleration", tr("Acceleration Smoothness"), tr("<b>How smoothly openpilot accelerates in \"Traffic Mode\".</b> Increase for gentler starts; decrease for faster but more abrupt takeoffs."), ""},
|
||||
{"TrafficJerkDeceleration", tr("Braking Smoothness"), tr("<b>How smoothly openpilot brakes in \"Traffic Mode\".</b> Increase for gentler stops; decrease for quicker but sharper braking."), ""},
|
||||
{"TrafficJerkDanger", tr("Safety Gap Bias"), tr("<b>How much extra space openpilot keeps from the vehicle ahead in \"Traffic Mode\".</b> Increase for larger gaps and more cautious following; decrease for tighter gaps and closer following."), ""},
|
||||
{"TrafficJerkSpeedDecrease", tr("Slowdown Response"), tr("<b>How smoothly openpilot slows down in \"Traffic Mode\".</b> Increase for more gradual deceleration; decrease for faster but sharper slowdowns."), ""},
|
||||
{"TrafficJerkSpeed", tr("Speed-Up Response"), tr("<b>How smoothly openpilot speeds up in \"Traffic Mode\".</b> Increase for more gradual acceleration; decrease for quicker but more jolting acceleration."), ""},
|
||||
{"ResetTrafficPersonality", tr("Reset to Defaults"), tr("<b>Reset \"Traffic Mode\" settings to defaults.</b>"), ""},
|
||||
|
||||
{"AggressivePersonalityProfile", tr("Aggressive Personality"), tr("Customize the <b>Aggressive</b> personality profile. Designed for a more assertive driving style."), "../../frogpilot/assets/stock_theme/distance_icons/aggressive.png"},
|
||||
{"AggressiveFollow", tr("Following Distance"), tr("How many seconds openpilot will follow behind lead vehicles while using the <b>Aggressive</b> personality profile.<br><br>Default: 1.25 seconds."), ""},
|
||||
{"AggressiveJerkAcceleration", tr("Acceleration Sensitivity"), tr("How sensitive openpilot is to changes in acceleration while using the <b>Aggressive</b> personality profile. Higher values result in smoother, more gradual acceleration, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"AggressiveJerkDeceleration", tr("Deceleration Sensitivity"), tr("How sensitive openpilot is to changes in deceleration while using the <b>Aggressive</b> personality profile. Higher values result in smoother, more gradual deceleration, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"AggressiveJerkDanger", tr("Safety Distance Sensitivity"), tr("How cautious openpilot is around other vehicles or obstacles while using the <b>Aggressive</b> personality profile. Higher values increase following distances and prioritize safety, leading to more cautious driving, while lower values allow for closer following but may reduce reaction time."), ""},
|
||||
{"AggressiveJerkSpeedDecrease", tr("Speed Decrease Response"), tr("How quickly openpilot decreases speed while using the <b>Aggressive</b> personality profile. Higher values ensure smoother, more gradual speed changes when slowing down, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"AggressiveJerkSpeed", tr("Speed Increase Response"), tr("How quickly openpilot increases speed while using the <b>Aggressive</b> personality profile. Higher values ensure smoother, more gradual speed changes when accelerating, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"ResetAggressivePersonality", tr("Reset Settings"), tr("Reset the <b>Aggressive</b> personality profile settings to default values."), ""},
|
||||
{"AggressivePersonalityProfile", tr("Aggressive"), tr("<b>Customize the \"Aggressive\" personality profile.</b> Designed for assertive driving with tighter gaps."), "../../frogpilot/assets/stock_theme/distance_icons/aggressive.png"},
|
||||
{"AggressiveFollow", tr("Following Distance"), tr("<b>How many seconds openpilot follows behind lead vehicles when using the \"Aggressive\" profile.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds."), ""},
|
||||
{"AggressiveJerkAcceleration", tr("Acceleration Smoothness"), tr("<b>How smoothly openpilot accelerates with the \"Aggressive\" profile.</b> Increase for gentler starts; decrease for faster but more abrupt takeoffs."), ""},
|
||||
{"AggressiveJerkDeceleration", tr("Braking Smoothness"), tr("<b>How smoothly openpilot brakes with the \"Aggressive\" profile.</b> Increase for gentler stops; decrease for quicker but sharper braking."), ""},
|
||||
{"AggressiveJerkDanger", tr("Safety Gap Bias"), tr("<b>How much extra space openpilot keeps from the vehicle ahead with the \"Aggressive\" profile.</b> Increase for larger gaps and more cautious following; decrease for tighter gaps and closer following."), ""},
|
||||
{"AggressiveJerkSpeedDecrease", tr("Slowdown Response"), tr("<b>How smoothly openpilot slows down with the \"Aggressive\" profile.</b> Increase for more gradual deceleration; decrease for faster but sharper slowdowns."), ""},
|
||||
{"AggressiveJerkSpeed", tr("Speed-Up Response"), tr("<b>How smoothly openpilot speeds up with the \"Aggressive\" profile.</b> Increase for more gradual acceleration; decrease for quicker but more jolting acceleration."), ""},
|
||||
{"ResetAggressivePersonality", tr("Reset to Defaults"), tr("<b>Reset the \"Aggressive\" profile to defaults.</b>"), ""},
|
||||
|
||||
{"StandardPersonalityProfile", tr("Standard Personality"), tr("Customize the <b>Standard</b> personality profile. Designed for a balanced driving style."), "../../frogpilot/assets/stock_theme/distance_icons/standard.png"},
|
||||
{"StandardFollow", tr("Following Distance"), tr("How many seconds openpilot will follow behind lead vehicles while using the <b>Standard</b> personality profile.<br><br>Default: 1.45 seconds."), ""},
|
||||
{"StandardJerkAcceleration", tr("Acceleration Sensitivity"), tr("How sensitive openpilot is to changes in acceleration while using the <b>Standard</b> personality profile. Higher values result in smoother, more gradual acceleration, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"StandardJerkDeceleration", tr("Deceleration Sensitivity"), tr("How sensitive openpilot is to changes in deceleration while using the <b>Standard</b> personality profile. Higher values result in smoother, more gradual deceleration, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"StandardJerkDanger", tr("Safety Distance Sensitivity"), tr("How cautious openpilot is around other vehicles or obstacles while using the <b>Standard</b> personality profile. Higher values increase following distances and prioritize safety, leading to more cautious driving, while lower values allow for closer following but may reduce reaction time."), ""},
|
||||
{"StandardJerkSpeedDecrease", tr("Speed Decrease Response"), tr("How quickly openpilot decreases speed while using the <b>Standard</b> personality profile. Higher values ensure smoother, more gradual speed changes when slowing down, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"StandardJerkSpeed", tr("Speed Increase Response"), tr("How quickly openpilot increases speed while using the <b>Standard</b> personality profile. Higher values ensure smoother, more gradual speed changes when accelerating, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"ResetStandardPersonality", tr("Reset Settings"), tr("Reset the <b>Standard</b> personality profile settings to default values."), ""},
|
||||
{"StandardPersonalityProfile", tr("Standard"), tr("<b>Customize the \"Standard\" personality profile.</b> Designed for balanced driving with moderate gaps."), "../../frogpilot/assets/stock_theme/distance_icons/standard.png"},
|
||||
{"StandardFollow", tr("Following Distance"), tr("<b>How many seconds openpilot follows behind lead vehicles when using the \"Standard\" profile.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds."), ""},
|
||||
{"StandardJerkAcceleration", tr("Acceleration Smoothness"), tr("<b>How smoothly openpilot accelerates with the \"Standard\" profile.</b> Increase for gentler starts; decrease for faster but more abrupt takeoffs."), ""},
|
||||
{"StandardJerkDeceleration", tr("Braking Smoothness"), tr("<b>How smoothly openpilot brakes with the \"Standard\" profile.</b> Increase for gentler stops; decrease for quicker but sharper braking."), ""},
|
||||
{"StandardJerkDanger", tr("Safety Gap Bias"), tr("<b>How much extra space openpilot keeps from the vehicle ahead with the \"Standard\" profile.</b> Increase for larger gaps and more cautious following; decrease for tighter gaps and closer following."), ""},
|
||||
{"StandardJerkSpeedDecrease", tr("Slowdown Response"), tr("<b>How smoothly openpilot slows down with the \"Standard\" profile.</b> Increase for more gradual deceleration; decrease for faster but sharper slowdowns."), ""},
|
||||
{"StandardJerkSpeed", tr("Speed-Up Response"), tr("<b>How smoothly openpilot speeds up with the \"Standard\" profile.</b> Increase for more gradual acceleration; decrease for quicker but more jolting acceleration."), ""},
|
||||
{"ResetStandardPersonality", tr("Reset to Defaults"), tr("<b>Reset the \"Standard\" profile to defaults.</b>"), ""},
|
||||
|
||||
{"RelaxedPersonalityProfile", tr("Relaxed Personality"), tr("Customize the <b>Relaxed</b> personality profile. Designed for a more laid-back driving style."), "../../frogpilot/assets/stock_theme/distance_icons/relaxed.png"},
|
||||
{"RelaxedFollow", tr("Following Distance"), tr("How many seconds openpilot will follow behind lead vehicles while using the <b>Relaxed</b> personality profile.<br><br>Default: 1.75 seconds."), ""},
|
||||
{"RelaxedJerkAcceleration", tr("Acceleration Sensitivity"), tr("How sensitive openpilot is to changes in acceleration while using the <b>Relaxed</b> personality profile. Higher values result in smoother, more gradual acceleration, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"RelaxedJerkDeceleration", tr("Deceleration Sensitivity"), tr("How sensitive openpilot is to changes in deceleration while using the <b>Relaxed</b> personality profile. Higher values result in smoother, more gradual deceleration, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"RelaxedJerkDanger", tr("Safety Distance Sensitivity"), tr("How cautious openpilot is around other vehicles or obstacles while using the <b>Relaxed</b> personality profile. Higher values increase following distances and prioritize safety, leading to more cautious driving, while lower values allow for closer following but may reduce reaction time."), ""},
|
||||
{"RelaxedJerkSpeedDecrease", tr("Speed Decrease Response"), tr("How quickly openpilot decreases speed while using the <b>Relaxed</b> personality profile. Higher values ensure smoother, more gradual speed changes when slowing down, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"RelaxedJerkSpeed", tr("Speed Increase Response"), tr("How quickly openpilot increases speed while using the <b>Relaxed</b> personality profile. Higher values ensure smoother, more gradual speed changes when accelerating, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""},
|
||||
{"ResetRelaxedPersonality", tr("Reset Settings"), tr("Reset the <b>Relaxed</b> personality profile settings to default values."), ""},
|
||||
{"RelaxedPersonalityProfile", tr("Relaxed"), tr("<b>Customize the \"Relaxed\" personality profile.</b> Designed for smoother, more comfortable driving with larger gaps."), "../../frogpilot/assets/stock_theme/distance_icons/relaxed.png"},
|
||||
{"RelaxedFollow", tr("Following Distance"), tr("<b>How many seconds openpilot follows behind lead vehicles when using the \"Relaxed\" profile.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds."), ""},
|
||||
{"RelaxedJerkAcceleration", tr("Acceleration Smoothness"), tr("<b>How smoothly openpilot accelerates with the \"Relaxed\" profile.</b> Increase for gentler starts; decrease for faster but more abrupt takeoffs."), ""},
|
||||
{"RelaxedJerkDeceleration", tr("Braking Smoothness"), tr("<b>How smoothly openpilot brakes with the \"Relaxed\" profile.</b> Increase for gentler stops; decrease for quicker but sharper braking."), ""},
|
||||
{"RelaxedJerkDanger", tr("Safety Gap Bias"), tr("<b>How much extra space openpilot keeps from the vehicle ahead with the \"Relaxed\" profile.</b> Increase for larger gaps and more cautious following; decrease for tighter gaps and closer following."), ""},
|
||||
{"RelaxedJerkSpeedDecrease", tr("Slowdown Response"), tr("<b>How smoothly openpilot slows down with the \"Relaxed\" profile.</b> Increase for more gradual deceleration; decrease for faster but sharper slowdowns."), ""},
|
||||
{"RelaxedJerkSpeed", tr("Speed-Up Response"), tr("<b>How smoothly openpilot speeds up with the \"Relaxed\" profile.</b> Increase for more gradual acceleration; decrease for quicker but more jolting acceleration."), ""},
|
||||
{"ResetRelaxedPersonality", tr("Reset to Defaults"), tr("<b>Reset the \"Relaxed\" profile to defaults.</b>"), ""},
|
||||
|
||||
{"LongitudinalTune", tr("Longitudinal Tuning"), tr("Settings that control how openpilot manages speed and acceleration."), "../../frogpilot/assets/toggle_icons/icon_longitudinal_tune.png"},
|
||||
{"AccelerationProfile", tr("Acceleration Profile"), tr("Enable either a sporty or eco-friendly acceleration profile. <b>Sport+</b> aims to make openpilot accelerate as fast as possible!"), ""},
|
||||
{"DecelerationProfile", tr("Deceleration Profile"), tr("Enable either a sporty or eco-friendly deceleration profile."), ""},
|
||||
{"HumanAcceleration", tr("Human-Like Acceleration"), tr("Use the lead vehicle's acceleration rate when at a takeoff and ramp off the acceleration rate when approaching the maximum set speed for a more \"human-like\" driving experience."), ""},
|
||||
{"HumanFollowing", tr("Human-Like Approach Behind Leads"), tr("Dynamically adjust the desired following distance when approaching slower or stopped vehicles for a more \"human-like\" driving experience."), ""},
|
||||
{"LeadDetectionThreshold", tr("Lead Detection Confidence"), tr("How sensitive openpilot is to detecting vehicles ahead. A lower value can help detect vehicles sooner and from farther away, but increases the chance openpilot mistakes other objects for vehicles."), ""},
|
||||
{"MaxDesiredAcceleration", tr("Maximum Acceleration Rate"), tr("Set a cap on how fast openpilot can accelerate."), ""},
|
||||
{"TacoTune", tr("\"Taco Bell Run\" Turn Speed Hack"), tr("The turn speed hack from comma’s 2022 \"Taco Bell Run\" drive. Designed to slow down when taking left/right turns for smoother turns."), ""},
|
||||
{"LongitudinalTune", tr("Longitudinal Tuning"), tr("<b>Acceleration and braking control changes</b> to fine-tune how openpilot drives."), "../../frogpilot/assets/toggle_icons/icon_longitudinal_tune.png"},
|
||||
{"AccelerationProfile", tr("Acceleration Profile"), tr("<b>How quickly openpilot speeds up.</b> \"Eco\" is gentle and efficient, \"Sport\" is firmer and more responsive, and \"Sport+\" accelerates at the maximum rate allowed."), ""},
|
||||
{"DecelerationProfile", tr("Deceleration Profile"), tr("<b>How firmly openpilot slows down.</b> \"Eco\" favors coasting, \"Sport\" applies stronger braking."), ""},
|
||||
{"HumanAcceleration", tr("Human-Like Acceleration"), tr("<b>Acceleration that mimics human behavior</b> by easing the throttle at low speeds and adding extra power when taking off from a stop."), ""},
|
||||
{"HumanFollowing", tr("Human-Like Following"), tr("<b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking."), ""},
|
||||
{"LeadDetectionThreshold", tr("Lead Detection Sensitivity"), tr("<b>How sensitive openpilot is to detecting vehicles.</b> Higher sensitivity allows quicker detection at longer distances but may react to non-vehicle objects; lower sensitivity is more conservative and reduces false detections."), ""},
|
||||
{"MaxDesiredAcceleration", tr("Maximum Acceleration"), tr("<b>Limit the strongest acceleration</b> openpilot can command."), ""},
|
||||
{"TacoTune", tr("\"Taco Bell Run\" Turn Speed Hack"), tr("<b>The turn-speed hack from comma's 2022 \"Taco Bell Run\".</b> Designed to slow down for left and right turns."), ""},
|
||||
|
||||
{"QOLLongitudinal", tr("Quality of Life"), tr("Miscellaneous features to improve the acceleration and braking experience."), "../../frogpilot/assets/toggle_icons/icon_quality_of_life.png"},
|
||||
{"CustomCruise", tr("Cruise Interval"), tr("The interval used when changing the cruise control speed."), ""},
|
||||
{"CustomCruiseLong", tr("Cruise Interval (Long Press)"), tr("The interval used when changing the cruise control speed while holding down the button for 0.5+ seconds."), ""},
|
||||
{"ForceStandstill", tr("Force Keep openpilot in the Standstill State"), tr("Keep openpilot in the standstill state until either the gas pedal or <b>resume</b> button is pressed."), ""},
|
||||
{"ForceStops", tr("Force Stop for \"Detected\" Stop Lights/Signs"), tr("Force a stop whenever openpilot <b>detects</b> a potential red light/stop sign to prevent it from running the red light/stop sign."), ""},
|
||||
{"IncreasedStoppedDistance", tr("Increase Stopped Distance"), tr("Increase the distance openpilot stops behind vehicles."), ""},
|
||||
{"SetSpeedOffset", tr("Set Speed Offset"), tr("How much higher or lower the set speed should be compared to your current set speed. For example, if you prefer to drive 5 mph above the speed limit, this setting will automatically add that difference when you adjust your set speed."), ""},
|
||||
{"MapGears", tr("Map Accel/Decel to Gears"), tr("Map the acceleration and deceleration profiles to your car's <b>Eco</b> or <b>Sport</b> gear modes."), ""},
|
||||
{"ReverseCruise", tr("Reverse Cruise Increase"), tr("Reverse the <b>long press</b> cruise increase feature to increase the max speed by 5 instead of 1 on short presses."), ""},
|
||||
{"QOLLongitudinal", tr("Quality of Life"), tr("<b>Miscellaneous acceleration and braking control changes</b> to fine-tune how openpilot drives."), "../../frogpilot/assets/toggle_icons/icon_quality_of_life.png"},
|
||||
{"CustomCruise", tr("Cruise Interval"), tr("<b>How much the set speed increases or decreases</b> for each + or – cruise control button press."), ""},
|
||||
{"CustomCruiseLong", tr("Cruise Interval (Hold)"), tr("<b>How much the set speed increases or decreases while holding the + or – cruise control buttons.</b>"), ""},
|
||||
{"ForceStops", tr("Force Stop at \"Detected\" Stop Lights/Signs"), tr("<b>Force openpilot to stop whenever the driving model \"detects\" a red light or stop sign.</b><br><br><i><b>Disclaimer</b>: openpilot does not explicitly detect traffic lights or stop signs. In \"Experimental Mode\", openpilot makes end-to-end driving decisions from camera input, which means it may stop even when there's no clear reason.</i>"), ""},
|
||||
{"IncreasedStoppedDistance", tr("Increase Stopped Distance by:"), tr("<b>Add extra space when stopped behind vehicles.</b> Increase for more room; decrease for shorter gaps."), ""},
|
||||
{"MapGears", tr("Map Accel/Decel to Gears"), tr("<b>Map the Acceleration or Deceleration profiles to the vehicle's \"Eco\" and \"Sport\" gear modes.</b>"), ""},
|
||||
{"SetSpeedOffset", tr("Offset Set Speed by:"), tr("<b>Increase the set speed by the chosen offset.</b> For example, set +5 if you usually drive 5 over the limit."), ""},
|
||||
{"ReverseCruise", tr("Reverse Cruise Increase"), tr("<b>Reverse the cruise control button behavior</b> so a short press increases the set speed by 5 instead of 1."), ""},
|
||||
|
||||
{"SpeedLimitController", tr("Speed Limit Controller"), tr("Limit openpilot's maximum driving speed based on data from downloaded maps, <b>Mapbox</b>, <b>Navigate on openpilot</b>, or the dashboard (supported vehicles: <b>Ford</b>, <b>Genesis</b>, <b>Hyundai</b>, <b>Kia</b>, <b>Lexus</b>, <b>Toyota</b>)."), "../assets/offroad/icon_speed_limit.png"},
|
||||
{"SLCFallback", tr("Fallback Speed"), tr("The speed limit source when no speed limit data is available."), ""},
|
||||
{"SLCOverride", tr("Override Speed"), tr("The speed openpilot uses after manually exceeding the posted speed limit.<br><br><b>- Set With Gas Pedal</b>: Uses the speed obtained while pressing the gas<br><b>- Max Set Speed</b>: Uses the cruise control set speed<br><br>Overrides clear upon disengagement."), ""},
|
||||
{"SLCQOL", tr("Quality of Life"), tr("Miscellaneous features to improve the <b>Speed Limit Controller</b> experience."), ""},
|
||||
{"SLCConfirmation", tr("Confirm New Speed Limits"), tr("Require confirmation before applying new speed limits. To accept, use the flashing widget on the driving screen or press the <b>Cruise Increase</b> button. To deny, press the <b>Cruise Decrease</b> button or simply ignore the prompt for 30 seconds."), ""},
|
||||
{"ForceMPHDashboard", tr("Force MPH Readings from Dashboard"), tr("Force dashboard speed limit readings to be in mph."), ""},
|
||||
{"SLCLookaheadHigher", tr("Higher Limit Lookahead Time"), tr("How far ahead openpilot anticipates upcoming higher speed limits from the downloaded map data."), ""},
|
||||
{"SLCLookaheadLower", tr("Lower Limit Lookahead Time"), tr("How far ahead openpilot anticipates upcoming lower speed limits from the downloaded map data."), ""},
|
||||
{"SetSpeedLimit", tr("Match Speed Limit on Engage"), tr("Automatically set cruise control speed to match the current speed limit when first enabling openpilot."), ""},
|
||||
{"SLCMapboxFiller", tr("Use Mapbox as Fallback"), tr("Use <b>Mapbox</b> speed limit data when no other sources are available."), ""},
|
||||
{"SLCPriority", tr("Speed Limit Source Priority"), tr("Define the priority order for speed limit sources (<b>Dashboard</b>, <b>Map Data</b>, <b>Navigation</b>). Higher-priority sources override lower ones when multiple limits are detected."), ""},
|
||||
{"SLCOffsets", tr("Speed Limit Offsets"), tr("Offsets relative to the posted speed limit for a more \"human-like\" driving experience."), ""},
|
||||
{"Offset1", tr("Speed Offset (0–24 mph)"), tr("Target speed offset applied for posted limits between 0 and 24 mph."), ""},
|
||||
{"Offset2", tr("Speed Offset (25–34 mph)"), tr("Target speed offset applied for posted limits between 25 and 34 mph."), ""},
|
||||
{"Offset3", tr("Speed Offset (35–44 mph)"), tr("Target speed offset applied for posted limits between 35 and 44 mph."), ""},
|
||||
{"Offset4", tr("Speed Offset (45–54 mph)"), tr("Target speed offset applied for posted limits between 45 and 54 mph."), ""},
|
||||
{"Offset5", tr("Speed Offset (55–64 mph)"), tr("Target speed offset applied for posted limits between 55 and 64 mph."), ""},
|
||||
{"Offset6", tr("Speed Offset (65–74 mph)"), tr("Target speed offset applied for posted limits between 65 and 74 mph."), ""},
|
||||
{"Offset7", tr("Speed Offset (75–99 mph)"), tr("Target speed offset applied for posted limits between 75 and 99 mph."), ""},
|
||||
{"SLCVisuals", tr("Visual Settings"), tr("Visual features to improve the <b>Speed Limit Controller</b> experience."), ""},
|
||||
{"ShowSLCOffset", tr("Show Speed Limit Offset"), tr("Display the speed limit offset separately on the driving screen."), ""},
|
||||
{"SpeedLimitSources", tr("Show Speed Limit Sources"), tr("Display the speed limit sources on the driving screen."), ""}
|
||||
{"SnowOffsets", tr("Snow"), tr("<b>Driving adjustments for snowy conditions.</b>"), ""},
|
||||
{"IncreaseFollowingSnow", tr("Increase Following Distance by:"), tr("<b>Add extra space behind lead vehicles in snow.</b> Increase for more space; decrease for tighter gaps."), ""},
|
||||
{"IncreasedStoppedDistanceSnow", tr("Increase Stopped Distance by:"), tr("<b>Add extra buffer when stopped behind vehicles in snow.</b> Increase for more room; decrease for shorter gaps."), ""},
|
||||
{"ReduceAccelerationSnow", tr("Reduce Acceleration by:"), tr("<b>Lower the maximum acceleration in snow.</b> Increase for softer takeoffs; decrease for quicker but less stable takeoffs."), ""},
|
||||
{"ReduceLateralAccelerationSnow", tr("Reduce Speed in Curves by:"), tr("<b>Lower the desired speed while driving through curves in snow.</b> Increase for safer, gentler turns; decrease for more aggressive driving in curves."), ""},
|
||||
|
||||
{"SpeedLimitController", tr("Speed Limit Controller"), tr("<b>Limit openpilot's maximum driving speed to the current speed limit</b> obtained from downloaded maps, Mapbox, Navigate on openpilot, or the dashboard for supported vehicles (Ford, Genesis, Hyundai, Kia, Lexus, Toyota)."), "../assets/offroad/icon_speed_limit.png"},
|
||||
{"SLCFallback", tr("Fallback Speed"), tr("<b>The speed used by \"Speed Limit Controller\" when no speed limit is found.</b><br><br>- <b>Set Speed</b>: Use the cruise set speed<br>- <b>Experimental Mode</b>: Estimate the limit using the driving model<br>- <b>Previous Limit</b>: Keep using the last confirmed limit"), ""},
|
||||
{"SLCOverride", tr("Override Speed"), tr("<b>The speed used by \"Speed Limit Controller\" after you manually drive faster than the posted limit.</b><br><br>- <b>Set with Gas Pedal</b>: Use the highest speed reached while pressing the gas<br>- <b>Max Set Speed</b>: Use the cruise set speed<br><br>Overrides clear when openpilot disengages."), ""},
|
||||
{"SLCQOL", tr("Quality of Life"), tr("<b>Miscellaneous \"Speed Limit Controller\" changes</b> to fine-tune how openpilot drives."), ""},
|
||||
{"SLCConfirmation", tr("Confirm New Speed Limits"), tr("<b>Ask before changing to a new speed limit.</b> To accept, tap the flashing on-screen widget or press the Cruise Increase button. To deny, press the Cruise Decrease button or ignore the prompt for 30 seconds."), ""},
|
||||
{"ForceMPHDashboard", tr("Force MPH from Dashboard"), tr("<b>Always read dashboard speed limit signs in mph.</b> Turn this on if the cluster shows mph but the limit is interpreted as km/h."), ""},
|
||||
{"SLCLookaheadHigher", tr("Higher Limit Lookahead Time"), tr("<b>How far ahead openpilot anticipates upcoming higher speed limits</b> from downloaded map data."), ""},
|
||||
{"SLCLookaheadLower", tr("Lower Limit Lookahead Time"), tr("<b>How far ahead openpilot anticipates upcoming lower speed limits</b> from downloaded map data."), ""},
|
||||
{"SetSpeedLimit", tr("Match Speed Limit on Engage"), tr("<b>When openpilot is first enabled, automatically set the max speed to the current posted limit.</b>"), ""},
|
||||
{"SLCMapboxFiller", tr("Use Mapbox as Fallback"), tr("<b>Use Mapbox speed-limit data when no other source is available.</b>"), ""},
|
||||
{"SLCPriority", tr("Speed Limit Source Priority"), tr("<b>The source order for speed limits</b> when more than one is available."), ""},
|
||||
{"SLCOffsets", tr("Speed Limit Offsets"), tr("<b>Add an offset to the posted speed limit</b> to better match your driving style."), ""},
|
||||
{"Offset1", tr("Speed Offset (0–24 mph)"), tr("<b>How much to offset posted speed-limits</b> between 0 and 24 mph."), ""},
|
||||
{"Offset2", tr("Speed Offset (25–34 mph)"), tr("<b>How much to offset posted speed-limits</b> between 25 and 34 mph."), ""},
|
||||
{"Offset3", tr("Speed Offset (35–44 mph)"), tr("<b>How much to offset posted speed-limits</b> between 35 and 44 mph."), ""},
|
||||
{"Offset4", tr("Speed Offset (45–54 mph)"), tr("<b>How much to offset posted speed-limits</b> between 45 and 54 mph."), ""},
|
||||
{"Offset5", tr("Speed Offset (55–64 mph)"), tr("<b>How much to offset posted speed-limits</b> between 55 and 64 mph."), ""},
|
||||
{"Offset6", tr("Speed Offset (65–74 mph)"), tr("<b>How much to offset posted speed-limits</b> between 65 and 74 mph."), ""},
|
||||
{"Offset7", tr("Speed Offset (75–99 mph)"), tr("<b>How much to offset posted speed-limits</b> between 75 and 99 mph."), ""},
|
||||
{"SLCVisuals", tr("Visual Settings"), tr("<b>Visual \"Speed Limit Controller\" changes</b> to fine-tune how the driving screen looks."), ""},
|
||||
{"ShowSLCOffset", tr("Show Speed Limit Offset"), tr("<b>Show the current offset from the posted limit</b> on the driving screen."), ""},
|
||||
{"SpeedLimitSources", tr("Show Speed Limit Sources"), tr("<b>Display the speed-limit sources and their current values</b> on the driving screen."), ""}
|
||||
};
|
||||
|
||||
for (const auto &[param, title, desc, icon] : longitudinalToggles) {
|
||||
@@ -197,7 +210,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
longitudinalToggle = conditionalExperimentalToggle;
|
||||
} else if (param == "CESpeed") {
|
||||
FrogPilotParamValueControl *CESpeed = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr(" mph"), std::map<float, QString>(), 1, true, 175);
|
||||
FrogPilotParamValueControl *CESpeedLead = new FrogPilotParamValueControl("CESpeedLead", tr("With Lead"), tr("Switch to <b>Experimental Mode</b> when driving below this speed with a lead."), icon, 0, 99, tr(" mph"), std::map<float, QString>(), 1, true, 175);
|
||||
FrogPilotParamValueControl *CESpeedLead = new FrogPilotParamValueControl("CESpeedLead", tr("With Lead"), tr("<b>Switch to \"Experimental Mode\" when driving below this speed with a lead</b> to help openpilot handle low-speed situations more smoothly."), icon, 0, 99, tr(" mph"), std::map<float, QString>(), 1, true, 175);
|
||||
FrogPilotDualParamValueControl *conditionalSpeeds = new FrogPilotDualParamValueControl(CESpeed, CESpeedLead);
|
||||
longitudinalToggle = reinterpret_cast<AbstractControl*>(conditionalSpeeds);
|
||||
} else if (param == "CECurves") {
|
||||
@@ -220,39 +233,38 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 9, QString(), stopTimeLabels);
|
||||
} else if (param == "CESignalSpeed") {
|
||||
std::vector<QString> ceSignalToggles{"CESignalLaneDetection"};
|
||||
std::vector<QString> ceSignalToggleNames{tr("Only For Detected Lanes")};
|
||||
std::vector<QString> ceSignalToggleNames{tr("Not For Detected Lanes")};
|
||||
longitudinalToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 99, tr(" mph"), std::map<float, QString>(), 1.0, true, ceSignalToggles, ceSignalToggleNames, true);
|
||||
|
||||
} else if (param == "CurveSpeedControl") {
|
||||
} else if (param == "CurveSpeedController") {
|
||||
FrogPilotManageControl *curveControlToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||
QObject::connect(curveControlToggle, &FrogPilotManageControl::manageButtonClicked, [this, longitudinalLayout, curveSpeedPanel]() {
|
||||
curveDetectionToggle->setEnabledButtons(0, QDir("/data/media/0/osm/offline").exists());
|
||||
|
||||
QObject::connect(curveControlToggle, &FrogPilotManageControl::manageButtonClicked, [longitudinalLayout, curveSpeedPanel]() {
|
||||
longitudinalLayout->setCurrentWidget(curveSpeedPanel);
|
||||
});
|
||||
longitudinalToggle = curveControlToggle;
|
||||
} else if (param == "CurveDetectionMethod") {
|
||||
std::vector<QString> curveDetectionToggles{"MapTurnControl", "VisionTurnControl"};
|
||||
std::vector<QString> curveDetectionToggleNames{tr("Map Based"), tr("Vision")};
|
||||
curveDetectionToggle = new FrogPilotButtonsControl(title, desc, icon, curveDetectionToggleNames, true, false);
|
||||
for (int i = 0; i < curveDetectionToggles.size(); ++i) {
|
||||
if (params.getBool(curveDetectionToggles[i].toStdString())) {
|
||||
curveDetectionToggle->setCheckedButton(i);
|
||||
}
|
||||
}
|
||||
QObject::connect(curveDetectionToggle, &FrogPilotButtonsControl::buttonClicked, [this, curveDetectionToggles](int id) {
|
||||
params.putBool(curveDetectionToggles[id].toStdString(), !params.getBool(curveDetectionToggles[id].toStdString()));
|
||||
} else if (param == "CalibrationProgress") {
|
||||
calibrationProgressLabel = new LabelControl(title, QString::number(params.getFloat("CalibrationProgress"), 'f', 2) + "%", desc);
|
||||
longitudinalToggle = calibrationProgressLabel;
|
||||
} else if (param == "CalibratedLateralAcceleration") {
|
||||
calibratedLateralAccelerationLabel = new LabelControl(title, QString::number(params.getFloat("CalibratedLateralAcceleration"), 'f', 2) + tr(" m/s²"), desc);
|
||||
longitudinalToggle = calibratedLateralAccelerationLabel;
|
||||
} else if (param == "ResetCurveData") {
|
||||
ButtonControl *resetCurveDataButton = new ButtonControl(title, tr("RESET"), desc);
|
||||
QObject::connect(resetCurveDataButton, &ButtonControl::clicked, [this]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your curvature data?"), this)) {
|
||||
params.putFloat("CalibratedLateralAcceleration", 2.00);
|
||||
params.remove("CalibrationProgress");
|
||||
params.remove("CurvatureData");
|
||||
|
||||
updateToggles();
|
||||
});
|
||||
QObject::connect(curveDetectionToggle, &FrogPilotButtonsControl::disabledButtonClicked, [this](int id) {
|
||||
if (id == 0) {
|
||||
ConfirmationDialog::alert(tr("The <b>Map Based</b> option is only available when some <b>Map Data</b> has been downloaded!"), this);
|
||||
params_cache.putFloat("CalibratedLateralAcceleration", 2.00);
|
||||
params_cache.remove("CalibrationProgress");
|
||||
params_cache.remove("CurvatureData");
|
||||
|
||||
calibratedLateralAccelerationLabel->setText(QString::number(2.00, 'f', 2) + tr(" m/s²"));
|
||||
calibrationProgressLabel->setText(QString::number(0.00, 'f', 2) + "%");
|
||||
}
|
||||
});
|
||||
longitudinalToggle = curveDetectionToggle;
|
||||
} else if (param == "CurveSensitivity" || param == "TurnAggressiveness") {
|
||||
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 200, "%");
|
||||
longitudinalToggle = resetCurveDataButton;
|
||||
|
||||
} else if (param == "CustomPersonalities") {
|
||||
FrogPilotManageControl *customPersonalitiesToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||
@@ -261,11 +273,11 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
});
|
||||
longitudinalToggle = customPersonalitiesToggle;
|
||||
} else if (param == "ResetTrafficPersonality" || param == "ResetAggressivePersonality" || param == "ResetStandardPersonality" || param == "ResetRelaxedPersonality") {
|
||||
ButtonControl *resetBtn = new ButtonControl(title, tr("RESET"), desc);
|
||||
longitudinalToggle = resetBtn;
|
||||
ButtonControl *resetButton = new ButtonControl(title, tr("RESET"), desc);
|
||||
longitudinalToggle = resetButton;
|
||||
} else if (param == "TrafficPersonalityProfile") {
|
||||
FrogPilotManageControl *trafficPersonalityToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||
QObject::connect(trafficPersonalityToggle, &FrogPilotManageControl::manageButtonClicked, [this, longitudinalLayout, trafficPersonalityPanel]() {
|
||||
QObject::connect(trafficPersonalityToggle, &FrogPilotManageControl::manageButtonClicked, [longitudinalLayout, trafficPersonalityPanel, this]() {
|
||||
openSubSubPanel();
|
||||
|
||||
longitudinalLayout->setCurrentWidget(trafficPersonalityPanel);
|
||||
@@ -275,7 +287,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
longitudinalToggle = trafficPersonalityToggle;
|
||||
} else if (param == "AggressivePersonalityProfile") {
|
||||
FrogPilotManageControl *aggressivePersonalityToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||
QObject::connect(aggressivePersonalityToggle, &FrogPilotManageControl::manageButtonClicked, [this, longitudinalLayout, aggressivePersonalityPanel]() {
|
||||
QObject::connect(aggressivePersonalityToggle, &FrogPilotManageControl::manageButtonClicked, [longitudinalLayout, aggressivePersonalityPanel, this]() {
|
||||
openSubSubPanel();
|
||||
|
||||
longitudinalLayout->setCurrentWidget(aggressivePersonalityPanel);
|
||||
@@ -285,7 +297,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
longitudinalToggle = aggressivePersonalityToggle;
|
||||
} else if (param == "StandardPersonalityProfile") {
|
||||
FrogPilotManageControl *standardPersonalityToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||
QObject::connect(standardPersonalityToggle, &FrogPilotManageControl::manageButtonClicked, [this, longitudinalLayout, standardPersonalityPanel]() {
|
||||
QObject::connect(standardPersonalityToggle, &FrogPilotManageControl::manageButtonClicked, [longitudinalLayout, standardPersonalityPanel, this]() {
|
||||
openSubSubPanel();
|
||||
|
||||
longitudinalLayout->setCurrentWidget(standardPersonalityPanel);
|
||||
@@ -295,7 +307,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
longitudinalToggle = standardPersonalityToggle;
|
||||
} else if (param == "RelaxedPersonalityProfile") {
|
||||
FrogPilotManageControl *relaxedPersonalityToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||
QObject::connect(relaxedPersonalityToggle, &FrogPilotManageControl::manageButtonClicked, [this, longitudinalLayout, relaxedPersonalityPanel]() {
|
||||
QObject::connect(relaxedPersonalityToggle, &FrogPilotManageControl::manageButtonClicked, [longitudinalLayout, relaxedPersonalityPanel, this]() {
|
||||
openSubSubPanel();
|
||||
|
||||
longitudinalLayout->setCurrentWidget(relaxedPersonalityPanel);
|
||||
@@ -303,19 +315,16 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
customPersonalityOpen = true;
|
||||
});
|
||||
longitudinalToggle = relaxedPersonalityToggle;
|
||||
} else if (aggressivePersonalityKeys.find(param) != aggressivePersonalityKeys.end() ||
|
||||
standardPersonalityKeys.find(param) != standardPersonalityKeys.end() ||
|
||||
relaxedPersonalityKeys.find(param) != relaxedPersonalityKeys.end() ||
|
||||
trafficPersonalityKeys.find(param) != trafficPersonalityKeys.end()) {
|
||||
} else if (aggressivePersonalityKeys.contains(param) || standardPersonalityKeys.contains(param) || relaxedPersonalityKeys.contains(param) || trafficPersonalityKeys.contains(param)) {
|
||||
if (param == "TrafficFollow" || param == "AggressiveFollow" || param == "StandardFollow" || param == "RelaxedFollow") {
|
||||
std::map<float, QString> followTimeLabels;
|
||||
for (float i = 0; i <= 5; i += 0.01) {
|
||||
for (float i = 0; i <= 3; i += 0.01) {
|
||||
followTimeLabels[i] = std::lround(i / 0.01) == 1 / 0.01 ? QString::number(i, 'f', 2) + tr(" second") : QString::number(i, 'f', 2) + tr(" seconds");
|
||||
}
|
||||
if (param == "TrafficFollow") {
|
||||
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0.5, 5, QString(), followTimeLabels, 0.01, true);
|
||||
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0.5, 3, QString(), followTimeLabels, 0.01, true);
|
||||
} else {
|
||||
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 5, QString(), followTimeLabels, 0.01, true);
|
||||
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 3, QString(), followTimeLabels, 0.01, true);
|
||||
}
|
||||
} else {
|
||||
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 25, 200, "%");
|
||||
@@ -430,27 +439,27 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
|
||||
longitudinalToggle = slcPriorityButton;
|
||||
} else if (param == "SLCOffsets") {
|
||||
ButtonControl *manageSLCOffsetsBtn = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(manageSLCOffsetsBtn, &ButtonControl::clicked, [this, longitudinalLayout, speedLimitControllerOffsetsPanel]() {
|
||||
ButtonControl *manageSLCOffsetsButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(manageSLCOffsetsButton, &ButtonControl::clicked, [longitudinalLayout, speedLimitControllerOffsetsPanel, this]() {
|
||||
openSubSubPanel();
|
||||
|
||||
longitudinalLayout->setCurrentWidget(speedLimitControllerOffsetsPanel);
|
||||
|
||||
slcOpen = true;
|
||||
});
|
||||
longitudinalToggle = manageSLCOffsetsBtn;
|
||||
} else if (speedLimitControllerOffsetsKeys.find(param) != speedLimitControllerOffsetsKeys.end()) {
|
||||
longitudinalToggle = manageSLCOffsetsButton;
|
||||
} else if (speedLimitControllerOffsetsKeys.contains(param)) {
|
||||
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, -99, 99, tr(" mph"));
|
||||
} else if (param == "SLCQOL") {
|
||||
ButtonControl *manageSLCQOLBtn = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(manageSLCQOLBtn, &ButtonControl::clicked, [this, longitudinalLayout, speedLimitControllerQOLPanel]() {
|
||||
ButtonControl *manageSLCQOLButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(manageSLCQOLButton, &ButtonControl::clicked, [longitudinalLayout, speedLimitControllerQOLPanel, this]() {
|
||||
openSubSubPanel();
|
||||
|
||||
longitudinalLayout->setCurrentWidget(speedLimitControllerQOLPanel);
|
||||
|
||||
slcOpen = true;
|
||||
});
|
||||
longitudinalToggle = manageSLCQOLBtn;
|
||||
longitudinalToggle = manageSLCQOLButton;
|
||||
} else if (param == "SLCConfirmation") {
|
||||
std::vector<QString> confirmationToggles{"SLCConfirmationLower", "SLCConfirmationHigher"};
|
||||
std::vector<QString> confirmationToggleNames{tr("Lower Limits"), tr("Higher Limits")};
|
||||
@@ -458,15 +467,15 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
} else if (param == "SLCLookaheadHigher" || param == "SLCLookaheadLower") {
|
||||
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 30, tr(" seconds"));
|
||||
} else if (param == "SLCVisuals") {
|
||||
ButtonControl *manageSLCVisualsBtn = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(manageSLCVisualsBtn, &ButtonControl::clicked, [this, longitudinalLayout, speedLimitControllerVisualPanel]() {
|
||||
ButtonControl *manageSLCVisualsButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(manageSLCVisualsButton, &ButtonControl::clicked, [longitudinalLayout, speedLimitControllerVisualPanel, this]() {
|
||||
openSubSubPanel();
|
||||
|
||||
longitudinalLayout->setCurrentWidget(speedLimitControllerVisualPanel);
|
||||
|
||||
slcOpen = true;
|
||||
});
|
||||
longitudinalToggle = manageSLCVisualsBtn;
|
||||
longitudinalToggle = manageSLCVisualsButton;
|
||||
|
||||
} else {
|
||||
longitudinalToggle = new ParamControl(param, title, desc, icon);
|
||||
@@ -474,33 +483,33 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
|
||||
toggles[param] = longitudinalToggle;
|
||||
|
||||
if (advancedLongitudinalTuneKeys.find(param) != advancedLongitudinalTuneKeys.end()) {
|
||||
if (advancedLongitudinalTuneKeys.contains(param)) {
|
||||
advancedLongitudinalTuneList->addItem(longitudinalToggle);
|
||||
} else if (aggressivePersonalityKeys.find(param) != aggressivePersonalityKeys.end()) {
|
||||
} else if (aggressivePersonalityKeys.contains(param)) {
|
||||
aggressivePersonalityList->addItem(longitudinalToggle);
|
||||
} else if (conditionalExperimentalKeys.find(param) != conditionalExperimentalKeys.end()) {
|
||||
} else if (conditionalExperimentalKeys.contains(param)) {
|
||||
conditionalExperimentalList->addItem(longitudinalToggle);
|
||||
} else if (curveSpeedKeys.find(param) != curveSpeedKeys.end()) {
|
||||
} else if (curveSpeedKeys.contains(param)) {
|
||||
curveSpeedList->addItem(longitudinalToggle);
|
||||
} else if (customDrivingPersonalityKeys.find(param) != customDrivingPersonalityKeys.end()) {
|
||||
} else if (customDrivingPersonalityKeys.contains(param)) {
|
||||
customDrivingPersonalityList->addItem(longitudinalToggle);
|
||||
} else if (longitudinalTuneKeys.find(param) != longitudinalTuneKeys.end()) {
|
||||
} else if (longitudinalTuneKeys.contains(param)) {
|
||||
longitudinalTuneList->addItem(longitudinalToggle);
|
||||
} else if (qolKeys.find(param) != qolKeys.end()) {
|
||||
} else if (qolKeys.contains(param)) {
|
||||
qolList->addItem(longitudinalToggle);
|
||||
} else if (relaxedPersonalityKeys.find(param) != relaxedPersonalityKeys.end()) {
|
||||
} else if (relaxedPersonalityKeys.contains(param)) {
|
||||
relaxedPersonalityList->addItem(longitudinalToggle);
|
||||
} else if (speedLimitControllerKeys.find(param) != speedLimitControllerKeys.end()) {
|
||||
} else if (speedLimitControllerKeys.contains(param)) {
|
||||
speedLimitControllerList->addItem(longitudinalToggle);
|
||||
} else if (speedLimitControllerOffsetsKeys.find(param) != speedLimitControllerOffsetsKeys.end()) {
|
||||
} else if (speedLimitControllerOffsetsKeys.contains(param)) {
|
||||
speedLimitControllerOffsetsList->addItem(longitudinalToggle);
|
||||
} else if (speedLimitControllerQOLKeys.find(param) != speedLimitControllerQOLKeys.end()) {
|
||||
} else if (speedLimitControllerQOLKeys.contains(param)) {
|
||||
speedLimitControllerQOLList->addItem(longitudinalToggle);
|
||||
} else if (speedLimitControllerVisualKeys.find(param) != speedLimitControllerVisualKeys.end()) {
|
||||
} else if (speedLimitControllerVisualKeys.contains(param)) {
|
||||
speedLimitControllerVisualList->addItem(longitudinalToggle);
|
||||
} else if (standardPersonalityKeys.find(param) != standardPersonalityKeys.end()) {
|
||||
} else if (standardPersonalityKeys.contains(param)) {
|
||||
standardPersonalityList->addItem(longitudinalToggle);
|
||||
} else if (trafficPersonalityKeys.find(param) != trafficPersonalityKeys.end()) {
|
||||
} else if (trafficPersonalityKeys.contains(param)) {
|
||||
trafficPersonalityList->addItem(longitudinalToggle);
|
||||
} else {
|
||||
longitudinalList->addItem(longitudinalToggle);
|
||||
@@ -509,15 +518,21 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
}
|
||||
|
||||
if (FrogPilotManageControl *frogPilotManageToggle = qobject_cast<FrogPilotManageControl*>(longitudinalToggle)) {
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, this, &FrogPilotLongitudinalPanel::openSubPanel);
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, [this]() {
|
||||
emit openSubPanel();
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(longitudinalToggle, &AbstractControl::hideDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
QObject::connect(longitudinalToggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
std::set<QString> forceUpdateKeys = {"HumanAcceleration", "LongitudinalTune"};
|
||||
QSet<QString> forceUpdateKeys = {"HumanAcceleration", "LongitudinalTune"};
|
||||
for (const QString &key : forceUpdateKeys) {
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, this, &FrogPilotLongitudinalPanel::updateToggles);
|
||||
}
|
||||
@@ -529,7 +544,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
FrogPilotParamValueControl *trafficSpeedToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficJerkSpeed"]);
|
||||
FrogPilotParamValueControl *trafficSpeedDecreaseToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficJerkSpeedDecrease"]);
|
||||
FrogPilotButtonsControl *trafficResetButton = static_cast<FrogPilotButtonsControl*>(toggles["ResetTrafficPersonality"]);
|
||||
QObject::connect(trafficResetButton, &FrogPilotButtonsControl::buttonClicked, this, [=]() {
|
||||
QObject::connect(trafficResetButton, &FrogPilotButtonsControl::buttonClicked, [=]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your settings for <b>Traffic Mode</b>?"), this)) {
|
||||
params.putFloat("TrafficFollow", params_default.getFloat("TrafficFollow"));
|
||||
params.putFloat("TrafficJerkAcceleration", params_default.getFloat("TrafficJerkAcceleration"));
|
||||
@@ -554,7 +569,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
FrogPilotParamValueControl *aggressiveSpeedToggle = static_cast<FrogPilotParamValueControl*>(toggles["AggressiveJerkSpeed"]);
|
||||
FrogPilotParamValueControl *aggressiveSpeedDecreaseToggle = static_cast<FrogPilotParamValueControl*>(toggles["AggressiveJerkSpeedDecrease"]);
|
||||
FrogPilotButtonsControl *aggressiveResetButton = static_cast<FrogPilotButtonsControl*>(toggles["ResetAggressivePersonality"]);
|
||||
QObject::connect(aggressiveResetButton, &FrogPilotButtonsControl::buttonClicked, this, [=]() {
|
||||
QObject::connect(aggressiveResetButton, &FrogPilotButtonsControl::buttonClicked, [=]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your settings for the <b>Aggressive</b> personality?"), this)) {
|
||||
params.putFloat("AggressiveFollow", params_default.getFloat("AggressiveFollow"));
|
||||
params.putFloat("AggressiveJerkAcceleration", params_default.getFloat("AggressiveJerkAcceleration"));
|
||||
@@ -579,7 +594,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
FrogPilotParamValueControl *standardSpeedToggle = static_cast<FrogPilotParamValueControl*>(toggles["StandardJerkSpeed"]);
|
||||
FrogPilotParamValueControl *standardSpeedDecreaseToggle = static_cast<FrogPilotParamValueControl*>(toggles["StandardJerkSpeedDecrease"]);
|
||||
FrogPilotButtonsControl *standardResetButton = static_cast<FrogPilotButtonsControl*>(toggles["ResetStandardPersonality"]);
|
||||
QObject::connect(standardResetButton, &FrogPilotButtonsControl::buttonClicked, this, [=]() {
|
||||
QObject::connect(standardResetButton, &FrogPilotButtonsControl::buttonClicked, [=]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your settings for the <b>Standard</b> personality?"), this)) {
|
||||
params.putFloat("StandardFollow", params_default.getFloat("StandardFollow"));
|
||||
params.putFloat("StandardJerkAcceleration", params_default.getFloat("StandardJerkAcceleration"));
|
||||
@@ -604,7 +619,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
FrogPilotParamValueControl *relaxedSpeedToggle = static_cast<FrogPilotParamValueControl*>(toggles["RelaxedJerkSpeed"]);
|
||||
FrogPilotParamValueControl *relaxedSpeedDecreaseToggle = static_cast<FrogPilotParamValueControl*>(toggles["RelaxedJerkSpeedDecrease"]);
|
||||
FrogPilotButtonsControl *relaxedResetButton = static_cast<FrogPilotButtonsControl*>(toggles["ResetRelaxedPersonality"]);
|
||||
QObject::connect(relaxedResetButton, &FrogPilotButtonsControl::buttonClicked, this, [=]() {
|
||||
QObject::connect(relaxedResetButton, &FrogPilotButtonsControl::buttonClicked, [=]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your settings for the <b>Relaxed</b> personality?"), this)) {
|
||||
params.putFloat("RelaxedFollow", params_default.getFloat("RelaxedFollow"));
|
||||
params.putFloat("RelaxedJerkAcceleration", params_default.getFloat("RelaxedJerkAcceleration"));
|
||||
@@ -622,8 +637,15 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [longitudinalLayout, longitudinalPanel] {longitudinalLayout->setCurrentWidget(longitudinalPanel);});
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubSubPanel, [this, longitudinalLayout, customDrivingPersonalityPanel, speedLimitControllerPanel]() {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [longitudinalLayout, longitudinalPanel, this] {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
longitudinalLayout->setCurrentWidget(longitudinalPanel);
|
||||
});
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubSubPanel, [longitudinalLayout, customDrivingPersonalityPanel, speedLimitControllerPanel, this]() {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
if (customPersonalityOpen) {
|
||||
longitudinalLayout->setCurrentWidget(customDrivingPersonalityPanel);
|
||||
|
||||
@@ -653,6 +675,9 @@ void FrogPilotLongitudinalPanel::showEvent(QShowEvent *event) {
|
||||
vEgoStarting = parent->vEgoStarting;
|
||||
vEgoStopping = parent->vEgoStopping;
|
||||
|
||||
calibratedLateralAccelerationLabel->setText(QString::number(params.getFloat("CalibratedLateralAcceleration"), 'f', 2) + tr(" m/s²"));
|
||||
calibrationProgressLabel->setText(QString::number(params.getFloat("CalibrationProgress"), 'f', 2) + "%");
|
||||
|
||||
longitudinalActuatorDelayToggle->setTitle(QString(tr("Actuator Delay (Default: %1)")).arg(QString::number(longitudinalActuatorDelay, 'f', 2)));
|
||||
startAccelToggle->setTitle(QString(tr("Start Acceleration (Default: %1)")).arg(QString::number(startAccel, 'f', 2)));
|
||||
stopAccelToggle->setTitle(QString(tr("Stop Acceleration (Default: %1)")).arg(QString::number(stopAccel, 'f', 2)));
|
||||
@@ -736,13 +761,13 @@ void FrogPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) {
|
||||
offset6Toggle->setTitle(tr("Speed Offset (100–119 km/h)"));
|
||||
offset7Toggle->setTitle(tr("Speed Offset (120–140 km/h)"));
|
||||
|
||||
offset1Toggle->setDescription(tr("Target speed offset applied for posted limits between 0 and 29 km/h."));
|
||||
offset2Toggle->setDescription(tr("Target speed offset applied for posted limits between 30 and 49 km/h."));
|
||||
offset3Toggle->setDescription(tr("Target speed offset applied for posted limits between 50 and 59 km/h."));
|
||||
offset4Toggle->setDescription(tr("Target speed offset applied for posted limits between 60 and 79 km/h."));
|
||||
offset5Toggle->setDescription(tr("Target speed offset applied for posted limits between 80 and 99 km/h."));
|
||||
offset6Toggle->setDescription(tr("Target speed offset applied for posted limits between 100 and 119 km/h."));
|
||||
offset7Toggle->setDescription(tr("Target speed offset applied for posted limits between 120 and 140 km/h."));
|
||||
offset1Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 0 and 24 mph."));
|
||||
offset2Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 25 and 34 mph."));
|
||||
offset3Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 35 and 44 mph."));
|
||||
offset4Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 45 and 54 mph."));
|
||||
offset5Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 55 and 64 mph."));
|
||||
offset6Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 65 and 74 mph."));
|
||||
offset7Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 75 and 99 mph."));
|
||||
|
||||
increasedStoppedDistanceToggle->updateControl(0, 3, metricDistanceLabels);
|
||||
|
||||
@@ -767,13 +792,13 @@ void FrogPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) {
|
||||
offset6Toggle->setTitle(tr("Speed Offset (65–74 mph)"));
|
||||
offset7Toggle->setTitle(tr("Speed Offset (75–99 mph)"));
|
||||
|
||||
offset1Toggle->setDescription(tr("Target speed offset applied for posted limits between 0 and 24 mph."));
|
||||
offset2Toggle->setDescription(tr("Target speed offset applied for posted limits between 25 and 34 mph."));
|
||||
offset3Toggle->setDescription(tr("Target speed offset applied for posted limits between 35 and 44 mph."));
|
||||
offset4Toggle->setDescription(tr("Target speed offset applied for posted limits between 45 and 54 mph."));
|
||||
offset5Toggle->setDescription(tr("Target speed offset applied for posted limits between 55 and 64 mph."));
|
||||
offset6Toggle->setDescription(tr("Target speed offset applied for posted limits between 65 and 74 mph."));
|
||||
offset7Toggle->setDescription(tr("Target speed offset applied for posted limits between 75 and 99 mph."));
|
||||
offset1Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 0 and 24 mph."));
|
||||
offset2Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 25 and 34 mph."));
|
||||
offset3Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 35 and 44 mph."));
|
||||
offset4Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 45 and 54 mph."));
|
||||
offset5Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 55 and 64 mph."));
|
||||
offset6Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 65 and 74 mph."));
|
||||
offset7Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 75 and 99 mph."));
|
||||
|
||||
increasedStoppedDistanceToggle->updateControl(0, 10, imperialDistanceLabels);
|
||||
|
||||
@@ -794,22 +819,18 @@ void FrogPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) {
|
||||
|
||||
void FrogPilotLongitudinalPanel::updateToggles() {
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
toggle->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool setVisible = tuningLevel >= frogpilotToggleLevels[key].toDouble();
|
||||
|
||||
if (key == "CurveSensitivity" || key == "TurnAggressiveness") {
|
||||
setVisible &= params.getBool("MapTurnControl") || params.getBool("VisionTurnControl");
|
||||
}
|
||||
|
||||
if (key == "CustomCruise" || key == "CustomCruiseLong" || key == "SetSpeedLimit" || key == "SetSpeedOffset") {
|
||||
setVisible &= !hasPCMCruise;
|
||||
}
|
||||
@@ -823,10 +844,6 @@ void FrogPilotLongitudinalPanel::updateToggles() {
|
||||
setVisible &= !isTSK;
|
||||
}
|
||||
|
||||
else if (key == "MTSCCurvatureCheck") {
|
||||
setVisible &= params.getBool("MapTurnControl");
|
||||
}
|
||||
|
||||
else if (key == "ReverseCruise") {
|
||||
setVisible &= isToyota;
|
||||
}
|
||||
@@ -847,37 +864,39 @@ void FrogPilotLongitudinalPanel::updateToggles() {
|
||||
toggle->setVisible(setVisible);
|
||||
|
||||
if (setVisible) {
|
||||
if (advancedLongitudinalTuneKeys.find(key) != advancedLongitudinalTuneKeys.end()) {
|
||||
if (advancedLongitudinalTuneKeys.contains(key)) {
|
||||
toggles["AdvancedLongitudinalTune"]->setVisible(true);
|
||||
} else if (aggressivePersonalityKeys.find(key) != aggressivePersonalityKeys.end()) {
|
||||
} else if (aggressivePersonalityKeys.contains(key)) {
|
||||
toggles["AggressivePersonalityProfile"]->setVisible(true);
|
||||
} else if (conditionalExperimentalKeys.find(key) != conditionalExperimentalKeys.end()) {
|
||||
} else if (conditionalExperimentalKeys.contains(key)) {
|
||||
toggles["ConditionalExperimental"]->setVisible(true);
|
||||
} else if (curveSpeedKeys.find(key) != curveSpeedKeys.end()) {
|
||||
toggles["CurveSpeedControl"]->setVisible(true);
|
||||
} else if (customDrivingPersonalityKeys.find(key) != customDrivingPersonalityKeys.end()) {
|
||||
} else if (curveSpeedKeys.contains(key)) {
|
||||
toggles["CurveSpeedController"]->setVisible(true);
|
||||
} else if (customDrivingPersonalityKeys.contains(key)) {
|
||||
toggles["CustomPersonalities"]->setVisible(true);
|
||||
} else if (longitudinalTuneKeys.find(key) != longitudinalTuneKeys.end()) {
|
||||
} else if (longitudinalTuneKeys.contains(key)) {
|
||||
toggles["LongitudinalTune"]->setVisible(true);
|
||||
} else if (qolKeys.find(key) != qolKeys.end()) {
|
||||
} else if (qolKeys.contains(key)) {
|
||||
toggles["QOLLongitudinal"]->setVisible(true);
|
||||
} else if (relaxedPersonalityKeys.find(key) != relaxedPersonalityKeys.end()) {
|
||||
} else if (relaxedPersonalityKeys.contains(key)) {
|
||||
toggles["RelaxedPersonalityProfile"]->setVisible(true);
|
||||
} else if (speedLimitControllerKeys.find(key) != speedLimitControllerKeys.end()) {
|
||||
} else if (speedLimitControllerKeys.contains(key)) {
|
||||
toggles["SpeedLimitController"]->setVisible(true);
|
||||
} else if (speedLimitControllerOffsetsKeys.find(key) != speedLimitControllerOffsetsKeys.end()) {
|
||||
} else if (speedLimitControllerOffsetsKeys.contains(key)) {
|
||||
toggles["SLCOffsets"]->setVisible(true);
|
||||
} else if (speedLimitControllerQOLKeys.find(key) != speedLimitControllerQOLKeys.end()) {
|
||||
} else if (speedLimitControllerQOLKeys.contains(key)) {
|
||||
toggles["SLCQOL"]->setVisible(true);
|
||||
} else if (speedLimitControllerVisualKeys.find(key) != speedLimitControllerVisualKeys.end()) {
|
||||
} else if (speedLimitControllerVisualKeys.contains(key)) {
|
||||
toggles["SLCVisuals"]->setVisible(true);
|
||||
} else if (standardPersonalityKeys.find(key) != standardPersonalityKeys.end()) {
|
||||
} else if (standardPersonalityKeys.contains(key)) {
|
||||
toggles["StandardPersonalityProfile"]->setVisible(true);
|
||||
} else if (trafficPersonalityKeys.find(key) != trafficPersonalityKeys.end()) {
|
||||
} else if (trafficPersonalityKeys.contains(key)) {
|
||||
toggles["TrafficPersonalityProfile"]->setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "frogpilot/ui/qt/offroad/frogpilot_settings.h"
|
||||
|
||||
class FrogPilotLongitudinalPanel : public FrogPilotListWidget {
|
||||
@@ -22,6 +20,7 @@ private:
|
||||
void updateToggles();
|
||||
|
||||
bool customPersonalityOpen;
|
||||
bool forceOpenDescriptions;
|
||||
bool hasDashSpeedLimits;
|
||||
bool hasPCMCruise;
|
||||
bool isGM;
|
||||
@@ -41,24 +40,22 @@ private:
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
std::set<QString> advancedLongitudinalTuneKeys = {"LongitudinalActuatorDelay", "StartAccel", "StopAccel", "StoppingDecelRate", "VEgoStarting", "VEgoStopping"};
|
||||
std::set<QString> aggressivePersonalityKeys = {"AggressiveFollow", "AggressiveJerkAcceleration", "AggressiveJerkDeceleration", "AggressiveJerkDanger", "AggressiveJerkSpeed", "AggressiveJerkSpeedDecrease", "ResetAggressivePersonality"};
|
||||
std::set<QString> conditionalExperimentalKeys = {"CESpeed", "CESpeedLead", "CECurves", "CELead", "CEModelStopTime", "CENavigation", "CESignalSpeed", "ShowCEMStatus"};
|
||||
std::set<QString> curveSpeedKeys = {"CurveDetectionMethod", "CurveSensitivity", "MTSCCurvatureCheck", "ShowCSCStatus", "TurnAggressiveness"};
|
||||
std::set<QString> customDrivingPersonalityKeys = {"AggressivePersonalityProfile", "RelaxedPersonalityProfile", "StandardPersonalityProfile", "TrafficPersonalityProfile"};
|
||||
std::set<QString> longitudinalTuneKeys = {"AccelerationProfile", "DecelerationProfile", "HumanAcceleration", "HumanFollowing", "LeadDetectionThreshold", "MaxDesiredAcceleration", "TacoTune"};
|
||||
std::set<QString> qolKeys = {"CustomCruise", "CustomCruiseLong", "ForceStandstill", "ForceStops", "IncreasedStoppedDistance", "MapGears", "ReverseCruise", "SetSpeedOffset"};
|
||||
std::set<QString> relaxedPersonalityKeys = {"RelaxedFollow", "RelaxedJerkAcceleration", "RelaxedJerkDeceleration", "RelaxedJerkDanger", "RelaxedJerkSpeed", "RelaxedJerkSpeedDecrease", "ResetRelaxedPersonality"};
|
||||
std::set<QString> speedLimitControllerKeys = {"SLCOffsets", "SLCFallback", "SLCOverride", "SLCPriority", "SLCQOL", "SLCVisuals"};
|
||||
std::set<QString> speedLimitControllerOffsetsKeys = {"Offset1", "Offset2", "Offset3", "Offset4", "Offset5", "Offset6", "Offset7"};
|
||||
std::set<QString> speedLimitControllerQOLKeys = {"ForceMPHDashboard", "SetSpeedLimit", "SLCConfirmation", "SLCLookaheadHigher", "SLCLookaheadLower", "SLCMapboxFiller"};
|
||||
std::set<QString> speedLimitControllerVisualKeys = {"ShowSLCOffset", "SpeedLimitSources"};
|
||||
std::set<QString> standardPersonalityKeys = {"StandardFollow", "StandardJerkAcceleration", "StandardJerkDeceleration", "StandardJerkDanger", "StandardJerkSpeed", "StandardJerkSpeedDecrease", "ResetStandardPersonality"};
|
||||
std::set<QString> trafficPersonalityKeys = {"TrafficFollow", "TrafficJerkAcceleration", "TrafficJerkDeceleration", "TrafficJerkDanger", "TrafficJerkSpeed", "TrafficJerkSpeedDecrease", "ResetTrafficPersonality"};
|
||||
QSet<QString> advancedLongitudinalTuneKeys = {"LongitudinalActuatorDelay", "StartAccel", "StopAccel", "StoppingDecelRate", "VEgoStarting", "VEgoStopping"};
|
||||
QSet<QString> aggressivePersonalityKeys = {"AggressiveFollow", "AggressiveJerkAcceleration", "AggressiveJerkDeceleration", "AggressiveJerkDanger", "AggressiveJerkSpeed", "AggressiveJerkSpeedDecrease", "ResetAggressivePersonality"};
|
||||
QSet<QString> conditionalExperimentalKeys = {"CESpeed", "CESpeedLead", "CECurves", "CELead", "CEModelStopTime", "CENavigation", "CESignalSpeed", "ShowCEMStatus"};
|
||||
QSet<QString> curveSpeedKeys = {"CalibratedLateralAcceleration", "CalibrationProgress", "ResetCurveData", "ShowCSCStatus"};
|
||||
QSet<QString> customDrivingPersonalityKeys = {"AggressivePersonalityProfile", "RelaxedPersonalityProfile", "StandardPersonalityProfile", "TrafficPersonalityProfile"};
|
||||
QSet<QString> longitudinalTuneKeys = {"AccelerationProfile", "DecelerationProfile", "HumanAcceleration", "HumanFollowing", "LeadDetectionThreshold", "MaxDesiredAcceleration", "TacoTune"};
|
||||
QSet<QString> qolKeys = {"CustomCruise", "CustomCruiseLong", "ForceStops", "IncreasedStoppedDistance", "MapGears", "ReverseCruise", "SetSpeedOffset"};
|
||||
QSet<QString> relaxedPersonalityKeys = {"RelaxedFollow", "RelaxedJerkAcceleration", "RelaxedJerkDeceleration", "RelaxedJerkDanger", "RelaxedJerkSpeed", "RelaxedJerkSpeedDecrease", "ResetRelaxedPersonality"};
|
||||
QSet<QString> speedLimitControllerKeys = {"SLCOffsets", "SLCFallback", "SLCOverride", "SLCPriority", "SLCQOL", "SLCVisuals"};
|
||||
QSet<QString> speedLimitControllerOffsetsKeys = {"Offset1", "Offset2", "Offset3", "Offset4", "Offset5", "Offset6", "Offset7"};
|
||||
QSet<QString> speedLimitControllerQOLKeys = {"ForceMPHDashboard", "SetSpeedLimit", "SLCConfirmation", "SLCLookaheadHigher", "SLCLookaheadLower", "SLCMapboxFiller"};
|
||||
QSet<QString> speedLimitControllerVisualKeys = {"ShowSLCOffset", "SpeedLimitSources"};
|
||||
QSet<QString> standardPersonalityKeys = {"StandardFollow", "StandardJerkAcceleration", "StandardJerkDeceleration", "StandardJerkDanger", "StandardJerkSpeed", "StandardJerkSpeedDecrease", "ResetStandardPersonality"};
|
||||
QSet<QString> trafficPersonalityKeys = {"TrafficFollow", "TrafficJerkAcceleration", "TrafficJerkDeceleration", "TrafficJerkDanger", "TrafficJerkSpeed", "TrafficJerkSpeedDecrease", "ResetTrafficPersonality"};
|
||||
|
||||
std::set<QString> parentKeys;
|
||||
|
||||
FrogPilotButtonsControl *curveDetectionToggle;
|
||||
QSet<QString> parentKeys;
|
||||
|
||||
FrogPilotParamValueControl *longitudinalActuatorDelayToggle;
|
||||
FrogPilotParamValueControl *startAccelToggle;
|
||||
@@ -69,6 +66,9 @@ private:
|
||||
|
||||
FrogPilotSettingsWindow *parent;
|
||||
|
||||
LabelControl *calibratedLateralAccelerationLabel;
|
||||
LabelControl *calibrationProgressLabel;
|
||||
|
||||
QJsonObject frogpilotToggleLevels;
|
||||
|
||||
Params params;
|
||||
|
||||
@@ -5,33 +5,32 @@
|
||||
#include "frogpilot/ui/qt/offroad/maps_settings.h"
|
||||
|
||||
FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
QStackedLayout *mapsLayout = new QStackedLayout();
|
||||
addItem(mapsLayout);
|
||||
|
||||
FrogPilotListWidget *settingsList = new FrogPilotListWidget(this);
|
||||
|
||||
std::vector<QString> scheduleOptions{tr("Manually"), tr("Weekly"), tr("Monthly")};
|
||||
ButtonParamControl *preferredSchedule = new ButtonParamControl("PreferredSchedule", tr("Automatically Update Maps"),
|
||||
tr("The frequency at which maps sync with the latest OpenStreetMap (OSM) changes. "
|
||||
"Weekly updates occur every Sunday, and monthly updates occur on the 1st."),
|
||||
preferredSchedule = new ButtonParamControl("PreferredSchedule", tr("Automatically Update Maps"),
|
||||
tr("<b>How often maps update</b> from \"OpenStreetMap (OSM)\" with the latest speed limit information. "
|
||||
"Weekly updates run every Sunday; monthly updates run on the 1st."),
|
||||
"",
|
||||
scheduleOptions);
|
||||
settingsList->addItem(preferredSchedule);
|
||||
|
||||
FrogPilotButtonsControl *selectMaps = new FrogPilotButtonsControl(tr("Data Sources"),
|
||||
tr("Select map data sources to use with \"Curve Speed Control\" and \"Speed Limit Controller\"."),
|
||||
"", {tr("COUNTRIES"), tr("STATES")});
|
||||
QObject::connect(selectMaps, &FrogPilotButtonsControl::buttonClicked, [this, mapsLayout](int id) {
|
||||
mapsLayout->setCurrentIndex(id + 1);
|
||||
|
||||
openSubPanel();
|
||||
});
|
||||
settingsList->addItem(selectMaps);
|
||||
|
||||
downloadMapsButton = new ButtonControl(tr("Download Maps"), tr("DOWNLOAD"), tr("Download the selected maps to use with \"Curve Speed Control\" and \"Speed Limit Controller\"."));
|
||||
downloadMapsButton = new ButtonControl(tr("Download Maps"), tr("DOWNLOAD"), tr("<b>Manually update your selected map sources</b> so \"Speed Limit Controller\" has the latest speed limit information."));
|
||||
QObject::connect(downloadMapsButton, &ButtonControl::clicked, [this] {
|
||||
if (downloadMapsButton->text() == tr("CANCEL")) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to cancel the download?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Cancel the download?"), this)) {
|
||||
cancelDownload();
|
||||
}
|
||||
} else {
|
||||
@@ -40,19 +39,29 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
});
|
||||
settingsList->addItem(downloadMapsButton);
|
||||
|
||||
settingsList->addItem(downloadETA = new LabelControl(tr("Download Completion ETA")));
|
||||
settingsList->addItem(downloadStatus = new LabelControl(tr("Download Progress")));
|
||||
settingsList->addItem(downloadTimeElapsed = new LabelControl(tr("Download Time Elapsed")));
|
||||
settingsList->addItem(lastMapsDownload = new LabelControl(tr("Maps Last Updated"), params.get("LastMapsUpdate").empty() ? "Never" : QString::fromStdString(params.get("LastMapsUpdate"))));
|
||||
settingsList->addItem(mapsSize = new LabelControl(tr("Maps Size"), calculateDirectorySize(mapsFolderPath)));
|
||||
settingsList->addItem(lastMapsDownload = new LabelControl(tr("Last Updated"), params.get("LastMapsUpdate").empty() ? "Never" : QString::fromStdString(params.get("LastMapsUpdate"))));
|
||||
|
||||
selectMaps = new FrogPilotButtonsControl(tr("Map Sources"),
|
||||
tr("<b>Select the countries or U.S. states to use with \"Speed Limit Controller\".</b>") ,
|
||||
"", {tr("COUNTRIES"), tr("STATES")});
|
||||
QObject::connect(selectMaps, &FrogPilotButtonsControl::buttonClicked, [mapsLayout, this](int id) {
|
||||
mapsLayout->setCurrentIndex(id + 1);
|
||||
|
||||
openSubPanel();
|
||||
});
|
||||
settingsList->addItem(selectMaps);
|
||||
|
||||
settingsList->addItem(downloadStatus = new LabelControl(tr("Progress")));
|
||||
settingsList->addItem(downloadTimeElapsed = new LabelControl(tr("Time Elapsed")));
|
||||
settingsList->addItem(downloadETA = new LabelControl(tr("Time Remaining")));
|
||||
|
||||
downloadETA->setVisible(false);
|
||||
downloadStatus->setVisible(false);
|
||||
downloadTimeElapsed->setVisible(false);
|
||||
|
||||
removeMapsButton = new ButtonControl(tr("Remove Maps"), tr("REMOVE"), tr("Remove downloaded maps to clear up storage space."));
|
||||
removeMapsButton = new ButtonControl(tr("Remove Maps"), tr("REMOVE"), tr("<b>Delete downloaded map data</b> to free up storage space."));
|
||||
QObject::connect(removeMapsButton, &ButtonControl::clicked, [this] {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to delete all of your downloaded maps?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Delete all downloaded maps?"), this)) {
|
||||
std::thread([this] {
|
||||
mapsSize->setText("0 MB");
|
||||
|
||||
@@ -62,25 +71,25 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
});
|
||||
settingsList->addItem(removeMapsButton);
|
||||
|
||||
resetMapdBtn = new ButtonControl(tr("Reset Map Downloader"), tr("RESET"),
|
||||
tr("Reset the map downloader. Use if you're running into issues with downloading maps."));
|
||||
QObject::connect(resetMapdBtn, &ButtonControl::clicked, [this, parent]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to reset the map downloader? This will force a reboot once completed."), tr("Reset"), this)) {
|
||||
std::thread([this, parent]() {
|
||||
resetMapdButton = new ButtonControl(tr("Reset Downloader"), tr("RESET"),
|
||||
tr("<b>Reset the map downloader.</b> Use this if downloads are stuck or failing."));
|
||||
QObject::connect(resetMapdButton, &ButtonControl::clicked, [parent, this]() {
|
||||
if (ConfirmationDialog::confirm(tr("Reset the map downloader? Your device will reboot afterward."), tr("Reset"), this)) {
|
||||
std::thread([parent, this]() {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
resetMapdBtn->setEnabled(false);
|
||||
resetMapdBtn->setValue(tr("Resetting..."));
|
||||
resetMapdButton->setEnabled(false);
|
||||
resetMapdButton->setValue(tr("Resetting..."));
|
||||
|
||||
std::system("pkill mapd");
|
||||
|
||||
QDir("/data/media/0/osm").removeRecursively();
|
||||
|
||||
resetMapdBtn->setValue(tr("Reset!"));
|
||||
resetMapdButton->setValue(tr("Reset!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
resetMapdBtn->setValue(tr("Rebooting..."));
|
||||
resetMapdButton->setValue(tr("Rebooting..."));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
@@ -88,7 +97,9 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
}).detach();
|
||||
}
|
||||
});
|
||||
settingsList->addItem(resetMapdBtn);
|
||||
settingsList->addItem(resetMapdButton);
|
||||
|
||||
settingsList->addItem(mapsSize = new LabelControl(tr("Storage Used"), calculateDirectorySize(mapsFolderPath)));
|
||||
|
||||
ScrollView *settingsPanel = new ScrollView(settingsList, this);
|
||||
mapsLayout->addWidget(settingsPanel);
|
||||
@@ -129,7 +140,15 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
ScrollView *stateMapsPanel = new ScrollView(statesList, this);
|
||||
mapsLayout->addWidget(stateMapsPanel);
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [this, mapsLayout, settingsPanel] {
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [mapsLayout, settingsPanel, this] {
|
||||
if (forceOpenDescriptions) {
|
||||
downloadMapsButton->showDescription();
|
||||
preferredSchedule->showDescription();
|
||||
removeMapsButton->showDescription();
|
||||
resetMapdButton->showDescription();
|
||||
selectMaps->showDescription();
|
||||
}
|
||||
|
||||
std::string mapsSelected = params.get("MapsSelected");
|
||||
hasMapsSelected = !QJsonDocument::fromJson(QByteArray::fromStdString(mapsSelected)).object().value("nations").toArray().isEmpty();
|
||||
hasMapsSelected |= !QJsonDocument::fromJson(QByteArray::fromStdString(mapsSelected)).object().value("states").toArray().isEmpty();
|
||||
@@ -140,6 +159,14 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
||||
}
|
||||
|
||||
void FrogPilotMapsPanel::showEvent(QShowEvent *event) {
|
||||
if (forceOpenDescriptions) {
|
||||
downloadMapsButton->showDescription();
|
||||
preferredSchedule->showDescription();
|
||||
removeMapsButton->showDescription();
|
||||
resetMapdButton->showDescription();
|
||||
selectMaps->showDescription();
|
||||
}
|
||||
|
||||
FrogPilotUIState &fs = *frogpilotUIState();
|
||||
UIState &s = *uiState();
|
||||
|
||||
@@ -160,7 +187,7 @@ void FrogPilotMapsPanel::showEvent(QShowEvent *event) {
|
||||
|
||||
lastMapsDownload->setVisible(false);
|
||||
removeMapsButton->setVisible(false);
|
||||
resetMapdBtn->setVisible(false);
|
||||
resetMapdButton->setVisible(false);
|
||||
|
||||
updateDownloadLabels(osmDownloadProgress);
|
||||
} else {
|
||||
@@ -216,7 +243,7 @@ void FrogPilotMapsPanel::cancelDownload() {
|
||||
|
||||
lastMapsDownload->setVisible(true);
|
||||
removeMapsButton->setVisible(mapsFolderPath.exists());
|
||||
resetMapdBtn->setVisible(true);
|
||||
resetMapdButton->setVisible(true);
|
||||
|
||||
update();
|
||||
});
|
||||
@@ -234,7 +261,7 @@ void FrogPilotMapsPanel::startDownload() {
|
||||
|
||||
lastMapsDownload->setVisible(false);
|
||||
removeMapsButton->setVisible(false);
|
||||
resetMapdBtn->setVisible(false);
|
||||
resetMapdButton->setVisible(false);
|
||||
|
||||
elapsedTime.start();
|
||||
startTime = QDateTime::currentDateTime();
|
||||
@@ -260,7 +287,7 @@ void FrogPilotMapsPanel::updateDownloadLabels(std::string &osmDownloadProgress)
|
||||
|
||||
lastMapsDownload->setVisible(true);
|
||||
removeMapsButton->setVisible(true);
|
||||
resetMapdBtn->setVisible(true);
|
||||
resetMapdButton->setVisible(true);
|
||||
|
||||
params.put("LastMapsUpdate", formatCurrentDate().toStdString());
|
||||
params.remove("OSMDownloadProgress");
|
||||
|
||||
@@ -22,11 +22,16 @@ private:
|
||||
void updateState(const UIState &s, const FrogPilotUIState &fs);
|
||||
|
||||
bool cancellingDownload;
|
||||
bool forceOpenDescriptions;
|
||||
bool hasMapsSelected;
|
||||
|
||||
ButtonControl *downloadMapsButton;
|
||||
ButtonControl *removeMapsButton;
|
||||
ButtonControl *resetMapdBtn;
|
||||
ButtonControl *resetMapdButton;
|
||||
|
||||
ButtonParamControl *preferredSchedule;
|
||||
|
||||
FrogPilotButtonsControl *selectMaps;
|
||||
|
||||
FrogPilotSettingsWindow *parent;
|
||||
|
||||
|
||||
@@ -16,7 +16,24 @@ bool hasAllTinygradFiles(const QDir &modelDir, const QString &modelKey) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QString normalizeModelKey(QString key) {
|
||||
key = key.toLower();
|
||||
if (key.endsWith("_default")) {
|
||||
key.chop(QString("_default").size());
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
QStackedLayout *modelLayout = new QStackedLayout();
|
||||
addItem(modelLayout);
|
||||
|
||||
@@ -33,21 +50,22 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
modelLayout->addWidget(modelLabelsPanel);
|
||||
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> modelToggles {
|
||||
{"AutomaticallyDownloadModels", tr("Automatically Download New Models"), tr("Automatically download new driving models as they become available."), ""},
|
||||
{"DeleteModel", tr("Delete Driving Models"), tr("Delete driving models from the device."), ""},
|
||||
{"DownloadModel", tr("Download Driving Models"), tr("Download driving models to the device."), ""},
|
||||
{"ModelRandomizer", tr("Model Randomizer"), tr("Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs."), ""},
|
||||
{"ManageBlacklistedModels", tr("Manage Model Blacklist"), tr("Add or remove models from the <b>Model Randomizer</b>'s blacklist list."), ""},
|
||||
{"ManageScores", tr("Manage Model Ratings"), tr("Reset or view the saved ratings for the driving models."), ""},
|
||||
{"SelectModel", tr("Select Driving Model"), tr("Select the active driving model."), ""},
|
||||
{"AutomaticallyDownloadModels", tr("Automatically Download New Models"), tr("<b>Automatically download new driving models</b> as they become available."), ""},
|
||||
{"DeleteModel", tr("Delete Driving Models"), tr("<b>Delete downloaded driving models</b> to free up storage space."), ""},
|
||||
{"DownloadModel", tr("Download Driving Models"), tr("<b>Manually download driving models</b> to the device."), ""},
|
||||
{"ModelRandomizer", tr("Model Randomizer"), tr("<b>Select a random driving model each drive</b> and use feedback prompts at the end of the drive to help find the model that best suits you!"), ""},
|
||||
{"ManageBlacklistedModels", tr("Manage Model Blacklist"), tr("<b>Add or remove driving models from the \"Model Randomizer\" blacklist.</b>"), ""},
|
||||
{"ManageScores", tr("Manage Model Ratings"), tr("<b>View or reset saved model ratings</b> used by the \"Model Randomizer\"."), ""},
|
||||
{"SelectModel", tr("Select Driving Model"), tr("<b>Choose which driving model openpilot uses.</b>"), ""},
|
||||
{"UpdateTinygrad", tr("Update Model Manager"), tr("<b>Update the \"Model Manager\"</b> to support the latest models."), ""}
|
||||
};
|
||||
|
||||
for (const auto &[param, title, desc, icon] : modelToggles) {
|
||||
AbstractControl *modelToggle;
|
||||
|
||||
if (param == "DeleteModel") {
|
||||
deleteModelBtn = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DELETE ALL")});
|
||||
QObject::connect(deleteModelBtn, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
deleteModelButton = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DELETE ALL")});
|
||||
QObject::connect(deleteModelButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
QStringList deletableModels;
|
||||
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
||||
QString base = QFileInfo(file).baseName();
|
||||
@@ -61,8 +79,7 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
}
|
||||
}
|
||||
deletableModels.removeAll(processModelName(currentModel));
|
||||
deletableModels.removeAll(modelFileToNameMapProcessed.value(QString::fromStdString(params_default.get("Model"))));
|
||||
deletableModels.removeAll("Space Lab");
|
||||
deletableModels.removeAll(modelFileToNameMapProcessed.value(normalizeModelKey(QString::fromStdString(params_default.get("Model")))));
|
||||
noModelsDownloaded = deletableModels.isEmpty();
|
||||
|
||||
if (id == 0) {
|
||||
@@ -96,11 +113,23 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
}
|
||||
}
|
||||
});
|
||||
modelToggle = deleteModelBtn;
|
||||
modelToggle = deleteModelButton;
|
||||
} else if (param == "DownloadModel") {
|
||||
downloadModelBtn = new FrogPilotButtonsControl(title, desc, icon, {tr("DOWNLOAD"), tr("DOWNLOAD ALL")});
|
||||
QObject::connect(downloadModelBtn, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
if (id == 0) {
|
||||
downloadModelButton = new FrogPilotButtonsControl(title, desc, icon, {tr("DOWNLOAD"), tr("DOWNLOAD ALL")});
|
||||
QObject::connect(downloadModelButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
if (tinygradUpdate) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Tinygrad is out of date and must be updated before you can download new models. Update now?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Updating Tinygrad will delete all existing Tinygrad-based models which will need to be re-downloaded. Proceed?"), this)) {
|
||||
params_memory.putBool("UpdateTinygrad", true);
|
||||
params_memory.put("ModelDownloadProgress", "Downloading...");
|
||||
|
||||
updateTinygradButton->setText(0, tr("CANCEL"));
|
||||
updateTinygradButton->setValue(tr("Updating..."));
|
||||
|
||||
updatingTinygrad = true;
|
||||
}
|
||||
}
|
||||
} else if (id == 0) {
|
||||
if (modelDownloading) {
|
||||
params_memory.putBool("CancelModelDownload", true);
|
||||
|
||||
@@ -109,11 +138,10 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
QStringList downloadableModels = availableModelNames;
|
||||
for (const QString &modelKey : modelFileToNameMap.keys()) {
|
||||
QString modelName = modelFileToNameMap.value(modelKey);
|
||||
if (modelDir.exists(modelKey + ".thneed")) {
|
||||
if (modelDir.exists(modelKey + ".thneed") || hasAllTinygradFiles(modelDir, modelKey)) {
|
||||
downloadableModels.removeAll(modelName);
|
||||
}
|
||||
}
|
||||
downloadableModels.removeAll("Space Lab 👀📡");
|
||||
allModelsDownloaded = downloadableModels.isEmpty();
|
||||
|
||||
QString modelToDownload = MultiOptionDialog::getSelection(tr("Select a driving model to download"), downloadableModels, "", this);
|
||||
@@ -121,11 +149,11 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
params_memory.put("ModelToDownload", modelFileToNameMap.key(modelToDownload).toStdString());
|
||||
params_memory.put("ModelDownloadProgress", "Downloading...");
|
||||
|
||||
downloadModelBtn->setText(0, tr("CANCEL"));
|
||||
downloadModelButton->setText(0, tr("CANCEL"));
|
||||
|
||||
downloadModelBtn->setValue("Downloading...");
|
||||
downloadModelButton->setValue("Downloading...");
|
||||
|
||||
downloadModelBtn->setVisibleButton(1, false);
|
||||
downloadModelButton->setVisibleButton(1, false);
|
||||
|
||||
modelDownloading = true;
|
||||
}
|
||||
@@ -139,20 +167,20 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
params_memory.putBool("DownloadAllModels", true);
|
||||
params_memory.put("ModelDownloadProgress", "Downloading...");
|
||||
|
||||
downloadModelBtn->setText(1, tr("CANCEL"));
|
||||
downloadModelButton->setText(1, tr("CANCEL"));
|
||||
|
||||
downloadModelBtn->setValue("Downloading...");
|
||||
downloadModelButton->setValue("Downloading...");
|
||||
|
||||
downloadModelBtn->setVisibleButton(0, false);
|
||||
downloadModelButton->setVisibleButton(0, false);
|
||||
|
||||
allModelsDownloading = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
modelToggle = downloadModelBtn;
|
||||
modelToggle = downloadModelButton;
|
||||
} else if (param == "ManageBlacklistedModels") {
|
||||
FrogPilotButtonsControl *blacklistBtn = new FrogPilotButtonsControl(title, desc, icon, {tr("ADD"), tr("REMOVE"), tr("REMOVE ALL")});
|
||||
QObject::connect(blacklistBtn, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
FrogPilotButtonsControl *blacklistButton = new FrogPilotButtonsControl(title, desc, icon, {tr("ADD"), tr("REMOVE"), tr("REMOVE ALL")});
|
||||
QObject::connect(blacklistButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
QStringList blacklistedModels = QString::fromStdString(params.get("BlacklistedModels")).split(",");
|
||||
blacklistedModels.removeAll("");
|
||||
|
||||
@@ -165,9 +193,9 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
}
|
||||
|
||||
if (blacklistableModels.size() <= 1) {
|
||||
ConfirmationDialog::alert(tr("There are no more models to blacklist! The only available model is \"%1\"!").arg(blacklistableModels.first()), this);
|
||||
ConfirmationDialog::alert(tr("There are no more driving models to blacklist. The only available model is \"%1\"!").arg(blacklistableModels.first()), this);
|
||||
} else {
|
||||
QString modelToBlacklist = MultiOptionDialog::getSelection(tr("Select a model to add to the blacklist"), blacklistableModels, "", this);
|
||||
QString modelToBlacklist = MultiOptionDialog::getSelection(tr("Select a driving model to add to the blacklist"), blacklistableModels, "", this);
|
||||
if (!modelToBlacklist.isEmpty()) {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to add the \"%1\" model to the blacklist?").arg(modelToBlacklist), tr("Add"), this)) {
|
||||
blacklistedModels.append(modelFileToNameMapProcessed.key(modelToBlacklist));
|
||||
@@ -184,7 +212,7 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
}
|
||||
whitelistableModels.sort();
|
||||
|
||||
QString modelToWhitelist = MultiOptionDialog::getSelection(tr("Select a model to remove from the blacklist"), whitelistableModels, "", this);
|
||||
QString modelToWhitelist = MultiOptionDialog::getSelection(tr("Select a driving model to remove from the blacklist"), whitelistableModels, "", this);
|
||||
if (!modelToWhitelist.isEmpty()) {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to remove the \"%1\" model from the blacklist?").arg(modelToWhitelist), tr("Remove"), this)) {
|
||||
blacklistedModels.removeAll(modelFileToNameMapProcessed.key(modelToWhitelist));
|
||||
@@ -193,18 +221,18 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
}
|
||||
}
|
||||
} else if (id == 2) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to remove all of your blacklisted models?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to remove all of your blacklisted driving models?"), this)) {
|
||||
params.remove("BlacklistedModels");
|
||||
params_cache.remove("BlacklistedModels");
|
||||
}
|
||||
}
|
||||
});
|
||||
modelToggle = blacklistBtn;
|
||||
modelToggle = blacklistButton;
|
||||
} else if (param == "ManageScores") {
|
||||
FrogPilotButtonsControl *manageScoresBtn = new FrogPilotButtonsControl(title, desc, icon, {tr("RESET"), tr("VIEW")});
|
||||
QObject::connect(manageScoresBtn, &FrogPilotButtonsControl::buttonClicked, [this, modelLayout, modelLabelsList, modelLabelsPanel](int id) {
|
||||
FrogPilotButtonsControl *manageScoresButton = new FrogPilotButtonsControl(title, desc, icon, {tr("RESET"), tr("VIEW")});
|
||||
QObject::connect(manageScoresButton, &FrogPilotButtonsControl::buttonClicked, [modelLayout, modelLabelsList, modelLabelsPanel, this](int id) {
|
||||
if (id == 0) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to reset all of your model drives and scores?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Reset all model drives and ratings? This clears your drive history and collected feedback!"), this)) {
|
||||
params.remove("ModelDrivesAndScores");
|
||||
params_cache.remove("ModelDrivesAndScores");
|
||||
}
|
||||
@@ -216,10 +244,10 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
modelLayout->setCurrentWidget(modelLabelsPanel);
|
||||
}
|
||||
});
|
||||
modelToggle = manageScoresBtn;
|
||||
modelToggle = manageScoresButton;
|
||||
} else if (param == "SelectModel") {
|
||||
selectModelBtn = new ButtonControl(title, tr("SELECT"), desc);
|
||||
QObject::connect(selectModelBtn, &ButtonControl::clicked, [this]() {
|
||||
selectModelButton = new ButtonControl(title, tr("SELECT"), desc);
|
||||
QObject::connect(selectModelButton, &ButtonControl::clicked, [this]() {
|
||||
QStringList selectableModels;
|
||||
for (const QString &modelKey : modelFileToNameMap.keys()) {
|
||||
QString modelName = modelFileToNameMap.value(modelKey);
|
||||
@@ -227,15 +255,14 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
continue;
|
||||
}
|
||||
|
||||
if (modelDir.exists(modelKey + ".thneed")) {
|
||||
if (modelDir.exists(modelKey + ".thneed") || hasAllTinygradFiles(modelDir, modelKey)) {
|
||||
selectableModels.append(modelName);
|
||||
}
|
||||
}
|
||||
selectableModels.append(modelFileToNameMap.value("space-lab"));
|
||||
selectableModels.sort();
|
||||
selectableModels.prepend(modelFileToNameMap.value(QString::fromStdString(params_default.get("Model"))));
|
||||
selectableModels.prepend(modelFileToNameMap.value(normalizeModelKey(QString::fromStdString(params_default.get("Model")))));
|
||||
|
||||
QString modelToSelect = MultiOptionDialog::getSelection(tr("Select a model - 🗺️ = Navigation | 📡 = Radar | 👀 = VOACC"), selectableModels, currentModel, this);
|
||||
QString modelToSelect = MultiOptionDialog::getSelection(tr("Select a Model — 🗺️ = Navigation | 📡 = Radar | 👀 = VOACC"), selectableModels, currentModel, this);
|
||||
if (!modelToSelect.isEmpty()) {
|
||||
currentModel = modelToSelect;
|
||||
|
||||
@@ -248,7 +275,7 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
Hardware::reboot();
|
||||
}
|
||||
}
|
||||
selectModelBtn->setValue(modelToSelect);
|
||||
selectModelButton->setValue(modelToSelect);
|
||||
|
||||
QStringList deletableModels;
|
||||
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
||||
@@ -263,11 +290,35 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
}
|
||||
}
|
||||
deletableModels.removeAll(processModelName(currentModel));
|
||||
deletableModels.removeAll(modelFileToNameMapProcessed.value(QString::fromStdString(params_default.get("Model"))));
|
||||
deletableModels.removeAll(modelFileToNameMapProcessed.value(normalizeModelKey(QString::fromStdString(params_default.get("Model")))));
|
||||
noModelsDownloaded = deletableModels.isEmpty();
|
||||
}
|
||||
});
|
||||
modelToggle = selectModelBtn;
|
||||
modelToggle = selectModelButton;
|
||||
|
||||
} else if (param == "UpdateTinygrad") {
|
||||
updateTinygradButton = new FrogPilotButtonsControl(title, desc, icon, {tr("UPDATE")});
|
||||
QObject::connect(updateTinygradButton, &FrogPilotButtonsControl::buttonClicked, [this]() {
|
||||
if (updatingTinygrad) {
|
||||
params_memory.putBool("CancelModelDownload", true);
|
||||
|
||||
updateTinygradButton->setEnabled(false);
|
||||
updateTinygradButton->setValue(tr("Cancelling..."));
|
||||
|
||||
cancellingDownload = true;
|
||||
} else {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Updating Tinygrad will delete existing Tinygrad-based driving models and need to be re-downloaded. Proceed?"), this)) {
|
||||
params_memory.putBool("UpdateTinygrad", true);
|
||||
params_memory.put("ModelDownloadProgress", "Downloading...");
|
||||
|
||||
updateTinygradButton->setText(0, tr("CANCEL"));
|
||||
updateTinygradButton->setValue(tr("Updating..."));
|
||||
|
||||
updatingTinygrad = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
modelToggle = updateTinygradButton;
|
||||
|
||||
} else {
|
||||
modelToggle = new ParamControl(param, title, desc, icon);
|
||||
@@ -277,27 +328,35 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
|
||||
modelList->addItem(modelToggle);
|
||||
|
||||
QObject::connect(modelToggle, &AbstractControl::hideDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
QObject::connect(modelToggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles["ModelRandomizer"]), &ToggleControl::toggleFlipped, [this](bool state) {
|
||||
updateToggles();
|
||||
|
||||
if (state && !allModelsDownloaded) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("The \"Model Randomizer\" only works with downloaded models. Do you want to download all the driving models?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("The \"Model Randomizer\" works only with downloaded models. Download all models now?"), this)) {
|
||||
params_memory.putBool("DownloadAllModels", true);
|
||||
params_memory.put("ModelDownloadProgress", "Downloading...");
|
||||
|
||||
downloadModelBtn->setValue("Downloading...");
|
||||
downloadModelButton->setValue("Downloading...");
|
||||
|
||||
allModelsDownloading = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [modelLayout, modelPanel] {modelLayout->setCurrentWidget(modelPanel);});
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [modelLayout, modelPanel, this] {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
modelLayout->setCurrentWidget(modelPanel);
|
||||
});
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotModelPanel::updateState);
|
||||
}
|
||||
|
||||
@@ -309,7 +368,11 @@ void FrogPilotModelPanel::showEvent(QShowEvent *event) {
|
||||
tuningLevel = parent->tuningLevel;
|
||||
|
||||
allModelsDownloading = params_memory.getBool("DownloadAllModels");
|
||||
modelDownloading = !params_memory.get("ModelToDownload").empty();
|
||||
modelDownloading = !params_memory.get("ModelDownloadProgress").empty();
|
||||
tinygradUpdate = params.getBool("TinygradUpdateAvailable");
|
||||
updatingTinygrad = params_memory.getBool("UpdateTinygrad");
|
||||
|
||||
modelDownloading &= !updatingTinygrad;
|
||||
|
||||
QStringList availableModels = QString::fromStdString(params.get("AvailableModels")).split(",");
|
||||
availableModels.sort();
|
||||
@@ -318,18 +381,15 @@ void FrogPilotModelPanel::showEvent(QShowEvent *event) {
|
||||
|
||||
modelFileToNameMap.clear();
|
||||
modelFileToNameMapProcessed.clear();
|
||||
int size = qMin(availableModels.size(), availableModelNames.size());
|
||||
for (int i = 0; i < size; ++i) {
|
||||
for (int i = 0; i < qMin(availableModels.size(), availableModelNames.size()); ++i) {
|
||||
modelFileToNameMap.insert(availableModels[i], availableModelNames[i]);
|
||||
modelFileToNameMapProcessed.insert(availableModels[i], processModelName(availableModelNames[i]));
|
||||
}
|
||||
modelFileToNameMap.insert("space-lab", "Space Lab 👀📡");
|
||||
modelFileToNameMapProcessed.insert("space-lab", "Space Lab");
|
||||
|
||||
QStringList downloadableModels = availableModelNames;
|
||||
for (const QString &modelKey : modelFileToNameMap.keys()) {
|
||||
QString modelName = modelFileToNameMap.value(modelKey);
|
||||
if (modelDir.exists(modelKey + ".thneed")) {
|
||||
if (modelDir.exists(modelKey + ".thneed") || hasAllTinygradFiles(modelDir, modelKey)) {
|
||||
downloadableModels.removeAll(modelName);
|
||||
}
|
||||
}
|
||||
@@ -348,24 +408,27 @@ void FrogPilotModelPanel::showEvent(QShowEvent *event) {
|
||||
}
|
||||
}
|
||||
deletableModels.removeAll(processModelName(currentModel));
|
||||
deletableModels.removeAll(modelFileToNameMapProcessed.value(QString::fromStdString(params_default.get("Model"))));
|
||||
deletableModels.removeAll(modelFileToNameMapProcessed.value(normalizeModelKey(QString::fromStdString(params_default.get("Model")))));
|
||||
noModelsDownloaded = deletableModels.isEmpty();
|
||||
|
||||
QString modelKey = QString::fromStdString(params.get("Model"));
|
||||
QString modelKey = normalizeModelKey(QString::fromStdString(params.get("Model")));
|
||||
if (!modelDir.exists(modelKey + ".thneed") && !hasAllTinygradFiles(modelDir, modelKey)) {
|
||||
modelKey = QString::fromStdString(params_default.get("Model"));
|
||||
modelKey = normalizeModelKey(QString::fromStdString(params_default.get("Model")));
|
||||
}
|
||||
currentModel = modelFileToNameMap.value(modelKey);
|
||||
selectModelBtn->setValue(currentModel);
|
||||
selectModelButton->setValue(currentModel);
|
||||
|
||||
bool parked = !s.scene.started || fs.frogpilot_scene.parked || fs.frogpilot_toggles.value("frogs_go_moo").toBool();
|
||||
|
||||
deleteModelBtn->setEnabled(!(allModelsDownloading || modelDownloading || noModelsDownloaded));
|
||||
deleteModelButton->setEnabled(!(allModelsDownloading || modelDownloading || noModelsDownloaded));
|
||||
|
||||
downloadModelBtn->setEnabledButtons(0, !allModelsDownloaded && !allModelsDownloading && !cancellingDownload && fs.frogpilot_scene.online && parked);
|
||||
downloadModelBtn->setEnabledButtons(1, !allModelsDownloaded && !modelDownloading && !cancellingDownload && fs.frogpilot_scene.online && parked);
|
||||
downloadModelButton->setEnabledButtons(0, !allModelsDownloaded && !allModelsDownloading && !cancellingDownload && !updatingTinygrad && fs.frogpilot_scene.online && parked);
|
||||
downloadModelButton->setEnabledButtons(1, !allModelsDownloaded && !modelDownloading && !cancellingDownload && !updatingTinygrad && fs.frogpilot_scene.online && parked);
|
||||
|
||||
downloadModelBtn->setValue(fs.frogpilot_scene.online ? (parked ? "" : "Not parked") : tr("Offline..."));
|
||||
downloadModelButton->setValue(fs.frogpilot_scene.online ? (parked ? "" : "Not parked") : tr("Offline..."));
|
||||
|
||||
updateTinygradButton->setEnabled(!modelDownloading && !cancellingDownload && fs.frogpilot_scene.online && parked && tinygradUpdate);
|
||||
updateTinygradButton->setValue(tinygradUpdate ? tr("Update available!") : tr("Up to date!"));
|
||||
|
||||
started = s.scene.started;
|
||||
|
||||
@@ -384,47 +447,90 @@ void FrogPilotModelPanel::updateState(const UIState &s, const FrogPilotUIState &
|
||||
bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|missing|offline", QRegularExpression::CaseInsensitiveOption));
|
||||
|
||||
if (progress != "Downloading...") {
|
||||
downloadModelBtn->setValue(progress);
|
||||
downloadModelButton->setValue(progress);
|
||||
}
|
||||
|
||||
if (progress == "All models downloaded!" && allModelsDownloading || progress == "Downloaded!" && modelDownloading || downloadFailed) {
|
||||
if (progress == "All models downloaded!" || progress == "Downloaded!" && !allModelsDownloading || downloadFailed) {
|
||||
finalizingDownload = true;
|
||||
|
||||
QTimer::singleShot(2500, [this, progress]() {
|
||||
allModelsDownloaded = progress == "All models downloaded!";
|
||||
QTimer::singleShot(2500, [progress, this]() {
|
||||
allModelsDownloading = false;
|
||||
cancellingDownload = false;
|
||||
finalizingDownload = false;
|
||||
modelDownloading = false;
|
||||
noModelsDownloaded = false;
|
||||
|
||||
params_memory.remove("CancelModelDownload");
|
||||
params_memory.remove("DownloadAllModels");
|
||||
params_memory.remove("ModelDownloadProgress");
|
||||
params_memory.remove("ModelToDownload");
|
||||
QStringList downloadableModels = availableModelNames;
|
||||
for (const QString &modelKey : modelFileToNameMap.keys()) {
|
||||
QString modelName = modelFileToNameMap.value(modelKey);
|
||||
if (modelDir.exists(modelKey + ".thneed") || hasAllTinygradFiles(modelDir, modelKey)) {
|
||||
downloadableModels.removeAll(modelName);
|
||||
}
|
||||
}
|
||||
allModelsDownloaded = downloadableModels.isEmpty();
|
||||
|
||||
downloadModelBtn->setEnabled(true);
|
||||
downloadModelBtn->setValue("");
|
||||
params_memory.remove("ModelDownloadProgress");
|
||||
|
||||
downloadModelButton->setEnabled(true);
|
||||
downloadModelButton->setValue("");
|
||||
});
|
||||
}
|
||||
} else {
|
||||
downloadModelBtn->setValue(fs.frogpilot_scene.online ? (parked ? "" : "Not parked") : tr("Offline..."));
|
||||
downloadModelButton->setValue(fs.frogpilot_scene.online ? (parked ? "" : "Not parked") : tr("Offline..."));
|
||||
}
|
||||
|
||||
deleteModelBtn->setEnabled(!(allModelsDownloading || modelDownloading || noModelsDownloaded));
|
||||
if (updatingTinygrad) {
|
||||
QString progress = QString::fromStdString(params_memory.get("ModelDownloadProgress"));
|
||||
bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|missing|offline", QRegularExpression::CaseInsensitiveOption));
|
||||
|
||||
downloadModelBtn->setText(0, modelDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
downloadModelBtn->setText(1, allModelsDownloading ? tr("CANCEL") : tr("DOWNLOAD ALL"));
|
||||
if (progress != "Downloading...") {
|
||||
updateTinygradButton->setValue(progress);
|
||||
}
|
||||
|
||||
downloadModelBtn->setEnabledButtons(0, !allModelsDownloaded && !allModelsDownloading && !cancellingDownload && !finalizingDownload && fs.frogpilot_scene.online && parked);
|
||||
downloadModelBtn->setEnabledButtons(1, !allModelsDownloaded && !modelDownloading && !cancellingDownload && !finalizingDownload && fs.frogpilot_scene.online && parked);
|
||||
if (progress == "Updated!" && updatingTinygrad || downloadFailed) {
|
||||
finalizingDownload = true;
|
||||
|
||||
downloadModelBtn->setVisibleButton(0, !allModelsDownloading);
|
||||
downloadModelBtn->setVisibleButton(1, !modelDownloading);
|
||||
QTimer::singleShot(2500, [progress, this]() {
|
||||
modelDownloading = !params_memory.get("ModelDownloadProgress").empty();
|
||||
|
||||
if (modelDownloading) {
|
||||
downloadModelButton->setText(1, tr("CANCEL"));
|
||||
|
||||
downloadModelButton->setValue("Downloading...");
|
||||
|
||||
downloadModelButton->setVisibleButton(0, false);
|
||||
} else {
|
||||
cancellingDownload = false;
|
||||
}
|
||||
|
||||
tinygradUpdate = params.getBool("TinygradUpdateAvailable");
|
||||
|
||||
finalizingDownload = false;
|
||||
updatingTinygrad = false;
|
||||
|
||||
updateTinygradButton->setEnabled(tinygradUpdate);
|
||||
updateTinygradButton->setText(0, tr("UPDATE"));
|
||||
updateTinygradButton->setValue(tinygradUpdate ? tr("Update available!") : tr("Up to date!"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
deleteModelButton->setEnabled(!(allModelsDownloading || modelDownloading || noModelsDownloaded));
|
||||
|
||||
downloadModelButton->setText(0, modelDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
downloadModelButton->setText(1, allModelsDownloading ? tr("CANCEL") : tr("DOWNLOAD ALL"));
|
||||
|
||||
downloadModelButton->setEnabledButtons(0, !allModelsDownloaded && !allModelsDownloading && !cancellingDownload && !finalizingDownload && !updatingTinygrad && fs.frogpilot_scene.online && parked);
|
||||
downloadModelButton->setEnabledButtons(1, !allModelsDownloaded && !modelDownloading && !cancellingDownload && !finalizingDownload && !updatingTinygrad && fs.frogpilot_scene.online && parked);
|
||||
|
||||
downloadModelButton->setVisibleButton(0, !allModelsDownloading);
|
||||
downloadModelButton->setVisibleButton(1, !modelDownloading);
|
||||
|
||||
updateTinygradButton->setEnabled(!modelDownloading && !cancellingDownload && !cancellingDownload && !finalizingDownload && fs.frogpilot_scene.online && parked && tinygradUpdate);
|
||||
|
||||
started = s.scene.started;
|
||||
|
||||
parent->keepScreenOn = allModelsDownloading || modelDownloading;
|
||||
parent->keepScreenOn = allModelsDownloading || modelDownloading || updatingTinygrad;
|
||||
}
|
||||
|
||||
void FrogPilotModelPanel::updateModelLabels(FrogPilotListWidget *labelsList) {
|
||||
@@ -464,5 +570,7 @@ void FrogPilotModelPanel::updateToggles() {
|
||||
toggle->setVisible(setVisible);
|
||||
}
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -25,18 +25,22 @@ private:
|
||||
bool allModelsDownloading;
|
||||
bool cancellingDownload;
|
||||
bool finalizingDownload;
|
||||
bool forceOpenDescriptions;
|
||||
bool modelDownloading;
|
||||
bool noModelsDownloaded;
|
||||
bool started;
|
||||
bool tinygradUpdate;
|
||||
bool updatingTinygrad;
|
||||
|
||||
int tuningLevel;
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
ButtonControl *selectModelBtn;
|
||||
ButtonControl *selectModelButton;
|
||||
|
||||
FrogPilotButtonsControl *deleteModelBtn;
|
||||
FrogPilotButtonsControl *downloadModelBtn;
|
||||
FrogPilotButtonsControl *deleteModelButton;
|
||||
FrogPilotButtonsControl *downloadModelButton;
|
||||
FrogPilotButtonsControl *updateTinygradButton;
|
||||
|
||||
FrogPilotSettingsWindow *parent;
|
||||
|
||||
|
||||
@@ -1,35 +1,15 @@
|
||||
#include "frogpilot/ui/qt/offroad/navigation_settings.h"
|
||||
|
||||
void FrogPilotNavigationPanel::createMapboxKeyControl(ButtonControl *&control, const QString &label, const std::string ¶mKey, const QString &prefix, FrogPilotListWidget *list) {
|
||||
control = new ButtonControl(label, "", tr("Manage your %1.").arg(label));
|
||||
QObject::connect(control, &ButtonControl::clicked, [=] {
|
||||
if (control->text() == tr("ADD")) {
|
||||
QString key = InputDialog::getText(tr("Enter your %1").arg(label), this).trimmed();
|
||||
|
||||
if (!key.startsWith(prefix)) {
|
||||
key = prefix + key;
|
||||
}
|
||||
if (key.length() >= 80) {
|
||||
params.put(paramKey, key.toStdString());
|
||||
} else {
|
||||
ConfirmationDialog::alert(tr("Inputted key is invalid or too short!"), this);
|
||||
}
|
||||
} else {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to remove your %1?").arg(label), this)) {
|
||||
control->setText(tr("ADD"));
|
||||
|
||||
params.put(paramKey, "0");
|
||||
params.put(paramKey, "0");
|
||||
|
||||
setupCompleted = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
control->setText(QString::fromStdString(params.get(paramKey)).startsWith(prefix) ? tr("REMOVE") : tr("ADD"));
|
||||
list->addItem(control);
|
||||
}
|
||||
|
||||
FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
primelessLayout = new QStackedLayout();
|
||||
addItem(primelessLayout);
|
||||
|
||||
@@ -37,18 +17,15 @@ FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *pare
|
||||
ipLabel = new LabelControl(tr("Manage Your Settings At"), tr("Offline..."));
|
||||
settingsList->addItem(ipLabel);
|
||||
|
||||
std::vector<QString> searchOptions{tr("MapBox"), tr("Amap"), tr("Google")};
|
||||
FrogPilotButtonsControl *searchInput = new FrogPilotButtonsControl(tr("Destination Search Provider"),
|
||||
tr("The search provider used for destination queries in \"Navigate on Openpilot\". "
|
||||
"Options include \"MapBox\" (recommended), \"Amap\", and \"Google Maps\"."),
|
||||
"", searchOptions, true);
|
||||
|
||||
std::vector<QString> searchOptions{tr("Mapbox"), tr("Amap")};
|
||||
searchInput = new FrogPilotButtonsControl(tr("Destination Search Provider"),
|
||||
tr("<b>The search provider used for destination queries</b> in \"Navigate on Openpilot\". "
|
||||
"Options include Mapbox (recommended) and Amap."),
|
||||
"", searchOptions, true);
|
||||
QObject::connect(searchInput, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
amapKeyControl1->setVisible(id == 1);
|
||||
amapKeyControl2->setVisible(id == 1);
|
||||
|
||||
googleKeyControl->setVisible(id == 2);
|
||||
|
||||
params.putInt("SearchInput", id);
|
||||
|
||||
update();
|
||||
@@ -56,78 +33,15 @@ FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *pare
|
||||
searchInput->setCheckedButton(params.getInt("SearchInput"));
|
||||
settingsList->addItem(searchInput);
|
||||
|
||||
amapKeyControl1 = new ButtonControl(tr("Amap Key #1"), "", tr("Manage your Amap key."));
|
||||
QObject::connect(amapKeyControl1, &ButtonControl::clicked, [=] {
|
||||
if (amapKeyControl1->text() == tr("ADD")) {
|
||||
QString key = InputDialog::getText(tr("Enter your Amap key"), this).trimmed();
|
||||
createKeyControl(amapKeyControl1, tr("Amap Key #1"), "AMapKey1", "", 39, settingsList);
|
||||
createKeyControl(amapKeyControl2, tr("Amap Key #2"), "AMapKey2", "", 39, settingsList);
|
||||
|
||||
if (key.length() >= 39) {
|
||||
params.put("AMapKey1", key.toStdString());
|
||||
} else {
|
||||
ConfirmationDialog::alert(tr("Inputted key is invalid or too short!"), this);
|
||||
}
|
||||
} else {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to remove your Amap key?"), this)) {
|
||||
amapKeyControl1->setText(tr("ADD"));
|
||||
createKeyControl(publicMapboxKeyControl, tr("Public Mapbox Key"), "MapboxPublicKey", "pk.", 80, settingsList);
|
||||
createKeyControl(secretMapboxKeyControl, tr("Secret Mapbox Key"), "MapboxSecretKey", "sk.", 80, settingsList);
|
||||
|
||||
params.put("AMapKey1", "0");
|
||||
params.put("AMapKey1", "0");
|
||||
}
|
||||
}
|
||||
});
|
||||
amapKeyControl1->setText(params.get("AMapKey1").empty() ? tr("ADD") : tr("REMOVE"));
|
||||
settingsList->addItem(amapKeyControl1);
|
||||
|
||||
amapKeyControl2 = new ButtonControl(tr("Amap Key #2"), "", tr("Manage your Amap key."));
|
||||
QObject::connect(amapKeyControl2, &ButtonControl::clicked, [=] {
|
||||
if (amapKeyControl2->text() == tr("ADD")) {
|
||||
QString key = InputDialog::getText(tr("Enter your Amap key"), this).trimmed();
|
||||
|
||||
if (key.length() >= 39) {
|
||||
params.put("AMapKey2", key.toStdString());
|
||||
} else {
|
||||
ConfirmationDialog::alert(tr("Inputted key is invalid or too short!"), this);
|
||||
}
|
||||
} else {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to remove your Amap key?"), this)) {
|
||||
amapKeyControl2->setText(tr("ADD"));
|
||||
|
||||
params.put("AMapKey2", "0");
|
||||
params.put("AMapKey2", "0");
|
||||
}
|
||||
}
|
||||
});
|
||||
amapKeyControl2->setText(params.get("AMapKey2").empty() ? tr("ADD") : tr("REMOVE"));
|
||||
settingsList->addItem(amapKeyControl2);
|
||||
|
||||
googleKeyControl = new ButtonControl(tr("Google Maps Key"), "", tr("Manage your Google Maps key."));
|
||||
QObject::connect(googleKeyControl, &ButtonControl::clicked, [=] {
|
||||
if (googleKeyControl->text() == tr("ADD")) {
|
||||
QString key = InputDialog::getText(tr("Enter your Google Maps key"), this).trimmed();
|
||||
|
||||
if (key.length() >= 25) {
|
||||
params.put("GMapKey", key.toStdString());
|
||||
} else {
|
||||
ConfirmationDialog::alert(tr("Inputted key is invalid or too short!"), this);
|
||||
}
|
||||
} else {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to remove your Google Maps key?"), this)) {
|
||||
googleKeyControl->setText(tr("ADD"));
|
||||
|
||||
params.put("GMapKey", "0");
|
||||
params.put("GMapKey", "0");
|
||||
}
|
||||
}
|
||||
});
|
||||
googleKeyControl->setText(params.get("GMapKey").empty() ? tr("ADD") : tr("REMOVE"));
|
||||
settingsList->addItem(googleKeyControl);
|
||||
|
||||
createMapboxKeyControl(publicMapboxKeyControl, tr("Public Mapbox Key"), "MapboxPublicKey", "pk.", settingsList);
|
||||
createMapboxKeyControl(secretMapboxKeyControl, tr("Secret Mapbox Key"), "MapboxSecretKey", "sk.", settingsList);
|
||||
|
||||
ButtonControl *setupButton = new ButtonControl(tr("MapBox Setup Instructions"), tr("VIEW"), tr("View the instructions to set up \"MapBox\" for \"Primeless Navigation\"."), this);
|
||||
setupButton = new ButtonControl(tr("Mapbox Setup Instructions"), tr("VIEW"), tr("<b>Instructions on how to set up Mapbox</b> for \"Primeless Navigation\"."), this);
|
||||
QObject::connect(setupButton, &ButtonControl::clicked, [this]() {
|
||||
openSubSubPanel();
|
||||
openSubPanel();
|
||||
|
||||
updateStep();
|
||||
|
||||
@@ -137,16 +51,16 @@ FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *pare
|
||||
|
||||
std::vector<QString> filterButtonNames{tr("CANCEL"), tr("Manually Update Speed Limits")};
|
||||
updateSpeedLimitsToggle = new FrogPilotButtonControl("SpeedLimitFiller", tr("Speed Limit Filler"),
|
||||
tr("Automatically collect missing or incorrect speed limits from your dashboard (if supported), "
|
||||
"<b>Mapbox</b>, and <b>Navigate-on-openpilot</b> while driving.<br><br>"
|
||||
"When the car is turned off and connected to Wi-Fi, your speed limit data is automatically processed "
|
||||
"into a compiled file formatted for the tool located at <b>SpeedLimitFiller.frogpilot.download</b>.<br><br>"
|
||||
"You can grab the processed file from <b>The Pond</b> via the <b>Download Speed Limits</b> menu.<br><br>"
|
||||
"Want a more thorough walkthrough? Check out the <b>#speed-limit-filler</b> channel in the <b>FrogPilot Discord</b>!"),
|
||||
tr("<b>Automatically collect missing or incorrect speed limits while you drive</b> using speeds limits sourced from your dashboard (if supported), "
|
||||
"Mapbox, and \"Navigate on openpilot\".<br><br>"
|
||||
"When you're parked and connected to Wi-Fi, FrogPilot will automatically processes this data into a file "
|
||||
"to be used with the tool located at \"SpeedLimitFiller.frogpilot.download\".<br><br>"
|
||||
"You can download this file from \"The Pond\" in the \"Download Speed Limits\" menu.<br><br>"
|
||||
"Need a step-by-step guide? Visit <b>#speed-limit-filler</b> in the FrogPilot Discord!"),
|
||||
"", filterButtonNames);
|
||||
QObject::connect(updateSpeedLimitsToggle, &FrogPilotButtonControl::buttonClicked, [this](int id) {
|
||||
if (id == 0) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to cancel the speed limit update process?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Cancel the speed-limit update?"), this)) {
|
||||
updatingLimits = false;
|
||||
|
||||
updateSpeedLimitsToggle->setEnabledButton(0, false);
|
||||
@@ -184,7 +98,7 @@ FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *pare
|
||||
int hours = secondsUntilMidnight / 3600;
|
||||
int minutes = (secondsUntilMidnight % 3600) / 60;
|
||||
|
||||
ConfirmationDialog::alert(QString(tr("You have reached the request limit.\n\nIt will reset in %1 hours and %2 minutes.")).arg(hours).arg(minutes), this);
|
||||
ConfirmationDialog::alert(QString(tr("You've hit today's request limit.\n\nIt will reset in %1 hours and %2 minutes.")).arg(hours).arg(minutes), this);
|
||||
|
||||
updateSpeedLimitsToggle->clearCheckedButtons(true);
|
||||
return;
|
||||
@@ -193,7 +107,7 @@ FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *pare
|
||||
updateSpeedLimitsToggle->setVisibleButton(0, true);
|
||||
updateSpeedLimitsToggle->setVisibleButton(1, false);
|
||||
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("This process will take awhile, so it's advised to start when you're done driving with a stable Wi-Fi connection. Do you wish to proceed?"), this)) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("This process takes a while. It's recommended to start when you're done driving and connected to stable Wi-Fi. Continue?"), this)) {
|
||||
updatingLimits = true;
|
||||
|
||||
updateSpeedLimitsToggle->setValue("Calculating...");
|
||||
@@ -219,11 +133,33 @@ FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *pare
|
||||
ScrollView *instructionsPanel = new ScrollView(imageLabel, this);
|
||||
primelessLayout->addWidget(instructionsPanel);
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubSubPanel, [this] {primelessLayout->setCurrentIndex(0);});
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [this]() {
|
||||
primelessLayout->setCurrentIndex(0);
|
||||
|
||||
if (forceOpenDescriptions) {
|
||||
amapKeyControl1->showDescription();
|
||||
amapKeyControl2->showDescription();
|
||||
publicMapboxKeyControl->showDescription();
|
||||
searchInput->showDescription();
|
||||
secretMapboxKeyControl->showDescription();
|
||||
setupButton->showDescription();
|
||||
updateSpeedLimitsToggle->showDescription();
|
||||
}
|
||||
});
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotNavigationPanel::updateState);
|
||||
}
|
||||
|
||||
void FrogPilotNavigationPanel::showEvent(QShowEvent *event) {
|
||||
if (forceOpenDescriptions) {
|
||||
amapKeyControl1->showDescription();
|
||||
amapKeyControl2->showDescription();
|
||||
publicMapboxKeyControl->showDescription();
|
||||
searchInput->showDescription();
|
||||
secretMapboxKeyControl->showDescription();
|
||||
setupButton->showDescription();
|
||||
updateSpeedLimitsToggle->showDescription();
|
||||
}
|
||||
|
||||
FrogPilotUIState &fs = *frogpilotUIState();
|
||||
UIState &s = *uiState();
|
||||
|
||||
@@ -239,12 +175,10 @@ void FrogPilotNavigationPanel::showEvent(QShowEvent *event) {
|
||||
|
||||
bool parked = !s.scene.started || fs.frogpilot_scene.parked || fs.frogpilot_toggles.value("frogs_go_moo").toBool();
|
||||
|
||||
int searchInput = params.getInt("SearchInput");
|
||||
int selectedSearchInput = params.getInt("SearchInput");
|
||||
|
||||
amapKeyControl1->setVisible(searchInput == 1);
|
||||
amapKeyControl2->setVisible(searchInput == 1);
|
||||
|
||||
googleKeyControl->setVisible(searchInput == 2);
|
||||
amapKeyControl1->setVisible(selectedSearchInput == 1);
|
||||
amapKeyControl2->setVisible(selectedSearchInput == 1);
|
||||
|
||||
updateSpeedLimitsToggle->setVisibleButton(0, updatingLimits);
|
||||
updateSpeedLimitsToggle->setVisibleButton(1, !updatingLimits);
|
||||
@@ -264,18 +198,56 @@ void FrogPilotNavigationPanel::hideEvent(QHideEvent *event) {
|
||||
|
||||
void FrogPilotNavigationPanel::mousePressEvent(QMouseEvent *event) {
|
||||
if (primelessLayout->currentIndex() == 1) {
|
||||
closeSubSubPanel();
|
||||
closeSubPanel();
|
||||
|
||||
primelessLayout->setCurrentIndex(0);
|
||||
|
||||
if (forceOpenDescriptions) {
|
||||
amapKeyControl1->showDescription();
|
||||
amapKeyControl2->showDescription();
|
||||
publicMapboxKeyControl->showDescription();
|
||||
searchInput->showDescription();
|
||||
secretMapboxKeyControl->showDescription();
|
||||
setupButton->showDescription();
|
||||
updateSpeedLimitsToggle->showDescription();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FrogPilotNavigationPanel::createKeyControl(ButtonControl *&control, const QString &label, const std::string ¶mKey, const QString &prefix, const int &minLength, FrogPilotListWidget *list) {
|
||||
control = new ButtonControl(label, "", tr("<b>Manage your \"%1\".</b>").arg(label));
|
||||
QObject::connect(control, &ButtonControl::clicked, [=] {
|
||||
if (control->text() == tr("ADD")) {
|
||||
QString key = InputDialog::getText(tr("Enter your %1").arg(label), this).trimmed();
|
||||
|
||||
if (!key.startsWith(prefix)) {
|
||||
key = prefix + key;
|
||||
}
|
||||
|
||||
if (key.length() >= minLength) {
|
||||
params.put(paramKey, key.toStdString());
|
||||
} else {
|
||||
ConfirmationDialog::alert(tr("Inputted key is invalid or too short!"), this);
|
||||
}
|
||||
} else {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Remove your %1?").arg(label), this)) {
|
||||
control->setText(tr("ADD"));
|
||||
|
||||
params.remove(paramKey);
|
||||
params_cache.remove(paramKey);
|
||||
|
||||
setupCompleted = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
control->setText(QString::fromStdString(params.get(paramKey)).startsWith(prefix) ? tr("REMOVE") : tr("ADD"));
|
||||
list->addItem(control);
|
||||
}
|
||||
|
||||
void FrogPilotNavigationPanel::updateButtons() {
|
||||
amapKeyControl1->setText(params.get("AMapKey1").empty() ? tr("ADD") : tr("REMOVE"));
|
||||
amapKeyControl2->setText(params.get("AMapKey2").empty() ? tr("ADD") : tr("REMOVE"));
|
||||
|
||||
googleKeyControl->setText(params.get("GMapKey").empty() ? tr("ADD") : tr("REMOVE"));
|
||||
|
||||
mapboxPublicKeySet = QString::fromStdString(params.get("MapboxPublicKey")).startsWith("pk");
|
||||
mapboxSecretKeySet = QString::fromStdString(params.get("MapboxSecretKey")).startsWith("sk");
|
||||
|
||||
|
||||
@@ -9,20 +9,21 @@ public:
|
||||
explicit FrogPilotNavigationPanel(FrogPilotSettingsWindow *parent);
|
||||
|
||||
signals:
|
||||
void closeSubSubPanel();
|
||||
void openSubSubPanel();
|
||||
void closeSubPanel();
|
||||
void openSubPanel();
|
||||
|
||||
protected:
|
||||
void hideEvent(QHideEvent *event);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
private:
|
||||
void createMapboxKeyControl(ButtonControl *&control, const QString &label, const std::string ¶mKey, const QString &prefix, FrogPilotListWidget *list);
|
||||
void createKeyControl(ButtonControl *&control, const QString &label, const std::string ¶mKey, const QString &prefix, const int &minLength, FrogPilotListWidget *list);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void updateButtons();
|
||||
void updateState(const UIState &s, const FrogPilotUIState &fs);
|
||||
void updateStep();
|
||||
|
||||
bool forceOpenDescriptions;
|
||||
bool mapboxPublicKeySet;
|
||||
bool mapboxSecretKeySet;
|
||||
bool setupCompleted;
|
||||
@@ -30,17 +31,20 @@ private:
|
||||
|
||||
ButtonControl *amapKeyControl1;
|
||||
ButtonControl *amapKeyControl2;
|
||||
ButtonControl *googleKeyControl;
|
||||
ButtonControl *publicMapboxKeyControl;
|
||||
ButtonControl *secretMapboxKeyControl;
|
||||
ButtonControl *setupButton;
|
||||
|
||||
FrogPilotButtonControl *updateSpeedLimitsToggle;
|
||||
|
||||
FrogPilotButtonsControl *searchInput;
|
||||
|
||||
FrogPilotSettingsWindow *parent;
|
||||
|
||||
LabelControl *ipLabel;
|
||||
|
||||
Params params;
|
||||
Params params_cache{"/cache/params"};
|
||||
Params params_memory{"/dev/shm/params"};
|
||||
|
||||
QLabel *imageLabel;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "frogpilot/ui/qt/offroad/sounds_settings.h"
|
||||
|
||||
void playSound(const QString &alert, int volume) {
|
||||
QString stockPath = "/data/openpilot/selfdrive/assets/sounds/" + alert + ".wav";
|
||||
QString themePath = "/data/openpilot/frogpilot/assets/active_theme/sounds/" + alert + ".wav";
|
||||
QString stockPath = "../../selfdrive/assets/sounds/" + alert + ".wav";
|
||||
QString themePath = "../../frogpilot/assets/active_theme/sounds/" + alert + ".wav";
|
||||
|
||||
QString filePath = QFile::exists(themePath) ? themePath : stockPath;
|
||||
|
||||
@@ -14,6 +14,15 @@ void playSound(const QString &alert, int volume) {
|
||||
}
|
||||
|
||||
FrogPilotSoundsPanel::FrogPilotSoundsPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
QStackedLayout *soundsLayout = new QStackedLayout();
|
||||
addItem(soundsLayout);
|
||||
|
||||
@@ -33,21 +42,21 @@ FrogPilotSoundsPanel::FrogPilotSoundsPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
soundsLayout->addWidget(customAlertsPanel);
|
||||
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> soundsToggles {
|
||||
{"AlertVolumeControl", tr("Alert Volume Control"), tr("Adjust the volume for each alert in openpilot."), "../../frogpilot/assets/toggle_icons/icon_mute.png"},
|
||||
{"DisengageVolume", tr("Disengage Volume"), tr("Adjust the volume for alerts like:<br><br><b>Adaptive Cruise Disabled</b><br><b>Brake Pedal Pressed</b><br><b>Parking Brake Engaged</b><br><b>Speed too Low</b>"), ""},
|
||||
{"EngageVolume", tr("Engage Volume"), tr("Adjust the volume for alerts like:<br><br><b>NNFF Torque Controller loaded</b><br><b>openpilot engaged</b>"), ""},
|
||||
{"PromptVolume", tr("Prompt Volume"), tr("Adjust the volume for alerts like:<br><br><b>Car Detected in Blindspot</b><br><b>Steer Unavailable Below \"X\"</b><br><b>Speed too Low</b><br><b>Take Control, Turn Exceeds Steering Limit</b>"), ""},
|
||||
{"PromptDistractedVolume", tr("Prompt Distracted Volume"), tr("Adjust the volume for alerts like:<br><br><b>Pay Attention, Driver Distracted</b><br><b>Touch Steering Wheel, Driver Unresponsive</b>"), ""},
|
||||
{"RefuseVolume", tr("Refuse Volume"), tr("Adjust the volume for alerts like:<br><br><b>openpilot Unavailable</b>"), ""},
|
||||
{"WarningSoftVolume", tr("Warning Soft Volume"), tr("Adjust the volume for alerts like:<br><br><b>BRAKE!, Risk of Collision</b><br><b>TAKE CONTROL IMMEDIATELY</b>"), ""},
|
||||
{"WarningImmediateVolume", tr("Warning Immediate Volume"), tr("Adjust the volume for alerts like:<br><br><b>DISENGAGE IMMEDIATELY, Driver Distracted</b><br><b>DISENGAGE IMMEDIATELY, Driver Unresponsive</b>"), ""},
|
||||
{"AlertVolumeControl", tr("Alert Volume Controller"), tr("<b>Set how loud each type of openpilot alert is</b> to keep routine prompts from becoming distracting."), "../../frogpilot/assets/toggle_icons/icon_mute.png"},
|
||||
{"DisengageVolume", tr("Disengage Volume"), tr("<b>Set the volume for alerts when openpilot disengages.</b><br><br>Examples include: \"Cruise Fault: Restart the Car\", \"Parking Brake Engaged\", \"Pedal Pressed\"."), ""},
|
||||
{"EngageVolume", tr("Engage Volume"), tr("<b>Set the volume for the chime when openpilot engages</b>, such as after pressing the \"RESUME\" or \"SET\" steering wheel buttons."), ""},
|
||||
{"PromptVolume", tr("Prompt Volume"), tr("<b>Set the volume for prompts that need attention.</b><br><br>Examples include: \"Car Detected in Blindspot\", \"Steering Temporarily Unavailable\", \"Turn Exceeds Steering Limit\"."), ""},
|
||||
{"PromptDistractedVolume", tr("Prompt Distracted Volume"), tr("<b>Set the volume for prompts when openpilot detects driver distraction or unresponsiveness.</b><br><br>Examples include: \"Pay Attention\", \"Touch Steering Wheel\"."), ""},
|
||||
{"RefuseVolume", tr("Refuse Volume"), tr("<b>Set the volume for alerts when openpilot refuses to engage.</b><br><br>Examples include: \"Brake Hold Active\", \"Door Open\", \"Seatbelt Unlatched\"."), ""},
|
||||
{"WarningSoftVolume", tr("Warning Soft Volume"), tr("<b>Set the volume for softer warnings about potential risks.</b><br><br>Examples include: \"BRAKE! Risk of Collision\", \"Steering Temporarily Unavailable\"."), ""},
|
||||
{"WarningImmediateVolume", tr("Warning Immediate Volume"), tr("<b>Set the volume for the loudest warnings that require urgent attention.</b><br><br>Examples include: \"DISENGAGE IMMEDIATELY — Driver Distracted\", \"DISENGAGE IMMEDIATELY — Driver Unresponsive\"."), ""},
|
||||
|
||||
{"CustomAlerts", tr("FrogPilot Alerts"), tr("FrogPilot alerts for various events in openpilot."), "../../frogpilot/assets/toggle_icons/icon_green_light.png"},
|
||||
{"GoatScream", tr("Goat Scream Steering Saturated Alert"), tr("The infamous \"Goat Scream\" that has brought both joy and anger to FrogPilot users all around the world!"), ""},
|
||||
{"GreenLightAlert", tr("Green Light Alert"), tr("Get an alert when the traffic light changes from red to green."), ""},
|
||||
{"LeadDepartingAlert", tr("Lead Departing Alert"), tr("Get an alert when the lead vehicle begins to depart from a standstill."), ""},
|
||||
{"LoudBlindspotAlert", tr("Loud \"Car Detected in Blindspot\" Alert"), tr("A louder alert for when a vehicle is detected in the blindspot when attempting to change lanes."), ""},
|
||||
{"SpeedLimitChangedAlert", tr("Speed Limit Changed Alert"), tr("Get an alert when the speed limit changes."), ""}
|
||||
{"CustomAlerts", tr("FrogPilot Alerts"), tr("<b>Optional FrogPilot alerts</b> that highlight driving events in a more noticeable way."), "../../frogpilot/assets/toggle_icons/icon_green_light.png"},
|
||||
{"GoatScream", tr("Goat Scream"), tr("<b>Play the infamous \"Goat Scream\" when the steering controller reaches its limit.</b> Based on the \"Turn Exceeds Steering Limit\" event."), ""},
|
||||
{"GreenLightAlert", tr("Green Light Alert"), tr("<b>Play an alert when the model predicts a red light has turned green.</b><br><br><i><b>Disclaimer</b>: openpilot does not explicitly detect traffic lights. This alert is based on end-to-end model predictions from camera input and may trigger even when the light has not changed.</i>"), ""},
|
||||
{"LeadDepartingAlert", tr("Lead Departing Alert"), tr("<b>Play an alert when the lead vehicle departs from a stop.</b>"), ""},
|
||||
{"LoudBlindspotAlert", tr("Loud \"Car Detected in Blindspot\" Alert"), tr("<b>Play a louder alert if a vehicle is in the blind spot when attempting to change lanes.</b> Based on the \"Car Detected in Blindspot\" event."), ""},
|
||||
{"SpeedLimitChangedAlert", tr("Speed Limit Changed Alert"), tr("<b>Play an alert when the posted speed limit changes.</b>"), ""}
|
||||
};
|
||||
|
||||
for (const auto &[param, title, desc, icon] : soundsToggles) {
|
||||
@@ -59,7 +68,7 @@ FrogPilotSoundsPanel::FrogPilotSoundsPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
soundsLayout->setCurrentWidget(alertVolumeControlPanel);
|
||||
});
|
||||
soundsToggle = alertVolumeControlToggle;
|
||||
} else if (alertVolumeControlKeys.find(param) != alertVolumeControlKeys.end()) {
|
||||
} else if (alertVolumeControlKeys.contains(param)) {
|
||||
std::map<float, QString> volumeLabels;
|
||||
for (int i = 0; i <= 101; ++i) {
|
||||
volumeLabels[i] = i == 0 ? tr("Muted") : i == 101 ? tr("Auto") : QString::number(i) + "%";
|
||||
@@ -84,9 +93,9 @@ FrogPilotSoundsPanel::FrogPilotSoundsPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
toggles[param] = soundsToggle;
|
||||
|
||||
if (alertVolumeControlKeys.find(param) != alertVolumeControlKeys.end()) {
|
||||
if (alertVolumeControlKeys.contains(param)) {
|
||||
alertVolumeControlList->addItem(soundsToggle);
|
||||
} else if (customAlertsKeys.find(param) != customAlertsKeys.end()) {
|
||||
} else if (customAlertsKeys.contains(param)) {
|
||||
customAlertsList->addItem(soundsToggle);
|
||||
} else {
|
||||
soundsList->addItem(soundsToggle);
|
||||
@@ -95,9 +104,15 @@ FrogPilotSoundsPanel::FrogPilotSoundsPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
}
|
||||
|
||||
if (FrogPilotManageControl *frogPilotManageToggle = qobject_cast<FrogPilotManageControl*>(soundsToggle)) {
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, this, &FrogPilotSoundsPanel::openSubPanel);
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, [this]() {
|
||||
emit openSubPanel();
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(soundsToggle, &AbstractControl::hideDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
QObject::connect(soundsToggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
@@ -105,7 +120,7 @@ FrogPilotSoundsPanel::FrogPilotSoundsPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
for (const QString &key : alertVolumeControlKeys) {
|
||||
FrogPilotParamValueButtonControl *toggle = static_cast<FrogPilotParamValueButtonControl*>(toggles[key]);
|
||||
QObject::connect(toggle, &FrogPilotParamValueButtonControl::buttonClicked, [this, key, toggle]() {
|
||||
QObject::connect(toggle, &FrogPilotParamValueButtonControl::buttonClicked, [key, toggle, this]() {
|
||||
toggle->updateParam();
|
||||
|
||||
updateFrogPilotToggles();
|
||||
@@ -130,15 +145,26 @@ FrogPilotSoundsPanel::FrogPilotSoundsPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
if (started) {
|
||||
params_memory.put("TestAlert", camelCaseAlert.toStdString());
|
||||
} else {
|
||||
std::thread([this, key, snakeCaseAlert]() {
|
||||
std::thread([key, snakeCaseAlert, this]() {
|
||||
playSound(snakeCaseAlert, params.getInt(key.toStdString()));
|
||||
}).detach();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [soundsLayout, soundsPanel] {soundsLayout->setCurrentWidget(soundsPanel);});
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [soundsLayout, soundsPanel, this] {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
soundsLayout->setCurrentWidget(soundsPanel);
|
||||
});
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotSoundsPanel::updateState);
|
||||
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (alertVolumeControlKeys.contains(key)) {
|
||||
toggle->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
updateToggles();
|
||||
}
|
||||
|
||||
void FrogPilotSoundsPanel::showEvent(QShowEvent *event) {
|
||||
@@ -160,13 +186,13 @@ void FrogPilotSoundsPanel::updateState(const UIState &s) {
|
||||
|
||||
void FrogPilotSoundsPanel::updateToggles() {
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
toggle->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -183,13 +209,15 @@ void FrogPilotSoundsPanel::updateToggles() {
|
||||
toggle->setVisible(setVisible);
|
||||
|
||||
if (setVisible) {
|
||||
if (alertVolumeControlKeys.find(key) != alertVolumeControlKeys.end()) {
|
||||
if (alertVolumeControlKeys.contains(key)) {
|
||||
toggles["AlertVolumeControl"]->setVisible(true);
|
||||
} else if (customAlertsKeys.find(key) != customAlertsKeys.end()) {
|
||||
} else if (customAlertsKeys.contains(key)) {
|
||||
toggles["CustomAlerts"]->setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "frogpilot/ui/qt/offroad/frogpilot_settings.h"
|
||||
|
||||
class FrogPilotSoundsPanel : public FrogPilotListWidget {
|
||||
@@ -20,6 +18,7 @@ private:
|
||||
void updateState(const UIState &s);
|
||||
void updateToggles();
|
||||
|
||||
bool forceOpenDescriptions;
|
||||
bool hasBSM;
|
||||
bool hasOpenpilotLongitudinal;
|
||||
bool started;
|
||||
@@ -28,10 +27,10 @@ private:
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
std::set<QString> alertVolumeControlKeys = {"DisengageVolume", "EngageVolume", "PromptDistractedVolume", "PromptVolume", "RefuseVolume", "WarningImmediateVolume", "WarningSoftVolume"};
|
||||
std::set<QString> customAlertsKeys = {"GoatScream", "GreenLightAlert", "LeadDepartingAlert", "LoudBlindspotAlert", "SpeedLimitChangedAlert"};
|
||||
QSet<QString> alertVolumeControlKeys {"DisengageVolume", "EngageVolume", "PromptDistractedVolume", "PromptVolume", "RefuseVolume", "WarningImmediateVolume", "WarningSoftVolume"};
|
||||
QSet<QString> customAlertsKeys {"GoatScream", "GreenLightAlert", "LeadDepartingAlert", "LoudBlindspotAlert", "SpeedLimitChangedAlert"};
|
||||
|
||||
std::set<QString> parentKeys;
|
||||
QSet<QString> parentKeys;
|
||||
|
||||
FrogPilotSettingsWindow *parent;
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include "frogpilot/ui/qt/offroad/theme_settings.h"
|
||||
|
||||
bool isUserCreatedTheme(const QString &themeName) {
|
||||
return themeName.endsWith("-user_created");
|
||||
}
|
||||
|
||||
void updateAssetParam(const QString &assetParam, Params ¶ms, const QString &value, bool add) {
|
||||
QStringList assets = QString::fromStdString(params.get(assetParam.toStdString())).split(",", QString::SkipEmptyParts);
|
||||
if (add) {
|
||||
@@ -17,19 +21,44 @@ void updateAssetParam(const QString &assetParam, Params ¶ms, const QString &
|
||||
void deleteThemeAsset(QDir &directory, const QString &subFolder, const QString &assetParam, const QString &themeToDelete, Params ¶ms) {
|
||||
bool useFiles = subFolder.isEmpty();
|
||||
|
||||
QString themeName = themeToDelete.toLower().replace(" (", "-").replace(")", "").replace(" ", "-");
|
||||
QString baseName = themeToDelete.toLower();
|
||||
baseName.replace("(", "-").replace(")", "").replace(" ", "-");
|
||||
baseName.remove(QRegularExpression("[^a-z0-9\\-]"));
|
||||
while (baseName.endsWith("-")) {
|
||||
baseName.chop(1);
|
||||
}
|
||||
|
||||
QString baseUnderscore = baseName;
|
||||
baseUnderscore.replace("-", "_");
|
||||
|
||||
QStringList candidateNames = {
|
||||
baseName,
|
||||
baseName + "-user-created",
|
||||
baseUnderscore,
|
||||
baseUnderscore + "-user_created"
|
||||
};
|
||||
|
||||
if (useFiles) {
|
||||
for (const QString &file : directory.entryList(QDir::Files)) {
|
||||
QString fileName = QFileInfo(file).baseName().toLower().replace("_", "-");
|
||||
if (fileName == themeName) {
|
||||
QStringList files = directory.entryList(QDir::Files);
|
||||
for (QString &file : files) {
|
||||
QString normalizedFile = QFileInfo(file).baseName().toLower();
|
||||
normalizedFile.replace("_", "-");
|
||||
normalizedFile.remove(QRegularExpression("[^a-z0-9\\-~]"));
|
||||
|
||||
if (candidateNames.contains(normalizedFile)) {
|
||||
QFile::remove(directory.filePath(file));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
QDir targetDir(directory.filePath(QDir(themeName).filePath(subFolder)));
|
||||
if (targetDir.exists()) {
|
||||
targetDir.removeRecursively();
|
||||
for (QString &candidate : candidateNames) {
|
||||
QString fullSubPath = QDir(candidate).filePath(subFolder);
|
||||
QDir targetDir(directory.filePath(fullSubPath));
|
||||
|
||||
if (targetDir.exists()) {
|
||||
targetDir.removeRecursively();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,12 +66,17 @@ void deleteThemeAsset(QDir &directory, const QString &subFolder, const QString &
|
||||
}
|
||||
|
||||
void downloadThemeAsset(const QString &input, const std::string ¶mKey, const QString &assetParam, Params ¶ms, Params ¶ms_memory) {
|
||||
QString output = input.toLower().remove("(").remove(")");
|
||||
QString output = input;
|
||||
int tilde = output.indexOf("~");
|
||||
if (tilde >= 0) {
|
||||
output = output.left(tilde).toLower() + "~" + output.mid(tilde + 1);
|
||||
} else {
|
||||
output = output.toLower();
|
||||
}
|
||||
output.remove("(").remove(")");
|
||||
output.replace(" ", input.contains("(") ? "-" : "_");
|
||||
|
||||
params_memory.put(paramKey, output.toStdString());
|
||||
|
||||
updateAssetParam(assetParam, params, input, false);
|
||||
}
|
||||
|
||||
QStringList getHolidayThemes() {
|
||||
@@ -84,12 +118,39 @@ QStringList getThemeList(const bool &randomThemes, const QDir &themePacksDirecto
|
||||
}
|
||||
}
|
||||
|
||||
QStringList parts = entry.baseName().split(entry.baseName().contains("-") ? "-" : "_", QString::SkipEmptyParts);
|
||||
QString baseName = entry.baseName();
|
||||
bool userCreated = isUserCreatedTheme(baseName);
|
||||
if (userCreated) {
|
||||
baseName = baseName.replace("-user_created", "");
|
||||
}
|
||||
|
||||
int tildeIdx = baseName.indexOf("~");
|
||||
QString creator;
|
||||
if (tildeIdx >= 0) {
|
||||
creator = baseName.mid(tildeIdx + 1);
|
||||
baseName = baseName.left(tildeIdx);
|
||||
}
|
||||
|
||||
QStringList parts = baseName.split(baseName.contains("-") ? "-" : "_", QString::SkipEmptyParts);
|
||||
for (QString &part : parts) {
|
||||
part[0] = part[0].toUpper();
|
||||
}
|
||||
|
||||
themeList.append(parts.size() <= 1 || useFiles ? parts.join(" ") : QString("%1 (%2)").arg(parts[0], parts.mid(1).join(" ")));
|
||||
QString displayName;
|
||||
if (userCreated) {
|
||||
displayName = parts.join(" ");
|
||||
} else {
|
||||
displayName = (parts.size() <= 1 || useFiles) ? parts.join(" ") : QString("%1 (%2)").arg(parts[0], parts.mid(1).join(" "));
|
||||
}
|
||||
|
||||
if (userCreated) {
|
||||
displayName += " 🌟";
|
||||
}
|
||||
if (!creator.isEmpty()) {
|
||||
displayName += " - by: " + creator;
|
||||
}
|
||||
|
||||
themeList.append(displayName);
|
||||
}
|
||||
|
||||
return themeList;
|
||||
@@ -98,26 +159,58 @@ QStringList getThemeList(const bool &randomThemes, const QDir &themePacksDirecto
|
||||
QString getThemeName(const std::string ¶mKey, Params ¶ms) {
|
||||
QString value = QString::fromStdString(params.get(paramKey));
|
||||
|
||||
QStringList parts = value.split(value.contains("-") ? "-" : "_", QString::SkipEmptyParts);
|
||||
QString baseName = value;
|
||||
|
||||
int tildeIdx = baseName.indexOf("~");
|
||||
QString creator;
|
||||
if (tildeIdx >= 0) {
|
||||
creator = baseName.mid(tildeIdx + 1);
|
||||
baseName = baseName.left(tildeIdx);
|
||||
}
|
||||
|
||||
QStringList parts = baseName.split(baseName.contains("-") ? "-" : "_", QString::SkipEmptyParts);
|
||||
for (QString &part : parts) {
|
||||
part[0] = part[0].toUpper();
|
||||
}
|
||||
|
||||
if (value.contains("-") && parts.size() > 1) {
|
||||
return QString("%1 (%2)").arg(parts[0], parts.mid(1).join(" "));
|
||||
QString displayName;
|
||||
if (baseName.contains("-") && parts.size() > 1) {
|
||||
displayName = QString("%1 (%2)").arg(parts[0], parts.mid(1).join(" "));
|
||||
} else {
|
||||
displayName = parts.join(" ");
|
||||
}
|
||||
return parts.join(" ");
|
||||
|
||||
if (isUserCreatedTheme(value)) {
|
||||
displayName = displayName.split(" (")[0] + " 🌟";
|
||||
}
|
||||
if (!creator.isEmpty()) {
|
||||
displayName += " - by: " + creator;
|
||||
}
|
||||
|
||||
return displayName;
|
||||
}
|
||||
|
||||
QString storeThemeName(const QString &input, const std::string ¶mKey, Params ¶ms) {
|
||||
QString output = input.toLower().remove("(").remove(")").remove("'").remove(".");
|
||||
output.replace(" ", input.contains("(") ? "-" : "_");
|
||||
output.replace("_🌟", "-user_created");
|
||||
output = output.trimmed();
|
||||
|
||||
params.put(paramKey, output.toStdString());
|
||||
|
||||
return getThemeName(paramKey, params);
|
||||
}
|
||||
|
||||
FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
QStackedLayout *themesLayout = new QStackedLayout();
|
||||
addItem(themesLayout);
|
||||
|
||||
@@ -134,20 +227,20 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
themesLayout->addWidget(customThemesPanel);
|
||||
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> themeToggles {
|
||||
{"PersonalizeOpenpilot", tr("Custom Theme"), tr("The overall appearance of openpilot."), "../../frogpilot/assets/toggle_icons/icon_frog.png"},
|
||||
{"CustomColors", tr("Color Scheme"), tr("openpilot's color scheme.\n\nWant to submit your own color scheme? Share it in the \"custom-themes\" channel on the FrogPilot Discord!"), ""},
|
||||
{"CustomDistanceIcons", "Distance Button", "The distance button icons displayed in the driving screen.\n\nWant to submit your own icon pack? Share it in the \"custom-themes\" channel on the FrogPilot Discord!", ""},
|
||||
{"CustomIcons", tr("Icon Pack"), tr("openpilot's icon pack.\n\nWant to submit your own icons? Share them in the \"custom-themes\" channel on the FrogPilot Discord!"), ""},
|
||||
{"CustomSounds", tr("Sound Pack"), tr("openpilot's sound effects.\n\nWant to submit your own sounds? Share them in the \"custom-themes\" channel on the FrogPilot Discord!"), ""},
|
||||
{"WheelIcon", tr("Steering Wheel"), tr("The steering wheel icon in the top right of the driving screen."), ""},
|
||||
{"CustomSignals", tr("Turn Signal"), tr("Themed turn signal animations.\n\nWant to submit your own animations? Share them in the \"custom-themes\" channel on the FrogPilot Discord!"), ""},
|
||||
{"PersonalizeOpenpilot", tr("Custom Themes"), tr("<b>The overall look and feel of openpilot.</b> Use the \"Theme Maker\" in \"The Pond\" to create and share your own themes!"), "../../frogpilot/assets/toggle_icons/icon_frog.png"},
|
||||
{"CustomColors", tr("Color Scheme"), tr("<b>The color scheme used throughout openpilot.</b> Use the \"Theme Maker\" in \"The Pond\" to create and share your own themes!"), ""},
|
||||
{"CustomDistanceIcons", tr("Distance Button"), tr("<b>The distance button icons shown on the driving screen.</b> Use the \"Theme Maker\" in \"The Pond\" to create and share your own themes!"), ""},
|
||||
{"CustomIcons", tr("Icon Pack"), tr("<b>The icon style used across openpilot.</b> Use the \"Theme Maker\" in \"The Pond\" to create and share your own themes!"), ""},
|
||||
{"CustomSounds", tr("Sound Pack"), tr("<b>The sound pack used by openpilot.</b> Use the \"Theme Maker\" in \"The Pond\" to create and share your own themes!"), ""},
|
||||
{"WheelIcon", tr("Steering Wheel"), tr("<b>The steering-wheel icon</b> shown at the top-right of the driving screen. Use the \"Theme Maker\" in \"The Pond\" to create and share your own themes!"), ""},
|
||||
{"CustomSignals", tr("Turn Signal"), tr("<b>Themed turn-signal animations.</b> Use the \"Theme Maker\" in \"The Pond\" to create and share your own themes!"), ""},
|
||||
{"DownloadStatusLabel", tr("Download Status"), "", ""},
|
||||
|
||||
{"HolidayThemes", tr("Holiday Themes"), tr("Holiday-based visual themes for openpilot. Minor holidays last one day; major holidays (Christmas, Easter, Halloween, etc.) continue all week."), "../../frogpilot/assets/toggle_icons/icon_calendar.png"},
|
||||
{"RainbowPath", tr("Rainbow Path"), tr("The path on the driving screen turns into a Mario Kart inspired \"Rainbow Path\"."), "../../frogpilot/assets/toggle_icons/icon_rainbow.png"},
|
||||
{"RandomEvents", tr("Random Events"), tr("Random cosmetic events that trigger after certain driving conditions. These events are purely for fun and don't affect driving controls!"), "../../frogpilot/assets/toggle_icons/icon_random.png"},
|
||||
{"RandomThemes", tr("Random Themes"), tr("Cycles through your downloaded themes randomly on each boot, giving every theme in your collection a chance to shine!"), "../../frogpilot/assets/toggle_icons/icon_random_themes.png"},
|
||||
{"StartupAlert", tr("Startup Alert"), tr("The text of the \"Startup Alert\" message that appears at the beginning of a drive."), "../../frogpilot/assets/toggle_icons/icon_message.png"}
|
||||
{"HolidayThemes", tr("Holiday Themes"), tr("<b>Themes based on U.S. holidays.</b> Minor holidays last one day; major holidays (Christmas, Easter, Halloween) run for a full week."), "../../frogpilot/assets/toggle_icons/icon_calendar.png"},
|
||||
{"RainbowPath", tr("Rainbow Path"), tr("<b>Color the driving path like a Mario Kart–style \"Rainbow Road\".</b>"), "../../frogpilot/assets/toggle_icons/icon_rainbow.png"},
|
||||
{"RandomEvents", tr("Random Events"), tr("<b>Occasional on-screen effects triggered by driving conditions.</b> These are purely a visual and don't impact how openpilot drives!"), "../../frogpilot/assets/toggle_icons/icon_random.png"},
|
||||
{"RandomThemes", tr("Random Themes"), tr("<b>Pick a random theme between each drive</b> from the themes you have downloaded. Great for variety without changing settings while driving."), "../../frogpilot/assets/toggle_icons/icon_random_themes.png"},
|
||||
{"StartupAlert", tr("Startup Alert"), tr("<b>Customize the \"Startup Alert\" message</b> shown at the start of each drive."), "../../frogpilot/assets/toggle_icons/icon_message.png"}
|
||||
};
|
||||
|
||||
for (const auto &[param, title, desc, icon] : themeToggles) {
|
||||
@@ -160,13 +253,13 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
});
|
||||
themeToggle = personalizeOpenpilotToggle;
|
||||
} else if (param == "CustomColors") {
|
||||
manageCustomColorsBtn = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")});
|
||||
QObject::connect(manageCustomColorsBtn, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
manageCustomColorsButton = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")});
|
||||
QObject::connect(manageCustomColorsButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
QStringList colorSchemes = getThemeList(randomThemes, QDir(themePacksDirectory.path()), "colors", "CustomColors", params);
|
||||
|
||||
if (id == 0) {
|
||||
QString colorSchemeToDelete = MultiOptionDialog::getSelection(tr("Select a color scheme to delete"), colorSchemes, "", this);
|
||||
if (!colorSchemeToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Are you sure you want to delete the \"%1\" color scheme?").arg(colorSchemeToDelete), tr("Delete"), this)) {
|
||||
if (!colorSchemeToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Delete the \"%1\" color scheme?").arg(colorSchemeToDelete), tr("Delete"), this)) {
|
||||
colorsDownloaded = false;
|
||||
|
||||
deleteThemeAsset(themePacksDirectory, "colors", "DownloadableColors", colorSchemeToDelete, params);
|
||||
@@ -177,8 +270,6 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
params_memory.putBool("CancelThemeDownload", true);
|
||||
|
||||
updateAssetParam("DownloadableColors", params, colorSchemeToDownload, true);
|
||||
|
||||
QTimer::singleShot(2500, [this]() {
|
||||
cancellingDownload = false;
|
||||
colorDownloading = false;
|
||||
@@ -207,20 +298,20 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
QString colorSchemeToSelect = MultiOptionDialog::getSelection(tr("Select a color scheme"), colorSchemes, getThemeName("CustomColors", params), this);
|
||||
if (!colorSchemeToSelect.isEmpty()) {
|
||||
manageCustomColorsBtn->setValue(storeThemeName(colorSchemeToSelect, "CustomColors", params));
|
||||
manageCustomColorsButton->setValue(storeThemeName(colorSchemeToSelect, "CustomColors", params));
|
||||
}
|
||||
}
|
||||
});
|
||||
manageCustomColorsBtn->setValue(getThemeName(param.toStdString(), params));
|
||||
themeToggle = manageCustomColorsBtn;
|
||||
manageCustomColorsButton->setValue(getThemeName(param.toStdString(), params));
|
||||
themeToggle = manageCustomColorsButton;
|
||||
} else if (param == "CustomDistanceIcons") {
|
||||
manageDistanceIconsBtn = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")});
|
||||
QObject::connect(manageDistanceIconsBtn, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
manageDistanceIconsButton = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")});
|
||||
QObject::connect(manageDistanceIconsButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
QStringList distanceIconPacks = getThemeList(randomThemes, QDir(themePacksDirectory.path()), "distance_icons", "CustomDistanceIcons", params);
|
||||
|
||||
if (id == 0) {
|
||||
QString distanceIconPackToDelete = MultiOptionDialog::getSelection(tr("Select a distance icon pack to delete"), distanceIconPacks, "", this);
|
||||
if (!distanceIconPackToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Are you sure you want to delete the \"%1\" distance icon pack?").arg(distanceIconPackToDelete), tr("Delete"), this)) {
|
||||
if (!distanceIconPackToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Delete the \"%1\" distance icon pack?").arg(distanceIconPackToDelete), tr("Delete"), this)) {
|
||||
distanceIconsDownloaded = false;
|
||||
|
||||
deleteThemeAsset(themePacksDirectory, "distance_icons", "DownloadableDistanceIcons", distanceIconPackToDelete, params);
|
||||
@@ -231,8 +322,6 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
params_memory.putBool("CancelThemeDownload", true);
|
||||
|
||||
updateAssetParam("DownloadableDistanceIcons", params, distanceIconPackToDownload, true);
|
||||
|
||||
QTimer::singleShot(2500, [this]() {
|
||||
cancellingDownload = false;
|
||||
distanceIconDownloading = false;
|
||||
@@ -261,20 +350,20 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
QString distanceIconPackToSelect = MultiOptionDialog::getSelection(tr("Select a distance icon pack"), distanceIconPacks, getThemeName("CustomDistanceIcons", params), this);
|
||||
if (!distanceIconPackToSelect.isEmpty()) {
|
||||
manageDistanceIconsBtn->setValue(storeThemeName(distanceIconPackToSelect, "CustomDistanceIcons", params));
|
||||
manageDistanceIconsButton->setValue(storeThemeName(distanceIconPackToSelect, "CustomDistanceIcons", params));
|
||||
}
|
||||
}
|
||||
});
|
||||
manageDistanceIconsBtn->setValue(getThemeName(param.toStdString(), params));
|
||||
themeToggle = manageDistanceIconsBtn;
|
||||
manageDistanceIconsButton->setValue(getThemeName(param.toStdString(), params));
|
||||
themeToggle = manageDistanceIconsButton;
|
||||
} else if (param == "CustomIcons") {
|
||||
manageCustomIconsBtn = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")});
|
||||
QObject::connect(manageCustomIconsBtn, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
manageCustomIconsButton = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")});
|
||||
QObject::connect(manageCustomIconsButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
QStringList iconPacks = getThemeList(randomThemes, QDir(themePacksDirectory.path()), "icons", "CustomIcons", params);
|
||||
|
||||
if (id == 0) {
|
||||
QString iconPackToDelete = MultiOptionDialog::getSelection(tr("Select an icon pack to delete"), iconPacks, "", this);
|
||||
if (!iconPackToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Are you sure you want to delete the \"%1\" icon pack?").arg(iconPackToDelete), tr("Delete"), this)) {
|
||||
if (!iconPackToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Delete the \"%1\" icon pack?").arg(iconPackToDelete), tr("Delete"), this)) {
|
||||
iconsDownloaded = false;
|
||||
|
||||
deleteThemeAsset(themePacksDirectory, "icons", "DownloadableIcons", iconPackToDelete, params);
|
||||
@@ -285,8 +374,6 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
params_memory.putBool("CancelThemeDownload", true);
|
||||
|
||||
updateAssetParam("DownloadableIcons", params, iconPackToDownload, true);
|
||||
|
||||
QTimer::singleShot(2500, [this]() {
|
||||
cancellingDownload = false;
|
||||
iconDownloading = false;
|
||||
@@ -315,20 +402,20 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
QString iconPackToSelect = MultiOptionDialog::getSelection(tr("Select an icon pack"), iconPacks, getThemeName("CustomIcons", params), this);
|
||||
if (!iconPackToSelect.isEmpty()) {
|
||||
manageCustomIconsBtn->setValue(storeThemeName(iconPackToSelect, "CustomIcons", params));
|
||||
manageCustomIconsButton->setValue(storeThemeName(iconPackToSelect, "CustomIcons", params));
|
||||
}
|
||||
}
|
||||
});
|
||||
manageCustomIconsBtn->setValue(getThemeName(param.toStdString(), params));
|
||||
themeToggle = manageCustomIconsBtn;
|
||||
manageCustomIconsButton->setValue(getThemeName(param.toStdString(), params));
|
||||
themeToggle = manageCustomIconsButton;
|
||||
} else if (param == "CustomSignals") {
|
||||
manageCustomSignalsBtn = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")});
|
||||
QObject::connect(manageCustomSignalsBtn, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
manageCustomSignalsButton = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")});
|
||||
QObject::connect(manageCustomSignalsButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
QStringList signalAnimations = getThemeList(randomThemes, QDir(themePacksDirectory.path()), "signals", "CustomSignals", params);
|
||||
|
||||
if (id == 0) {
|
||||
QString signalAnimationToDelete = MultiOptionDialog::getSelection(tr("Select a signal animation to delete"), signalAnimations, "", this);
|
||||
if (!signalAnimationToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Are you sure you want to delete the \"%1\" signal animation?").arg(signalAnimationToDelete), tr("Delete"), this)) {
|
||||
if (!signalAnimationToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Delete the \"%1\" signal animation?").arg(signalAnimationToDelete), tr("Delete"), this)) {
|
||||
signalsDownloaded = false;
|
||||
|
||||
deleteThemeAsset(themePacksDirectory, "signals", "DownloadableSignals", signalAnimationToDelete, params);
|
||||
@@ -339,8 +426,6 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
params_memory.putBool("CancelThemeDownload", true);
|
||||
|
||||
updateAssetParam("DownloadableSignals", params, signalAnimationToDownload, true);
|
||||
|
||||
QTimer::singleShot(2500, [this]() {
|
||||
cancellingDownload = false;
|
||||
signalDownloading = false;
|
||||
@@ -369,20 +454,20 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
QString signalAnimationToSelect = MultiOptionDialog::getSelection(tr("Select a signal animation"), signalAnimations, getThemeName("CustomSignals", params), this);
|
||||
if (!signalAnimationToSelect.isEmpty()) {
|
||||
manageCustomSignalsBtn->setValue(storeThemeName(signalAnimationToSelect, "CustomSignals", params));
|
||||
manageCustomSignalsButton->setValue(storeThemeName(signalAnimationToSelect, "CustomSignals", params));
|
||||
}
|
||||
}
|
||||
});
|
||||
manageCustomSignalsBtn->setValue(getThemeName(param.toStdString(), params));
|
||||
themeToggle = manageCustomSignalsBtn;
|
||||
manageCustomSignalsButton->setValue(getThemeName(param.toStdString(), params));
|
||||
themeToggle = manageCustomSignalsButton;
|
||||
} else if (param == "CustomSounds") {
|
||||
manageCustomSoundsBtn = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")});
|
||||
QObject::connect(manageCustomSoundsBtn, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
manageCustomSoundsButton = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")});
|
||||
QObject::connect(manageCustomSoundsButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
QStringList soundPacks = getThemeList(randomThemes, QDir(themePacksDirectory.path()), "sounds", "CustomSounds", params);
|
||||
|
||||
if (id == 0) {
|
||||
QString soundPackToDelete = MultiOptionDialog::getSelection(tr("Select a sound pack to delete"), soundPacks, "", this);
|
||||
if (!soundPackToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Are you sure you want to delete the \"%1\" sound pack?").arg(soundPackToDelete), tr("Delete"), this)) {
|
||||
if (!soundPackToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Delete the \"%1\" sound pack?").arg(soundPackToDelete), tr("Delete"), this)) {
|
||||
soundsDownloaded = false;
|
||||
|
||||
deleteThemeAsset(themePacksDirectory, "sounds", "DownloadableSounds", soundPackToDelete, params);
|
||||
@@ -393,8 +478,6 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
params_memory.putBool("CancelThemeDownload", true);
|
||||
|
||||
updateAssetParam("DownloadableSounds", params, soundPackToDownload, true);
|
||||
|
||||
QTimer::singleShot(2500, [this]() {
|
||||
cancellingDownload = false;
|
||||
soundDownloading = false;
|
||||
@@ -423,20 +506,20 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
QString soundPackToSelect = MultiOptionDialog::getSelection(tr("Select a sound pack"), soundPacks, getThemeName("CustomSounds", params), this);
|
||||
if (!soundPackToSelect.isEmpty()) {
|
||||
manageCustomSoundsBtn->setValue(storeThemeName(soundPackToSelect, "CustomSounds", params));
|
||||
manageCustomSoundsButton->setValue(storeThemeName(soundPackToSelect, "CustomSounds", params));
|
||||
}
|
||||
}
|
||||
});
|
||||
manageCustomSoundsBtn->setValue(getThemeName(param.toStdString(), params));
|
||||
themeToggle = manageCustomSoundsBtn;
|
||||
manageCustomSoundsButton->setValue(getThemeName(param.toStdString(), params));
|
||||
themeToggle = manageCustomSoundsButton;
|
||||
} else if (param == "WheelIcon") {
|
||||
manageWheelIconsBtn = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")});
|
||||
QObject::connect(manageWheelIconsBtn, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
manageWheelIconsButton = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")});
|
||||
QObject::connect(manageWheelIconsButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
QStringList wheelIcons = getThemeList(randomThemes, QDir(wheelsDirectory.path()), "", "WheelIcon", params);
|
||||
|
||||
if (id == 0) {
|
||||
QString wheelIconToDelete = MultiOptionDialog::getSelection(tr("Select a steering wheel to delete"), wheelIcons, "", this);
|
||||
if (!wheelIconToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Are you sure you want to delete the \"%1\" steering wheel?").arg(wheelIconToDelete), tr("Delete"), this)) {
|
||||
if (!wheelIconToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Delete the \"%1\" steering wheel?").arg(wheelIconToDelete), tr("Delete"), this)) {
|
||||
wheelsDownloaded = false;
|
||||
|
||||
deleteThemeAsset(wheelsDirectory, "", "DownloadableWheels", wheelIconToDelete, params);
|
||||
@@ -447,8 +530,6 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
params_memory.putBool("CancelThemeDownload", true);
|
||||
|
||||
updateAssetParam("DownloadableWheels", params, wheelToDownload, true);
|
||||
|
||||
QTimer::singleShot(2500, [this]() {
|
||||
cancellingDownload = false;
|
||||
wheelDownloading = false;
|
||||
@@ -478,12 +559,12 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
QString steeringWheelToSelect = MultiOptionDialog::getSelection(tr("Select a steering wheel"), wheelIcons, getThemeName("WheelIcon", params), this);
|
||||
if (!steeringWheelToSelect.isEmpty()) {
|
||||
manageWheelIconsBtn->setValue(storeThemeName(steeringWheelToSelect, "WheelIcon", params));
|
||||
manageWheelIconsButton->setValue(storeThemeName(steeringWheelToSelect, "WheelIcon", params));
|
||||
}
|
||||
}
|
||||
});
|
||||
manageWheelIconsBtn->setValue(getThemeName(param.toStdString(), params));
|
||||
themeToggle = manageWheelIconsBtn;
|
||||
manageWheelIconsButton->setValue(getThemeName(param.toStdString(), params));
|
||||
themeToggle = manageWheelIconsButton;
|
||||
} else if (param == "DownloadStatusLabel") {
|
||||
downloadStatusLabel = new LabelControl(title, "Idle");
|
||||
themeToggle = downloadStatusLabel;
|
||||
@@ -543,7 +624,7 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
|
||||
toggles[param] = themeToggle;
|
||||
|
||||
if (customThemeKeys.find(param) != customThemeKeys.end()) {
|
||||
if (customThemeKeys.contains(param)) {
|
||||
customThemesList->addItem(themeToggle);
|
||||
} else {
|
||||
themesList->addItem(themeToggle);
|
||||
@@ -554,60 +635,71 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
||||
}
|
||||
|
||||
if (FrogPilotManageControl *frogPilotManageToggle = qobject_cast<FrogPilotManageControl*>(themeToggle)) {
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, this, &FrogPilotThemesPanel::openSubPanel);
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, [this]() {
|
||||
emit openSubPanel();
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(themeToggle, &AbstractControl::hideDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
QObject::connect(themeToggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
QObject::connect(static_cast<ToggleControl *>(toggles["PersonalizeOpenpilot"]), &ToggleControl::toggleFlipped, this, &FrogPilotThemesPanel::updateToggles);
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles["RandomThemes"]), &ToggleControl::toggleFlipped, [this](bool state) {
|
||||
if (state) {
|
||||
ConfirmationDialog::alert(tr("\"Random Themes\" only works with downloaded themes, so make sure you download the themes you want it to use!"), this);
|
||||
|
||||
manageCustomColorsBtn->setValue("");
|
||||
manageCustomColorsBtn->setVisibleButton(2, false);
|
||||
manageCustomColorsButton->setValue("");
|
||||
manageCustomColorsButton->setVisibleButton(2, false);
|
||||
|
||||
manageCustomIconsBtn->setValue("");
|
||||
manageCustomIconsBtn->setVisibleButton(2, false);
|
||||
manageCustomIconsButton->setValue("");
|
||||
manageCustomIconsButton->setVisibleButton(2, false);
|
||||
|
||||
manageCustomSignalsBtn->setValue("");
|
||||
manageCustomSignalsBtn->setVisibleButton(2, false);
|
||||
manageCustomSignalsButton->setValue("");
|
||||
manageCustomSignalsButton->setVisibleButton(2, false);
|
||||
|
||||
manageCustomSoundsBtn->setValue("");
|
||||
manageCustomSoundsBtn->setVisibleButton(2, false);
|
||||
manageCustomSoundsButton->setValue("");
|
||||
manageCustomSoundsButton->setVisibleButton(2, false);
|
||||
|
||||
manageDistanceIconsBtn->setValue("");
|
||||
manageDistanceIconsBtn->setVisibleButton(2, false);
|
||||
manageDistanceIconsButton->setValue("");
|
||||
manageDistanceIconsButton->setVisibleButton(2, false);
|
||||
|
||||
manageWheelIconsBtn->setValue("");
|
||||
manageWheelIconsBtn->setVisibleButton(2, false);
|
||||
manageWheelIconsButton->setValue("");
|
||||
manageWheelIconsButton->setVisibleButton(2, false);
|
||||
} else {
|
||||
manageCustomColorsBtn->setValue(getThemeName("CustomColors", params));
|
||||
manageCustomColorsBtn->setVisibleButton(2, true);
|
||||
manageCustomColorsButton->setValue(getThemeName("CustomColors", params));
|
||||
manageCustomColorsButton->setVisibleButton(2, true);
|
||||
|
||||
manageCustomIconsBtn->setValue(getThemeName("CustomIcons", params));
|
||||
manageCustomIconsBtn->setVisibleButton(2, true);
|
||||
manageCustomIconsButton->setValue(getThemeName("CustomIcons", params));
|
||||
manageCustomIconsButton->setVisibleButton(2, true);
|
||||
|
||||
manageCustomSignalsBtn->setValue(getThemeName("CustomSignals", params));
|
||||
manageCustomSignalsBtn->setVisibleButton(2, true);
|
||||
manageCustomSignalsButton->setValue(getThemeName("CustomSignals", params));
|
||||
manageCustomSignalsButton->setVisibleButton(2, true);
|
||||
|
||||
manageCustomSoundsBtn->setValue(getThemeName("CustomSounds", params));
|
||||
manageCustomSoundsBtn->setVisibleButton(2, true);
|
||||
manageCustomSoundsButton->setValue(getThemeName("CustomSounds", params));
|
||||
manageCustomSoundsButton->setVisibleButton(2, true);
|
||||
|
||||
manageDistanceIconsBtn->setValue(getThemeName("CustomDistanceIcons", params));
|
||||
manageDistanceIconsBtn->setVisibleButton(2, true);
|
||||
manageDistanceIconsButton->setValue(getThemeName("CustomDistanceIcons", params));
|
||||
manageDistanceIconsButton->setVisibleButton(2, true);
|
||||
|
||||
manageWheelIconsBtn->setValue(getThemeName("WheelIcon", params));
|
||||
manageWheelIconsBtn->setVisibleButton(2, true);
|
||||
manageWheelIconsButton->setValue(getThemeName("WheelIcon", params));
|
||||
manageWheelIconsButton->setVisibleButton(2, true);
|
||||
}
|
||||
|
||||
randomThemes = state;
|
||||
});
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [themesLayout, themesPanel] {themesLayout->setCurrentWidget(themesPanel);});
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [themesLayout, themesPanel, this] {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
themesLayout->setCurrentWidget(themesPanel);
|
||||
});
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotThemesPanel::updateState);
|
||||
}
|
||||
|
||||
@@ -623,23 +715,23 @@ void FrogPilotThemesPanel::showEvent(QShowEvent *event) {
|
||||
tuningLevel = parent->tuningLevel;
|
||||
|
||||
if (params.getBool("RandomThemes")) {
|
||||
manageCustomColorsBtn->setValue("");
|
||||
manageCustomColorsBtn->setVisibleButton(2, false);
|
||||
manageCustomColorsButton->setValue("");
|
||||
manageCustomColorsButton->setVisibleButton(2, false);
|
||||
|
||||
manageCustomIconsBtn->setValue("");
|
||||
manageCustomIconsBtn->setVisibleButton(2, false);
|
||||
manageCustomIconsButton->setValue("");
|
||||
manageCustomIconsButton->setVisibleButton(2, false);
|
||||
|
||||
manageCustomSignalsBtn->setValue("");
|
||||
manageCustomSignalsBtn->setVisibleButton(2, false);
|
||||
manageCustomSignalsButton->setValue("");
|
||||
manageCustomSignalsButton->setVisibleButton(2, false);
|
||||
|
||||
manageCustomSoundsBtn->setValue("");
|
||||
manageCustomSoundsBtn->setVisibleButton(2, false);
|
||||
manageCustomSoundsButton->setValue("");
|
||||
manageCustomSoundsButton->setVisibleButton(2, false);
|
||||
|
||||
manageDistanceIconsBtn->setValue("");
|
||||
manageDistanceIconsBtn->setVisibleButton(2, false);
|
||||
manageDistanceIconsButton->setValue("");
|
||||
manageDistanceIconsButton->setVisibleButton(2, false);
|
||||
|
||||
manageWheelIconsBtn->setValue("");
|
||||
manageWheelIconsBtn->setVisibleButton(2, false);
|
||||
manageWheelIconsButton->setValue("");
|
||||
manageWheelIconsButton->setVisibleButton(2, false);
|
||||
|
||||
randomThemes = true;
|
||||
}
|
||||
@@ -681,13 +773,7 @@ void FrogPilotThemesPanel::updateState(const UIState &s, const FrogPilotUIState
|
||||
wheelsDownloaded = params.get("DownloadableWheels").empty();
|
||||
|
||||
params_memory.remove("CancelThemeDownload");
|
||||
params_memory.remove("ColorToDownload");
|
||||
params_memory.remove("DistanceIconToDownload");
|
||||
params_memory.remove("IconToDownload");
|
||||
params_memory.remove("SignalToDownload");
|
||||
params_memory.remove("SoundToDownload");
|
||||
params_memory.remove("ThemeDownloadProgress");
|
||||
params_memory.remove("WheelToDownload");
|
||||
|
||||
downloadStatusLabel->setText("Idle");
|
||||
});
|
||||
@@ -696,48 +782,48 @@ void FrogPilotThemesPanel::updateState(const UIState &s, const FrogPilotUIState
|
||||
|
||||
bool parked = !s.scene.started || fs.frogpilot_scene.parked || fs.frogpilot_toggles.value("frogs_go_moo").toBool();
|
||||
|
||||
manageCustomColorsBtn->setText(1, colorDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
manageCustomColorsBtn->setEnabledButtons(0, !themeDownloading);
|
||||
manageCustomColorsBtn->setEnabledButtons(1, fs.frogpilot_scene.online && (!themeDownloading || colorDownloading) && !cancellingDownload && !colorsDownloaded && parked);
|
||||
manageCustomColorsBtn->setEnabledButtons(2, !themeDownloading);
|
||||
manageCustomColorsButton->setText(1, colorDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
manageCustomColorsButton->setEnabledButtons(0, !themeDownloading);
|
||||
manageCustomColorsButton->setEnabledButtons(1, fs.frogpilot_scene.online && (!themeDownloading || colorDownloading) && !cancellingDownload && !finalizingDownload && !colorsDownloaded && parked);
|
||||
manageCustomColorsButton->setEnabledButtons(2, !themeDownloading);
|
||||
|
||||
manageCustomIconsBtn->setText(1, iconDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
manageCustomIconsBtn->setEnabledButtons(0, !themeDownloading);
|
||||
manageCustomIconsBtn->setEnabledButtons(1, fs.frogpilot_scene.online && (!themeDownloading || iconDownloading) && !cancellingDownload && !iconsDownloaded && parked);
|
||||
manageCustomIconsBtn->setEnabledButtons(2, !themeDownloading);
|
||||
manageCustomIconsButton->setText(1, iconDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
manageCustomIconsButton->setEnabledButtons(0, !themeDownloading);
|
||||
manageCustomIconsButton->setEnabledButtons(1, fs.frogpilot_scene.online && (!themeDownloading || iconDownloading) && !cancellingDownload && !finalizingDownload && !iconsDownloaded && parked);
|
||||
manageCustomIconsButton->setEnabledButtons(2, !themeDownloading);
|
||||
|
||||
manageCustomSignalsBtn->setText(1, signalDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
manageCustomSignalsBtn->setEnabledButtons(0, !themeDownloading);
|
||||
manageCustomSignalsBtn->setEnabledButtons(1, fs.frogpilot_scene.online && (!themeDownloading || signalDownloading) && !cancellingDownload && !signalsDownloaded && parked);
|
||||
manageCustomSignalsBtn->setEnabledButtons(2, !themeDownloading);
|
||||
manageCustomSignalsButton->setText(1, signalDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
manageCustomSignalsButton->setEnabledButtons(0, !themeDownloading);
|
||||
manageCustomSignalsButton->setEnabledButtons(1, fs.frogpilot_scene.online && (!themeDownloading || signalDownloading) && !cancellingDownload && !finalizingDownload && !signalsDownloaded && parked);
|
||||
manageCustomSignalsButton->setEnabledButtons(2, !themeDownloading);
|
||||
|
||||
manageCustomSoundsBtn->setText(1, soundDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
manageCustomSoundsBtn->setEnabledButtons(0, !themeDownloading);
|
||||
manageCustomSoundsBtn->setEnabledButtons(1, fs.frogpilot_scene.online && (!themeDownloading || soundDownloading) && !cancellingDownload && !soundsDownloaded && parked);
|
||||
manageCustomSoundsBtn->setEnabledButtons(2, !themeDownloading);
|
||||
manageCustomSoundsButton->setText(1, soundDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
manageCustomSoundsButton->setEnabledButtons(0, !themeDownloading);
|
||||
manageCustomSoundsButton->setEnabledButtons(1, fs.frogpilot_scene.online && (!themeDownloading || soundDownloading) && !cancellingDownload && !finalizingDownload && !soundsDownloaded && parked);
|
||||
manageCustomSoundsButton->setEnabledButtons(2, !themeDownloading);
|
||||
|
||||
manageDistanceIconsBtn->setText(1, distanceIconDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
manageDistanceIconsBtn->setEnabledButtons(0, !themeDownloading);
|
||||
manageDistanceIconsBtn->setEnabledButtons(1, fs.frogpilot_scene.online && (!themeDownloading || distanceIconDownloading) && !cancellingDownload && !distanceIconsDownloaded && parked);
|
||||
manageDistanceIconsBtn->setEnabledButtons(2, !themeDownloading);
|
||||
manageDistanceIconsButton->setText(1, distanceIconDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
manageDistanceIconsButton->setEnabledButtons(0, !themeDownloading);
|
||||
manageDistanceIconsButton->setEnabledButtons(1, fs.frogpilot_scene.online && (!themeDownloading || distanceIconDownloading) && !cancellingDownload && !finalizingDownload && !distanceIconsDownloaded && parked);
|
||||
manageDistanceIconsButton->setEnabledButtons(2, !themeDownloading);
|
||||
|
||||
manageWheelIconsBtn->setText(1, wheelDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
manageWheelIconsBtn->setEnabledButtons(0, !themeDownloading);
|
||||
manageWheelIconsBtn->setEnabledButtons(1, fs.frogpilot_scene.online && (!themeDownloading || wheelDownloading) && !cancellingDownload && !wheelsDownloaded && parked);
|
||||
manageWheelIconsBtn->setEnabledButtons(2, !themeDownloading);
|
||||
manageWheelIconsButton->setText(1, wheelDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
||||
manageWheelIconsButton->setEnabledButtons(0, !themeDownloading);
|
||||
manageWheelIconsButton->setEnabledButtons(1, fs.frogpilot_scene.online && (!themeDownloading || wheelDownloading) && !cancellingDownload && !finalizingDownload && !wheelsDownloaded && parked);
|
||||
manageWheelIconsButton->setEnabledButtons(2, !themeDownloading);
|
||||
|
||||
parent->keepScreenOn = themeDownloading;
|
||||
}
|
||||
|
||||
void FrogPilotThemesPanel::updateToggles() {
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
toggle->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -754,11 +840,13 @@ void FrogPilotThemesPanel::updateToggles() {
|
||||
toggle->setVisible(setVisible);
|
||||
|
||||
if (setVisible) {
|
||||
if (customThemeKeys.find(key) != customThemeKeys.end()) {
|
||||
if (customThemeKeys.contains(key)) {
|
||||
toggles["PersonalizeOpenpilot"]->setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "frogpilot/ui/qt/offroad/frogpilot_settings.h"
|
||||
|
||||
class FrogPilotThemesPanel : public FrogPilotListWidget {
|
||||
@@ -26,6 +24,7 @@ private:
|
||||
bool distanceIconDownloading;
|
||||
bool distanceIconsDownloaded;
|
||||
bool finalizingDownload;
|
||||
bool forceOpenDescriptions;
|
||||
bool iconDownloading;
|
||||
bool iconsDownloaded;
|
||||
bool randomThemes;
|
||||
@@ -41,16 +40,16 @@ private:
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
std::set<QString> customThemeKeys = {"CustomColors", "CustomDistanceIcons", "CustomIcons", "CustomSignals", "CustomSounds", "DownloadStatusLabel", "WheelIcon"};
|
||||
QSet<QString> customThemeKeys = {"CustomColors", "CustomDistanceIcons", "CustomIcons", "CustomSignals", "CustomSounds", "DownloadStatusLabel", "WheelIcon"};
|
||||
|
||||
std::set<QString> parentKeys;
|
||||
QSet<QString> parentKeys;
|
||||
|
||||
FrogPilotButtonsControl *manageCustomColorsBtn;
|
||||
FrogPilotButtonsControl *manageCustomIconsBtn;
|
||||
FrogPilotButtonsControl *manageCustomSignalsBtn;
|
||||
FrogPilotButtonsControl *manageCustomSoundsBtn;
|
||||
FrogPilotButtonsControl *manageDistanceIconsBtn;
|
||||
FrogPilotButtonsControl *manageWheelIconsBtn;
|
||||
FrogPilotButtonsControl *manageCustomColorsButton;
|
||||
FrogPilotButtonsControl *manageCustomIconsButton;
|
||||
FrogPilotButtonsControl *manageCustomSignalsButton;
|
||||
FrogPilotButtonsControl *manageCustomSoundsButton;
|
||||
FrogPilotButtonsControl *manageDistanceIconsButton;
|
||||
FrogPilotButtonsControl *manageWheelIconsButton;
|
||||
|
||||
FrogPilotSettingsWindow *parent;
|
||||
|
||||
|
||||
@@ -1,28 +1,41 @@
|
||||
#include "frogpilot/ui/qt/offroad/utilities.h"
|
||||
|
||||
FrogPilotUtilitiesPanel::FrogPilotUtilitiesPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
ParamControl *debugModeToggle = new ParamControl("DebugMode", tr("Debug Mode"), tr("Debug FrogPilot during the next drive by utilizing all of FrogPilot's developer metrics for either bug reporting, or self-debugging."), "");
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
bool forceOpenDescriptions = false;
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
ParamControl *debugModeToggle = new ParamControl("DebugMode", tr("Debug Mode"), tr("<b>Use FrogPilot's developer metrics on your next drive</b> to diagnose issues and improve bug reports."), "");
|
||||
if (forceOpenDescriptions) {
|
||||
debugModeToggle->showDescription();
|
||||
}
|
||||
addItem(debugModeToggle);
|
||||
|
||||
ButtonControl *flashPandaBtn = new ButtonControl(tr("Flash Panda"), tr("FLASH"), tr("Flash the Panda's firmware. Use if you're running into issues with the Panda."));
|
||||
QObject::connect(flashPandaBtn, &ButtonControl::clicked, [this, parent, flashPandaBtn]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to flash the Panda?"), tr("Flash"), this)) {
|
||||
std::thread([this, parent, flashPandaBtn]() {
|
||||
ButtonControl *flashPandaButton = new ButtonControl(tr("Flash Panda"), tr("FLASH"), tr("<b>Reinstall the Panda firmware</b> to fix connection or reliability issues."));
|
||||
QObject::connect(flashPandaButton, &ButtonControl::clicked, [parent, flashPandaButton, this]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to flash the Panda firmware?"), tr("Flash"), this)) {
|
||||
std::thread([parent, flashPandaButton, this]() {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
flashPandaBtn->setEnabled(false);
|
||||
flashPandaBtn->setValue(tr("Flashing..."));
|
||||
flashPandaButton->setEnabled(false);
|
||||
flashPandaButton->setValue(tr("Flashing..."));
|
||||
|
||||
params_memory.putBool("FlashPanda", true);
|
||||
while (params_memory.getBool("FlashPanda")) {
|
||||
util::sleep_for(UI_FREQ);
|
||||
}
|
||||
|
||||
flashPandaBtn->setValue(tr("Flashed!"));
|
||||
flashPandaButton->setValue(tr("Flashed!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
flashPandaBtn->setValue(tr("Rebooting..."));
|
||||
flashPandaButton->setValue(tr("Rebooting..."));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
@@ -30,30 +43,26 @@ FrogPilotUtilitiesPanel::FrogPilotUtilitiesPanel(FrogPilotSettingsWindow *parent
|
||||
}).detach();
|
||||
}
|
||||
});
|
||||
addItem(flashPandaBtn);
|
||||
if (forceOpenDescriptions) {
|
||||
flashPandaButton->showDescription();
|
||||
}
|
||||
addItem(flashPandaButton);
|
||||
|
||||
FrogPilotButtonsControl *forceStartedBtn = new FrogPilotButtonsControl(tr("Force Started State"), tr("Force openpilot either offroad or onroad."), "", {tr("OFFROAD"), tr("ONROAD"), tr("OFF")}, true);
|
||||
QObject::connect(forceStartedBtn, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
FrogPilotButtonsControl *forceStartedButton = new FrogPilotButtonsControl(tr("Force Drive State"), tr("<b>Manually set openpilot to be offroad or onroad.</b>"), "", {tr("OFFROAD"), tr("ONROAD"), tr("OFF")}, true);
|
||||
QObject::connect(forceStartedButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
if (id == 0) {
|
||||
params_memory.putBool("ForceOffroad", true);
|
||||
params_memory.putBool("ForceOnroad", false);
|
||||
|
||||
updateFrogPilotToggles();
|
||||
} else if (id == 1) {
|
||||
params.put("CarParams", params.get("CarParamsPersistent"));
|
||||
params.put("FrogPilotCarParams", params.get("FrogPilotCarParamsPersistent"));
|
||||
|
||||
params_memory.putBool("ForceOffroad", false);
|
||||
params_memory.putBool("ForceOnroad", true);
|
||||
|
||||
params.put("CarParams", params.get("CarParamsPersistent"));
|
||||
params.put("FrogPilotCarParams", params.get("FrogPilotCarParamsPersistent"));
|
||||
|
||||
updateFrogPilotToggles();
|
||||
|
||||
while (!params.get("CarParams").empty()) {
|
||||
util::sleep_for(UI_FREQ);
|
||||
}
|
||||
|
||||
params.put("CarParams", params.get("CarParamsPersistent"));
|
||||
params.put("FrogPilotCarParams", params.get("FrogPilotCarParamsPersistent"));
|
||||
} else if (id == 2) {
|
||||
params_memory.putBool("ForceOffroad", false);
|
||||
params_memory.putBool("ForceOnroad", false);
|
||||
@@ -61,13 +70,16 @@ FrogPilotUtilitiesPanel::FrogPilotUtilitiesPanel(FrogPilotSettingsWindow *parent
|
||||
updateFrogPilotToggles();
|
||||
}
|
||||
});
|
||||
forceStartedBtn->setCheckedButton(2);
|
||||
addItem(forceStartedBtn);
|
||||
forceStartedButton->setCheckedButton(2);
|
||||
if (forceOpenDescriptions) {
|
||||
forceStartedButton->showDescription();
|
||||
}
|
||||
addItem(forceStartedButton);
|
||||
|
||||
ButtonControl *reportIssueBtn = new ButtonControl(tr("Report a Bug or an Issue"), tr("REPORT"), tr("Let FrogsGoMoo know about an issue you're facing!"));
|
||||
QObject::connect(reportIssueBtn, &ButtonControl::clicked, [this]() {
|
||||
ButtonControl *reportIssueButton = new ButtonControl(tr("Report a Bug or an Issue"), tr("REPORT"), tr("<b>Send a bug report</b> so we can help fix the problem!"));
|
||||
QObject::connect(reportIssueButton, &ButtonControl::clicked, [this]() {
|
||||
if (!frogpilotUIState()->frogpilot_scene.online) {
|
||||
ConfirmationDialog::alert(tr("Ensure your device has an internet connection before sending a report!"), this);
|
||||
ConfirmationDialog::alert(tr("Please connect to the internet before sending a report!"), this);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -77,21 +89,19 @@ FrogPilotUtilitiesPanel::FrogPilotUtilitiesPanel(FrogPilotSettingsWindow *parent
|
||||
report_messages << crash_report;
|
||||
}
|
||||
QStringList additional_issues = {
|
||||
tr("Acceleration feels too harsh or jerky"),
|
||||
tr("An alert confused me and I didn’t know what it meant"),
|
||||
tr("Acceleration feels harsh or jerky"),
|
||||
tr("An alert was unclear and I didn't know what it meant"),
|
||||
tr("Braking is too sudden or uncomfortable"),
|
||||
tr("I’m not sure if this is normal or a bug:"),
|
||||
tr("Lane changes don’t work properly or feel unsafe"),
|
||||
tr("My screen froze or got stuck on loading"),
|
||||
tr("My steering wheel buttons aren’t working"),
|
||||
tr("I'm not sure if this is normal or a bug:"),
|
||||
tr("My screen froze or is stuck loading something"),
|
||||
tr("My steering wheel buttons aren't working"),
|
||||
tr("openpilot disengages when I don't expect it"),
|
||||
tr("openpilot doesn’t resume after I stop"),
|
||||
tr("openpilot doesn't react to stopped vehicles ahead"),
|
||||
tr("openpilot doesn't resume from a stop"),
|
||||
tr("openpilot feels sluggish or slow to respond"),
|
||||
tr("Steering feels twitchy or unnatural"),
|
||||
tr("The car doesn’t follow curves well"),
|
||||
tr("The car isn’t staying centered in its lane"),
|
||||
tr("The speed or display info looks wrong"),
|
||||
tr("The car doesn't follow curves well"),
|
||||
tr("The car isn't staying centered in its lane"),
|
||||
tr("Something else (please describe)")
|
||||
};
|
||||
report_messages.append(additional_issues);
|
||||
@@ -126,27 +136,30 @@ FrogPilotUtilitiesPanel::FrogPilotUtilitiesPanel(FrogPilotSettingsWindow *parent
|
||||
params.putNonBlocking("DiscordUsername", reportData["DiscordUser"].toString().toStdString());
|
||||
params_memory.put("IssueReported", QJsonDocument(reportData).toJson(QJsonDocument::Compact).toStdString());
|
||||
|
||||
ConfirmationDialog::alert(tr("Your report has been submitted. Thanks for letting us know!"), this);
|
||||
ConfirmationDialog::alert(tr("Report Sent! Thanks for letting us know!"), this);
|
||||
});
|
||||
addItem(reportIssueBtn);
|
||||
reportIssueBtn->setVisible(QString::fromStdString(params.get("GitRemote")).toLower() == "https://github.com/frogai/openpilot.git");
|
||||
if (forceOpenDescriptions) {
|
||||
reportIssueButton->showDescription();
|
||||
}
|
||||
addItem(reportIssueButton);
|
||||
reportIssueButton->setVisible(QString::fromStdString(params.get("GitRemote")).toLower() == "https://github.com/frogai/openpilot.git");
|
||||
|
||||
ButtonControl *resetTogglesBtn = new ButtonControl(tr("Reset Toggles to Default"), tr("RESET"), tr("Reset all toggles to their default values."));
|
||||
QObject::connect(resetTogglesBtn, &ButtonControl::clicked, [this, parent, resetTogglesBtn]() {
|
||||
ButtonControl *resetTogglesButton = new ButtonControl(tr("Reset Toggles to Default"), tr("RESET"), tr("<b>Reset all toggles to their default values.</b>"));
|
||||
QObject::connect(resetTogglesButton, &ButtonControl::clicked, [parent, resetTogglesButton, this]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to reset all toggles to their default values?"), tr("Reset"), this)) {
|
||||
std::thread([this, parent, resetTogglesBtn]() mutable {
|
||||
std::thread([parent, resetTogglesButton, this]() mutable {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
resetTogglesBtn->setEnabled(false);
|
||||
resetTogglesBtn->setValue(tr("Resetting..."));
|
||||
resetTogglesButton->setEnabled(false);
|
||||
resetTogglesButton->setValue(tr("Resetting..."));
|
||||
|
||||
params.putBool("DoToggleReset", true);
|
||||
|
||||
resetTogglesBtn->setValue(tr("Reset!"));
|
||||
resetTogglesButton->setValue(tr("Reset!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
resetTogglesBtn->setValue(tr("Rebooting..."));
|
||||
resetTogglesButton->setValue(tr("Rebooting..."));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
@@ -154,24 +167,27 @@ FrogPilotUtilitiesPanel::FrogPilotUtilitiesPanel(FrogPilotSettingsWindow *parent
|
||||
}).detach();
|
||||
}
|
||||
});
|
||||
addItem(resetTogglesBtn);
|
||||
if (forceOpenDescriptions) {
|
||||
resetTogglesButton->showDescription();
|
||||
}
|
||||
addItem(resetTogglesButton);
|
||||
|
||||
ButtonControl *resetTogglesBtnStock = new ButtonControl(tr("Reset Toggles to Match Stock openpilot"), tr("RESET"), tr("Reset all toggles to match stock openpilot."));
|
||||
QObject::connect(resetTogglesBtnStock, &ButtonControl::clicked, [this, parent, resetTogglesBtnStock]() {
|
||||
ButtonControl *resetTogglesButtonStock = new ButtonControl(tr("Reset Toggles to Stock openpilot"), tr("RESET"), tr("<b>Reset all toggles to match stock openpilot.</b>"));
|
||||
QObject::connect(resetTogglesButtonStock, &ButtonControl::clicked, [parent, resetTogglesButtonStock, this]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to reset all toggles to match stock openpilot?"), tr("Reset"), this)) {
|
||||
std::thread([this, parent, resetTogglesBtnStock]() mutable {
|
||||
std::thread([parent, resetTogglesButtonStock, this]() mutable {
|
||||
parent->keepScreenOn = true;
|
||||
|
||||
resetTogglesBtnStock->setEnabled(false);
|
||||
resetTogglesBtnStock->setValue(tr("Resetting..."));
|
||||
resetTogglesButtonStock->setEnabled(false);
|
||||
resetTogglesButtonStock->setValue(tr("Resetting..."));
|
||||
|
||||
params.putBool("DoToggleResetStock", true);
|
||||
|
||||
resetTogglesBtnStock->setValue(tr("Reset!"));
|
||||
resetTogglesButtonStock->setValue(tr("Reset!"));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
resetTogglesBtnStock->setValue(tr("Rebooting..."));
|
||||
resetTogglesButtonStock->setValue(tr("Rebooting..."));
|
||||
|
||||
util::sleep_for(2500);
|
||||
|
||||
@@ -179,5 +195,8 @@ FrogPilotUtilitiesPanel::FrogPilotUtilitiesPanel(FrogPilotSettingsWindow *parent
|
||||
}).detach();
|
||||
}
|
||||
});
|
||||
addItem(resetTogglesBtnStock);
|
||||
if (forceOpenDescriptions) {
|
||||
resetTogglesButtonStock->showDescription();
|
||||
}
|
||||
addItem(resetTogglesButtonStock);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,15 @@ QStringList getCarNames(const QString &carMake, QMap<QString, QString> &carModel
|
||||
}
|
||||
|
||||
FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
QStackedLayout *vehiclesLayout = new QStackedLayout();
|
||||
addItem(vehiclesLayout);
|
||||
|
||||
@@ -97,9 +106,9 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
||||
"Volkswagen"
|
||||
};
|
||||
|
||||
ButtonControl *selectMakeButton = new ButtonControl(tr("Select Make"), tr("SELECT"));
|
||||
QObject::connect(selectMakeButton, &ButtonControl::clicked, [this, makes, selectMakeButton]() {
|
||||
QString makeSelection = MultiOptionDialog::getSelection(tr("Select a Make"), makes, "", this);
|
||||
ButtonControl *selectMakeButton = new ButtonControl(tr("Car Make"), tr("SELECT"));
|
||||
QObject::connect(selectMakeButton, &ButtonControl::clicked, [makes, selectMakeButton, this]() {
|
||||
QString makeSelection = MultiOptionDialog::getSelection(tr("Choose your car make"), makes, "", this);
|
||||
if (!makeSelection.isEmpty()) {
|
||||
params.put("CarMake", makeSelection.toStdString());
|
||||
selectMakeButton->setValue(makeSelection);
|
||||
@@ -107,9 +116,9 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
||||
});
|
||||
settingsList->addItem(selectMakeButton);
|
||||
|
||||
ButtonControl *selectModelButton = new ButtonControl(tr("Select Model"), tr("SELECT"));
|
||||
QObject::connect(selectModelButton, &ButtonControl::clicked, [this, selectModelButton]() {
|
||||
QString modelSelection = MultiOptionDialog::getSelection(tr("Select a Model"), getCarNames(QString::fromStdString(params.get("CarMake")).toLower(), carModels), "", this);
|
||||
ButtonControl *selectModelButton = new ButtonControl(tr("Car Model"), tr("SELECT"));
|
||||
QObject::connect(selectModelButton, &ButtonControl::clicked, [selectModelButton, this]() {
|
||||
QString modelSelection = MultiOptionDialog::getSelection(tr("Choose your car model"), getCarNames(QString::fromStdString(params.get("CarMake")).toLower(), carModels), "", this);
|
||||
if (!modelSelection.isEmpty()) {
|
||||
params.put("CarModel", carModels.value(modelSelection).toStdString());
|
||||
params.put("CarModelName", modelSelection.toStdString());
|
||||
@@ -118,11 +127,11 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
||||
});
|
||||
settingsList->addItem(selectModelButton);
|
||||
|
||||
forceFingerprint = new ParamControl("ForceFingerprint", tr("Disable Automatic Fingerprint Detection"), tr("Forces the selected fingerprint and prevents it from ever changing."), "");
|
||||
forceFingerprint = new ParamControl("ForceFingerprint", tr("Disable Automatic Fingerprint Detection"), tr("<b>Force the selected fingerprint</b> and prevent it from ever changing."), "");
|
||||
settingsList->addItem(forceFingerprint);
|
||||
|
||||
disableOpenpilotLong = new ParamControl("DisableOpenpilotLongitudinal", tr("Disable openpilot Longitudinal Control"), tr("Disables openpilot longitudinal control and uses the car's stock ACC instead."), "");
|
||||
QObject::connect(disableOpenpilotLong, &ToggleControl::toggleFlipped, [this, parent](bool state) {
|
||||
disableOpenpilotLong = new ParamControl("DisableOpenpilotLongitudinal", tr("Disable openpilot Longitudinal Control"), tr("<b>Disable openpilot longitudinal</b> and use the car's stock ACC instead."), "");
|
||||
QObject::connect(disableOpenpilotLong, &ToggleControl::toggleFlipped, [parent, this](bool state) {
|
||||
if (state) {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely disable openpilot longitudinal control?"), this)) {
|
||||
if (started) {
|
||||
@@ -144,56 +153,71 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
||||
FrogPilotListWidget *gmList = new FrogPilotListWidget(this);
|
||||
FrogPilotListWidget *hkgList = new FrogPilotListWidget(this);
|
||||
FrogPilotListWidget *toyotaList = new FrogPilotListWidget(this);
|
||||
FrogPilotListWidget *vehicleInfoList = new FrogPilotListWidget(this);
|
||||
|
||||
ScrollView *gmPanel = new ScrollView(gmList, this);
|
||||
ScrollView *hkgPanel = new ScrollView(hkgList, this);
|
||||
ScrollView *toyotaPanel = new ScrollView(toyotaList, this);
|
||||
ScrollView *vehicleInfoPanel = new ScrollView(vehicleInfoList, this);
|
||||
|
||||
vehiclesLayout->addWidget(gmPanel);
|
||||
vehiclesLayout->addWidget(hkgPanel);
|
||||
vehiclesLayout->addWidget(toyotaPanel);
|
||||
vehiclesLayout->addWidget(vehicleInfoPanel);
|
||||
|
||||
std::vector<std::tuple<QString, QString, QString, QString>> vehicleToggles {
|
||||
{"GMToggles", tr("General Motors Settings"), tr("Settings specific to <b>General Motors</b> vehicles."), ""},
|
||||
{"ExperimentalGMTune", tr("FrogsGoMoo's Experimental Tune"), tr("<b>FrogsGoMoo's</b> experimental <b>General Motors</b> tune that aims to smoothen out stopping and takeoff control based on nothing but guesswork. Use at your own risk!"), ""},
|
||||
{"LongPitch", tr("Smooth Pedal Response on Hills"), tr("Smoothen the acceleration and braking when driving uphill or downhill."), ""},
|
||||
{"VoltSNG", tr("Stop and Go Hack"), tr("Force stop and go on the <b>2017 Chevy Volt</b>."), ""},
|
||||
{"GMToggles", tr("General Motors Settings"), tr("<b>FrogPilot features for General Motors vehicles.</b>"), ""},
|
||||
{"ExperimentalGMTune", tr("FrogsGoMoo's Experimental Tune"), tr("<b>Experimental GM tune by FrogsGoMoo</b> that attempts to smoothen stopping and takeoff control. Use at your own risk!"), ""},
|
||||
{"LongPitch", tr("Smooth Pedal Response on Hills"), tr("<b>Smoothen acceleration and braking</b> when driving downhill/uphill."), ""},
|
||||
{"VoltSNG", tr("Stop-and-Go Hack"), tr("<b>Force stop-and-go</b> on the 2017 Chevy Volt."), ""},
|
||||
|
||||
{"HKGToggles", tr("Hyundai/Kia/Genesis Settings"), tr("Settings specific to <b>Hyundai</b>, <b>Kia</b>, and <b>Genesis</b> vehicles."), ""},
|
||||
{"NewLongAPI", tr("comma's New Longitudinal API"), tr("comma's new longitudinal control system that has shown great improvement with acceleration and braking, but has issues on some <b>Hyundai</b>/<b>Kia</b>/<b>Genesis</b> vehicles."), ""},
|
||||
{"TacoTuneHacks", tr("\"Taco Bell Run\" Torque Hack"), tr("The torque hack from comma’s 2022 \"Taco Bell Run\" drive. Designed to improve turning at low speeds by increasing the allowed steering torque."), ""},
|
||||
{"HKGToggles", tr("Hyundai/Kia/Genesis Settings"), tr("<b>FrogPilot features for Genesis, Hyundai, and Kia vehicles.</b>"), ""},
|
||||
{"NewLongAPI", tr("comma's New Longitudinal API"), tr("<b>comma's new gas and brake control system</b> that improves acceleration and braking but may cause issues on some Genesis/Hyundai/Kia vehicles."), ""},
|
||||
{"TacoTuneHacks", tr("\"Taco Bell Run\" Torque Hack"), tr("<b>The steering torque hack from comma's 2022 \"Taco Bell Run\".</b> Designed to increase steering torque at low speeds for left and right turns."), ""},
|
||||
|
||||
{"ToyotaToggles", tr("Toyota/Lexus Settings"), tr("Settings specific to <b>Toyota</b> and <b>Lexus</b> vehicles."), ""},
|
||||
{"ToyotaDoors", tr("Automatically Lock/Unlock Doors"), tr("Automatically lock the doors when shifting into drive and unlock them when shifting into park."), ""},
|
||||
{"ClusterOffset", tr("Cluster Speed Offset"), tr("The cluster speed offset used by openpilot to match the speed displayed on the dash."), ""},
|
||||
{"FrogsGoMoosTweak", tr("FrogsGoMoo's Personal Tweaks"), tr("<b>FrogsGoMoo's</b> personal tweaks for quicker acceleration and smoother braking."), ""},
|
||||
{"LockDoorsTimer", tr("Lock Doors On Ignition Off After"), tr("Automatically lock the doors after the car's ignition has been turned off and no one is detected in either of the front seats."), ""},
|
||||
{"SNGHack", tr("Stop and Go Hack"), tr("Force stop and go on <b>Toyota</b>/<b>Lexus</b> vehicles without stock stop and go functionality."), ""}
|
||||
{"ToyotaToggles", tr("Toyota/Lexus Settings"), tr("<b>FrogPilot features for Lexus and Toyota vehicles.</b>"), ""},
|
||||
{"ToyotaDoors", tr("Automatically Lock/Unlock Doors"), tr("<b>Automatically lock/unlock doors</b> when shifting in and out of drive."), ""},
|
||||
{"ClusterOffset", tr("Dashboard Speed Offset"), tr("<b>The speed offset openpilot uses to match the speed on the dashboard display.</b>"), ""},
|
||||
{"FrogsGoMoosTweak", tr("FrogsGoMoo's Personal Tweaks"), tr("<b>Personal tweaks by FrogsGoMoo for quicker acceleration and smoother braking.</b>"), ""},
|
||||
{"LockDoorsTimer", tr("Lock Doors On Ignition Off After"), tr("<b>Automatically lock the doors on ignition off</b> when no one is detected in the front seats."), ""},
|
||||
{"SNGHack", tr("Stop-and-Go Hack"), tr("<b>Force stop-and-go</b> on Lexus/Toyota vehicles without stock stop-and-go functionality."), ""},
|
||||
|
||||
{"VehicleInfo", tr("Vehicle Info"), tr("<b>Information about your vehicle in regards to openpilot support and functionality.</b>"), ""},
|
||||
{"HardwareDetected", tr("3rd Party Hardware Detected"), tr("<b>Detected 3rd party hardware.</b>"), ""},
|
||||
{"BlindSpotSupport", tr("Blind Spot Support"), tr("<b>Does openpilot use the vehicle's blind spot data?</b>"), ""},
|
||||
{"PedalSupport", tr("comma Pedal Support"), tr("<b>Does your vehicle support the \"comma pedal\"?</b>"), ""},
|
||||
{"OpenpilotLongitudinal", tr("openpilot Longitudinal Support"), tr("<b>Can openpilot control the vehicle's acceleration and braking?</b>"), ""},
|
||||
{"RadarSupport", tr("Radar Support"), tr("<b>Does openpilot use the vehicle's radar data</b> alongside the device's camera for tracking lead vehicles?"), ""},
|
||||
{"SDSUSupport", tr("SDSU Support"), tr("<b>Does your vehicle support \"SDSUs\"?</b>"), ""},
|
||||
{"SNGSupport", tr("Stop-and-Go Support"), tr("<b>Does your vehicle support stop-and-go driving?</b>"), ""}
|
||||
};
|
||||
|
||||
for (const auto &[param, title, desc, icon] : vehicleToggles) {
|
||||
AbstractControl *vehicleToggle;
|
||||
|
||||
if (param == "GMToggles") {
|
||||
ButtonControl *gmToggle = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(gmToggle, &ButtonControl::clicked, [vehiclesLayout, gmPanel]() {
|
||||
ButtonControl *gmButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(gmButton, &ButtonControl::clicked, [vehiclesLayout, gmPanel, this]() {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
vehiclesLayout->setCurrentWidget(gmPanel);
|
||||
});
|
||||
vehicleToggle = gmToggle;
|
||||
vehicleToggle = gmButton;
|
||||
|
||||
} else if (param == "HKGToggles") {
|
||||
ButtonControl *hkgToggle = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(hkgToggle, &ButtonControl::clicked, [vehiclesLayout, hkgPanel]() {
|
||||
ButtonControl *hkgButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(hkgButton, &ButtonControl::clicked, [vehiclesLayout, hkgPanel, this]() {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
vehiclesLayout->setCurrentWidget(hkgPanel);
|
||||
});
|
||||
vehicleToggle = hkgToggle;
|
||||
vehicleToggle = hkgButton;
|
||||
|
||||
} else if (param == "ToyotaToggles") {
|
||||
ButtonControl *toyotaToggle = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(toyotaToggle, &ButtonControl::clicked, [vehiclesLayout, toyotaPanel]() {
|
||||
ButtonControl *toyotaButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||
QObject::connect(toyotaButton, &ButtonControl::clicked, [vehiclesLayout, toyotaPanel, this]() {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
vehiclesLayout->setCurrentWidget(toyotaPanel);
|
||||
});
|
||||
vehicleToggle = toyotaToggle;
|
||||
vehicleToggle = toyotaButton;
|
||||
} else if (param == "ToyotaDoors") {
|
||||
std::vector<QString> lockToggles{"LockDoors", "UnlockDoors"};
|
||||
std::vector<QString> lockToggleNames{tr("Lock"), tr("Unlock")};
|
||||
@@ -207,24 +231,36 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
||||
} else if (param == "ClusterOffset") {
|
||||
std::vector<QString> clusterOffsetButton{"Reset"};
|
||||
FrogPilotParamValueButtonControl *clusterOffsetToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 1.000, 1.050, "x", std::map<float, QString>(), 0.001, false, {}, clusterOffsetButton, false, false);
|
||||
QObject::connect(clusterOffsetToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this, clusterOffsetToggle]() {
|
||||
QObject::connect(clusterOffsetToggle, &FrogPilotParamValueButtonControl::buttonClicked, [clusterOffsetToggle, this]() {
|
||||
params.putFloat("ClusterOffset", params_default.getFloat("ClusterOffset"));
|
||||
clusterOffsetToggle->refresh();
|
||||
});
|
||||
vehicleToggle = clusterOffsetToggle;
|
||||
|
||||
} else if (param == "VehicleInfo") {
|
||||
ButtonControl *VehicleInfoButton = new ButtonControl(title, tr("VIEW"), desc);
|
||||
QObject::connect(VehicleInfoButton, &ButtonControl::clicked, [vehiclesLayout, vehicleInfoPanel, this]() {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
vehiclesLayout->setCurrentWidget(vehicleInfoPanel);
|
||||
});
|
||||
vehicleToggle = VehicleInfoButton;
|
||||
} else if (vehicleInfoKeys.contains(param)) {
|
||||
vehicleToggle = new LabelControl(title, "", desc);
|
||||
|
||||
} else {
|
||||
vehicleToggle = new ParamControl(param, title, desc, icon);
|
||||
}
|
||||
|
||||
toggles[param] = vehicleToggle;
|
||||
|
||||
if (gmKeys.find(param) != gmKeys.end()) {
|
||||
if (gmKeys.contains(param)) {
|
||||
gmList->addItem(vehicleToggle);
|
||||
} else if (hkgKeys.find(param) != hkgKeys.end()) {
|
||||
} else if (hkgKeys.contains(param)) {
|
||||
hkgList->addItem(vehicleToggle);
|
||||
} else if (toyotaKeys.find(param) != toyotaKeys.end()) {
|
||||
} else if (toyotaKeys.contains(param)) {
|
||||
toyotaList->addItem(vehicleToggle);
|
||||
} else if (vehicleInfoKeys.contains(param)) {
|
||||
vehicleInfoList->addItem(vehicleToggle);
|
||||
} else {
|
||||
settingsList->addItem(vehicleToggle);
|
||||
|
||||
@@ -235,6 +271,9 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
||||
QObject::connect(buttonControl, &ButtonControl::clicked, this, &FrogPilotVehiclesPanel::openSubPanel);
|
||||
}
|
||||
|
||||
QObject::connect(vehicleToggle, &AbstractControl::hideDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
QObject::connect(vehicleToggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
@@ -242,9 +281,9 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
||||
|
||||
static_cast<FrogPilotParamValueControl*>(toggles["LockDoorsTimer"])->setWarning("<b>Warning:</b> openpilot can't detect if keys are still inside the car, so ensure you have a spare key to prevent accidental lockouts!");
|
||||
|
||||
std::set<QString> rebootKeys = {"NewLongAPI", "TacoTuneHacks"};
|
||||
QSet<QString> rebootKeys = {"NewLongAPI", "TacoTuneHacks"};
|
||||
for (const QString &key : rebootKeys) {
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, [this, key](bool state) {
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, [key, this](bool state) {
|
||||
if (started) {
|
||||
if (key == "TacoTuneHacks" && state) {
|
||||
if (FrogPilotConfirmationDialog::toggleReboot(this)) {
|
||||
@@ -259,18 +298,33 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, [this, selectMakeButton, selectModelButton]() {
|
||||
std::thread([this, selectMakeButton, selectModelButton]() {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, [selectMakeButton, selectModelButton, this]() {
|
||||
std::thread([selectMakeButton, selectModelButton, this]() {
|
||||
selectMakeButton->setValue(QString::fromStdString(params.get("CarMake", true)));
|
||||
selectModelButton->setValue(QString::fromStdString(params.get(params.get("CarModelName").empty() ? "CarModel" : "CarModelName")));
|
||||
}).detach();
|
||||
});
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [vehiclesLayout, vehiclesPanel] {vehiclesLayout->setCurrentWidget(vehiclesPanel);});
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [vehiclesLayout, vehiclesPanel, this] {
|
||||
if (forceOpenDescriptions) {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
disableOpenpilotLong->showDescription();
|
||||
forceFingerprint->showDescription();
|
||||
}
|
||||
vehiclesLayout->setCurrentWidget(vehiclesPanel);
|
||||
});
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotVehiclesPanel::updateState);
|
||||
}
|
||||
|
||||
void FrogPilotVehiclesPanel::showEvent(QShowEvent *event) {
|
||||
if (forceOpenDescriptions) {
|
||||
disableOpenpilotLong->showDescription();
|
||||
forceFingerprint->showDescription();
|
||||
}
|
||||
|
||||
frogpilotToggleLevels = parent->frogpilotToggleLevels;
|
||||
hasExperimentalOpenpilotLongitudinal = parent->hasExperimentalOpenpilotLongitudinal;
|
||||
hasOpenpilotLongitudinal = parent->hasOpenpilotLongitudinal;
|
||||
@@ -285,6 +339,19 @@ void FrogPilotVehiclesPanel::showEvent(QShowEvent *event) {
|
||||
openpilotLongitudinalControlDisabled = parent->openpilotLongitudinalControlDisabled || params.getBool("DisableOpenpilotLongitudinal");
|
||||
tuningLevel = parent->tuningLevel;
|
||||
|
||||
QStringList detected;
|
||||
if (hasPedal) detected << "comma Pedal";
|
||||
if (parent->hasSDSU) detected << "SDSU";
|
||||
if (parent->hasZSS) detected << "ZSS";
|
||||
static_cast<LabelControl*>(toggles["HardwareDetected"])->setText(detected.isEmpty() ? tr("None") : detected.join(", "));
|
||||
|
||||
static_cast<LabelControl*>(toggles["BlindSpotSupport"])->setText(parent->hasBSM ? tr("Yes") : tr("No"));
|
||||
static_cast<LabelControl*>(toggles["OpenpilotLongitudinal"])->setText(hasOpenpilotLongitudinal ? tr("Yes") : tr("No"));
|
||||
static_cast<LabelControl*>(toggles["PedalSupport"])->setText(parent->canUsePedal ? tr("Yes") : tr("No"));
|
||||
static_cast<LabelControl*>(toggles["RadarSupport"])->setText(parent->hasRadar ? tr("Yes") : tr("No"));
|
||||
static_cast<LabelControl*>(toggles["SDSUSupport"])->setText(parent->canUseSDSU ? tr("Yes") : tr("No"));
|
||||
static_cast<LabelControl*>(toggles["SNGSupport"])->setText(hasSNG ? tr("Yes") : tr("No"));
|
||||
|
||||
updateToggles();
|
||||
}
|
||||
|
||||
@@ -298,27 +365,29 @@ void FrogPilotVehiclesPanel::updateState(const UIState &s) {
|
||||
|
||||
void FrogPilotVehiclesPanel::updateToggles() {
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
toggle->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool setVisible = tuningLevel >= frogpilotToggleLevels[key].toDouble();
|
||||
|
||||
if (gmKeys.find(key) != gmKeys.end()) {
|
||||
if (gmKeys.contains(key)) {
|
||||
setVisible &= isGM;
|
||||
} else if (hkgKeys.find(key) != hkgKeys.end()) {
|
||||
} else if (hkgKeys.contains(key)) {
|
||||
setVisible &= isHKG;
|
||||
} else if (toyotaKeys.find(key) != toyotaKeys.end()) {
|
||||
} else if (toyotaKeys.contains(key)) {
|
||||
setVisible &= isToyota;
|
||||
} else if (vehicleInfoKeys.contains(key)) {
|
||||
setVisible = true;
|
||||
}
|
||||
|
||||
if (longitudinalKeys.find(key) != longitudinalKeys.end()) {
|
||||
if (longitudinalKeys.contains(key)) {
|
||||
setVisible &= hasOpenpilotLongitudinal;
|
||||
}
|
||||
|
||||
@@ -341,12 +410,14 @@ void FrogPilotVehiclesPanel::updateToggles() {
|
||||
toggle->setVisible(setVisible);
|
||||
|
||||
if (setVisible) {
|
||||
if (gmKeys.find(key) != gmKeys.end()) {
|
||||
if (gmKeys.contains(key)) {
|
||||
toggles["GMToggles"]->setVisible(true);
|
||||
} else if (hkgKeys.find(key) != hkgKeys.end()) {
|
||||
} else if (hkgKeys.contains(key)) {
|
||||
toggles["HKGToggles"]->setVisible(true);
|
||||
} else if (toyotaKeys.find(key) != toyotaKeys.end()) {
|
||||
} else if (toyotaKeys.contains(key)) {
|
||||
toggles["ToyotaToggles"]->setVisible(true);
|
||||
} else if (vehicleInfoKeys.contains(key)) {
|
||||
toggles["VehicleInfo"]->setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -354,5 +425,7 @@ void FrogPilotVehiclesPanel::updateToggles() {
|
||||
disableOpenpilotLong->setVisible((hasOpenpilotLongitudinal || openpilotLongitudinalControlDisabled) && !hasExperimentalOpenpilotLongitudinal && tuningLevel >= frogpilotToggleLevels["DisableOpenpilotLongitudinal"].toDouble());
|
||||
forceFingerprint->setVisible(tuningLevel >= frogpilotToggleLevels["ForceFingerprint"].toDouble());
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "frogpilot/ui/qt/offroad/frogpilot_settings.h"
|
||||
|
||||
class FrogPilotVehiclesPanel : public FrogPilotListWidget {
|
||||
@@ -20,6 +18,7 @@ private:
|
||||
void updateState(const UIState &s);
|
||||
void updateToggles();
|
||||
|
||||
bool forceOpenDescriptions;
|
||||
bool hasExperimentalOpenpilotLongitudinal;
|
||||
bool hasOpenpilotLongitudinal;
|
||||
bool hasPedal;
|
||||
@@ -37,22 +36,23 @@ private:
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
std::set<QString> gmKeys = {"ExperimentalGMTune", "LongPitch", "VoltSNG"};
|
||||
std::set<QString> hkgKeys = {"NewLongAPI", "TacoTuneHacks"};
|
||||
std::set<QString> longitudinalKeys = {"ExperimentalGMTune", "FrogsGoMoosTweak", "LongPitch", "NewLongAPI", "SNGHack", "VoltSNG"};
|
||||
std::set<QString> toyotaKeys = {"ClusterOffset", "FrogsGoMoosTweak", "LockDoorsTimer", "SNGHack", "ToyotaDoors"};
|
||||
QSet<QString> gmKeys = {"ExperimentalGMTune", "LongPitch", "VoltSNG"};
|
||||
QSet<QString> hkgKeys = {"NewLongAPI", "TacoTuneHacks"};
|
||||
QSet<QString> longitudinalKeys = {"ExperimentalGMTune", "FrogsGoMoosTweak", "LongPitch", "NewLongAPI", "SNGHack", "VoltSNG"};
|
||||
QSet<QString> toyotaKeys = {"ClusterOffset", "FrogsGoMoosTweak", "LockDoorsTimer", "SNGHack", "ToyotaDoors"};
|
||||
QSet<QString> vehicleInfoKeys = {"BlindSpotSupport", "HardwareDetected", "OpenpilotLongitudinal", "PedalSupport", "RadarSupport", "SDSUSupport", "SNGSupport"};
|
||||
|
||||
std::set<QString> parentKeys;
|
||||
QSet<QString> parentKeys;
|
||||
|
||||
FrogPilotSettingsWindow *parent;
|
||||
|
||||
QJsonObject frogpilotToggleLevels;
|
||||
|
||||
QMap<QString, QString> carModels;
|
||||
|
||||
ParamControl *disableOpenpilotLong;
|
||||
ParamControl *forceFingerprint;
|
||||
|
||||
Params params;
|
||||
Params params_default{"/dev/shm/params_default"};
|
||||
|
||||
QJsonObject frogpilotToggleLevels;
|
||||
|
||||
QMap<QString, QString> carModels;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
#include "frogpilot/ui/qt/offroad/visual_settings.h"
|
||||
|
||||
FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
QStackedLayout *visualsLayout = new QStackedLayout();
|
||||
addItem(visualsLayout);
|
||||
|
||||
@@ -41,67 +50,66 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
|
||||
visualsLayout->addWidget(qualityOfLifePanel);
|
||||
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> visualToggles {
|
||||
{"AdvancedCustomUI", tr("Advanced UI Controls"), tr("Advanced settings for fine-tuning openpilot's driving screen."), "../../frogpilot/assets/toggle_icons/icon_advanced_device.png"},
|
||||
{"HideSpeed", tr("Hide Current Speed"), tr("Hide the current speed from the driving screen."), ""},
|
||||
{"HideLeadMarker", tr("Hide Lead Marker"), tr("Hide the marker for lead vehicles from the driving screen."), ""},
|
||||
{"HideMapIcon", tr("Hide Map Settings Button"), tr("Hide the map settings button from the driving screen."), ""},
|
||||
{"HideMaxSpeed", tr("Hide Max Speed"), tr("Hide the max speed from the driving screen."), ""},
|
||||
{"HideAlerts", tr("Hide Non-Critical Alerts"), tr("Hide non-critical alerts from the driving screen."), ""},
|
||||
{"HideSpeedLimit", tr("Hide Speed Limits"), tr("Hide the speed limits from the driving screen."), ""},
|
||||
{"WheelSpeed", tr("Use Wheel Speed"), tr("Use the vehicle's wheel speed instead of the cluster speed. This is purely a visual change and doesn't impact how openpilot drives."), ""},
|
||||
{"AdvancedCustomUI", tr("Advanced UI Controls"), tr("<b>Advanced visual changes</b> to fine-tune how the driving screen looks."), "../../frogpilot/assets/toggle_icons/icon_advanced_device.png"},
|
||||
{"HideSpeed", tr("Hide Current Speed"), tr("<b>Hide the current speed</b> from the driving screen."), ""},
|
||||
{"HideLeadMarker", tr("Hide Lead Marker"), tr("<b>Hide the lead-vehicle marker</b> from the driving screen."), ""},
|
||||
{"HideMapIcon", tr("Hide Map Settings Button"), tr("<b>Hide the map settings button or map</b> from the driving screen."), ""},
|
||||
{"HideMaxSpeed", tr("Hide Max Speed"), tr("<b>Hide the max speed</b> from the driving screen."), ""},
|
||||
{"HideAlerts", tr("Hide Non-Critical Alerts"), tr("<b>Hide non-critical alerts</b> from the driving screen."), ""},
|
||||
{"HideSpeedLimit", tr("Hide Speed Limits"), tr("<b>Hide posted speed limits</b> from the driving screen."), ""},
|
||||
{"WheelSpeed", tr("Use Wheel Speed"), tr("<b>Use the vehicle's wheel speed</b> instead of the cluster speed. This is purely a visual change and doesn't impact how openpilot drives!"), ""},
|
||||
|
||||
{"DeveloperUI", tr("Developer UI"), tr("Detailed information about openpilot's internal operations."), "../assets/offroad/icon_shell.png"},
|
||||
{"AdjacentPathMetrics", tr("Adjacent Path Metrics"), tr("Metrics displayed on top of the adjacent lanes measuring their current width."), ""},
|
||||
{"DeveloperMetrics", tr("Developer Metrics"), tr("Performance data, sensor readings, and system metrics for debugging and optimizing openpilot."), ""},
|
||||
{"BorderMetrics", tr("Border Metrics"), tr("Metrics displayed around the border of the driving screen.<br><br><b>Blind Spot</b>: Turn the border red when a vehicle is detected in a blind spot<br><b>Steering Torque</b>: Highlight the border green to red in accordance to the amount of steering torque being used<br><b>Turn Signal</b>: Flash the border yellow when a turn signal is active"), ""},
|
||||
{"LeadInfo", tr("Lead Info"), tr("Metrics displayed under vehicle markers listing their distance and current speed."), ""},
|
||||
{"FPSCounter", tr("FPS Display"), tr("Display the <b>Frames Per Second (FPS)</b> at the bottom of the driving screen."), ""},
|
||||
{"NumericalTemp", tr("Numerical Temperature Gauge"), tr("Use numerical temperature readings instead of status labels in the sidebar."), ""},
|
||||
{"SidebarMetrics", tr("Sidebar Metrics"), tr("Display system information (<b>CPU</b>, <b>GPU</b>, <b>RAM usage</b>, <b>IP address</b>, <b>device storage</b>) in the sidebar."), ""},
|
||||
{"UseSI", tr("Use International System of Units"), tr("Display measurements using the <b>International System of Units (SI)</b> standard."), ""},
|
||||
{"DeveloperSidebar", tr("Developer Sidebar"), tr("Display debugging info and metrics in a dedicated sidebar on the right side of the screen."), ""},
|
||||
{"DeveloperSidebarMetric1", tr("Metric #1"), tr("Metric to display in the first metric in the \"Developer Sidebar\"."), ""},
|
||||
{"DeveloperSidebarMetric2", tr("Metric #2"), tr("Metric to display in the second metric in the \"Developer Sidebar\"."), ""},
|
||||
{"DeveloperSidebarMetric3", tr("Metric #3"), tr("Metric to display in the third metric in the \"Developer Sidebar\"."), ""},
|
||||
{"DeveloperSidebarMetric4", tr("Metric #4"), tr("Metric to display in the fourth metric in the \"Developer Sidebar\"."), ""},
|
||||
{"DeveloperSidebarMetric5", tr("Metric #5"), tr("Metric to display in the fifth metric in the \"Developer Sidebar\"."), ""},
|
||||
{"DeveloperSidebarMetric6", tr("Metric #6"), tr("Metric to display in the sixth metric in the \"Developer Sidebar\"."), ""},
|
||||
{"DeveloperSidebarMetric7", tr("Metric #7"), tr("Metric to display in the seventh metric in the \"Developer Sidebar\"."), ""},
|
||||
{"DeveloperWidgets", tr("Developer Widgets"), tr("Overlays displaying debugging visuals, internal states, and model predictions on the driving screen."), ""},
|
||||
{"AdjacentLeadsUI", tr("Adjacent Leads Tracking"), tr("Adjacent leads detected by the car's radar to the left and right of the current driving path."), ""},
|
||||
{"ShowStoppingPoint", tr("Model Stopping Point"), tr("Display an image on the screen where openpilot is wanting to stop."), ""},
|
||||
{"RadarTracksUI", tr("Radar Tracks"), tr("Display all of the radar points produced by the car's radar."), ""},
|
||||
{"DeveloperUI", tr("Developer UI"), tr("<b>Detailed information about openpilot's internal operations.</b>"), "../assets/offroad/icon_shell.png"},
|
||||
{"AdjacentPathMetrics", tr("Adjacent Path Metrics"), tr("<b>Show the width of the adjacent lanes.</b>"), ""},
|
||||
{"DeveloperMetrics", tr("Developer Metrics"), tr("<b>Performance data, sensor readings, and system metrics</b> for debugging and optimizing openpilot."), ""},
|
||||
{"BorderMetrics", tr("Border Metrics"), tr("<b>Show statuses along the border of the driving screen.</b><br><br><b>Blind Spot</b>: The border turns red when a vehicle is in a blind spot<br><b>Steering Torque</b>: The border goes from green to red according to how much steering torque is being used<br><b>Turn Signal</b>: The border flashes yellow when a turn signal is on"), ""},
|
||||
{"LeadInfo", tr("Lead Info"), tr("<b>Show each tracked vehicle's distance and speed</b> below its marker."), ""},
|
||||
{"FPSCounter", tr("FPS Display"), tr("<b>Show the frames per second (FPS)</b> at the bottom of the driving screen."), ""},
|
||||
{"NumericalTemp", tr("Numerical Temperature Gauge"), tr("<b>Show a numerical temperature in the sidebar</b> instead of the status labels."), ""},
|
||||
{"SidebarMetrics", tr("Sidebar Metrics"), tr("<b>Display system information</b> (CPU, GPU, RAM usage, IP address, device storage) in the sidebar."), ""},
|
||||
{"UseSI", tr("Use International System of Units"), tr("<b>Display measurements using the \"International System of Units\" (SI)</b> standard."), ""},
|
||||
{"DeveloperSidebar", tr("Developer Sidebar"), tr("<b>Display debugging info and metrics</b> in a dedicated sidebar on the right side of the screen."), ""},
|
||||
{"DeveloperSidebarMetric1", tr("Metric #1"), tr("<b>Select the metric shown in the first \"Developer Sidebar\" widget.</b>"), ""},
|
||||
{"DeveloperSidebarMetric2", tr("Metric #2"), tr("<b>Select the metric shown in the second \"Developer Sidebar\" widget.</b>"), ""},
|
||||
{"DeveloperSidebarMetric3", tr("Metric #3"), tr("<b>Select the metric shown in the third \"Developer Sidebar\" widget.</b>"), ""},
|
||||
{"DeveloperSidebarMetric4", tr("Metric #4"), tr("<b>Select the metric shown in the fourth \"Developer Sidebar\" widget.</b>"), ""},
|
||||
{"DeveloperSidebarMetric5", tr("Metric #5"), tr("<b>Select the metric shown in the fifth \"Developer Sidebar\" widget.</b>"), ""},
|
||||
{"DeveloperSidebarMetric6", tr("Metric #6"), tr("<b>Select the metric shown in the sixth \"Developer Sidebar\" widget.</b>"), ""},
|
||||
{"DeveloperSidebarMetric7", tr("Metric #7"), tr("<b>Select the metric shown in the seventh \"Developer Sidebar\" widget.</b>"), ""},
|
||||
{"DeveloperWidgets", tr("Developer Widgets"), tr("<b>Overlays for debugging visuals, internal states, and model predictions</b> on the driving screen."), ""},
|
||||
{"AdjacentLeadsUI", tr("Adjacent Leads Tracking"), tr("<b>Display adjacent leads detected by the car's radar</b> to the left and right of the current driving path."), ""},
|
||||
{"ShowStoppingPoint", tr("Model Stopping Point"), tr("<b>Show a stop-sign marker where the model intends to stop.</b>"), ""},
|
||||
{"RadarTracksUI", tr("Radar Tracks"), tr("<b>Display all radar points</b> produced by the car's radar."), ""},
|
||||
|
||||
{"CustomUI", tr("Driving Screen Widgets"), tr("Custom FrogPilot widgets for the driving screen."), "../assets/offroad/icon_road.png"},
|
||||
{"AccelerationPath", tr("Acceleration Path"), tr("Colorize the driving path based on openpilot's current desired acceleration and deceleration rate."), ""},
|
||||
{"AdjacentPath", tr("Adjacent Lanes"), tr("Driving paths for the left and right adjacent lanes."), ""},
|
||||
{"BlindSpotPath", tr("Blind Spot Path"), tr("Display a red driving path for detected vehicles in the corresponding lane's blind spot."), ""},
|
||||
{"Compass", tr("Compass"), tr("A compass to show the current driving direction."), ""},
|
||||
{"OnroadDistanceButton", tr("Driving Personality Button"), tr("Display the current driving personality on the screen. Tap to switch personalities, or long press for 0.5 seconds to change the current state of <b>Experimental Mode</b>, or 2.5 seconds for <b>Traffic Mode</b>."), ""},
|
||||
{"PedalsOnUI", tr("Gas / Brake Pedal Indicators"), tr("Pedals to indicate when either of the pedals are currently being used.<br><br><b>Dynamic</b>: The pedals change in opacity in accordance to how much openpilot is accelerating or decelerating<br><b>Static</b>: The pedals are displayed with full opacity when active, and dimmed when not in use"), ""},
|
||||
{"RotatingWheel", tr("Rotating Steering Wheel"), tr("Rotate the steering wheel alongside the vehicle's physical steering wheel."), ""},
|
||||
{"CustomUI", tr("Driving Screen Widgets"), tr("<b>Custom FrogPilot widgets</b> for the driving screen."), "../assets/offroad/icon_road.png"},
|
||||
{"AccelerationPath", tr("Acceleration Path"), tr("<b>Color the driving path by planned acceleration and braking.</b>"), ""},
|
||||
{"AdjacentPath", tr("Adjacent Lanes"), tr("<b>Show the driving paths for the left and right lanes.</b>"), ""},
|
||||
{"BlindSpotPath", tr("Blind Spot Path"), tr("<b>Show a red path when a vehicle is in that lane's blind spot.</b>"), ""},
|
||||
{"Compass", tr("Compass"), tr("<b>Show the current driving direction</b> with a simple on-screen compass."), ""},
|
||||
{"OnroadDistanceButton", tr("Driving Personality Button"), tr("<b>Control and view the current driving personality</b> via a driving screen widget."), ""},
|
||||
{"PedalsOnUI", tr("Gas / Brake Pedal Indicators"), tr("<b>On-screen gas and brake indicators.</b><br><br><b>Dynamic</b>: Opacity changes according to how much openpilot is accelerating or braking<br><b>Static</b>: Full when active, dim when not"), ""},
|
||||
{"RotatingWheel", tr("Rotating Steering Wheel"), tr("<b>Rotate the driving screen wheel</b> with the physical steering wheel."), ""},
|
||||
|
||||
{"ModelUI", tr("Model UI"), tr("Model visualizations on the driving screen for the driving path, lane lines, path edges, and road edges."), "../../frogpilot/assets/toggle_icons/icon_vtc.png"},
|
||||
{"DynamicPathWidth", tr("Dynamic Path Width"), tr("Adjust the width of the driving path based on the current engagement state.<br><br><b>Fully engaged</b>: 100%<br><b>Always On Lateral</b>: 75%<br><b>Fully disengaged</b>: 50%"), ""},
|
||||
{"LaneLinesWidth", tr("Lane Lines Width"), tr("The thickness of the lane lines on the driving screen.<br><br><b>Default matches the <b>MUTCD</b> lane line width standard of 4 inches."), ""},
|
||||
{"PathEdgeWidth", tr("Path Edges Width"), tr("The width of the edges of the driving path that represent different driving modes and statuses.<br><br>Default is <b>20%</b> of the total path width.<br><br>Color Guide:<br><br>- <b>Blue</b>: Navigation<br>- <b>Light Blue</b>: Always On Lateral<br>- <b>Green</b>: Default<br>- <b>Orange</b>: Experimental Mode<br>- <b>Red</b>: Traffic Mode<br>- <b>Yellow</b>: Conditional Experimental Mode overridden"), ""},
|
||||
{"PathWidth", tr("Path Width"), tr("The width of the driving path on the driving screen.<br><br>Default <b>(6.1 feet)</b> matches the width of a <b>2019 Lexus ES 350</b>."), ""},
|
||||
{"RoadEdgesWidth", tr("Road Edges Width"), tr("The thickness of the road edges on the driving screen.<br><br><b>Default matches half of the <b>MUTCD</b> lane line width standard of 4 inches."), ""},
|
||||
{"UnlimitedLength", tr("\"Unlimited\" Road UI"), tr("Extend the display of the driving path, lane lines, and road edges as far as the model can see."), ""},
|
||||
{"ModelUI", tr("Model UI"), tr("<b>Model visualizations</b> for the driving path, lane lines, path edges, and road edges."), "../../frogpilot/assets/toggle_icons/icon_vtc.png"},
|
||||
{"DynamicPathWidth", tr("Dynamic Path Width"), tr("<b>Change the path width based on engagement.</b><br><br><b>Fully Engaged</b>: 100%<br><b>Always On Lateral</b>: 75%<br><b>Disengaged</b>: 50%"), ""},
|
||||
{"LaneLinesWidth", tr("Lane Lines Width"), tr("<b>Set the lane-line thickness.</b><br><br>Default matches the MUTCD lane-line width standard of 4 inches."), ""},
|
||||
{"PathEdgeWidth", tr("Path Edges Width"), tr("<b>Set the driving-path edge width</b> that represents different driving modes and statuses.<br><br>Default is 20% of the total path width.<br><br>Color Guide:<br><br>- <b>Blue</b>: Navigation<br>- <b>Light Blue</b>: Always On Lateral<br>- <b>Green</b>: Default<br>- <b>Orange</b>: Experimental Mode<br>- <b>Red</b>: Traffic Mode<br>- <b>Yellow</b>: Conditional Experimental Mode overridden"), ""},
|
||||
{"PathWidth", tr("Path Width"), tr("<b>Set the driving-path width.</b><br><br>Default (6.1 feet) matches the width of a 2019 Lexus ES 350."), ""},
|
||||
{"RoadEdgesWidth", tr("Road Edges Width"), tr("<b>Set the road-edge thickness.</b><br><br>Default matches half of the MUTCD lane-line width standard of 4 inches."), ""},
|
||||
{"UnlimitedLength", tr("\"Unlimited\" Road UI"), tr("<b>Extend the length of the driving path, lane lines, and road edges</b> for as far as the model can see."), ""},
|
||||
|
||||
{"NavigationUI", tr("Navigation Widgets"), tr("Map style tweaks, speed limits, and other navigation related widgets."), "../../frogpilot/assets/toggle_icons/icon_map.png"},
|
||||
{"BigMap", tr("Larger Map Display"), tr("Increase the size of the map for easier navigation readings."), ""},
|
||||
{"MapStyle", tr("Map Style"), tr("The map style used for <b>Navigate on openpilot (NOO)</b>:<br><br><b>Stock</b>: Default comma.ai style<br><b>Mapbox Streets</b>: Standard street-focused view<br><b>Mapbox Outdoors</b>: Emphasizes outdoor and terrain features<br><b>Mapbox Light</b>: Minimalist, bright theme<br><b>Mapbox Dark</b>: Minimalist, dark theme<br><b>Mapbox Navigation Day</b>: Optimized for daytime navigation<br><b>Mapbox Navigation Night</b>: Optimized for nighttime navigation<br><b>Mapbox Satellite</b>: Satellite imagery only<br><b>Mapbox Satellite Streets</b>: Hybrid satellite imagery with street labels<br><b>Mapbox Traffic Night</b>: Dark theme emphasizing traffic conditions<br><b>mike854's (Satellite hybrid)</b>: Customized hybrid satellite view"), ""},
|
||||
{"RoadNameUI", tr("Road Name"), tr("Display the road name at the bottom of the driving screen using data from <b>OpenStreetMap</b>."), ""},
|
||||
{"ShowSpeedLimits", tr("Show Speed Limits"), tr("Display speed limits in the top left corner of the driving screen. Uses data from your car's dashboard (if supported) and data from <b>OpenStreetMaps</b>."), ""},
|
||||
{"SLCMapboxFiller", tr("Show Speed Limits from Mapbox"), tr("Use <b>Mapbox</b> speed limit data when no other sources are available."), ""},
|
||||
{"UseVienna", tr("Use Vienna-Style Speed Signs"), tr("Force <b>Vienna-style (EU)</b> speed limit signs instead of <b>MUTCD (US)</b>."), ""},
|
||||
{"NavigationUI", tr("Navigation Widgets"), tr("<b>Map style, speed limits, and other navigation widgets.</b>"), "../../frogpilot/assets/toggle_icons/icon_map.png"},
|
||||
{"BigMap", tr("Larger Map Display"), tr("<b>Increase the map size</b> for easier navigation readings."), ""},
|
||||
{"MapStyle", tr("Map Style"), tr("<b>Select the map style</b> for \"Navigate on openpilot\" (NOO):<br><br><b>Stock openpilot</b>: Default comma.ai style<br><b>FrogPilot</b>: Official FrogPilot map style<br><b>Mapbox Streets</b>: Standard street-focused view<br><b>Mapbox Outdoors</b>: Emphasizes outdoor and terrain features<br><b>Mapbox Light</b>: Minimalist, bright theme<br><b>Mapbox Dark</b>: Minimalist, dark theme<br><b>Mapbox Navigation Day</b>: Optimized for daytime navigation<br><b>Mapbox Navigation Night</b>: Optimized for nighttime navigation<br><b>Mapbox Satellite</b>: Satellite imagery only<br><b>Mapbox Satellite Streets</b>: Hybrid satellite imagery with street labels<br><b>Mapbox Traffic Night</b>: Dark theme emphasizing traffic conditions<br><b>Mike's Personalized Style</b>: Customized hybrid satellite view"), ""},
|
||||
{"RoadNameUI", tr("Road Name"), tr("<b>Display the road name at the bottom of the driving screen</b> using data from \"OpenStreetMap (OSM)\"."), ""},
|
||||
{"ShowSpeedLimits", tr("Show Speed Limits"), tr("<b>Show speed limits</b> in the top-left corner of the driving screen. Uses data from the car's dashboard (if supported) and \"OpenStreetMap (OSM)\"."), ""},
|
||||
{"SLCMapboxFiller", tr("Show Speed Limits from Mapbox"), tr("<b>Use Mapbox speed-limit data when no other source is available.</b>"), ""},
|
||||
{"UseVienna", tr("Use Vienna-Style Speed Signs"), tr("<b>Show Vienna-style (EU) speed-limit signs</b> instead of MUTCD (US)."), ""},
|
||||
|
||||
{"QOLVisuals", tr("Quality of Life"), tr("Visual features to improve your overall openpilot experience."), "../../frogpilot/assets/toggle_icons/icon_quality_of_life.png"},
|
||||
{"CameraView", tr("Camera View"), tr("The active camera view display. This is purely a visual change and doesn't impact how openpilot drives!"), ""},
|
||||
{"DriverCamera", tr("Show Driver Camera When In Reverse"), tr("Display the driver camera feed when the vehicle is in reverse."), ""},
|
||||
{"StandbyMode", tr("Standby Mode"), tr("Turn the screen off when driving and automatically wake it up if engagement state changes or important alerts occur."), ""},
|
||||
{"StoppedTimer", tr("Stopped Timer"), tr("Replace the current speed with a timer when stopped to indicate how long the vehicle has been stopped for."), ""}
|
||||
{"QOLVisuals", tr("Quality of Life"), tr("<b>Miscellaneous visual changes</b> to fine-tune how the driving screen looks."), "../../frogpilot/assets/toggle_icons/icon_quality_of_life.png"},
|
||||
{"CameraView", tr("Camera View"), tr("<b>Select the active camera view.</b> This is purely a visual change and doesn't impact how openpilot drives!"), ""},
|
||||
{"DriverCamera", tr("Show Driver Camera When In Reverse"), tr("<b>Show the driver camera feed</b> when the vehicle is in reverse."), ""},
|
||||
{"StoppedTimer", tr("Stopped Timer"), tr("<b>Show a timer when stopped</b> in place of the current speed to indicate how long the vehicle has been stopped."), ""}
|
||||
};
|
||||
|
||||
for (const auto &[param, title, desc, icon] : visualToggles) {
|
||||
@@ -113,6 +121,10 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
|
||||
visualsLayout->setCurrentWidget(advancedCustomPanel);
|
||||
});
|
||||
visualToggle = advancedCustomUIToggle;
|
||||
} else if (param == "HideMapIcon") {
|
||||
std::vector<QString> mapIconToggles{"HideMap"};
|
||||
std::vector<QString> mapIconToggleNames{tr("Hide Map")};
|
||||
visualToggle = new FrogPilotButtonToggleControl(param, title, desc, icon, mapIconToggles, mapIconToggleNames);
|
||||
|
||||
} else if (param == "DeveloperUI") {
|
||||
FrogPilotManageControl *developerUIToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||
@@ -122,7 +134,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
|
||||
visualToggle = developerUIToggle;
|
||||
} else if (param == "DeveloperMetrics") {
|
||||
FrogPilotManageControl *developerMetricsToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||
QObject::connect(developerMetricsToggle, &FrogPilotManageControl::manageButtonClicked, [this, visualsLayout, developerMetricPanel]() {
|
||||
QObject::connect(developerMetricsToggle, &FrogPilotManageControl::manageButtonClicked, [visualsLayout, developerMetricPanel, this]() {
|
||||
openSubSubPanel();
|
||||
|
||||
visualsLayout->setCurrentWidget(developerMetricPanel);
|
||||
@@ -133,8 +145,8 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
|
||||
} else if (param == "BorderMetrics") {
|
||||
std::vector<QString> borderToggles{"BlindSpotMetrics", "ShowSteering", "SignalMetrics"};
|
||||
std::vector<QString> borderToggleNames{tr("Blind Spot"), tr("Steering Torque"), tr("Turn Signal")};
|
||||
borderMetricsBtn = new FrogPilotButtonToggleControl(param, title, desc, icon, borderToggles, borderToggleNames);
|
||||
visualToggle = borderMetricsBtn;
|
||||
borderMetricsButton = new FrogPilotButtonToggleControl(param, title, desc, icon, borderToggles, borderToggleNames);
|
||||
visualToggle = borderMetricsButton;
|
||||
} else if (param == "NumericalTemp") {
|
||||
std::vector<QString> temperatureToggles{"Fahrenheit"};
|
||||
std::vector<QString> temperatureToggleNames{tr("Fahrenheit")};
|
||||
@@ -176,7 +188,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
|
||||
visualToggle = sidebarMetricsToggle;
|
||||
} else if (param == "DeveloperSidebar") {
|
||||
FrogPilotManageControl *developerSidebarToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||
QObject::connect(developerSidebarToggle, &FrogPilotManageControl::manageButtonClicked, [this, visualsLayout, developerSidebarPanel]() {
|
||||
QObject::connect(developerSidebarToggle, &FrogPilotManageControl::manageButtonClicked, [visualsLayout, developerSidebarPanel, this]() {
|
||||
openSubSubPanel();
|
||||
|
||||
visualsLayout->setCurrentWidget(developerSidebarPanel);
|
||||
@@ -184,7 +196,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
|
||||
developerUIOpen = true;
|
||||
});
|
||||
visualToggle = developerSidebarToggle;
|
||||
} else if (developerSidebarKeys.find(param) != developerSidebarKeys.end()) {
|
||||
} else if (developerSidebarKeys.contains(param)) {
|
||||
QMap<int, QString> developerSidebarMetricOptions {
|
||||
{0, tr("None")},
|
||||
{1, tr("Acceleration: Current")},
|
||||
@@ -205,7 +217,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
|
||||
};
|
||||
|
||||
ButtonControl *metricToggle = new ButtonControl(title, tr("SELECT"), desc);
|
||||
QObject::connect(metricToggle, &ButtonControl::clicked, [this, metricToggle, key = param, developerSidebarMetricOptions]() mutable {
|
||||
QObject::connect(metricToggle, &ButtonControl::clicked, [metricToggle, key = param, developerSidebarMetricOptions, this]() mutable {
|
||||
QString current = developerSidebarMetricOptions.value(params.getInt(key.toStdString()), tr("None"));
|
||||
QString selection = MultiOptionDialog::getSelection(tr("Select a metric to display"), developerSidebarMetricOptions.values(), current, this);
|
||||
|
||||
@@ -221,7 +233,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
|
||||
visualToggle = metricToggle;
|
||||
} else if (param == "DeveloperWidgets") {
|
||||
FrogPilotManageControl *developerWidgetsToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||
QObject::connect(developerWidgetsToggle, &FrogPilotManageControl::manageButtonClicked, [this, visualsLayout, developerWidgetPanel]() {
|
||||
QObject::connect(developerWidgetsToggle, &FrogPilotManageControl::manageButtonClicked, [visualsLayout, developerWidgetPanel, this]() {
|
||||
openSubSubPanel();
|
||||
|
||||
visualsLayout->setCurrentWidget(developerWidgetPanel);
|
||||
@@ -283,7 +295,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
|
||||
} else if (param == "MapStyle") {
|
||||
QMap<int, QString> styleMap {
|
||||
{0, tr("Stock openpilot")},
|
||||
{1, tr("FrogsGoMoo's Personalized Style")},
|
||||
{1, tr("FrogPilot")},
|
||||
{2, tr("Mapbox Streets")},
|
||||
{3, tr("Mapbox Outdoors")},
|
||||
{4, tr("Mapbox Light")},
|
||||
@@ -297,7 +309,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
|
||||
};
|
||||
|
||||
ButtonControl *mapStyleButton = new ButtonControl(title, tr("SELECT"), desc);
|
||||
QObject::connect(mapStyleButton, &ButtonControl::clicked, [this, mapStyleButton, styleMap]() {
|
||||
QObject::connect(mapStyleButton, &ButtonControl::clicked, [mapStyleButton, styleMap, this]() {
|
||||
QString selection = MultiOptionDialog::getSelection(tr("Select a map style"), styleMap.values(), "", this);
|
||||
if (!selection.isEmpty()) {
|
||||
int selectedStyle = styleMap.key(selection);
|
||||
@@ -329,23 +341,23 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
|
||||
|
||||
toggles[param] = visualToggle;
|
||||
|
||||
if (advancedCustomOnroadUIKeys.find(param) != advancedCustomOnroadUIKeys.end()) {
|
||||
if (advancedCustomOnroadUIKeys.contains(param)) {
|
||||
advancedCustomList->addItem(visualToggle);
|
||||
} else if (customOnroadUIKeys.find(param) != customOnroadUIKeys.end()) {
|
||||
} else if (customOnroadUIKeys.contains(param)) {
|
||||
customUIList->addItem(visualToggle);
|
||||
} else if (developerMetricKeys.find(param) != developerMetricKeys.end()) {
|
||||
} else if (developerMetricKeys.contains(param)) {
|
||||
developerMetricList->addItem(visualToggle);
|
||||
} else if (developerSidebarKeys.find(param) != developerSidebarKeys.end()) {
|
||||
} else if (developerSidebarKeys.contains(param)) {
|
||||
developerSidebarList->addItem(visualToggle);
|
||||
} else if (developerUIKeys.find(param) != developerUIKeys.end()) {
|
||||
} else if (developerUIKeys.contains(param)) {
|
||||
developerUIList->addItem(visualToggle);
|
||||
} else if (developerWidgetKeys.find(param) != developerWidgetKeys.end()) {
|
||||
} else if (developerWidgetKeys.contains(param)) {
|
||||
developerWidgetList->addItem(visualToggle);
|
||||
} else if (modelUIKeys.find(param) != modelUIKeys.end()) {
|
||||
} else if (modelUIKeys.contains(param)) {
|
||||
modelUIList->addItem(visualToggle);
|
||||
} else if (navigationUIKeys.find(param) != navigationUIKeys.end()) {
|
||||
} else if (navigationUIKeys.contains(param)) {
|
||||
navigationUIList->addItem(visualToggle);
|
||||
} else if (qualityOfLifeKeys.find(param) != qualityOfLifeKeys.end()) {
|
||||
} else if (qualityOfLifeKeys.contains(param)) {
|
||||
qualityOfLifeList->addItem(visualToggle);
|
||||
} else {
|
||||
visualsList->addItem(visualToggle);
|
||||
@@ -354,21 +366,34 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
|
||||
}
|
||||
|
||||
if (FrogPilotManageControl *frogPilotManageToggle = qobject_cast<FrogPilotManageControl*>(visualToggle)) {
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, this, &FrogPilotVisualsPanel::openSubPanel);
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, [this]() {
|
||||
emit openSubPanel();
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(visualToggle, &AbstractControl::hideDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
QObject::connect(visualToggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
std::set<QString> forceUpdateKeys = {"ShowSpeedLimits"};
|
||||
QSet<QString> forceUpdateKeys = {"HideLeadMarker", "ShowSpeedLimits"};
|
||||
for (const QString &key : forceUpdateKeys) {
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, this, &FrogPilotVisualsPanel::updateToggles);
|
||||
}
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [visualsLayout, visualsPanel] {visualsLayout->setCurrentWidget(visualsPanel);});
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubSubPanel, [this, visualsLayout, developerUIPanel]() {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [visualsLayout, visualsPanel, this] {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
visualsLayout->setCurrentWidget(visualsPanel);
|
||||
});
|
||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubSubPanel, [visualsLayout, developerUIPanel, this]() {
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
if (developerUIOpen) {
|
||||
visualsLayout->setCurrentWidget(developerUIPanel);
|
||||
|
||||
@@ -439,18 +464,18 @@ void FrogPilotVisualsPanel::updateMetric(bool metric, bool bootRun) {
|
||||
FrogPilotParamValueControl *roadEdgesWidthToggle = static_cast<FrogPilotParamValueControl*>(toggles["RoadEdgesWidth"]);
|
||||
|
||||
if (metric) {
|
||||
laneLinesWidthToggle->setDescription(tr("The thickness of the lane lines on the driving screen.<br><br><b>Default matches the <b>MUTCD</b> lane line width standard of 10 centimeters."));
|
||||
pathWidthToggle->setDescription(tr("The width of the driving path on the driving screen.<br><br>Default <b>(1.9 meters)</b> matches the width of a <b>2019 Lexus ES 350</b>."));
|
||||
roadEdgesWidthToggle->setDescription(tr("The thickness of the road edges on the driving screen.<br><br><b>Default matches half of the <b>MUTCD</b> lane line width standard of 10 centimeters."));
|
||||
laneLinesWidthToggle->setDescription(tr("<b>Set the lane-line thickness.</b><br><br>Default matches the MUTCD lane-line width standard of 10 centimeters."));
|
||||
pathWidthToggle->setDescription(tr("<b>Set the driving-path width.</b><br><br>Default (1.9 meters) matches the width of a 2019 Lexus ES 350."));
|
||||
roadEdgesWidthToggle->setDescription(tr("<b>Set the road-edge thickness.</b><br><br>Default matches half of the MUTCD lane-line width standard of 10 centimeters."));
|
||||
|
||||
laneLinesWidthToggle->updateControl(0, 60, metricSmallDistanceLabels);
|
||||
roadEdgesWidthToggle->updateControl(0, 60, metricSmallDistanceLabels);
|
||||
|
||||
pathWidthToggle->updateControl(0, 3, metricDistanceLabels);
|
||||
} else {
|
||||
laneLinesWidthToggle->setDescription(tr("The thickness of the lane lines on the driving screen.<br><br><b>Default matches the <b>MUTCD</b> lane line width standard of 4 inches."));
|
||||
pathWidthToggle->setDescription(tr("The width of the driving path on the driving screen.<br><br>Default <b>(6.1 feet)</b> matches the width of a <b>2019 Lexus ES 350</b>."));
|
||||
roadEdgesWidthToggle->setDescription(tr("The thickness of the road edges on the driving screen.<br><br><b>Default matches half of the <b>MUTCD</b> lane line width standard of 4 inches."));
|
||||
laneLinesWidthToggle->setDescription(tr("<b>Set the lane-line thickness.</b><br><br>Default matches the MUTCD lane-line width standard of 4 inches."));
|
||||
pathWidthToggle->setDescription(tr("<b>Set the driving-path width.</b><br><br>Default (6.1 feet) matches the width of a 2019 Lexus ES 350."));
|
||||
roadEdgesWidthToggle->setDescription(tr("<b>Set the road-edge thickness.</b><br><br>Default matches half of the MUTCD lane-line width standard of 4 inches."));
|
||||
|
||||
laneLinesWidthToggle->updateControl(0, 24, imperialSmallDistanceLabels);
|
||||
roadEdgesWidthToggle->updateControl(0, 24, imperialSmallDistanceLabels);
|
||||
@@ -461,13 +486,13 @@ void FrogPilotVisualsPanel::updateMetric(bool metric, bool bootRun) {
|
||||
|
||||
void FrogPilotVisualsPanel::updateToggles() {
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
toggle->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.find(key) != parentKeys.end()) {
|
||||
if (parentKeys.contains(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -521,27 +546,29 @@ void FrogPilotVisualsPanel::updateToggles() {
|
||||
toggle->setVisible(setVisible);
|
||||
|
||||
if (setVisible) {
|
||||
if (advancedCustomOnroadUIKeys.find(key) != advancedCustomOnroadUIKeys.end()) {
|
||||
if (advancedCustomOnroadUIKeys.contains(key)) {
|
||||
toggles["AdvancedCustomUI"]->setVisible(true);
|
||||
} else if (customOnroadUIKeys.find(key) != customOnroadUIKeys.end()) {
|
||||
} else if (customOnroadUIKeys.contains(key)) {
|
||||
toggles["CustomUI"]->setVisible(true);
|
||||
} else if (developerMetricKeys.find(key) != developerMetricKeys.end()) {
|
||||
} else if (developerMetricKeys.contains(key)) {
|
||||
toggles["DeveloperMetrics"]->setVisible(true);
|
||||
} else if (developerUIKeys.find(key) != developerUIKeys.end()) {
|
||||
} else if (developerUIKeys.contains(key)) {
|
||||
toggles["DeveloperUI"]->setVisible(true);
|
||||
} else if (developerWidgetKeys.find(key) != developerWidgetKeys.end()) {
|
||||
} else if (developerWidgetKeys.contains(key)) {
|
||||
toggles["DeveloperWidgets"]->setVisible(true);
|
||||
} else if (modelUIKeys.find(key) != modelUIKeys.end()) {
|
||||
} else if (modelUIKeys.contains(key)) {
|
||||
toggles["ModelUI"]->setVisible(true);
|
||||
} else if (navigationUIKeys.find(key) != navigationUIKeys.end()) {
|
||||
} else if (navigationUIKeys.contains(key)) {
|
||||
toggles["NavigationUI"]->setVisible(true);
|
||||
} else if (qualityOfLifeKeys.find(key) != qualityOfLifeKeys.end()) {
|
||||
} else if (qualityOfLifeKeys.contains(key)) {
|
||||
toggles["QOLVisuals"]->setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
borderMetricsBtn->setVisibleButton(0, hasBSM);
|
||||
borderMetricsButton->setVisibleButton(0, hasBSM);
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "frogpilot/ui/qt/offroad/frogpilot_settings.h"
|
||||
|
||||
class FrogPilotVisualsPanel : public FrogPilotListWidget {
|
||||
@@ -22,6 +20,7 @@ private:
|
||||
void updateToggles();
|
||||
|
||||
bool developerUIOpen;
|
||||
bool forceOpenDescriptions;
|
||||
bool hasAutoTune;
|
||||
bool hasBSM;
|
||||
bool hasOpenpilotLongitudinal;
|
||||
@@ -31,23 +30,23 @@ private:
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
std::set<QString> advancedCustomOnroadUIKeys = {"HideAlerts", "HideLeadMarker", "HideMapIcon", "HideMaxSpeed", "HideSpeed", "HideSpeedLimit", "WheelSpeed"};
|
||||
std::set<QString> customOnroadUIKeys = {"AccelerationPath", "AdjacentPath", "BlindSpotPath", "Compass", "OnroadDistanceButton", "PedalsOnUI", "RotatingWheel"};
|
||||
std::set<QString> developerMetricKeys = {"AdjacentPathMetrics", "BorderMetrics", "FPSCounter", "LeadInfo", "NumericalTemp", "SidebarMetrics", "UseSI"};
|
||||
std::set<QString> developerSidebarKeys = {"DeveloperSidebarMetric1", "DeveloperSidebarMetric2", "DeveloperSidebarMetric3", "DeveloperSidebarMetric4", "DeveloperSidebarMetric5", "DeveloperSidebarMetric6", "DeveloperSidebarMetric7"};
|
||||
std::set<QString> developerUIKeys = {"DeveloperMetrics", "DeveloperSidebar", "DeveloperWidgets"};
|
||||
std::set<QString> developerWidgetKeys = {"AdjacentLeadsUI", "RadarTracksUI", "ShowStoppingPoint"};
|
||||
std::set<QString> modelUIKeys = {"DynamicPathWidth", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"};
|
||||
std::set<QString> navigationUIKeys = {"BigMap", "MapStyle", "RoadNameUI", "ShowSpeedLimits", "SLCMapboxFiller", "UseVienna"};
|
||||
std::set<QString> qualityOfLifeKeys = {"CameraView", "DriverCamera", "StandbyMode", "StoppedTimer"};
|
||||
QSet<QString> advancedCustomOnroadUIKeys = {"HideAlerts", "HideLeadMarker", "HideMapIcon", "HideMaxSpeed", "HideSpeed", "HideSpeedLimit", "WheelSpeed"};
|
||||
QSet<QString> customOnroadUIKeys = {"AccelerationPath", "AdjacentPath", "BlindSpotPath", "Compass", "OnroadDistanceButton", "PedalsOnUI", "RotatingWheel"};
|
||||
QSet<QString> developerMetricKeys = {"AdjacentPathMetrics", "BorderMetrics", "FPSCounter", "LeadInfo", "NumericalTemp", "SidebarMetrics", "UseSI"};
|
||||
QSet<QString> developerSidebarKeys = {"DeveloperSidebarMetric1", "DeveloperSidebarMetric2", "DeveloperSidebarMetric3", "DeveloperSidebarMetric4", "DeveloperSidebarMetric5", "DeveloperSidebarMetric6", "DeveloperSidebarMetric7"};
|
||||
QSet<QString> developerUIKeys = {"DeveloperMetrics", "DeveloperSidebar", "DeveloperWidgets"};
|
||||
QSet<QString> developerWidgetKeys = {"AdjacentLeadsUI", "RadarTracksUI", "ShowStoppingPoint"};
|
||||
QSet<QString> modelUIKeys = {"DynamicPathWidth", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"};
|
||||
QSet<QString> navigationUIKeys = {"BigMap", "MapStyle", "RoadNameUI", "ShowSpeedLimits", "SLCMapboxFiller", "UseVienna"};
|
||||
QSet<QString> qualityOfLifeKeys = {"CameraView", "DriverCamera", "StoppedTimer"};
|
||||
|
||||
std::set<QString> parentKeys;
|
||||
QSet<QString> parentKeys;
|
||||
|
||||
std::vector<QString> sidebarMetricsToggles;
|
||||
|
||||
FrogPilotButtonsControl *sidebarMetricsToggle;
|
||||
|
||||
FrogPilotButtonToggleControl *borderMetricsBtn;
|
||||
FrogPilotButtonToggleControl *borderMetricsButton;
|
||||
|
||||
FrogPilotSettingsWindow *parent;
|
||||
|
||||
|
||||
@@ -1,29 +1,38 @@
|
||||
#include "frogpilot/ui/qt/offroad/wheel_settings.h"
|
||||
|
||||
FrogPilotWheelPanel::FrogPilotWheelPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||
QString className = this->metaObject()->className();
|
||||
|
||||
if (!shownDescriptions.value(className).toBool(false)) {
|
||||
forceOpenDescriptions = true;
|
||||
shownDescriptions.insert(className, true);
|
||||
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
||||
}
|
||||
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> wheelToggles {
|
||||
{"DistanceButtonControl", tr("Distance Button"), tr("The action for a short press of the <b>Distance</b> button."), "../../frogpilot/assets/toggle_icons/icon_mute.png"},
|
||||
{"LongDistanceButtonControl", tr("Distance Button (Long Press)"), tr("The action for a 0.5+ second press of the <b>Distance</b> button."), "../../frogpilot/assets/toggle_icons/icon_mute.png"},
|
||||
{"VeryLongDistanceButtonControl", tr("Distance Button (Very Long Press)"), tr("The action for a 2.5+ second press of the <b>Distance</b> button."), "../../frogpilot/assets/toggle_icons/icon_mute.png"},
|
||||
{"LKASButtonControl", tr("LKAS Button"), tr("The action for pressing the <b>LKAS</b> button."), "../../frogpilot/assets/toggle_icons/icon_mute.png"}
|
||||
{"DistanceButtonControl", tr("Distance Button"), tr("<b>Action performed when the \"Distance\" button is pressed.</b>"), "../../frogpilot/assets/toggle_icons/icon_mute.png"},
|
||||
{"LongDistanceButtonControl", tr("Distance Button (Long Press)"), tr("<b>Action performed when the \"Distance\" button is pressed for more than 0.5 seconds.</b>"), "../../frogpilot/assets/toggle_icons/icon_mute.png"},
|
||||
{"VeryLongDistanceButtonControl", tr("Distance Button (Very Long Press)"), tr("<b>Action performed when the \"Distance\" button is pressed for more than 2.5 seconds.</b>"), "../../frogpilot/assets/toggle_icons/icon_mute.png"},
|
||||
{"LKASButtonControl", tr("LKAS Button"), tr("<b>Action performed when the \"LKAS\" button is pressed.</b>"), "../../frogpilot/assets/toggle_icons/icon_mute.png"}
|
||||
};
|
||||
|
||||
for (const auto &[param, title, desc, icon] : wheelToggles) {
|
||||
QMap<int, QString> functionsMap {
|
||||
{0, tr("Nothing")},
|
||||
{3, tr("Pause Lateral")}
|
||||
{0, tr("No Action")},
|
||||
{3, tr("Pause Steering")}
|
||||
};
|
||||
|
||||
QMap<int, QString> longitudinalFunctionsMap {
|
||||
{1, tr("Change \"Personality Profile\"")},
|
||||
{2, tr("Force openpilot to Coast")},
|
||||
{4, tr("Pause Longitudinal")},
|
||||
{4, tr("Pause Acceleration/Braking")},
|
||||
{5, tr("Toggle \"Experimental Mode\" On/Off")},
|
||||
{6, tr("Toggle \"Traffic Mode\" On/Off")}
|
||||
};
|
||||
|
||||
ButtonControl *wheelToggle = new ButtonControl(title, tr("SELECT"), desc);
|
||||
QObject::connect(wheelToggle, &ButtonControl::clicked, [this, functionsMap, longitudinalFunctionsMap, key = param, wheelToggle]() mutable {
|
||||
QObject::connect(wheelToggle, &ButtonControl::clicked, [functionsMap, longitudinalFunctionsMap, key = param, wheelToggle, this]() mutable {
|
||||
if (hasOpenpilotLongitudinal) {
|
||||
QMap<int, QString>::const_iterator it;
|
||||
for (it = longitudinalFunctionsMap.constBegin(); it != longitudinalFunctionsMap.constEnd(); ++it) {
|
||||
@@ -49,10 +58,15 @@ FrogPilotWheelPanel::FrogPilotWheelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
|
||||
addItem(wheelToggle);
|
||||
|
||||
QObject::connect(wheelToggle, &AbstractControl::hideDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
QObject::connect(wheelToggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
}
|
||||
|
||||
void FrogPilotWheelPanel::showEvent(QShowEvent *event) {
|
||||
@@ -76,5 +90,7 @@ void FrogPilotWheelPanel::updateToggles() {
|
||||
toggle->setVisible(setVisible);
|
||||
}
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ protected:
|
||||
private:
|
||||
void updateToggles();
|
||||
|
||||
bool forceOpenDescriptions;
|
||||
bool hasOpenpilotLongitudinal;
|
||||
bool isSubaru;
|
||||
|
||||
|
||||
@@ -6,14 +6,9 @@ FrogPilotAnnotatedCameraWidget::FrogPilotAnnotatedCameraWidget(QWidget *parent)
|
||||
animationTimer = new QTimer(this);
|
||||
|
||||
brakePedalImg = loadPixmap("../../frogpilot/assets/other_images/brake_pedal.png", {btn_size, btn_size});
|
||||
chillModeIcon = loadPixmap("../../frogpilot/assets/other_images/chill_mode_icon.png", {btn_size / 2, btn_size / 2});
|
||||
curveIcon = loadPixmap("../../frogpilot/assets/other_images/curve_icon.png", {btn_size / 2, btn_size / 2});
|
||||
curveSpeedIcon = loadPixmap("../../frogpilot/assets/other_images/curve_speed_left.png", {btn_size, btn_size});
|
||||
curveSpeedIcon = loadPixmap("../../frogpilot/assets/other_images/curve_speed.png", {btn_size, btn_size});
|
||||
dashboardIcon = loadPixmap("../../frogpilot/assets/other_images/dashboard_icon.png", {btn_size / 2, btn_size / 2});
|
||||
experimentalModeIcon = loadPixmap("../assets/img_experimental.svg", {btn_size / 2, btn_size / 2});
|
||||
gasPedalImg = loadPixmap("../../frogpilot/assets/other_images/gas_pedal.png", {btn_size, btn_size});
|
||||
leadIcon = loadPixmap("../../frogpilot/assets/other_images/lead_icon.png", {btn_size / 2, btn_size / 2});
|
||||
lightIcon = loadPixmap("../../frogpilot/assets/other_images/light_icon.png", {btn_size / 2, btn_size / 2});
|
||||
mapDataIcon = loadPixmap("../../frogpilot/assets/other_images/offline_maps_icon.png", {btn_size / 2, btn_size / 2});
|
||||
navigationIcon = loadPixmap("../../frogpilot/assets/other_images/navigation_icon.png", {btn_size / 2, btn_size / 2});
|
||||
nextMapsIcon = loadPixmap("../../frogpilot/assets/other_images/next_maps_icon.png", {btn_size / 2, btn_size / 2});
|
||||
@@ -22,12 +17,26 @@ FrogPilotAnnotatedCameraWidget::FrogPilotAnnotatedCameraWidget(QWidget *parent)
|
||||
stopSignImg = loadPixmap("../../frogpilot/assets/other_images/stop_sign.png", {btn_size, btn_size});
|
||||
turnIcon = loadPixmap("../../frogpilot/assets/other_images/turn_icon.png", {btn_size / 2, btn_size / 2});
|
||||
|
||||
loadGif("../../frogpilot/assets/other_images/curve_icon.gif", cemCurveIcon, QSize(btn_size / 2, btn_size / 2), this);
|
||||
loadGif("../../frogpilot/assets/other_images/lead_icon.gif", cemLeadIcon, QSize(btn_size / 2, btn_size / 2), this);
|
||||
loadGif("../../frogpilot/assets/other_images/speed_icon.gif", cemSpeedIcon, QSize(btn_size / 2, btn_size / 2), this);
|
||||
loadGif("../../frogpilot/assets/other_images/light_icon.gif", cemStopIcon, QSize(btn_size / 2, btn_size / 2), this);
|
||||
loadGif("../../frogpilot/assets/other_images/turn_icon.gif", cemTurnIcon, QSize(btn_size / 2, btn_size / 2), this);
|
||||
loadGif("../../frogpilot/assets/other_images/chill_mode_icon.gif", chillModeIcon, QSize(btn_size / 2, btn_size / 2), this);
|
||||
loadGif("../../frogpilot/assets/other_images/experimental_mode_icon.gif", experimentalModeIcon, QSize(btn_size / 2, btn_size / 2), this);
|
||||
|
||||
QObject::connect(animationTimer, &QTimer::timeout, [this] {
|
||||
animationFrameIndex = (animationFrameIndex + 1) % totalFrames;
|
||||
});
|
||||
QObject::connect(frogpilotUIState(), &FrogPilotUIState::themeUpdated, this, &FrogPilotAnnotatedCameraWidget::updateSignals);
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, [this] {
|
||||
standstillTimer.invalidate();
|
||||
|
||||
QJsonObject stats = QJsonDocument::fromJson(QString::fromStdString(params.get("FrogPilotStats")).toUtf8()).object();
|
||||
stats["FrogHops"] = stats.value("FrogHops").toInt(0) + frogHopCount;
|
||||
params.putNonBlocking("FrogPilotStats", QJsonDocument(stats).toJson(QJsonDocument::Compact).toStdString());
|
||||
|
||||
frogHopCount = 0;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -59,13 +68,13 @@ void FrogPilotAnnotatedCameraWidget::showEvent(QShowEvent *event) {
|
||||
}
|
||||
|
||||
void FrogPilotAnnotatedCameraWidget::updateSignals() {
|
||||
blindspotImages.clear();
|
||||
signalImages.clear();
|
||||
QVector<QPixmap>().swap(blindspotImages);
|
||||
QVector<QPixmap>().swap(signalImages);
|
||||
|
||||
bool isGif = false;
|
||||
|
||||
QFileInfoList files = QDir("../../frogpilot/assets/active_theme/signals/").entryInfoList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
|
||||
for (QFileInfo &fileInfo : files) {
|
||||
for (const QFileInfo &fileInfo : files) {
|
||||
QString fileName = fileInfo.fileName();
|
||||
QString filePath = fileInfo.absoluteFilePath();
|
||||
|
||||
@@ -73,15 +82,16 @@ void FrogPilotAnnotatedCameraWidget::updateSignals() {
|
||||
isGif = true;
|
||||
|
||||
QMovie movie(filePath);
|
||||
movie.setCacheMode(QMovie::CacheAll);
|
||||
movie.setCacheMode(QMovie::CacheNone);
|
||||
movie.start();
|
||||
|
||||
int frameCount = movie.frameCount();
|
||||
signalImages.reserve(frameCount);
|
||||
|
||||
for (int i = 0; i < frameCount; ++i) {
|
||||
movie.jumpToFrame(i);
|
||||
|
||||
QImage image = movie.currentPixmap().toImage().convertToFormat(QImage::Format_Indexed8);
|
||||
|
||||
QPixmap frame = QPixmap::fromImage(image);
|
||||
signalImages.append(frame);
|
||||
}
|
||||
@@ -106,7 +116,7 @@ void FrogPilotAnnotatedCameraWidget::updateSignals() {
|
||||
totalFrames = signalImages.size();
|
||||
|
||||
if (isGif && signalStyle == "traditional") {
|
||||
signalMovement = (width() + (signalWidth * 2)) / totalFrames;
|
||||
signalMovement = (width() + signalWidth * 2) / totalFrames;
|
||||
|
||||
signalStyle = "traditional_gif";
|
||||
} else {
|
||||
@@ -131,9 +141,8 @@ void FrogPilotAnnotatedCameraWidget::updateState(const FrogPilotUIState &fs, con
|
||||
|
||||
float speedLimitOffset = frogpilotPlan.getSlcSpeedLimitOffset() * speedConversion;
|
||||
|
||||
mtscSpeedStr = (frogpilotPlan.getMtscSpeed() != 0) ? QString::number(std::nearbyint(fmin(speed, frogpilotPlan.getMtscSpeed() * speedConversion))) + speedUnit : "–";
|
||||
cscSpeedStr = QString::number(std::nearbyint(fmin(speed, frogpilotPlan.getCscSpeed() * speedConversion))) + speedUnit;
|
||||
speedLimitOffsetStr = (speedLimitOffset != 0) ? QString::number(speedLimitOffset, 'f', 0).prepend((speedLimitOffset > 0) ? "+" : "-") : "–";
|
||||
vtscSpeedStr = (frogpilotPlan.getVtscSpeed() != 0) ? QString::number(std::nearbyint(fmin(speed, frogpilotPlan.getVtscSpeed() * speedConversion))) + speedUnit : "–";
|
||||
|
||||
if (frogpilot_scene.standstill && frogpilot_toggles.value("stopped_timer").toBool()) {
|
||||
if (!standstillTimer.isValid()) {
|
||||
@@ -147,6 +156,12 @@ void FrogPilotAnnotatedCameraWidget::updateState(const FrogPilotUIState &fs, con
|
||||
standstillTimer.invalidate();
|
||||
}
|
||||
|
||||
static int lastFrameIndex;
|
||||
if (lastFrameIndex > animationFrameIndex && frogpilot_toggles.value("signal_icons").toString() == "frog") {
|
||||
frogHopCount++;
|
||||
}
|
||||
lastFrameIndex = animationFrameIndex;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -161,7 +176,7 @@ void FrogPilotAnnotatedCameraWidget::paintFrogPilotWidgets(QPainter &p, UIState
|
||||
const cereal::ModelDataV2::Reader &model = sm["modelV2"].getModelV2();
|
||||
|
||||
if (!hideBottomIcons && frogpilot_toggles.value("cem_status").toBool()) {
|
||||
paintCEMStatus(p, frogpilot_scene, sm);
|
||||
paintCEMStatus(p, frogpilotPlan, frogpilot_scene, sm);
|
||||
} else {
|
||||
cemStatusPosition.setX(0);
|
||||
cemStatusPosition.setY(0);
|
||||
@@ -169,10 +184,23 @@ void FrogPilotAnnotatedCameraWidget::paintFrogPilotWidgets(QPainter &p, UIState
|
||||
|
||||
if (!frogpilot_scene.map_open && !hideBottomIcons && frogpilot_toggles.value("compass").toBool()) {
|
||||
paintCompass(p, frogpilot_toggles);
|
||||
} else {
|
||||
compassPosition.setX(0);
|
||||
compassPosition.setY(0);
|
||||
}
|
||||
|
||||
if (!frogpilot_scene.map_open && !frogpilotPlan.getSpeedLimitChanged() && !(signalStyle == "static" && carState.getLeftBlinker()) && frogpilot_toggles.value("csc_status").toBool()) {
|
||||
paintCurveSpeedControl(p, frogpilotPlan, frogpilot_toggles);
|
||||
if (frogpilotPlan.getCscTraining()) {
|
||||
paintSmartControllerTraining(p, frogpilotPlan);
|
||||
} else {
|
||||
glowTimer.invalidate();
|
||||
|
||||
if (isCruiseSet && frogpilotPlan.getCscControllingSpeed()) {
|
||||
paintCurveSpeedControl(p, frogpilotPlan);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
glowTimer.invalidate();
|
||||
}
|
||||
|
||||
if (!frogpilot_scene.map_open && frogpilotCarState.getPauseLateral() && !hideBottomIcons) {
|
||||
@@ -227,7 +255,7 @@ void FrogPilotAnnotatedCameraWidget::paintFrogPilotWidgets(QPainter &p, UIState
|
||||
}
|
||||
|
||||
void FrogPilotAnnotatedCameraWidget::paintAdjacentPaths(QPainter &p, const cereal::CarState::Reader &carState, const FrogPilotUIScene &frogpilot_scene, const QJsonObject &frogpilot_toggles) {
|
||||
std::function<void(bool, float, float, const QPolygonF &)> drawAdjacentPath = [this, &p, &frogpilot_toggles](bool isBlindSpot, float width, float requirement, const QPolygonF &polygon) {
|
||||
std::function<void(bool, float, float, const QPolygonF &)> drawAdjacentPath = [&p, &frogpilot_toggles, this](bool isBlindSpot, float width, float requirement, const QPolygonF &polygon) {
|
||||
QLinearGradient gradient(0, height(), 0, 0);
|
||||
if (isBlindSpot && frogpilot_toggles.value("blind_spot_path").toBool()) {
|
||||
gradient.setColorAt(0.0f, QColor::fromHslF(0 / 360.0f, 0.75f, 0.5f, 0.6f));
|
||||
@@ -246,7 +274,7 @@ void FrogPilotAnnotatedCameraWidget::paintAdjacentPaths(QPainter &p, const cerea
|
||||
p.drawPolygon(polygon);
|
||||
};
|
||||
|
||||
std::function<void(bool, float, const QPolygonF &)> drawAdjacentPathMetric = [this, &p, &frogpilot_toggles](bool isBlindSpot, float width, const QPolygonF &polygon) {
|
||||
std::function<void(bool, float, const QPolygonF &)> drawAdjacentPathMetric = [&p, &frogpilot_toggles, this](bool isBlindSpot, float width, const QPolygonF &polygon) {
|
||||
QString text = isBlindSpot && frogpilot_toggles.value("blind_spot_path").toBool() ? tr("Vehicle in blind spot") : QString::number(width * distanceConversion, 'f', 2) + leadDistanceUnit;
|
||||
|
||||
p.setFont(InterFont(40, QFont::DemiBold));
|
||||
@@ -298,7 +326,7 @@ void FrogPilotAnnotatedCameraWidget::paintBlindSpotPath(QPainter &p, const cerea
|
||||
p.restore();
|
||||
}
|
||||
|
||||
void FrogPilotAnnotatedCameraWidget::paintCEMStatus(QPainter &p, FrogPilotUIScene &frogpilot_scene, SubMaster &sm) {
|
||||
void FrogPilotAnnotatedCameraWidget::paintCEMStatus(QPainter &p, const cereal::FrogPilotPlan::Reader &frogpilotPlan, FrogPilotUIScene &frogpilot_scene, SubMaster &sm) {
|
||||
if (dmIconPosition == QPoint(0, 0)) {
|
||||
return;
|
||||
}
|
||||
@@ -321,29 +349,27 @@ void FrogPilotAnnotatedCameraWidget::paintCEMStatus(QPainter &p, FrogPilotUIScen
|
||||
}
|
||||
p.drawRoundedRect(cemWidget, 24, 24);
|
||||
|
||||
QPixmap iconToDraw;
|
||||
QSharedPointer<QMovie> icon = chillModeIcon;
|
||||
if (frogpilot_scene.enabled && sm["controlsState"].getControlsState().getExperimentalMode()) {
|
||||
if (frogpilot_scene.conditional_status == 1) {
|
||||
iconToDraw = chillModeIcon;
|
||||
icon = chillModeIcon;
|
||||
} else if (frogpilot_scene.conditional_status == 2) {
|
||||
iconToDraw = experimentalModeIcon;
|
||||
icon = experimentalModeIcon;
|
||||
} else if (frogpilot_scene.conditional_status == 3 || frogpilot_scene.conditional_status == 4) {
|
||||
iconToDraw = speedIcon;
|
||||
icon = cemSpeedIcon;
|
||||
} else if (frogpilot_scene.conditional_status == 5 || frogpilot_scene.conditional_status == 7) {
|
||||
iconToDraw = turnIcon;
|
||||
icon = cemTurnIcon;
|
||||
} else if (frogpilot_scene.conditional_status == 6 || frogpilot_scene.conditional_status == 11 || frogpilot_scene.conditional_status == 12) {
|
||||
iconToDraw = lightIcon;
|
||||
icon = cemStopIcon;
|
||||
} else if (frogpilot_scene.conditional_status == 8) {
|
||||
iconToDraw = curveIcon;
|
||||
icon = cemCurveIcon;
|
||||
} else if (frogpilot_scene.conditional_status == 9 || frogpilot_scene.conditional_status == 10) {
|
||||
iconToDraw = leadIcon;
|
||||
icon = cemLeadIcon;
|
||||
} else {
|
||||
iconToDraw = experimentalModeIcon;
|
||||
icon = experimentalModeIcon;
|
||||
}
|
||||
} else {
|
||||
iconToDraw = chillModeIcon;
|
||||
}
|
||||
p.drawPixmap(cemWidget, iconToDraw);
|
||||
p.drawPixmap(cemWidget, icon->currentPixmap());
|
||||
|
||||
p.restore();
|
||||
}
|
||||
@@ -351,17 +377,17 @@ void FrogPilotAnnotatedCameraWidget::paintCEMStatus(QPainter &p, FrogPilotUIScen
|
||||
void FrogPilotAnnotatedCameraWidget::paintCompass(QPainter &p, QJsonObject &frogpilot_toggles) {
|
||||
p.save();
|
||||
|
||||
int x_position = rightHandDM ? UI_BORDER_SIZE + widget_size / 2 : width() - UI_BORDER_SIZE - btn_size;
|
||||
compassPosition.rx() = rightHandDM ? UI_BORDER_SIZE + widget_size / 2 : width() - UI_BORDER_SIZE - btn_size;
|
||||
if (mapButtonVisible) {
|
||||
if (rightHandDM) {
|
||||
x_position += btn_size - UI_BORDER_SIZE;
|
||||
compassPosition.rx() += btn_size - UI_BORDER_SIZE;
|
||||
} else {
|
||||
x_position -= btn_size + UI_BORDER_SIZE;
|
||||
compassPosition.rx() -= btn_size + UI_BORDER_SIZE;
|
||||
}
|
||||
}
|
||||
int y_position = dmIconPosition.y() - widget_size / 2;
|
||||
compassPosition.ry() = dmIconPosition.y() - widget_size / 2;
|
||||
|
||||
QRect compassWidget(QPoint(x_position, y_position), QSize(widget_size, widget_size));
|
||||
QRect compassWidget(compassPosition, QSize(widget_size, widget_size));
|
||||
|
||||
p.setBrush(blackColor(166));
|
||||
p.setPen(QPen(blackColor(), 10));
|
||||
@@ -441,56 +467,28 @@ void FrogPilotAnnotatedCameraWidget::paintCompass(QPainter &p, QJsonObject &frog
|
||||
p.restore();
|
||||
}
|
||||
|
||||
void FrogPilotAnnotatedCameraWidget::paintCurveSpeedControl(QPainter &p, const cereal::FrogPilotPlan::Reader &frogpilotPlan, QJsonObject &frogpilot_toggles) {
|
||||
void FrogPilotAnnotatedCameraWidget::paintCurveSpeedControl(QPainter &p, const cereal::FrogPilotPlan::Reader &frogpilotPlan) {
|
||||
p.save();
|
||||
|
||||
std::function<void(QRect&, const QString&, bool)> drawCurveSpeedControl = [&](QRect &rect, const QString &speedStr, bool isMtsc) {
|
||||
if (isMtsc && !frogpilotPlan.getVtscControllingCurve()) {
|
||||
p.setPen(QPen(greenColor(), 10));
|
||||
p.setBrush(greenColor(166));
|
||||
p.setFont(InterFont(45, QFont::Bold));
|
||||
} else if (!isMtsc && frogpilotPlan.getVtscControllingCurve()) {
|
||||
p.setPen(QPen(redColor(), 10));
|
||||
p.setBrush(redColor(166));
|
||||
p.setFont(InterFont(45, QFont::Bold));
|
||||
} else {
|
||||
p.setPen(QPen(blackColor(), 10));
|
||||
p.setBrush(blackColor(166));
|
||||
p.setFont(InterFont(35, QFont::DemiBold));
|
||||
}
|
||||
|
||||
p.drawRoundedRect(rect, 24, 24);
|
||||
|
||||
p.setPen(QPen(whiteColor(), 6));
|
||||
p.drawText(rect.adjusted(20, 0, 0, 0), Qt::AlignVCenter | Qt::AlignLeft, speedStr);
|
||||
};
|
||||
|
||||
QRect curveSpeedRect(QPoint(setSpeedRect.right() + UI_BORDER_SIZE, setSpeedRect.top()), QSize(defaultSize.width() * 1.25, defaultSize.width() * 1.25));
|
||||
QPixmap scaledCurveSpeedIcon = (frogpilotPlan.getRoadCurvature() < 0 ? curveSpeedIcon : curveSpeedIcon.transformed(QTransform().scale(-1, 1))).scaled(curveSpeedRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
QPixmap curveSpeedImage = frogpilotPlan.getRoadCurvature() < 0 ? curveSpeedIcon : curveSpeedIcon.transformed(QTransform().scale(-1, 1));
|
||||
QSize curveSpeedSize = curveSpeedImage.size();
|
||||
QPoint curveSpeedPoint(curveSpeedRect.x() + (curveSpeedRect.width() - curveSpeedSize.width()) / 2, curveSpeedRect.y() + (curveSpeedRect.height() - curveSpeedSize.height()) / 2);
|
||||
|
||||
p.setOpacity(1.0);
|
||||
|
||||
if (frogpilotPlan.getVCruise() == frogpilotPlan.getMtscSpeed() && setSpeed - frogpilotPlan.getMtscSpeed() > 1 && frogpilot_toggles.value("map_turn_speed_controller").toBool()) {
|
||||
QRect mtscRect(curveSpeedRect.topLeft() + QPoint(0, curveSpeedRect.height() + 10), QSize(curveSpeedRect.width(), frogpilotPlan.getVtscControllingCurve() ? 50 : 100));
|
||||
drawCurveSpeedControl(mtscRect, mtscSpeedStr, true);
|
||||
QRect cscRect(curveSpeedRect.topLeft() + QPoint(0, curveSpeedRect.height() + 10), QSize(curveSpeedRect.width(), 100));
|
||||
|
||||
if (frogpilot_toggles.value("vision_turn_speed_controller").toBool()) {
|
||||
QRect vtscRect(mtscRect.topLeft() + QPoint(0, mtscRect.height() + 20), QSize(mtscRect.width(), frogpilotPlan.getVtscControllingCurve() ? 100 : 50));
|
||||
drawCurveSpeedControl(vtscRect, vtscSpeedStr, false);
|
||||
}
|
||||
p.setBrush(blueColor(166));
|
||||
p.setFont(InterFont(45, QFont::Bold));
|
||||
p.setPen(QPen(blueColor(), 10));
|
||||
|
||||
p.drawPixmap(curveSpeedRect, scaledCurveSpeedIcon);
|
||||
} else if (frogpilotPlan.getVCruise() == frogpilotPlan.getVtscSpeed() && setSpeed - frogpilotPlan.getVtscSpeed() > 1 && frogpilot_toggles.value("vision_turn_speed_controller").toBool()) {
|
||||
QRect vtscRect(curveSpeedRect.topLeft() + QPoint(0, curveSpeedRect.height() + 10), QSize(curveSpeedRect.width(), frogpilotPlan.getVtscControllingCurve() ? 100 : 50));
|
||||
drawCurveSpeedControl(vtscRect, vtscSpeedStr, false);
|
||||
p.drawRoundedRect(cscRect, 24, 24);
|
||||
p.setPen(QPen(whiteColor(), 6));
|
||||
p.drawText(cscRect.adjusted(20, 0, 0, 0), Qt::AlignVCenter | Qt::AlignLeft, cscSpeedStr);
|
||||
|
||||
if (frogpilot_toggles.value("map_turn_speed_controller").toBool()) {
|
||||
QRect mtscRect(vtscRect.topLeft() + QPoint(0, vtscRect.height() + 20), QSize(vtscRect.width(), frogpilotPlan.getVtscControllingCurve() ? 50 : 100));
|
||||
drawCurveSpeedControl(mtscRect, mtscSpeedStr, true);
|
||||
}
|
||||
|
||||
p.drawPixmap(curveSpeedRect, scaledCurveSpeedIcon);
|
||||
}
|
||||
p.drawPixmap(curveSpeedPoint, curveSpeedImage);
|
||||
|
||||
p.restore();
|
||||
}
|
||||
@@ -545,7 +543,7 @@ void FrogPilotAnnotatedCameraWidget::paintLeadMetrics(QPainter &p, bool adjacent
|
||||
.arg(QString("Desired: %1").arg(frogpilotPlan.getDesiredFollowDistance() * distanceConversion))
|
||||
.arg(qRound(leadSpeed * speedConversionMetrics))
|
||||
.arg(leadSpeedUnit)
|
||||
.arg(QString::number(std::max(leadDistance / std::max(speed / speedConversion, 1.0f), 1.0f), 'f', 2))
|
||||
.arg(QString::number(leadDistance / std::max(speed / speedConversion, 1.0f), 'f', 2))
|
||||
.arg("s");
|
||||
}
|
||||
|
||||
@@ -772,6 +770,46 @@ void FrogPilotAnnotatedCameraWidget::paintRoadName(QPainter &p) {
|
||||
p.restore();
|
||||
}
|
||||
|
||||
void FrogPilotAnnotatedCameraWidget::paintSmartControllerTraining(QPainter &p, const cereal::FrogPilotPlan::Reader &frogpilotPlan) {
|
||||
p.save();
|
||||
|
||||
if (!glowTimer.isValid()) {
|
||||
glowTimer.start();
|
||||
}
|
||||
|
||||
QRect curveSpeedRect(QPoint(setSpeedRect.right() + UI_BORDER_SIZE, setSpeedRect.top()), QSize(defaultSize.width() * 1.25, defaultSize.width() * 1.25));
|
||||
QPixmap curveSpeedImage = frogpilotPlan.getRoadCurvature() < 0 ? curveSpeedIcon : curveSpeedIcon.transformed(QTransform().scale(-1, 1));
|
||||
|
||||
qreal phase = (glowTimer.elapsed() % 2000) / 2000.0 * 2 * M_PI;
|
||||
qreal alphaFactor = 0.5 + 0.5 * sin(phase);
|
||||
|
||||
QColor glowColor = blueColor();
|
||||
glowColor.setAlphaF(0.3 + 0.7 * alphaFactor);
|
||||
|
||||
int glowWidth = 8 + static_cast<int>(2 * alphaFactor);
|
||||
|
||||
p.setOpacity(1.0);
|
||||
|
||||
p.setBrush(blackColor(166));
|
||||
p.setPen(QPen(glowColor, glowWidth));
|
||||
p.drawRoundedRect(curveSpeedRect, 24, 24);
|
||||
|
||||
QSize curveSpeedSize = curveSpeedImage.size();
|
||||
QPoint curveSpeedPoint(curveSpeedRect.x() + (curveSpeedRect.width() - curveSpeedSize.width()) / 2, curveSpeedRect.y() + (curveSpeedRect.height() - curveSpeedSize.height()) / 2);
|
||||
p.drawPixmap(curveSpeedPoint, curveSpeedImage);
|
||||
|
||||
QRect textRect(curveSpeedRect.topLeft() + QPoint(0, curveSpeedRect.height() + 10), QSize(curveSpeedRect.width(), 50));
|
||||
p.setBrush(blackColor(166));
|
||||
p.setPen(QPen(blackColor(), 10));
|
||||
p.drawRoundedRect(textRect, 24, 24);
|
||||
|
||||
p.setFont(InterFont(35, QFont::Bold));
|
||||
p.setPen(QPen(whiteColor(), 6));
|
||||
p.drawText(textRect.adjusted(20, 0, 0, 0), Qt::AlignVCenter | Qt::AlignLeft, "Training...");
|
||||
|
||||
p.restore();
|
||||
}
|
||||
|
||||
void FrogPilotAnnotatedCameraWidget::paintSpeedLimitSources(QPainter &p, const cereal::FrogPilotCarState::Reader &frogpilotCarState, const cereal::FrogPilotNavigation::Reader &frogpilotNavigation, const cereal::FrogPilotPlan::Reader &frogpilotPlan) {
|
||||
p.save();
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "selfdrive/ui/qt/onroad/buttons.h"
|
||||
#include "selfdrive/ui/qt/widgets/cameraview.h"
|
||||
|
||||
@@ -28,6 +31,7 @@ public:
|
||||
bool viennaSpeedLimit;
|
||||
|
||||
int alertHeight;
|
||||
int frogHopCount;
|
||||
int signMargin;
|
||||
int standstillDuration;
|
||||
|
||||
@@ -61,15 +65,16 @@ protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
private:
|
||||
void paintCEMStatus(QPainter &p, FrogPilotUIScene &frogpilot_scene, SubMaster &sm);
|
||||
void paintCEMStatus(QPainter &p, const cereal::FrogPilotPlan::Reader &frogpilotPlan, FrogPilotUIScene &frogpilot_scene, SubMaster &sm);
|
||||
void paintCompass(QPainter &p, QJsonObject &frogpilot_toggles);
|
||||
void paintCurveSpeedControl(QPainter &p, const cereal::FrogPilotPlan::Reader &frogpilotPlan, QJsonObject &frogpilot_toggles);
|
||||
void paintCurveSpeedControl(QPainter &p, const cereal::FrogPilotPlan::Reader &frogpilotPlan);
|
||||
void paintLateralPaused(QPainter &p, FrogPilotUIScene &frogpilot_scene);
|
||||
void paintLongitudinalPaused(QPainter &p, FrogPilotUIScene &frogpilot_scene);
|
||||
void paintPedalIcons(QPainter &p, const cereal::CarState::Reader &carState, const cereal::FrogPilotCarState::Reader &frogpilotCarState, FrogPilotUIScene &frogpilot_scene, QJsonObject &frogpilot_toggles);
|
||||
void paintPendingSpeedLimit(QPainter &p, const cereal::FrogPilotPlan::Reader &frogpilotPlan);
|
||||
void paintRadarTracks(QPainter &p, const cereal::ModelDataV2::Reader &model, UIState &s, FrogPilotUIScene &frogpilot_scene, SubMaster &sm, SubMaster &fpsm);
|
||||
void paintRoadName(QPainter &p);
|
||||
void paintSmartControllerTraining(QPainter &p, const cereal::FrogPilotPlan::Reader &frogpilotPlan);
|
||||
void paintSpeedLimitSources(QPainter &p, const cereal::FrogPilotCarState::Reader &frogpilotCarState, const cereal::FrogPilotNavigation::Reader &frogpilotNavigation, const cereal::FrogPilotPlan::Reader &frogpilotPlan);
|
||||
void paintStandstillTimer(QPainter &p);
|
||||
void paintStoppingPoint(QPainter &p, UIScene &scene, FrogPilotUIScene &frogpilot_scene, QJsonObject &frogpilot_toggles);
|
||||
@@ -83,6 +88,7 @@ private:
|
||||
int signalWidth;
|
||||
int totalFrames;
|
||||
|
||||
Params params;
|
||||
Params params_memory{"/dev/shm/params"};
|
||||
|
||||
QColor blackColor(int alpha = 255) { return QColor(0, 0, 0, alpha); }
|
||||
@@ -90,18 +96,14 @@ private:
|
||||
QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); }
|
||||
QColor whiteColor(int alpha = 255) { return QColor(255, 255, 255, alpha); }
|
||||
|
||||
QElapsedTimer glowTimer;
|
||||
QElapsedTimer pendingLimitTimer;
|
||||
QElapsedTimer standstillTimer;
|
||||
|
||||
QPixmap brakePedalImg;
|
||||
QPixmap chillModeIcon;
|
||||
QPixmap curveIcon;
|
||||
QPixmap curveSpeedIcon;
|
||||
QPixmap dashboardIcon;
|
||||
QPixmap experimentalModeIcon;
|
||||
QPixmap gasPedalImg;
|
||||
QPixmap leadIcon;
|
||||
QPixmap lightIcon;
|
||||
QPixmap mapDataIcon;
|
||||
QPixmap navigationIcon;
|
||||
QPixmap nextMapsIcon;
|
||||
@@ -111,10 +113,18 @@ private:
|
||||
QPixmap turnIcon;
|
||||
|
||||
QPoint cemStatusPosition;
|
||||
QPoint compassPosition;
|
||||
QPoint lateralPausedPosition;
|
||||
|
||||
QString mtscSpeedStr;
|
||||
QString vtscSpeedStr;
|
||||
QSharedPointer<QMovie> cemCurveIcon;
|
||||
QSharedPointer<QMovie> cemLeadIcon;
|
||||
QSharedPointer<QMovie> cemSpeedIcon;
|
||||
QSharedPointer<QMovie> cemStopIcon;
|
||||
QSharedPointer<QMovie> cemTurnIcon;
|
||||
QSharedPointer<QMovie> chillModeIcon;
|
||||
QSharedPointer<QMovie> experimentalModeIcon;
|
||||
|
||||
QString cscSpeedStr;
|
||||
|
||||
QTimer *animationTimer;
|
||||
|
||||
|
||||
@@ -83,9 +83,8 @@ void FrogPilotOnroadWindow::paintFPS(QPainter &p, const QRect &rect) {
|
||||
totalFPS += fps;
|
||||
|
||||
while (!fpsHistory.isEmpty() && now - fpsHistory.first().first > 60000) {
|
||||
fpsHistory.removeFirst();
|
||||
|
||||
totalFPS -= fpsHistory.first().second;
|
||||
fpsHistory.removeFirst();
|
||||
}
|
||||
|
||||
double avgFPS = fpsHistory.isEmpty() ? 0.0 : totalFPS / fpsHistory.size();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "selfdrive/ui/qt/request_repeater.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
#include "frogpilot/ui/qt/widgets/drive_stats.h"
|
||||
|
||||
@@ -10,8 +9,8 @@ static QLabel *newLabel(const QString &text, const QString &type) {
|
||||
}
|
||||
|
||||
DriveStats::DriveStats(QWidget *parent) : QFrame(parent) {
|
||||
isMetric = params.getBool("IsMetric");
|
||||
konik = useKonikServer();
|
||||
metric = params.getBool("IsMetric");
|
||||
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
||||
main_layout->setContentsMargins(50, 25, 50, 20);
|
||||
@@ -33,13 +32,19 @@ DriveStats::DriveStats(QWidget *parent) : QFrame(parent) {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
QLabel[type="title"] { font-size: 50px; font-weight: 500; }
|
||||
QLabel[type="frogpilot_title"] { font-size: 50px; font-weight: 500; color: #178643; }
|
||||
QLabel[type="number"] { font-size: 65px; font-weight: 400; }
|
||||
QLabel[type="title"] { font-size: 50px; font-weight: 500; }
|
||||
QLabel[type="unit"] { font-size: 50px; font-weight: 300; color: #A0A0A0; }
|
||||
)");
|
||||
}
|
||||
|
||||
void DriveStats::showEvent(QShowEvent *event) {
|
||||
isMetric = params.getBool("IsMetric");
|
||||
|
||||
updateStats();
|
||||
}
|
||||
|
||||
void DriveStats::addStatsLayouts(const QString &title, StatsLabels &labels, bool FrogPilot) {
|
||||
QGridLayout *grid_layout = new QGridLayout;
|
||||
grid_layout->setVerticalSpacing(10);
|
||||
@@ -54,7 +59,7 @@ void DriveStats::addStatsLayouts(const QString &title, StatsLabels &labels, bool
|
||||
grid_layout->addWidget(labels.hours = newLabel("0", "number"), row, 2, Qt::AlignLeft);
|
||||
|
||||
grid_layout->addWidget(newLabel(tr("Drives"), "unit"), row + 1, 0, Qt::AlignLeft);
|
||||
grid_layout->addWidget(labels.distance_unit = newLabel(getDistanceUnit(), "unit"), row + 1, 1, Qt::AlignLeft);
|
||||
grid_layout->addWidget(labels.distance_unit = newLabel(isMetric ? tr("KM") : tr("Miles"), "unit"), row + 1, 1, Qt::AlignLeft);
|
||||
grid_layout->addWidget(newLabel(tr("Hours"), "unit"), row + 1, 2, Qt::AlignLeft);
|
||||
|
||||
QVBoxLayout *main_layout = static_cast<QVBoxLayout *>(layout());
|
||||
@@ -62,31 +67,6 @@ void DriveStats::addStatsLayouts(const QString &title, StatsLabels &labels, bool
|
||||
main_layout->addStretch(1);
|
||||
}
|
||||
|
||||
void DriveStats::updateStatsForLabel(const QJsonObject &obj, StatsLabels &labels) {
|
||||
labels.routes->setText(QString::number((int)obj["routes"].toDouble()));
|
||||
labels.distance->setText(QString::number(int(obj["distance"].toDouble() * (metric ? MILE_TO_KM : 1))));
|
||||
labels.distance_unit->setText(getDistanceUnit());
|
||||
labels.hours->setText(QString::number((int)(obj["minutes"].toDouble() / 60)));
|
||||
}
|
||||
|
||||
void DriveStats::updateFrogPilotStats(const QJsonObject &obj, StatsLabels &labels) {
|
||||
labels.routes->setText(QString::number(paramsTracking.getInt("FrogPilotDrives")));
|
||||
labels.distance->setText(QString::number(int(paramsTracking.getFloat("FrogPilotKilometers") * (metric ? 1 : KM_TO_MILE))));
|
||||
labels.distance_unit->setText(getDistanceUnit());
|
||||
labels.hours->setText(QString::number(int(paramsTracking.getFloat("FrogPilotMinutes") / 60)));
|
||||
}
|
||||
|
||||
void DriveStats::updateStats() {
|
||||
QJsonObject json = stats.object();
|
||||
|
||||
updateFrogPilotStats(json["frogpilot"].toObject(), frogPilot);
|
||||
updateStatsForLabel(json["all"].toObject(), all);
|
||||
updateStatsForLabel(json["week"].toObject(), week);
|
||||
|
||||
int all_time_minutes = (int)(json["all"].toObject()["minutes"].toDouble());
|
||||
params.put(konik ? "KonikMinutes" : "openpilotMinutes", QString::number(all_time_minutes).toStdString());
|
||||
}
|
||||
|
||||
void DriveStats::parseResponse(const QString &response, bool success) {
|
||||
if (!success) {
|
||||
return;
|
||||
@@ -101,8 +81,28 @@ void DriveStats::parseResponse(const QString &response, bool success) {
|
||||
updateStats();
|
||||
}
|
||||
|
||||
void DriveStats::showEvent(QShowEvent *event) {
|
||||
metric = params.getBool("IsMetric");
|
||||
void DriveStats::updateStatsForLabel(const QJsonObject &obj, StatsLabels &labels) {
|
||||
labels.distance->setText(QString::number(int(obj["distance"].toDouble() * (isMetric ? MILE_TO_KM : 1))));
|
||||
labels.distance_unit->setText(isMetric ? tr("KM") : tr("Miles"));
|
||||
labels.hours->setText(QString::number((int)(obj["minutes"].toDouble() / 60)));
|
||||
labels.routes->setText(QString::number((int)obj["routes"].toDouble()));
|
||||
}
|
||||
|
||||
updateStats();
|
||||
void DriveStats::updateFrogPilotStatsForLabel(StatsLabels &labels) {
|
||||
QJsonObject frogpilot_stats = QJsonDocument::fromJson(QString::fromStdString(params.get("FrogPilotStats")).toUtf8()).object();
|
||||
|
||||
labels.distance->setText(QString::number(int(frogpilot_stats.value("FrogPilotMeters").toDouble() * (isMetric ? 0.001 : METER_TO_MILE))));
|
||||
labels.distance_unit->setText(isMetric ? tr("KM") : tr("Miles"));
|
||||
labels.hours->setText(QString::number(int(frogpilot_stats.value("FrogPilotSeconds").toDouble() / (60 * 60))));
|
||||
labels.routes->setText(QString::number(frogpilot_stats.value("FrogPilotDrives").toInt()));
|
||||
}
|
||||
|
||||
void DriveStats::updateStats() {
|
||||
QJsonObject json = stats.object();
|
||||
|
||||
updateStatsForLabel(json["all"].toObject(), all);
|
||||
updateStatsForLabel(json["week"].toObject(), week);
|
||||
updateFrogPilotStatsForLabel(frogPilot);
|
||||
|
||||
params.put(konik ? "KonikMinutes" : "openpilotMinutes", QString::number((int)(json["all"].toObject()["minutes"].toDouble())).toStdString());
|
||||
}
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
#include "selfdrive/ui/ui.h"
|
||||
|
||||
struct StatsLabels {
|
||||
QLabel *distance;
|
||||
QLabel *distance_unit;
|
||||
QLabel *hours;
|
||||
QLabel *routes;
|
||||
};
|
||||
|
||||
class DriveStats : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -9,30 +16,22 @@ public:
|
||||
explicit DriveStats(QWidget *parent = 0);
|
||||
|
||||
private:
|
||||
inline QString getDistanceUnit() const { return metric ? tr("KM") : tr("Miles"); }
|
||||
|
||||
struct StatsLabels {
|
||||
QLabel *routes;
|
||||
QLabel *distance;
|
||||
QLabel *distance_unit;
|
||||
QLabel *hours;
|
||||
};
|
||||
|
||||
void addStatsLayouts(const QString &title, StatsLabels &labels, bool FrogPilot = false);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void updateStats();
|
||||
void updateStatsForLabel(const QJsonObject &obj, StatsLabels &labels);
|
||||
void updateFrogPilotStats(const QJsonObject &obj, StatsLabels &labels);
|
||||
void updateFrogPilotStatsForLabel(StatsLabels &labels);
|
||||
|
||||
bool isMetric;
|
||||
bool konik;
|
||||
|
||||
Params params;
|
||||
Params paramsTracking{"/cache/tracking"};
|
||||
|
||||
bool konik;
|
||||
bool metric;
|
||||
|
||||
QJsonDocument stats;
|
||||
|
||||
StatsLabels all, week, frogPilot;
|
||||
StatsLabels all;
|
||||
StatsLabels frogPilot;
|
||||
StatsLabels week;
|
||||
|
||||
private slots:
|
||||
void parseResponse(const QString &response, bool success);
|
||||
|
||||
@@ -24,48 +24,54 @@ bool useKonikServer() {
|
||||
void loadGif(const QString &gifPath, QSharedPointer<QMovie> &movie, const QSize &size, QWidget *parent) {
|
||||
if (!movie.isNull()) {
|
||||
QObject::disconnect(movie.data(), nullptr, parent, nullptr);
|
||||
|
||||
movie->stop();
|
||||
movie.clear();
|
||||
}
|
||||
|
||||
QFileInfo gifFile(gifPath);
|
||||
if (!gifFile.exists()) {
|
||||
return;
|
||||
if (QFileInfo::exists(gifPath)) {
|
||||
QSharedPointer<QMovie> gif(QSharedPointer<QMovie>::create(gifPath, QByteArray(), parent));
|
||||
gif->setCacheMode(QMovie::CacheAll);
|
||||
gif->setScaledSize(size);
|
||||
|
||||
QObject::connect(gif.data(), &QMovie::frameChanged, parent, [parent](int) { parent->update(); }, Qt::UniqueConnection);
|
||||
|
||||
gif->start();
|
||||
|
||||
movie = gif;
|
||||
}
|
||||
|
||||
QSharedPointer<QMovie> gif(new QMovie(gifFile.filePath(), QByteArray(), parent));
|
||||
if (!gif->isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gif->setCacheMode(QMovie::CacheAll);
|
||||
gif->setScaledSize(size);
|
||||
|
||||
QObject::connect(gif.data(), &QMovie::frameChanged, parent, [parent](int){ parent->update(); }, Qt::UniqueConnection);
|
||||
|
||||
gif->start();
|
||||
|
||||
movie = gif;
|
||||
|
||||
parent->update();
|
||||
}
|
||||
|
||||
void loadImage(const QString &basePath, QPixmap &pixmap, QSharedPointer<QMovie> &movie, const QSize &size, QWidget *parent, Qt::AspectRatioMode aspectRatioMode) {
|
||||
QFileInfo gifFile(basePath + ".gif");
|
||||
if (gifFile.exists()) {
|
||||
loadGif(gifFile.filePath(), movie, size, parent);
|
||||
QString gifPath = basePath + ".gif";
|
||||
if (QFileInfo::exists(gifPath)) {
|
||||
loadGif(gifPath, movie, size, parent);
|
||||
|
||||
parent->update();
|
||||
} else {
|
||||
if (!movie.isNull()) {
|
||||
pixmap = QPixmap();
|
||||
return;
|
||||
QObject::disconnect(movie.data(), nullptr, parent, nullptr);
|
||||
|
||||
movie->stop();
|
||||
movie.clear();
|
||||
}
|
||||
|
||||
pixmap = QPixmap(basePath + ".png").scaled(size, aspectRatioMode, Qt::SmoothTransformation);
|
||||
|
||||
parent->update();
|
||||
}
|
||||
}
|
||||
|
||||
void openDescriptions(bool forceOpenDescriptions, std::map<QString, AbstractControl*> toggles) {
|
||||
if (forceOpenDescriptions) {
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (key != "CESpeed") {
|
||||
toggle->showDescription();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QImage image(basePath + ".png");
|
||||
image = image.convertToFormat(QImage::Format_Indexed8);
|
||||
pixmap = QPixmap::fromImage(image).scaled(size, aspectRatioMode, Qt::SmoothTransformation);
|
||||
|
||||
parent->update();
|
||||
}
|
||||
|
||||
void updateFrogPilotToggles() {
|
||||
|
||||
@@ -11,6 +11,7 @@ bool useKonikServer();
|
||||
|
||||
void loadGif(const QString &gifPath, QSharedPointer<QMovie> &movie, const QSize &size, QWidget *parent);
|
||||
void loadImage(const QString &basePath, QPixmap &pixmap, QSharedPointer<QMovie> &movie, const QSize &size, QWidget *parent, Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio);
|
||||
void openDescriptions(bool forceOpenDescriptions, std::map<QString, AbstractControl*> toggles);
|
||||
void updateFrogPilotToggles();
|
||||
|
||||
QColor loadThemeColors(const QString &colorKey, bool clearCache = false);
|
||||
@@ -369,17 +370,17 @@ public:
|
||||
QObject::connect(&decrement_button, &QPushButton::pressed, this, &FrogPilotParamValueControl::decrementPressed);
|
||||
QObject::connect(&increment_button, &QPushButton::pressed, this, &FrogPilotParamValueControl::incrementPressed);
|
||||
|
||||
QObject::connect(&decrement_button, &QPushButton::released, this, [this]() {
|
||||
QObject::connect(&decrement_button, &QPushButton::released, [this]() {
|
||||
decrement_repeating_timer.start(decrement_button.autoRepeatInterval());
|
||||
});
|
||||
QObject::connect(&increment_button, &QPushButton::released, this, [this]() {
|
||||
QObject::connect(&increment_button, &QPushButton::released, [this]() {
|
||||
increment_repeating_timer.start(increment_button.autoRepeatInterval());
|
||||
});
|
||||
|
||||
QObject::connect(&decrement_repeating_timer, &QTimer::timeout, this, [this]() {
|
||||
QObject::connect(&decrement_repeating_timer, &QTimer::timeout, [this]() {
|
||||
decrement_repeating = false;
|
||||
});
|
||||
QObject::connect(&increment_repeating_timer, &QTimer::timeout, this, [this]() {
|
||||
QObject::connect(&increment_repeating_timer, &QTimer::timeout, [this]() {
|
||||
increment_repeating = false;
|
||||
});
|
||||
}
|
||||
@@ -442,6 +443,9 @@ public:
|
||||
button.setAutoRepeatInterval(150);
|
||||
button.setFixedSize(150, 100);
|
||||
button.setStyleSheet(buttonStyle);
|
||||
if (text == "+" || text == "-") {
|
||||
button.setStyleSheet(button.styleSheet() + " QPushButton { font-size: 50px; }");
|
||||
}
|
||||
button.setText(text);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,125 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "frogpilot/ui/qt/widgets/model_reviewer.h"
|
||||
|
||||
ModelReview::ModelReview(QWidget *parent) : QFrame(parent) {
|
||||
static QLabel *addLabel(QWidget *parent, QVBoxLayout *layout, const QString &text, int fontSize=50) {
|
||||
QLabel *label = new QLabel(text, parent);
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
label->setStyleSheet(QString(R"(
|
||||
QLabel {
|
||||
color: #FFFFFF;
|
||||
font-size: %2px;
|
||||
font-weight: bold;
|
||||
}
|
||||
)").arg(fontSize));
|
||||
layout->addWidget(label);
|
||||
return label;
|
||||
}
|
||||
|
||||
static QLabel *addTitleLabel(QWidget *parent, QVBoxLayout *layout, const QString &text) {
|
||||
QLabel *label = new QLabel(text, parent);
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
label->setStyleSheet(R"(
|
||||
QLabel {
|
||||
background-color: #444444;
|
||||
border-radius: 12px;
|
||||
color: #FFFFFF;
|
||||
font-size: 50px;
|
||||
font-weight: bold;
|
||||
padding: 12px 28px;
|
||||
}
|
||||
)");
|
||||
label->setMaximumHeight(label->sizeHint().height());
|
||||
layout->addWidget(label);
|
||||
layout->addSpacing(10);
|
||||
return label;
|
||||
}
|
||||
|
||||
static QPushButton *createButton(QWidget *parent, const QString &text, const QString &name, int rating, int width, int height) {
|
||||
QPushButton *button = new QPushButton(text, parent);
|
||||
button->setFixedSize(width, height);
|
||||
button->setObjectName(name);
|
||||
button->setProperty("rating", rating);
|
||||
return button;
|
||||
}
|
||||
|
||||
static QWidget *createStatBox(const QString &title, QLabel **valueLabel, QWidget *parent) {
|
||||
QWidget *box = new QWidget(parent);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(box);
|
||||
layout->setAlignment(Qt::AlignCenter);
|
||||
layout->setContentsMargins(8, 8, 8, 8);
|
||||
layout->setSpacing(10);
|
||||
|
||||
QLabel *statTitleLabel = new QLabel(title, box);
|
||||
statTitleLabel->setAlignment(Qt::AlignCenter);
|
||||
statTitleLabel->setStyleSheet(R"(
|
||||
QLabel {
|
||||
color: #AAAAAA;
|
||||
font-size: 40px;
|
||||
font-weight: 600;
|
||||
}
|
||||
)");
|
||||
layout->addWidget(statTitleLabel);
|
||||
|
||||
QLabel *value = new QLabel("-", box);
|
||||
value->setAlignment(Qt::AlignCenter);
|
||||
value->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
value->setStyleSheet(R"(
|
||||
QLabel {
|
||||
color: #FFFFFF;
|
||||
font-size: 75px;
|
||||
font-weight: bold;
|
||||
}
|
||||
)");
|
||||
*valueLabel = value;
|
||||
layout->addWidget(value);
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
FrogPilotModelReview::FrogPilotModelReview(QWidget *parent) : QFrame(parent) {
|
||||
mainLayout = new QStackedLayout(this);
|
||||
|
||||
QVBoxLayout *ratingLayout = new QVBoxLayout();
|
||||
ratingLayout->setContentsMargins(50, 25, 50, 20);
|
||||
ratingLayout->setContentsMargins(50, 25, 50, 25);
|
||||
|
||||
questionLabel = addLabel(ratingLayout, tr("How would you rate that drive?"), "question");
|
||||
addTitleLabel(this, ratingLayout, tr("Drive Rating Selection"));
|
||||
ratingLayout->addStretch(1);
|
||||
|
||||
QHBoxLayout *ratingButtonsLayout = new QHBoxLayout();
|
||||
QStringList emojis = {"🤩", "🙂", "🤔", "🙁", "🤕"};
|
||||
QList<int> scores = {100, 80, 60, 40, 20};
|
||||
QVBoxLayout *ratingGroup = new QVBoxLayout();
|
||||
ratingGroup->setAlignment(Qt::AlignCenter);
|
||||
addLabel(this, ratingGroup, tr("How would you rate that drive?"));
|
||||
|
||||
for (int i = 0; i < emojis.size(); ++i) {
|
||||
QPushButton *ratingButton = createButton(emojis[i], "rating_button", scores[i], 150, 150);
|
||||
ratingButtonsLayout->addWidget(ratingButton);
|
||||
QObject::connect(ratingButton, &QPushButton::clicked, this, &ModelReview::onRatingButtonClicked);
|
||||
QHBoxLayout *row = new QHBoxLayout();
|
||||
row->setSpacing(25);
|
||||
|
||||
QList<QPair<QString, int>> ratings{
|
||||
{QStringLiteral("🤩"), 100},
|
||||
{QStringLiteral("🙂"), 80},
|
||||
{QStringLiteral("🤔"), 60},
|
||||
{QStringLiteral("🙁"), 40},
|
||||
{QStringLiteral("🤕"), 20}
|
||||
};
|
||||
|
||||
for (const QPair<QString, int> &rating : ratings) {
|
||||
QPushButton *button = createButton(this, rating.first, "ratingButton", rating.second, 150, 150);
|
||||
QObject::connect(button, &QPushButton::clicked, this, &FrogPilotModelReview::onRatingButtonClicked);
|
||||
row->addWidget(button);
|
||||
}
|
||||
|
||||
ratingLayout->addLayout(ratingButtonsLayout);
|
||||
ratingGroup->addLayout(row);
|
||||
ratingLayout->addLayout(ratingGroup);
|
||||
ratingLayout->addStretch(1);
|
||||
|
||||
blacklistButton = createButton(tr("Blacklist this model"), "blacklist_button", 0, 600, 100);
|
||||
QObject::connect(blacklistButton, &QPushButton::clicked, this, &ModelReview::onBlacklistButtonClicked);
|
||||
ratingLayout->addWidget(blacklistButton, 0, Qt::AlignCenter);
|
||||
QVBoxLayout *blacklistGroup = new QVBoxLayout();
|
||||
blacklistGroup->setAlignment(Qt::AlignCenter);
|
||||
addLabel(this, blacklistGroup, tr("Blacklist this model to remove it from rotation"), 40);
|
||||
|
||||
blacklistButton = createButton(this, tr("Blacklist Model"), "blacklistButton", 0, 600, 100);
|
||||
QObject::connect(blacklistButton, &QPushButton::clicked, this, &FrogPilotModelReview::onBlacklistButtonClicked);
|
||||
blacklistGroup->addWidget(blacklistButton, 0, Qt::AlignCenter);
|
||||
|
||||
ratingLayout->addLayout(blacklistGroup);
|
||||
|
||||
QWidget *ratingWidget = new QWidget(this);
|
||||
ratingWidget->setLayout(ratingLayout);
|
||||
@@ -34,17 +128,40 @@ ModelReview::ModelReview(QWidget *parent) : QFrame(parent) {
|
||||
QVBoxLayout *modelInfoLayout = new QVBoxLayout();
|
||||
modelInfoLayout->setContentsMargins(50, 25, 50, 20);
|
||||
|
||||
titleLabel = addLabel(modelInfoLayout, tr("The model used during that drive was:"), "title");
|
||||
modelLabel = addLabel(modelInfoLayout, "", "model");
|
||||
addLabel(this, modelInfoLayout, tr("Model used during that drive:"));
|
||||
|
||||
modelInfoLayout->addItem(new QSpacerItem(20, 75, QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
modelLabel = new QLabel("", this);
|
||||
modelLabel->setAlignment(Qt::AlignCenter);
|
||||
modelLabel->setStyleSheet(R"(
|
||||
QLabel {
|
||||
background-color: #444444;
|
||||
border-radius: 12px;
|
||||
color: #FFFFFF;
|
||||
font-size: 65px;
|
||||
font-weight: bold;
|
||||
padding: 12px 24px;
|
||||
}
|
||||
)");
|
||||
modelInfoLayout->addWidget(modelLabel);
|
||||
|
||||
modelInfoLayout->addSpacing(50);
|
||||
|
||||
QVBoxLayout *bottomLayout = new QVBoxLayout();
|
||||
modelScoreLabel = addLabel(bottomLayout, tr("Current Model Score: 0"), "score");
|
||||
modelRankLabel = addLabel(bottomLayout, tr("Current Model Rank: 0"), "rank");
|
||||
totalDrivesLabel = addLabel(bottomLayout, tr("Total Model Drives: 0"), "drives");
|
||||
totalOverallDrivesLabel = addLabel(bottomLayout, tr("Total Overall Model Drives: 0"), "drives");
|
||||
blacklistMessageLabel = addLabel(bottomLayout, "", "blacklist_message");
|
||||
bottomLayout->addWidget(createStatBox(tr("Model Rank"), &modelRankLabel, this));
|
||||
bottomLayout->addWidget(createStatBox(tr("Model Rating"), &modelRatingLabel, this));
|
||||
bottomLayout->addWidget(createStatBox(tr("Model Drives"), &totalDrivesLabel, this));
|
||||
bottomLayout->addWidget(createStatBox(tr("Total Drives"), &totalOverallDrivesLabel, this));
|
||||
|
||||
blacklistMessageLabel = new QLabel("", this);
|
||||
blacklistMessageLabel->setAlignment(Qt::AlignCenter);
|
||||
blacklistMessageLabel->setStyleSheet(R"(
|
||||
QLabel {
|
||||
color: #C92231;
|
||||
font-size: 50px;
|
||||
font-weight: bold;
|
||||
}
|
||||
)");
|
||||
bottomLayout->addWidget(blacklistMessageLabel);
|
||||
|
||||
modelInfoLayout->addLayout(bottomLayout);
|
||||
|
||||
@@ -53,192 +170,143 @@ ModelReview::ModelReview(QWidget *parent) : QFrame(parent) {
|
||||
mainLayout->addWidget(modelInfoWidget);
|
||||
|
||||
setStyleSheet(R"(
|
||||
ModelReview {
|
||||
FrogPilotModelReview {
|
||||
background-color: #333333;
|
||||
border-radius: 5px;
|
||||
}
|
||||
QLabel[type="drives"], QLabel[type="question"], QLabel[type="rank"], QLabel[type="score"], QLabel[type="title"] {
|
||||
font-size: 50px;
|
||||
font-weight: semi-bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
QLabel[type="model"] {
|
||||
font-size: 75px;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
QLabel[type="blacklist_message"] {
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
QPushButton#blacklistButton {
|
||||
background-color: #444444;
|
||||
border-radius: 12px;
|
||||
color: #C92231;
|
||||
}
|
||||
QPushButton[type="rating_button"] {
|
||||
font-size: 75px;
|
||||
font-size: 45px;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
padding: 12px 24px;
|
||||
}
|
||||
QPushButton#ratingButton {
|
||||
background-color: #444444;
|
||||
border-radius: 12px;
|
||||
color: #FFFFFF;
|
||||
background-color: #555555;
|
||||
border: 2px solid #FFFFFF;
|
||||
border-radius: 5px;
|
||||
}
|
||||
QPushButton[type="rating_button"]:hover {
|
||||
background-color: #777777;
|
||||
}
|
||||
QPushButton[type="blacklist_button"] {
|
||||
font-size: 50px;
|
||||
font-size: 100px;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
color: #C92231;
|
||||
background-color: #000000;
|
||||
border: 2px solid #FFFFFF;
|
||||
border-radius: 5px;
|
||||
padding: 12px 24px;
|
||||
}
|
||||
QPushButton#ratingButton:hover {
|
||||
background-color: #666666;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
QLabel *ModelReview::addLabel(QVBoxLayout *layout, const QString &text, const QString &type) {
|
||||
QLabel *label = new QLabel(text, this);
|
||||
label->setProperty("type", type);
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
layout->addWidget(label);
|
||||
return label;
|
||||
}
|
||||
|
||||
QPushButton *ModelReview::createButton(const QString &text, const QString &type, int rating, int width, int height) {
|
||||
QPushButton *button = new QPushButton(text, this);
|
||||
button->setProperty("type", type);
|
||||
button->setProperty("rating", rating);
|
||||
button->setFixedSize(width, height);
|
||||
return button;
|
||||
}
|
||||
|
||||
void ModelReview::showEvent(QShowEvent *event) {
|
||||
QStringList availableModels = QString::fromStdString(params.get("AvailableModels")).split(",");
|
||||
QStringList availableModelNames = QString::fromStdString(params.get("AvailableModelNames")).split(",");
|
||||
|
||||
QMap<QString, QString> modelFileToNameMap;
|
||||
for (int i = 0; i < qMin(availableModels.size(), availableModelNames.size()); ++i) {
|
||||
modelFileToNameMap.insert(availableModels[i], processModelName(availableModelNames[i]));
|
||||
}
|
||||
|
||||
currentModel = frogpilotUIState()->frogpilot_toggles.value("model").toString();
|
||||
currentModelFiltered = modelFileToNameMap.value(currentModel);
|
||||
|
||||
mainLayout->setCurrentIndex(modelRated ? 1 : 0);
|
||||
|
||||
checkBlacklistButtonVisibility();
|
||||
}
|
||||
|
||||
void ModelReview::mousePressEvent(QMouseEvent *e) {
|
||||
if (mainLayout->currentIndex() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit driveRated();
|
||||
}
|
||||
|
||||
void ModelReview::updateLabel() {
|
||||
totalDrivesLabel->setText(QString(tr("Total Model Drives: %1")).arg(totalDrives));
|
||||
modelLabel->setText(currentModelFiltered);
|
||||
modelRankLabel->setText(QString(tr("Current Model Rank: %1")).arg(getModelRank()));
|
||||
modelScoreLabel->setText(QString(tr("Current Model Score: %1")).arg(finalRating));
|
||||
totalOverallDrivesLabel->setText(QString(tr("Total Overall Drives: %1")).arg(totalOverallDrives));
|
||||
|
||||
mainLayout->setCurrentIndex(1);
|
||||
|
||||
QTimer::singleShot(30000, [this]() {
|
||||
emit driveRated();
|
||||
modelRated = false;
|
||||
QObject::connect(device(), &Device::interactiveTimeout, [this]() {
|
||||
if (isVisible()) {
|
||||
emit driveRated();
|
||||
modelRated = false;
|
||||
}
|
||||
});
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, [this](bool offroad) {
|
||||
if (!offroad) {
|
||||
emit driveRated();
|
||||
modelRated = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ModelReview::onRatingButtonClicked() {
|
||||
int newRating = qobject_cast<QPushButton*>(sender())->property("rating").toInt();
|
||||
|
||||
QString jsonString = QString::fromStdString(params.get("ModelDrivesAndScores"));
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8());
|
||||
QJsonObject jsonObject = jsonDoc.isObject() ? jsonDoc.object() : QJsonObject();
|
||||
|
||||
QJsonObject modelData = jsonObject.value(currentModelFiltered).toObject();
|
||||
int modelDrives = modelData.value("Drives").toInt();
|
||||
int modelScore = modelData.value("Score").toInt();
|
||||
|
||||
totalDrives = modelDrives + 1;
|
||||
finalRating = ((modelScore * modelDrives) + newRating) / totalDrives;
|
||||
|
||||
modelData["Drives"] = totalDrives;
|
||||
modelData["Score"] = finalRating;
|
||||
jsonObject[currentModelFiltered] = modelData;
|
||||
|
||||
params.put("ModelDrivesAndScores", QString(QJsonDocument(jsonObject).toJson(QJsonDocument::Compact)).toStdString());
|
||||
|
||||
modelRated = true;
|
||||
updateLabel();
|
||||
void FrogPilotModelReview::mousePressEvent(QMouseEvent *e) {
|
||||
if (mainLayout->currentIndex() == 1) {
|
||||
emit driveRated();
|
||||
}
|
||||
}
|
||||
|
||||
void ModelReview::onBlacklistButtonClicked() {
|
||||
QString jsonString = QString::fromStdString(params.get("ModelDrivesAndScores"));
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8());
|
||||
QJsonObject jsonObject = jsonDoc.isObject() ? jsonDoc.object() : QJsonObject();
|
||||
void FrogPilotModelReview::showEvent(QShowEvent *event) {
|
||||
QStringList availableModels = QString::fromStdString(params.get("AvailableModels")).split(",", QString::SkipEmptyParts);
|
||||
availableModelNames = QString::fromStdString(params.get("AvailableModelNames")).split(",", QString::SkipEmptyParts);
|
||||
blacklistedModels = QString::fromStdString(params.get("BlacklistedModels")).split(",", QString::SkipEmptyParts);
|
||||
|
||||
QJsonObject modelData = jsonObject.value(currentModelFiltered).toObject();
|
||||
int modelDrives = modelData.value("Drives").toInt();
|
||||
blacklistButton->setVisible(!(QSet<QString>::fromList(availableModels) - QSet<QString>::fromList(blacklistedModels)).isEmpty());
|
||||
|
||||
totalDrives = modelDrives + 1;
|
||||
modelData["Drives"] = totalDrives;
|
||||
modelData["Score"] = 0;
|
||||
jsonObject[currentModelFiltered] = modelData;
|
||||
QMap<QString, QString> modelMap;
|
||||
for (int i = 0; i < qMin(availableModels.size(), availableModelNames.size()); ++i) {
|
||||
modelMap.insert(availableModels[i], processModelName(availableModelNames[i]));
|
||||
}
|
||||
currentModel = frogpilotUIState()->frogpilot_toggles.value("model").toString();
|
||||
currentModelFiltered = modelMap.value(currentModel);
|
||||
|
||||
modelDrivesAndScores = QJsonDocument::fromJson(QString::fromStdString(params.get("ModelDrivesAndScores")).toUtf8()).object();
|
||||
currentModelData = modelDrivesAndScores.value(currentModelFiltered).toObject();
|
||||
|
||||
mainLayout->setCurrentIndex(modelRated ? 1 : 0);
|
||||
}
|
||||
|
||||
int FrogPilotModelReview::getModelRank() {
|
||||
QList<QPair<QString, int>> modelRatings;
|
||||
totalOverallDrives = 0;
|
||||
|
||||
for (const QString &model : availableModelNames) {
|
||||
QString processedModel = processModelName(model);
|
||||
|
||||
QJsonObject modelData = modelDrivesAndScores.value(processedModel).toObject();
|
||||
int modelDrives = modelData.value("Drives").toInt();
|
||||
int modelRating = modelData.value("Score").toInt();
|
||||
totalOverallDrives += modelDrives;
|
||||
|
||||
if (modelRating > 0) {
|
||||
modelRatings.append(qMakePair(processedModel, modelRating));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(modelRatings.begin(), modelRatings.end(), [](const QPair<QString, int> &a, const QPair<QString, int> &b) {
|
||||
if (a.second == b.second) {
|
||||
return a.first < b.first;
|
||||
}
|
||||
return a.second > b.second;
|
||||
});
|
||||
for (int i = 0; i < modelRatings.size(); ++i) {
|
||||
if (modelRatings[i].first == currentModelFiltered) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
return modelRatings.size();
|
||||
}
|
||||
|
||||
void FrogPilotModelReview::onBlacklistButtonClicked() {
|
||||
totalDrives = currentModelData.value("Drives").toInt() + 1;
|
||||
currentModelData["Drives"] = totalDrives;
|
||||
currentModelData["Score"] = 0;
|
||||
modelDrivesAndScores[currentModelFiltered] = currentModelData;
|
||||
|
||||
if (!blacklistedModels.contains(currentModel)) {
|
||||
blacklistedModels.append(currentModel);
|
||||
params.put("BlacklistedModels", blacklistedModels.join(",").toStdString());
|
||||
}
|
||||
|
||||
params.put("ModelDrivesAndScores", QString(QJsonDocument(jsonObject).toJson(QJsonDocument::Compact)).toStdString());
|
||||
params.put("ModelDrivesAndScores", QJsonDocument(modelDrivesAndScores).toJson(QJsonDocument::Compact).toStdString());
|
||||
|
||||
blacklistMessageLabel->setText(tr("Model successfully blacklisted!"));
|
||||
|
||||
updateLabel();
|
||||
}
|
||||
|
||||
void ModelReview::checkBlacklistButtonVisibility() {
|
||||
QStringList availableModels = QString::fromStdString(params.get("AvailableModels")).split(",");
|
||||
blacklistedModels = QString::fromStdString(params.get("BlacklistedModels")).split(",", QString::SkipEmptyParts);
|
||||
void FrogPilotModelReview::onRatingButtonClicked() {
|
||||
int modelDrives = currentModelData.value("Drives").toInt();
|
||||
int modelRating = currentModelData.value("Score").toInt();
|
||||
|
||||
blacklistButton->setVisible(availableModels.size() > blacklistedModels.size());
|
||||
totalDrives = modelDrives + 1;
|
||||
finalRating = ((modelRating * modelDrives) + sender()->property("rating").toInt()) / totalDrives;
|
||||
|
||||
currentModelData["Drives"] = totalDrives;
|
||||
currentModelData["Score"] = finalRating;
|
||||
modelDrivesAndScores[currentModelFiltered] = currentModelData;
|
||||
|
||||
params.put("ModelDrivesAndScores", QJsonDocument(modelDrivesAndScores).toJson(QJsonDocument::Compact).toStdString());
|
||||
|
||||
modelRated = true;
|
||||
|
||||
updateLabel();
|
||||
}
|
||||
|
||||
int ModelReview::getModelRank() {
|
||||
QString jsonString = QString::fromStdString(params.get("ModelDrivesAndScores"));
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8());
|
||||
QJsonObject jsonObject = jsonDoc.isObject() ? jsonDoc.object() : QJsonObject();
|
||||
void FrogPilotModelReview::updateLabel() {
|
||||
modelLabel->setText(currentModelFiltered);
|
||||
modelRankLabel->setText(tr("#%1").arg(getModelRank()));
|
||||
modelRatingLabel->setText(tr("%1%").arg(finalRating));
|
||||
totalDrivesLabel->setText(tr("%1 %2").arg(totalDrives).arg(totalDrives == 1 ? tr("Drive") : tr("Drives")));
|
||||
totalOverallDrivesLabel->setText(tr("%1 Total %2").arg(totalOverallDrives).arg(totalOverallDrives == 1 ? tr("Drive") : tr("Drives")));
|
||||
|
||||
QList<QPair<QString, int>> modelScores;
|
||||
totalOverallDrives = 0;
|
||||
|
||||
QStringList availableModels = QString::fromStdString(params.get("AvailableModelNames")).split(",");
|
||||
for (const QString &model : availableModels) {
|
||||
QString processedModel = processModelName(model);
|
||||
QJsonObject modelData = jsonObject.value(processedModel).toObject();
|
||||
|
||||
int modelDrives = modelData.value("Drives").toInt();
|
||||
int modelScore = modelData.value("Score").toInt();
|
||||
|
||||
totalOverallDrives += modelDrives;
|
||||
|
||||
if (modelScore > 0) {
|
||||
modelScores.append(qMakePair(processedModel, modelScore));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(modelScores.begin(), modelScores.end(), [](QPair<QString, int> &a, QPair<QString, int> &b) {
|
||||
return a.second > b.second;
|
||||
});
|
||||
|
||||
for (int i = 0; i < modelScores.size(); ++i) {
|
||||
if (modelScores[i].first == currentModelFiltered) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
mainLayout->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
#include "selfdrive/ui/ui.h"
|
||||
|
||||
class ModelReview : public QFrame {
|
||||
class FrogPilotModelReview : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ModelReview(QWidget *parent = nullptr);
|
||||
explicit FrogPilotModelReview(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void driveRated();
|
||||
@@ -22,37 +22,33 @@ private slots:
|
||||
private:
|
||||
int getModelRank();
|
||||
|
||||
QLabel *addLabel(QVBoxLayout *layout, const QString &text, const QString &type);
|
||||
|
||||
QPushButton *createButton(const QString &text, const QString &type, int rating, int width, int height);
|
||||
|
||||
void checkBlacklistButtonVisibility();
|
||||
void updateLabel();
|
||||
|
||||
QStackedLayout *mainLayout;
|
||||
|
||||
QLabel *blacklistMessageLabel;
|
||||
QLabel *modelLabel;
|
||||
QLabel *modelRankLabel;
|
||||
QLabel *modelScoreLabel;
|
||||
QLabel *questionLabel;
|
||||
QLabel *titleLabel;
|
||||
QLabel *totalDrivesLabel;
|
||||
QLabel *totalOverallDrivesLabel;
|
||||
|
||||
QPushButton *blacklistButton;
|
||||
|
||||
Params params;
|
||||
Params params_memory{"/dev/shm/params"};
|
||||
|
||||
QString currentModel;
|
||||
QString currentModelFiltered;
|
||||
|
||||
QStringList blacklistedModels;
|
||||
|
||||
bool modelRated;
|
||||
|
||||
int finalRating;
|
||||
int totalDrives;
|
||||
int totalOverallDrives;
|
||||
|
||||
Params params;
|
||||
|
||||
QJsonObject currentModelData;
|
||||
QJsonObject modelDrivesAndScores;
|
||||
|
||||
QLabel *blacklistMessageLabel;
|
||||
QLabel *modelLabel;
|
||||
QLabel *modelRankLabel;
|
||||
QLabel *modelRatingLabel;
|
||||
QLabel *totalDrivesLabel;
|
||||
QLabel *totalOverallDrivesLabel;
|
||||
|
||||
QPushButton *blacklistButton;
|
||||
|
||||
QStackedLayout *mainLayout;
|
||||
|
||||
QString currentModel;
|
||||
QString currentModelFiltered;
|
||||
|
||||
QStringList availableModelNames;
|
||||
QStringList blacklistedModels;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user