wip
This commit is contained in:
385
selfdrive/ui/qt/offroad/settings.cc
Executable file → Normal file
385
selfdrive/ui/qt/offroad/settings.cc
Executable file → Normal file
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
@@ -25,9 +27,9 @@
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
|
||||
#include "selfdrive/frogpilot/navigation/ui/navigation_settings.h"
|
||||
#include "selfdrive/frogpilot/ui/control_settings.h"
|
||||
#include "selfdrive/frogpilot/ui/vehicle_settings.h"
|
||||
#include "selfdrive/frogpilot/ui/visual_settings.h"
|
||||
#include "selfdrive/frogpilot/ui/qt/offroad/control_settings.h"
|
||||
#include "selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h"
|
||||
#include "selfdrive/frogpilot/ui/qt/offroad/visual_settings.h"
|
||||
|
||||
TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
// param, title, desc, icon
|
||||
@@ -97,9 +99,14 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
std::vector<QString> longi_button_texts{tr("Aggressive"), tr("Standard"), tr("Relaxed")};
|
||||
long_personality_setting = new ButtonParamControl("LongitudinalPersonality", tr("Driving Personality"),
|
||||
tr("Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. "
|
||||
"In relaxed mode openpilot will stay further away from lead cars."),
|
||||
"In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with "
|
||||
"your steering wheel distance button."),
|
||||
"../assets/offroad/icon_speed_limit.png",
|
||||
longi_button_texts);
|
||||
|
||||
// set up uiState update for personality setting
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &TogglesPanel::updateState);
|
||||
|
||||
for (auto &[param, title, desc, icon] : toggle_defs) {
|
||||
auto toggle = new ParamControl(param, title, desc, icon, this);
|
||||
|
||||
@@ -110,7 +117,7 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
toggles[param.toStdString()] = toggle;
|
||||
|
||||
// insert longitudinal personality after NDOG toggle
|
||||
if (param == "DisengageOnAccelerator" && !params.getInt("AdjustablePersonalities")) {
|
||||
if (param == "DisengageOnAccelerator") {
|
||||
addItem(long_personality_setting);
|
||||
}
|
||||
}
|
||||
@@ -129,6 +136,18 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
});
|
||||
}
|
||||
|
||||
void TogglesPanel::updateState(const UIState &s) {
|
||||
const SubMaster &sm = *(s.sm);
|
||||
|
||||
if (sm.updated("controlsState")) {
|
||||
auto personality = sm["controlsState"].getControlsState().getPersonality();
|
||||
if (personality != s.scene.personality && s.scene.started && isVisible()) {
|
||||
long_personality_setting->setCheckedButton(static_cast<int>(personality));
|
||||
}
|
||||
uiState()->scene.personality = personality;
|
||||
}
|
||||
}
|
||||
|
||||
void TogglesPanel::expandToggleDescription(const QString ¶m) {
|
||||
toggles[param.toStdString()]->showDescription();
|
||||
}
|
||||
@@ -138,6 +157,13 @@ void TogglesPanel::showEvent(QShowEvent *event) {
|
||||
}
|
||||
|
||||
void TogglesPanel::updateToggles() {
|
||||
auto disengage_on_accelerator_toggle = toggles["DisengageOnAccelerator"];
|
||||
disengage_on_accelerator_toggle->setVisible(!params.getBool("AlwaysOnLateral"));
|
||||
auto driver_camera_toggle = toggles["RecordFront"];
|
||||
driver_camera_toggle->setVisible(!(params.getBool("DeviceManagement") && params.getBool("NoLogging") && params.getBool("NoUploads")));
|
||||
auto nav_settings_left_toggle = toggles["NavSettingLeftSide"];
|
||||
nav_settings_left_toggle->setVisible(!params.getBool("FullMap"));
|
||||
|
||||
auto experimental_mode_toggle = toggles["ExperimentalMode"];
|
||||
auto op_long_toggle = toggles["ExperimentalLongitudinalEnabled"];
|
||||
const QString e2e_description = QString("%1<br>"
|
||||
@@ -173,7 +199,12 @@ void TogglesPanel::updateToggles() {
|
||||
op_long_toggle->setVisible(CP.getExperimentalLongitudinalAvailable() && !is_release);
|
||||
if (hasLongitudinalControl(CP)) {
|
||||
// normal description and toggle
|
||||
experimental_mode_toggle->setEnabled(!params.getBool("ConditionalExperimental"));
|
||||
bool conditional_experimental = params.getBool("ConditionalExperimental");
|
||||
if (conditional_experimental) {
|
||||
params.putBool("ExperimentalMode", true);
|
||||
experimental_mode_toggle->refresh();
|
||||
}
|
||||
experimental_mode_toggle->setEnabled(!conditional_experimental);
|
||||
experimental_mode_toggle->setDescription(e2e_description);
|
||||
long_personality_setting->setEnabled(true);
|
||||
} else {
|
||||
@@ -225,15 +256,13 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
});
|
||||
addItem(resetCalibBtn);
|
||||
|
||||
if (!params.getBool("Passive")) {
|
||||
auto retrainingBtn = new ButtonControl(tr("Review Training Guide"), tr("REVIEW"), tr("Review the rules, features, and limitations of openpilot"));
|
||||
connect(retrainingBtn, &ButtonControl::clicked, [=]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to review the training guide?"), tr("Review"), this)) {
|
||||
emit reviewTrainingGuide();
|
||||
}
|
||||
});
|
||||
addItem(retrainingBtn);
|
||||
}
|
||||
auto retrainingBtn = new ButtonControl(tr("Review Training Guide"), tr("REVIEW"), tr("Review the rules, features, and limitations of openpilot"));
|
||||
connect(retrainingBtn, &ButtonControl::clicked, [=]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to review the training guide?"), tr("Review"), this)) {
|
||||
emit reviewTrainingGuide();
|
||||
}
|
||||
});
|
||||
addItem(retrainingBtn);
|
||||
|
||||
if (Hardware::TICI()) {
|
||||
auto regulatoryBtn = new ButtonControl(tr("Regulatory"), tr("VIEW"), "");
|
||||
@@ -258,44 +287,251 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
addItem(translateBtn);
|
||||
|
||||
// Delete driving footage button
|
||||
auto deleteFootageBtn = new ButtonControl(tr("Delete Driving Data"), tr("DELETE"), tr("This button provides a swift and secure way to permanently delete all "
|
||||
auto deleteDrivingDataBtn = new ButtonControl(tr("Delete Driving Data"), tr("DELETE"), tr("This button provides a swift and secure way to permanently delete all "
|
||||
"stored driving footage and data from your device. Ideal for maintaining privacy or freeing up space.")
|
||||
);
|
||||
connect(deleteFootageBtn, &ButtonControl::clicked, [this]() {
|
||||
connect(deleteDrivingDataBtn, &ButtonControl::clicked, [=]() {
|
||||
if (!ConfirmationDialog::confirm(tr("Are you sure you want to permanently delete all of your driving footage and data?"), tr("Delete"), this)) return;
|
||||
std::thread([&] {
|
||||
deleteDrivingDataBtn->setValue(tr("Deleting footage..."));
|
||||
std::system("rm -rf /data/media/0/realdata");
|
||||
deleteDrivingDataBtn->setValue(tr("Deleted!"));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
deleteDrivingDataBtn->setValue("");
|
||||
}).detach();
|
||||
});
|
||||
addItem(deleteFootageBtn);
|
||||
addItem(deleteDrivingDataBtn);
|
||||
|
||||
// Panda flashing button
|
||||
auto flashPandaBtn = new ButtonControl(tr("Flash Panda"), tr("FLASH"), "Use this button to troubleshoot and update the Panda device's firmware.");
|
||||
connect(flashPandaBtn, &ButtonControl::clicked, [this]() {
|
||||
if (!ConfirmationDialog::confirm(tr("Are you sure you want to flash the Panda?"), tr("Flash"), this)) return;
|
||||
QProcess process;
|
||||
// Get Panda type
|
||||
SubMaster &sm = *(uiState()->sm);
|
||||
auto pandaStates = sm["pandaStates"].getPandaStates();
|
||||
// Choose recovery script based on Panda type
|
||||
if (pandaStates.size() != 0) {
|
||||
auto pandaType = pandaStates[0].getPandaType();
|
||||
bool isRedPanda = (pandaType == cereal::PandaState::PandaType::RED_PANDA ||
|
||||
pandaType == cereal::PandaState::PandaType::RED_PANDA_V2);
|
||||
QString recoveryScript = isRedPanda ? "./recover.sh" : "./recover.py";
|
||||
// Run recovery script and flash Panda
|
||||
process.setWorkingDirectory("/data/openpilot/panda/board");
|
||||
process.start("/bin/sh", QStringList{"-c", recoveryScript});
|
||||
process.waitForFinished();
|
||||
auto flashPandaBtn = new ButtonControl(tr("Flash Panda"), tr("FLASH"), tr("Use this button to troubleshoot and update the Panda device's firmware."));
|
||||
connect(flashPandaBtn, &ButtonControl::clicked, [=]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to flash the Panda?"), tr("Flash"), this)) {
|
||||
std::thread([=]() {
|
||||
flashPandaBtn->setValue(tr("Flashing..."));
|
||||
|
||||
QProcess process;
|
||||
|
||||
process.setWorkingDirectory("/data/openpilot/panda/board");
|
||||
process.start("/bin/sh", QStringList{"-c", "./recover.py"});
|
||||
process.waitForFinished();
|
||||
process.start("/bin/sh", QStringList{"-c", "./flash.py"});
|
||||
process.waitForFinished();
|
||||
|
||||
process.setWorkingDirectory("/data/openpilot/panda/tests");
|
||||
process.start("/bin/sh", QStringList{"-c", "python reflash_internal_panda.py"});
|
||||
process.waitForFinished();
|
||||
|
||||
Hardware::soft_reboot();
|
||||
}).detach();
|
||||
}
|
||||
// Run the killall script as a redundancy
|
||||
process.setWorkingDirectory("/data/openpilot/panda");
|
||||
process.start("/bin/sh", QStringList{"-c", "pkill -f boardd; PYTHONPATH=.. python -c \"from panda import Panda; Panda().flash()\""});
|
||||
process.waitForFinished();
|
||||
Hardware::reboot();
|
||||
});
|
||||
addItem(flashPandaBtn);
|
||||
|
||||
// Reset toggle button
|
||||
auto resetTogglesBtn = new ButtonControl(tr("Reset Toggle Settings"), tr("RESET"), tr("Reset your toggle settings back to default."));
|
||||
connect(resetTogglesBtn, &ButtonControl::clicked, [=]() {
|
||||
if (!ConfirmationDialog::confirm(tr("Are you sure you want to completely reset your toggle settings? This is irreversible!"), tr("Reset"), this)) return;
|
||||
std::thread([&] {
|
||||
resetTogglesBtn->setValue(tr("Resetting toggles..."));
|
||||
|
||||
std::system("find /data/params -type f ! -name 'FrogPilotDrives' ! -name 'FrogPilotMinutes' ! -name 'FrogPilotKilometers' -exec rm {} +");
|
||||
std::system("find /persist/params -type f ! -name 'FrogPilotDrives' ! -name 'FrogPilotMinutes' ! -name 'FrogPilotKilometers' -exec rm {} +");
|
||||
|
||||
Hardware::soft_reboot();
|
||||
}).detach();
|
||||
});
|
||||
addItem(resetTogglesBtn);
|
||||
|
||||
// Backup FrogPilot
|
||||
std::vector<QString> frogpilotBackupOptions{tr("Backup"), tr("Delete"), tr("Restore")};
|
||||
FrogPilotButtonsControl *frogpilotBackup = new FrogPilotButtonsControl(tr("FrogPilot Backups"), tr("Backup, delete, or restore your FrogPilot backups."), "", frogpilotBackupOptions);
|
||||
|
||||
connect(frogpilotBackup, &FrogPilotButtonsControl::buttonClicked, [=](int id) {
|
||||
QDir backupDir("/data/backups");
|
||||
|
||||
if (id == 0) {
|
||||
QString nameSelection = InputDialog::getText(tr("Name your backup"), this, "", false, 1);
|
||||
if (!nameSelection.isEmpty()) {
|
||||
std::thread([=]() {
|
||||
frogpilotBackup->setValue(tr("Backing up..."));
|
||||
|
||||
std::string fullBackupPath = backupDir.absolutePath().toStdString() + "/" + nameSelection.toStdString();
|
||||
|
||||
std::ostringstream commandStream;
|
||||
commandStream << "mkdir -p " << std::quoted(fullBackupPath)
|
||||
<< " && rsync -av /data/openpilot/ " << std::quoted(fullBackupPath + "/");
|
||||
std::string command = commandStream.str();
|
||||
|
||||
int result = std::system(command.c_str());
|
||||
if (result == 0) {
|
||||
std::cout << "Backup successful to " << fullBackupPath << std::endl;
|
||||
frogpilotBackup->setValue(tr("Success!"));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
frogpilotBackup->setValue("");
|
||||
} else {
|
||||
std::cerr << "Backup failed with error code: " << result << std::endl;
|
||||
frogpilotBackup->setValue(tr("Failed..."));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
frogpilotBackup->setValue("");
|
||||
}
|
||||
}).detach();
|
||||
}
|
||||
} else if (id == 1) {
|
||||
QStringList backupNames = backupDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
|
||||
QString selection = MultiOptionDialog::getSelection(tr("Select a backup to delete"), backupNames, "", this);
|
||||
if (!selection.isEmpty()) {
|
||||
if (!ConfirmationDialog::confirm(tr("Are you sure you want to delete this backup?"), tr("Delete"), this)) return;
|
||||
std::thread([=]() {
|
||||
frogpilotBackup->setValue(tr("Deleting..."));
|
||||
QDir dirToDelete(backupDir.absoluteFilePath(selection));
|
||||
if (dirToDelete.removeRecursively()) {
|
||||
frogpilotBackup->setValue(tr("Deleted!"));
|
||||
} else {
|
||||
frogpilotBackup->setValue(tr("Failed..."));
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
frogpilotBackup->setValue("");
|
||||
}).detach();
|
||||
}
|
||||
} else {
|
||||
QStringList backupNames = backupDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
|
||||
QString selection = MultiOptionDialog::getSelection(tr("Select a restore point"), backupNames, "", this);
|
||||
if (!selection.isEmpty()) {
|
||||
if (!ConfirmationDialog::confirm(tr("Are you sure you want to restore this version of FrogPilot?"), tr("Restore"), this)) return;
|
||||
std::thread([=]() {
|
||||
frogpilotBackup->setValue(tr("Restoring..."));
|
||||
|
||||
std::string sourcePath = backupDir.absolutePath().toStdString() + "/" + selection.toStdString();
|
||||
std::string targetPath = "/data/safe_staging/finalized";
|
||||
std::string consistentFilePath = targetPath + "/.overlay_consistent";
|
||||
|
||||
std::ostringstream commandStream;
|
||||
commandStream << "rsync -av --delete --exclude='.overlay_consistent' " << std::quoted(sourcePath + "/") << " " << std::quoted(targetPath + "/");
|
||||
std::string command = commandStream.str();
|
||||
int result = std::system(command.c_str());
|
||||
|
||||
if (result == 0) {
|
||||
std::cout << "Restore successful from " << sourcePath << " to " << targetPath << std::endl;
|
||||
std::ofstream consistentFile(consistentFilePath);
|
||||
if (consistentFile) {
|
||||
consistentFile.close();
|
||||
std::cout << ".overlay_consistent file created successfully." << std::endl;
|
||||
} else {
|
||||
std::cerr << "Failed to create .overlay_consistent file." << std::endl;
|
||||
frogpilotBackup->setValue(tr("Failed..."));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
frogpilotBackup->setValue("");
|
||||
}
|
||||
Hardware::soft_reboot();
|
||||
} else {
|
||||
std::cerr << "Restore failed with error code: " << result << std::endl;
|
||||
}
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
});
|
||||
addItem(frogpilotBackup);
|
||||
|
||||
// Backup toggles
|
||||
std::vector<QString> toggleBackupOptions{tr("Backup"), tr("Delete"), tr("Restore")};
|
||||
FrogPilotButtonsControl *toggleBackup = new FrogPilotButtonsControl(tr("Toggle Backups"), tr("Backup, delete, or restore your toggle backups."), "", toggleBackupOptions);
|
||||
|
||||
connect(toggleBackup, &FrogPilotButtonsControl::buttonClicked, [=](int id) {
|
||||
QDir backupDir("/data/toggle_backups");
|
||||
|
||||
if (id == 0) {
|
||||
QString nameSelection = InputDialog::getText(tr("Name your backup"), this, "", false, 1);
|
||||
if (!nameSelection.isEmpty()) {
|
||||
std::thread([=]() {
|
||||
toggleBackup->setValue(tr("Backing up..."));
|
||||
|
||||
std::string fullBackupPath = backupDir.absolutePath().toStdString() + "/" + nameSelection.toStdString() + "/";
|
||||
|
||||
std::ostringstream commandStream;
|
||||
commandStream << "mkdir -p " << std::quoted(fullBackupPath)
|
||||
<< " && rsync -av /data/params/d/ " << std::quoted(fullBackupPath);
|
||||
std::string command = commandStream.str();
|
||||
|
||||
int result = std::system(command.c_str());
|
||||
if (result == 0) {
|
||||
std::cout << "Backup successful to " << fullBackupPath << std::endl;
|
||||
toggleBackup->setValue(tr("Success!"));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
toggleBackup->setValue("");
|
||||
} else {
|
||||
std::cerr << "Backup failed with error code: " << result << std::endl;
|
||||
toggleBackup->setValue(tr("Failed..."));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
toggleBackup->setValue("");
|
||||
}
|
||||
}).detach();
|
||||
}
|
||||
} else if (id == 1) {
|
||||
QStringList backupNames = backupDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
|
||||
QString selection = MultiOptionDialog::getSelection(tr("Select a backup to delete"), backupNames, "", this);
|
||||
if (!selection.isEmpty()) {
|
||||
if (!ConfirmationDialog::confirm(tr("Are you sure you want to delete this backup?"), tr("Delete"), this)) return;
|
||||
std::thread([=]() {
|
||||
toggleBackup->setValue(tr("Deleting..."));
|
||||
QDir dirToDelete(backupDir.absoluteFilePath(selection));
|
||||
if (dirToDelete.removeRecursively()) {
|
||||
toggleBackup->setValue(tr("Deleted!"));
|
||||
} else {
|
||||
toggleBackup->setValue(tr("Failed..."));
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
toggleBackup->setValue("");
|
||||
}).detach();
|
||||
}
|
||||
} else {
|
||||
QStringList backupNames = backupDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
|
||||
QString selection = MultiOptionDialog::getSelection(tr("Select a restore point"), backupNames, "", this);
|
||||
if (!selection.isEmpty()) {
|
||||
if (!ConfirmationDialog::confirm(tr("Are you sure you want to restore this toggle backup?"), tr("Restore"), this)) return;
|
||||
std::thread([=]() {
|
||||
toggleBackup->setValue(tr("Restoring..."));
|
||||
|
||||
std::string sourcePath = backupDir.absolutePath().toStdString() + "/" + selection.toStdString() + "/";
|
||||
std::string targetPath = "/data/params/d/";
|
||||
|
||||
std::ostringstream commandStream;
|
||||
commandStream << "rsync -av --delete " << std::quoted(sourcePath) << " " << std::quoted(targetPath);
|
||||
std::string command = commandStream.str();
|
||||
|
||||
int result = std::system(command.c_str());
|
||||
|
||||
if (result == 0) {
|
||||
std::cout << "Restore successful from " << sourcePath << " to " << targetPath << std::endl;
|
||||
toggleBackup->setValue(tr("Success!"));
|
||||
paramsMemory.putBool("FrogPilotTogglesUpdated", true);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
toggleBackup->setValue("");
|
||||
paramsMemory.putBool("FrogPilotTogglesUpdated", false);
|
||||
} else {
|
||||
std::cerr << "Restore failed with error code: " << result << std::endl;
|
||||
toggleBackup->setValue(tr("Failed..."));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
toggleBackup->setValue("");
|
||||
}
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
});
|
||||
addItem(toggleBackup);
|
||||
|
||||
auto lockDoorsButton = new ButtonControl(tr("Lock Doors"), tr("LOCK"), tr("Use this button to lock the doors on Toyota/Lexus vehicles."));
|
||||
connect(lockDoorsButton, &ButtonControl::clicked, [this]() {
|
||||
QProcess *process = new QProcess(this);
|
||||
QString scriptPath = "/data/openpilot/frogpilot/controls/lib/lock_doors.py";
|
||||
QStringList arguments{"--lock"};
|
||||
process->start("python3", QStringList() << scriptPath << arguments);
|
||||
});
|
||||
addItem(lockDoorsButton);
|
||||
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) {
|
||||
for (auto btn : findChildren<ButtonControl *>()) {
|
||||
btn->setEnabled(offroad);
|
||||
@@ -311,6 +547,11 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
power_layout->addWidget(reboot_btn);
|
||||
QObject::connect(reboot_btn, &QPushButton::clicked, this, &DevicePanel::reboot);
|
||||
|
||||
QPushButton *softreboot_btn = new QPushButton(tr("Soft Reboot"));
|
||||
softreboot_btn->setObjectName("softreboot_btn");
|
||||
power_layout->addWidget(softreboot_btn);
|
||||
QObject::connect(softreboot_btn, &QPushButton::clicked, this, &DevicePanel::softreboot);
|
||||
|
||||
QPushButton *poweroff_btn = new QPushButton(tr("Power Off"));
|
||||
poweroff_btn->setObjectName("poweroff_btn");
|
||||
power_layout->addWidget(poweroff_btn);
|
||||
@@ -321,6 +562,8 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
}
|
||||
|
||||
setStyleSheet(R"(
|
||||
#softreboot_btn { height: 120px; border-radius: 15px; background-color: #e2e22c; }
|
||||
#softreboot_btn:pressed { background-color: #ffe224; }
|
||||
#reboot_btn { height: 120px; border-radius: 15px; background-color: #393939; }
|
||||
#reboot_btn:pressed { background-color: #4a4a4a; }
|
||||
#poweroff_btn { height: 120px; border-radius: 15px; background-color: #E22C2C; }
|
||||
@@ -366,6 +609,18 @@ void DevicePanel::reboot() {
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePanel::softreboot() {
|
||||
if (!uiState()->engaged()) {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to soft reboot?"), tr("Soft Reboot"), this)) {
|
||||
if (!uiState()->engaged()) {
|
||||
params.putBool("DoSoftReboot", true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ConfirmationDialog::alert(tr("Disengage to Soft Reboot"), this);
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePanel::poweroff() {
|
||||
if (!uiState()->engaged()) {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to power off?"), tr("Power Off"), this)) {
|
||||
@@ -379,6 +634,15 @@ void DevicePanel::poweroff() {
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsWindow::hideEvent(QHideEvent *event) {
|
||||
closeParentToggle();
|
||||
|
||||
parentToggleOpen = false;
|
||||
subParentToggleOpen = false;
|
||||
|
||||
previousScrollPosition = 0;
|
||||
}
|
||||
|
||||
void SettingsWindow::showEvent(QShowEvent *event) {
|
||||
setCurrentPanel(0);
|
||||
}
|
||||
@@ -396,33 +660,34 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
// setup two main layouts
|
||||
sidebar_widget = new QWidget;
|
||||
QVBoxLayout *sidebar_layout = new QVBoxLayout(sidebar_widget);
|
||||
sidebar_layout->setMargin(0);
|
||||
panel_widget = new QStackedWidget();
|
||||
|
||||
// close button
|
||||
QPushButton *close_btn = new QPushButton(tr("← Back"));
|
||||
close_btn->setStyleSheet(R"(
|
||||
QPushButton {
|
||||
font-size: 50px;
|
||||
padding-bottom: 0px;
|
||||
border 1px grey solid;
|
||||
color: white;
|
||||
border-radius: 25px;
|
||||
background-color: #292929;
|
||||
background: #292929;
|
||||
font-size: 50px;
|
||||
font-weight: 500;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #3B3B3B;
|
||||
color: #ADADAD;
|
||||
}
|
||||
)");
|
||||
close_btn->setFixedSize(300, 125);
|
||||
sidebar_layout->addSpacing(10);
|
||||
sidebar_layout->addWidget(close_btn, 0, Qt::AlignRight);
|
||||
QObject::connect(close_btn, &QPushButton::clicked, [this]() {
|
||||
if (frogPilotTogglesOpen) {
|
||||
frogPilotTogglesOpen = false;
|
||||
this->closeParentToggle();
|
||||
if (subParentToggleOpen) {
|
||||
closeSubParentToggle();
|
||||
subParentToggleOpen = false;
|
||||
} else if (parentToggleOpen) {
|
||||
closeParentToggle();
|
||||
parentToggleOpen = false;
|
||||
} else {
|
||||
this->closeSettings();
|
||||
closeSettings();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -435,20 +700,19 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription);
|
||||
QObject::connect(toggles, &TogglesPanel::updateMetric, this, &SettingsWindow::updateMetric);
|
||||
|
||||
// FrogPilotControlsPanel *frogpilotControls = new FrogPilotControlsPanel(this);
|
||||
// QObject::connect(frogpilotControls, &FrogPilotControlsPanel::closeParentToggle, this, [this]() {frogPilotTogglesOpen = false;});
|
||||
// QObject::connect(frogpilotControls, &FrogPilotControlsPanel::openParentToggle, this, [this]() {frogPilotTogglesOpen = true;});
|
||||
FrogPilotControlsPanel *frogpilotControls = new FrogPilotControlsPanel(this);
|
||||
QObject::connect(frogpilotControls, &FrogPilotControlsPanel::openSubParentToggle, this, [this]() {subParentToggleOpen = true;});
|
||||
QObject::connect(frogpilotControls, &FrogPilotControlsPanel::openParentToggle, this, [this]() {parentToggleOpen = true;});
|
||||
|
||||
FrogPilotVisualsPanel *frogpilotVisuals = new FrogPilotVisualsPanel(this);
|
||||
QObject::connect(frogpilotVisuals, &FrogPilotVisualsPanel::closeParentToggle, this, [this]() {frogPilotTogglesOpen = false;});
|
||||
QObject::connect(frogpilotVisuals, &FrogPilotVisualsPanel::openParentToggle, this, [this]() {frogPilotTogglesOpen = true;});
|
||||
QObject::connect(frogpilotVisuals, &FrogPilotVisualsPanel::openParentToggle, this, [this]() {parentToggleOpen = true;});
|
||||
|
||||
QList<QPair<QString, QWidget *>> panels = {
|
||||
{tr("Device"), device},
|
||||
{tr("Network"), new Networking(this)},
|
||||
{tr("Toggles"), toggles},
|
||||
{tr("Software"), new SoftwarePanel(this)},
|
||||
// {tr("Controls"), frogpilotControls},
|
||||
{tr("Controls"), frogpilotControls},
|
||||
{tr("Navigation"), new FrogPilotNavigationPanel(this)},
|
||||
{tr("Vehicles"), new FrogPilotVehiclesPanel(this)},
|
||||
{tr("Visuals"), frogpilotVisuals},
|
||||
@@ -484,21 +748,24 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
ScrollView *panel_frame = new ScrollView(panel, this);
|
||||
panel_widget->addWidget(panel_frame);
|
||||
|
||||
if (name == tr("Controls") || name == tr("Visuals")) {
|
||||
if (name == tr("Controls")) {
|
||||
QScrollBar *scrollbar = panel_frame->verticalScrollBar();
|
||||
|
||||
QObject::connect(scrollbar, &QScrollBar::valueChanged, this, [this](int value) {
|
||||
if (!frogPilotTogglesOpen) {
|
||||
if (!parentToggleOpen) {
|
||||
previousScrollPosition = value;
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(scrollbar, &QScrollBar::rangeChanged, this, [this, panel_frame]() {
|
||||
panel_frame->restorePosition(previousScrollPosition);
|
||||
if (!parentToggleOpen) {
|
||||
panel_frame->restorePosition(previousScrollPosition);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(btn, &QPushButton::clicked, [=, w = panel_frame]() {
|
||||
closeParentToggle();
|
||||
previousScrollPosition = 0;
|
||||
btn->setChecked(true);
|
||||
panel_widget->setCurrentWidget(w);
|
||||
|
||||
Reference in New Issue
Block a user