diff --git a/selfdrive/ui/sunnypilot/SConscript b/selfdrive/ui/sunnypilot/SConscript deleted file mode 100644 index 449093886a..0000000000 --- a/selfdrive/ui/sunnypilot/SConscript +++ /dev/null @@ -1,107 +0,0 @@ -widgets_src = [ - "sunnypilot/qt/request_repeater.cc", - "sunnypilot/qt/widgets/toggle.cc", - "sunnypilot/qt/widgets/controls.cc", - "sunnypilot/qt/widgets/drive_stats.cc", - "sunnypilot/qt/widgets/expandable_row.cc", - "sunnypilot/qt/widgets/external_storage.cc", - "sunnypilot/qt/widgets/prime.cc", - "sunnypilot/qt/widgets/scrollview.cc", - "sunnypilot/qt/network/networking.cc", -] - -qt_util = [ - "sunnypilot/qt/util.cc", -] - -qt_src = [ - "sunnypilot/ui.cc", - "sunnypilot/qt/api.cc", - "sunnypilot/qt/sidebar.cc", - "sunnypilot/qt/window.cc", - "sunnypilot/qt/home.cc", - "sunnypilot/qt/offroad/exit_offroad_button.cc", - "sunnypilot/qt/offroad/offroad_home.cc", - "sunnypilot/qt/offroad/settings/developer_panel.cc", - "sunnypilot/qt/offroad/settings/device_panel.cc", - "sunnypilot/qt/offroad/settings/display_panel.cc", - "sunnypilot/qt/offroad/settings/lateral_panel.cc", - "sunnypilot/qt/offroad/settings/longitudinal_panel.cc", - "sunnypilot/qt/offroad/settings/max_time_offroad.cc", - "sunnypilot/qt/offroad/settings/brightness.cc", - "sunnypilot/qt/offroad/settings/models_panel.cc", - "sunnypilot/qt/offroad/settings/osm_panel.cc", - "sunnypilot/qt/offroad/settings/settings.cc", - "sunnypilot/qt/offroad/settings/software_panel.cc", - "sunnypilot/qt/offroad/settings/sunnylink_panel.cc", - "sunnypilot/qt/offroad/settings/sunnylink/sponsor_widget.cc", - "sunnypilot/qt/offroad/settings/sunnylink/community_widget.cc", - "sunnypilot/qt/offroad/settings/trips_panel.cc", - "sunnypilot/qt/offroad/settings/vehicle_panel.cc", - "sunnypilot/qt/offroad/settings/visuals_panel.cc", - "sunnypilot/qt/onroad/alerts.cc", - "sunnypilot/qt/onroad/annotated_camera.cc", - "sunnypilot/qt/onroad/buttons.cc", - "sunnypilot/qt/onroad/developer_ui/developer_ui.cc", - "sunnypilot/qt/onroad/hud.cc", - "sunnypilot/qt/onroad/model.cc", - "sunnypilot/qt/onroad/onroad_home.cc", -] - -lateral_panel_qt_src = [ - "sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.cc", - "sunnypilot/qt/offroad/settings/lateral/lane_change_settings.cc", - "sunnypilot/qt/offroad/settings/lateral/mads_settings.cc", - "sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc", - "sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.cc", - "sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.cc", -] - -longitudinal_panel_qt_src = [ - "sunnypilot/qt/offroad/settings/longitudinal/custom_acc_increment.cc", - "sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.cc", - "sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc", -] - -network_src = [ - "sunnypilot/qt/network/sunnylink/sunnylink_client.cc", - "sunnypilot/qt/network/sunnylink/services/base_device_service.cc", - "sunnypilot/qt/network/sunnylink/services/role_service.cc", - "sunnypilot/qt/network/sunnylink/services/user_service.cc", -] - -osm_panel_qt_src = [ - "sunnypilot/qt/offroad/settings/osm/models_fetcher.cc", -] - -vehicle_panel_qt_src = [ - "sunnypilot/qt/offroad/settings/vehicle/brand_settings_factory.cc", - "sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.cc", - "sunnypilot/qt/offroad/settings/vehicle/platform_selector.cc", -] - -brand_settings_qt_src = [ - "sunnypilot/qt/offroad/settings/vehicle/chrysler_settings.cc", - "sunnypilot/qt/offroad/settings/vehicle/ford_settings.cc", - "sunnypilot/qt/offroad/settings/vehicle/gm_settings.cc", - "sunnypilot/qt/offroad/settings/vehicle/honda_settings.cc", - "sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.cc", - "sunnypilot/qt/offroad/settings/vehicle/mazda_settings.cc", - "sunnypilot/qt/offroad/settings/vehicle/nissan_settings.cc", - "sunnypilot/qt/offroad/settings/vehicle/rivian_settings.cc", - "sunnypilot/qt/offroad/settings/vehicle/subaru_settings.cc", - "sunnypilot/qt/offroad/settings/vehicle/tesla_settings.cc", - "sunnypilot/qt/offroad/settings/vehicle/toyota_settings.cc", - "sunnypilot/qt/offroad/settings/vehicle/volkswagen_settings.cc", -] - -display_panel_qt_src = [ - "sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.cc", -] - -sp_widgets_src = widgets_src + network_src -sp_qt_src = qt_src + lateral_panel_qt_src + vehicle_panel_qt_src + brand_settings_qt_src + \ - longitudinal_panel_qt_src + osm_panel_qt_src + display_panel_qt_src -sp_qt_util = qt_util - -Export('sp_widgets_src', 'sp_qt_src', "sp_qt_util") diff --git a/selfdrive/ui/sunnypilot/qt/api.cc b/selfdrive/ui/sunnypilot/qt/api.cc deleted file mode 100644 index d75d8d39f0..0000000000 --- a/selfdrive/ui/sunnypilot/qt/api.cc +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/api.h" - -#include -#include - -#include "util.h" -#include "selfdrive/ui/qt/util.h" - -namespace SunnylinkApi { - QString create_jwt(const QJsonObject &payloads, int expiry, bool sunnylink) { - QJsonObject header = {{"alg", "RS256"}}; - - auto t = QDateTime::currentSecsSinceEpoch(); - auto dongle_id = sunnylink ? getSunnylinkDongleId() : getDongleId(); - QJsonObject payload = {{"identity", dongle_id.value_or("")}, {"nbf", t}, {"iat", t}, {"exp", t + expiry}}; - for (auto it = payloads.begin(); it != payloads.end(); ++it) { - payload.insert(it.key(), it.value()); - } - - auto b64_opts = QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals; - QString jwt = QJsonDocument(header).toJson(QJsonDocument::Compact).toBase64(b64_opts) + '.' + - QJsonDocument(payload).toJson(QJsonDocument::Compact).toBase64(b64_opts); - - auto hash = QCryptographicHash::hash(jwt.toUtf8(), QCryptographicHash::Sha256); - return jwt + "." + CommaApi::rsa_sign(hash).toBase64(b64_opts); - } -} // namespace SunnylinkApi - -void HttpRequestSP::sendRequest(const QString& requestURL, Method method, const QByteArray& payload) { - if (active()) { - return; - } - QNetworkRequest request = prepareRequest(requestURL); - - if(!payload.isEmpty() && (method == Method::POST || method == Method::PUT)) { - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - } - - switch (method) { - case Method::GET: - reply = nam()->get(request); - break; - case Method::DELETE: - reply = nam()->deleteResource(request); - break; - case Method::POST: - reply = nam()->post(request, payload); - break; - case Method::PUT: - reply = nam()->put(request, payload); - break; - } - - networkTimer->start(); - connect(reply, &QNetworkReply::finished, this, &HttpRequestSP::requestFinished); -} diff --git a/selfdrive/ui/sunnypilot/qt/api.h b/selfdrive/ui/sunnypilot/qt/api.h deleted file mode 100644 index 592b2e668f..0000000000 --- a/selfdrive/ui/sunnypilot/qt/api.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/api.h" -#include "selfdrive/ui/sunnypilot/qt/util.h" -#include "common/util.h" - -namespace SunnylinkApi { - QByteArray rsa_encrypt(const QByteArray& data); - QByteArray rsa_decrypt(const QByteArray& data); - QString create_jwt(const QJsonObject& payloads = {}, int expiry = 3600, bool sunnylink = false); -} - -class HttpRequestSP : public HttpRequest { - Q_OBJECT - -public: - explicit HttpRequestSP(QObject* parent, bool create_jwt = true, int timeout = 20000, bool sunnylink = false) : - HttpRequest(parent, create_jwt, timeout), sunnylink(sunnylink) {} - - using HttpRequest::sendRequest; - void sendRequest(const QString& requestURL, Method method, const QByteArray& payload); - -private: - bool sunnylink; - -protected: - [[nodiscard]] QString GetJwtToken() const override { return SunnylinkApi::create_jwt({}, 3600, sunnylink); } - [[nodiscard]] QString GetUserAgent() const override { return getUserAgent(sunnylink); } -}; diff --git a/selfdrive/ui/sunnypilot/qt/common/json_fetcher.h b/selfdrive/ui/sunnypilot/qt/common/json_fetcher.h deleted file mode 100644 index 5691f600a6..0000000000 --- a/selfdrive/ui/sunnypilot/qt/common/json_fetcher.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include -#include -#include -#include - -class JsonFetcher { -public: - static QJsonObject getJsonFromURL(const QString &url) { - const auto qurl = QUrl(url); - QNetworkAccessManager manager; - const QNetworkRequest request(qurl); - QNetworkReply *reply = manager.get(request); - QEventLoop loop; - - // Send GET request - - QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); - loop.exec(); - - if (reply->error() != QNetworkReply::NoError) { - qWarning() << "Failed to fetch data from URL: " << reply->errorString(); - return QJsonObject(); - } - - const QByteArray responseData = reply->readAll(); - const QJsonDocument doc = QJsonDocument::fromJson(responseData); - QJsonObject json = doc.object(); - - reply->deleteLater(); - return json; - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/home.cc b/selfdrive/ui/sunnypilot/qt/home.cc deleted file mode 100644 index 92b6e724fe..0000000000 --- a/selfdrive/ui/sunnypilot/qt/home.cc +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/home.h" - -#include "selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h" - -HomeWindowSP::HomeWindowSP(QWidget *parent) : HomeWindow(parent) { -} - -void HomeWindowSP::updateState(const UIState &s) { - HomeWindow::updateState(s); -} - -void HomeWindowSP::mousePressEvent(QMouseEvent *e) { - HomeWindow::mousePressEvent(e); -} diff --git a/selfdrive/ui/sunnypilot/qt/home.h b/selfdrive/ui/sunnypilot/qt/home.h deleted file mode 100644 index 4cf532d14c..0000000000 --- a/selfdrive/ui/sunnypilot/qt/home.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include -#include - -#include "common/params.h" -#include "selfdrive/ui/qt/body.h" -#include "selfdrive/ui/qt/widgets/offroad_alerts.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/qt/home.h" - -#ifdef SUNNYPILOT -#include "selfdrive/ui/sunnypilot/qt/sidebar.h" -#define OnroadWindow OnroadWindowSP -#else -#include "selfdrive/ui/qt/sidebar.h" -#include "selfdrive/ui/qt/onroad/onroad_home.h" -#endif - -class HomeWindowSP : public HomeWindow { - Q_OBJECT - -public: - explicit HomeWindowSP(QWidget *parent = 0); - -protected: - void mousePressEvent(QMouseEvent *e) override; - -private slots: - void updateState(const UIState &s) override; -}; diff --git a/selfdrive/ui/sunnypilot/qt/network/networking.cc b/selfdrive/ui/sunnypilot/qt/network/networking.cc deleted file mode 100644 index 3db65a5b51..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/networking.cc +++ /dev/null @@ -1,45 +0,0 @@ -#include "selfdrive/ui/sunnypilot/qt/network/networking.h" -#include -#include -#include - -NetworkingSP::NetworkingSP(QWidget *parent) : Networking(parent) { - auto vlayout = wifiScreen->findChild(); - auto hlayout = new QHBoxLayout(); - - // Create and setup scan button - auto scanButton = new QPushButton(tr("Scan")); - scanButton->setObjectName("scan_btn"); - scanButton->setFixedSize(400, 100); - - connect(wifi, &WifiManager::refreshSignal, this, [=]() { scanButton->setText(tr("Scan")); scanButton->setEnabled(true); }); - connect(scanButton, &QPushButton::clicked, [=]() { scanButton->setText(tr("Scanning...")); scanButton->setEnabled(false); wifi->requestScan(); }); - - hlayout->addWidget(scanButton); - hlayout->addStretch(1); - - // Look for an existing Advanced button - QPushButton* existingAdvanced = wifiScreen->findChild("advanced_btn"); - if (existingAdvanced) { - hlayout->addWidget(existingAdvanced); - } - - // Insert our new layout at the top of vlayout - vlayout->setMargin(40); - vlayout->insertLayout(0, hlayout); - - // Add our scan button to the existing style selectors - auto newStyleSheet = styleSheet().replace( - ", #advanced_btn ", - ", #advanced_btn, #scan_btn " - ).replace( - ", #advanced_btn:pressed", - ", #advanced_btn:pressed, #scan_btn:pressed" - ).append(R"( - #scan_btn:disabled { - background-color: #121212; - color: #33FFFFFF; - } - )"); - setStyleSheet(newStyleSheet); -} diff --git a/selfdrive/ui/sunnypilot/qt/network/networking.h b/selfdrive/ui/sunnypilot/qt/network/networking.h deleted file mode 100644 index f220b8a50a..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/networking.h +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once -#include "selfdrive/ui/qt/network/networking.h" - - -class NetworkingSP : public Networking { - Q_OBJECT - -public: - explicit NetworkingSP(QWidget *parent = nullptr); -}; diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h deleted file mode 100644 index 04b4dccf14..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include - -enum class RoleType { - ReadOnly, - Sponsor, - Admin -}; - -// haha, a role model xD -class RoleModel { -protected: - QJsonObject m_raw_json_object; - -public: - RoleType roleType; - - explicit RoleModel(const RoleType &roleType) : roleType(roleType) { m_raw_json_object = toJson(); } - explicit RoleModel(const QJsonObject &json) : RoleModel(stringToRoleType(json["role_type"].toString())) { m_raw_json_object = json; } - - [[nodiscard]] QJsonObject toJson() const { - QJsonObject json; - json["role_type"] = roleTypeToString(roleType); - return json; - } - - static RoleType stringToRoleType(const QString &roleTypeString) { - if (roleTypeString == "ReadOnly") return RoleType::ReadOnly; - if (roleTypeString == "Sponsor") return RoleType::Sponsor; - - return RoleType::Admin; // Default to Admin - } - - static QString roleTypeToString(const RoleType &roleType) { - switch (roleType) { - case RoleType::ReadOnly: - return "ReadOnly"; - case RoleType::Sponsor: - return "Sponsor"; - default: // RoleType::Admin - return "Admin"; - } - } - - template ::value>::type> T as() const { - return T(m_raw_json_object); - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/sponsor_role_model.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/sponsor_role_model.h deleted file mode 100644 index 7e1772b591..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/sponsor_role_model.h +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include - -enum class SponsorTier { - Free, - Novice, - Supporter, - Contributor, - Benefactor, - Guardian, -}; - -// haha, a role model xD -class SponsorRoleModel final : RoleModel { -public: - SponsorTier roleTier; - - explicit SponsorRoleModel(const RoleType &roleType, const SponsorTier &roleTier) : RoleModel(roleType), roleTier(roleTier) {} - explicit SponsorRoleModel(const QJsonObject &json) : RoleModel(json), roleTier(stringToSponsorTier(json["role_tier"].toString())) {} - - [[nodiscard]] QJsonObject toJson() const { - QJsonObject json = RoleModel::toJson(); - json["role_tier"] = sponsorTierToString(roleTier); - return json; - } - - static SponsorTier stringToSponsorTier(const QString &sponsorTierString) { - const auto sponsorTierStringLower = sponsorTierString.toLower(); - if (sponsorTierStringLower == "guardian") return SponsorTier::Guardian; - if (sponsorTierStringLower == "novice") return SponsorTier::Novice; - if (sponsorTierStringLower == "supporter") return SponsorTier::Supporter; - if (sponsorTierStringLower == "contributor") return SponsorTier::Contributor; - if (sponsorTierStringLower == "benefactor") return SponsorTier::Benefactor; - - // Default to Free - return SponsorTier::Free; - } - - static QString sponsorTierToString(const SponsorTier &sponsorTier) { - switch (sponsorTier) { - case SponsorTier::Guardian: - return "Guardian"; - case SponsorTier::Novice: - return "Novice"; - case SponsorTier::Supporter: - return "Supporter"; - case SponsorTier::Contributor: - return "Contributor"; - case SponsorTier::Benefactor: - return "Benefactor"; - - default: // SponsorTier::Free - return "Free"; - } - } - [[nodiscard]] auto getSponsorTierString() const { return sponsorTierToString(roleTier); } - - static QString sponsorTierToColor(const SponsorTier &sponsorTier) { - switch (sponsorTier) { - case SponsorTier::Guardian: - return "gold"; - case SponsorTier::Benefactor: - return "mediumseagreen"; - case SponsorTier::Contributor: - return "steelblue"; - case SponsorTier::Supporter: - return "mediumpurple"; - case SponsorTier::Novice: - return "white"; - default: // SponsorTier::Free - return "silver"; - } - } - [[nodiscard]] auto getSponsorTierColor() const { return sponsorTierToColor(roleTier); } -}; diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/user_model.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/user_model.h deleted file mode 100644 index 4d255ac8e3..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/user_model.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include - -class UserModel { -public: - QString device_id; - QString user_id; - qint64 created_at; - qint64 updated_at; - QString token_hash; - - explicit UserModel(const QJsonObject &json) { - device_id = json["device_id"].toString(); - user_id = json["user_id"].toString(); - created_at = json["created_at"].toInt(); - updated_at = json["updated_at"].toInt(); - token_hash = json["token_hash"].toString(); - } - - [[nodiscard]] QJsonObject toJson() const { - QJsonObject json; - json["device_id"] = device_id; - json["user_id"] = user_id; - json["created_at"] = created_at; - json["updated_at"] = updated_at; - json["token_hash"] = token_hash; - return json; - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.cc b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.cc deleted file mode 100644 index 3919a1821f..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.cc +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink//services/base_device_service.h" - -#include "selfdrive/ui/sunnypilot/qt/request_repeater.h" - -#include "common/swaglog.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.h" - -BaseDeviceService::BaseDeviceService(QObject* parent) : QObject(parent) { - param_watcher = new ParamWatcher(this); - connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { - paramsRefresh(); - }); - param_watcher->addParam("SunnylinkEnabled"); -} - -void BaseDeviceService::paramsRefresh() { -} - -void BaseDeviceService::loadDeviceData(const QString &url, bool poll) { - if (!is_sunnylink_enabled()) { - LOGW("Sunnylink is not enabled, refusing to load data."); - return; - } - - auto sl_dongle_id = getSunnylinkDongleId(); - if (!sl_dongle_id.has_value()) - return; - - QString fullUrl = SUNNYLINK_BASE_URL + "/device/" + *sl_dongle_id + url; - if (poll && !isCurrentyPolling()) { - LOGD("Polling %s", qPrintable(fullUrl)); - LOGD("Cache key: SunnylinkCache_%s", qPrintable(QString(getCacheKey()))); - repeater = new RequestRepeaterSP(this, fullUrl, "SunnylinkCache_" + getCacheKey(), 60, false, true); - connect(repeater, &RequestRepeaterSP::requestDone, this, &BaseDeviceService::handleResponse); - } else if (isCurrentyPolling()) { - repeater->ForceUpdate(); - } else { - LOGD("Sending one-time %s", qPrintable(fullUrl)); - initial_request = new HttpRequestSP(this, true, 10000, true); - connect(initial_request, &HttpRequestSP::requestDone, this, &BaseDeviceService::handleResponse); - } -} - -void BaseDeviceService::stopPolling() { - if (repeater != nullptr) { - repeater->deleteLater(); - repeater = nullptr; - } -} diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.h deleted file mode 100644 index 8ef99d1013..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/request_repeater.h" -#include "selfdrive/ui/qt/util.h" - -class BaseDeviceService : public QObject { - Q_OBJECT - -protected: - void paramsRefresh(); - void loadDeviceData(const QString &url, bool poll = false); - virtual void handleResponse(const QString &response, bool success) = 0; - - static bool is_sunnylink_enabled() { return Params().getBool("SunnylinkEnabled");} - ParamWatcher* param_watcher; - HttpRequestSP* initial_request = nullptr; - RequestRepeaterSP* repeater = nullptr; - -public: - explicit BaseDeviceService(QObject* parent = nullptr); - virtual QString getCacheKey() const = 0; - bool isCurrentyPolling() {return repeater != nullptr;} - void stopPolling(); -}; diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.cc b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.cc deleted file mode 100644 index bffe32839f..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.cc +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.h" - -#include -#include - -RoleService::RoleService(QObject* parent) : BaseDeviceService(parent) {} - -void RoleService::load() { - loadDeviceData(url); -} - -void RoleService::startPolling() { - loadDeviceData(url, true); -} - -void RoleService::handleResponse(const QString &response, bool success) { - if (!success) return; - - QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); - QJsonArray jsonArray = doc.array(); - - std::vector roles; - for (const auto &value : jsonArray) { - roles.emplace_back(value.toObject()); - } - - emit rolesReady(roles); - uiStateSP()->setSunnylinkRoles(roles); -} diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.h deleted file mode 100644 index abd0e1ab83..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include - -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.h" -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h" - -class RoleService : public BaseDeviceService { - Q_OBJECT - -public: - explicit RoleService(QObject* parent = nullptr); - void load(); - void startPolling(); - [[nodiscard]] QString getCacheKey() const final { return "Roles"; } - -signals: - void rolesReady(const std::vector &roles); - -protected: - void handleResponse(const QString&response, bool success) override; - -private: - QString url = "/roles"; -}; diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.cc b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.cc deleted file mode 100644 index cd16360c26..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.cc +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h" - -#include -#include - -#include "selfdrive/ui/sunnypilot/ui.h" - -UserService::UserService(QObject* parent) : BaseDeviceService(parent) { - url = "/users"; -} - -void UserService::load() { - loadDeviceData(url); -} - -void UserService::startPolling() { - loadDeviceData(url, true); -} - -void UserService::handleResponse(const QString &response, bool success) { - if (!success) { - return; - } - - QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); - QJsonArray jsonArray = doc.array(); - - std::vector users; - for (const auto &value : jsonArray) { - users.emplace_back(value.toObject()); - } - - emit usersReady(users); - uiStateSP()->setSunnylinkDeviceUsers(users); -} diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h deleted file mode 100644 index 90eb354751..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include - -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.h" -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/user_model.h" - -class UserService : public BaseDeviceService { - Q_OBJECT - -public: - explicit UserService(QObject* parent = nullptr); - void load(); - void startPolling(); - [[nodiscard]] QString getCacheKey() const final { return "Users"; }; - -signals: - void usersReady(const std::vector&users); - -protected: - void handleResponse(const QString&response, bool success) override; - -private: - QString url = "/users"; -}; diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.cc b/selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.cc deleted file mode 100644 index 4428eb55c4..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.cc +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.h" -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h" - -SunnylinkClient::SunnylinkClient(QObject* parent) : QObject(parent) { - role_service = new RoleService(parent); - user_service = new UserService(parent); -} diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.h deleted file mode 100644 index 0961449926..0000000000 --- a/selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include - -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.h" -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h" - -class SunnylinkClient : public QObject { - Q_OBJECT - -public: - explicit SunnylinkClient(QObject* parent); - RoleService* role_service; - UserService* user_service; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/exit_offroad_button.cc b/selfdrive/ui/sunnypilot/qt/offroad/exit_offroad_button.cc deleted file mode 100644 index 0c7902476a..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/exit_offroad_button.cc +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include -#include -#include - -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/widgets/input.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/exit_offroad_button.h" - - -ExitOffroadButton::ExitOffroadButton(QWidget *parent) : QPushButton(parent), glowTimer(new QTimer(this)) { - setMouseTracking(true); - - connect(glowTimer, &QTimer::timeout, this, [this]() { - // Pulse alpha up and down - glowAlpha += glowDelta; - if (glowAlpha > 220 || glowAlpha < 10) { - glowDelta *= -1; - } - update(); // trigger repaint - }); - - glowTimer->start(45); - - pixmap = QPixmap("../../sunnypilot/selfdrive/assets/offroad/icon_exit_offroad.png").scaledToWidth(img_width, Qt::SmoothTransformation); - - // go to toggles and expand experimental mode description - connect(this, &QPushButton::clicked, [=]() { - if (ConfirmationDialog::confirm(tr("Are you sure you want to exit Always Offroad mode?"), tr("Confirm"), this)) { - params.remove("OffroadMode"); - } - }); - - setFixedHeight(125); - QHBoxLayout *main_layout = new QHBoxLayout; - main_layout->setContentsMargins(horizontal_padding, 0, horizontal_padding, 0); - - mode_label = new QLabel(tr("EXIT ALWAYS OFFROAD MODE")); - mode_icon = new QLabel; - mode_icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); - mode_icon->setPixmap(pixmap); - - main_layout->addWidget(mode_label, 1, Qt::AlignLeft); - main_layout->addWidget(mode_icon, 0, Qt::AlignRight); - - setLayout(main_layout); - - setStyleSheet(R"( - QPushButton { - border: none; - } - - QLabel { - font-size: 45px; - font-weight: 300; - text-align: left; - font-family: JetBrainsMono; - color: #000000; - } - )"); -} - -void drawPulsingGlowOverlay(QPainter &p, QPainterPath path, int glowAlpha) { - // Draw pulsing glow effect clipped to button area - p.save(); - p.setClipPath(path); - p.setCompositionMode(QPainter::CompositionMode_HardLight); - - const QColor animatedGlowColor(255, 255, 255, std::min(255, glowAlpha)); - QPen glowPen(animatedGlowColor, 8); - glowPen.setJoinStyle(Qt::RoundJoin); - p.setPen(glowPen); - p.drawPath(path); - - p.restore(); -} - -void ExitOffroadButton::paintEvent(QPaintEvent *event) { - QPainter p(this); - p.setRenderHint(QPainter::Antialiasing); - - QPainterPath path; - path.addRoundedRect(rect(), 10, 10); - - // gradient - bool pressed = isDown(); - QLinearGradient gradient(rect().left(), 0, rect().right(), 0); - gradient.setColorAt(0, QColor(35, 149, 255, pressed ? 0xcc : 0xff)); - gradient.setColorAt(0.3, QColor(35, 149, 255, pressed ? 0xcc : 0xff)); - gradient.setColorAt(1, QColor(20, 255, 171, pressed ? 0xcc : 0xff)); - p.fillPath(path, gradient); - - drawPulsingGlowOverlay(p, path, glowAlpha); - - // vertical line - p.setPen(QPen(QColor(0, 0, 0, 0x4d), 3, Qt::SolidLine)); - int line_x = rect().right() - img_width - (2 * horizontal_padding); - p.drawLine(line_x, rect().bottom(), line_x, rect().top()); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/exit_offroad_button.h b/selfdrive/ui/sunnypilot/qt/offroad/exit_offroad_button.h deleted file mode 100644 index 673d9fff73..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/exit_offroad_button.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include - -#include "common/params.h" - -class ExitOffroadButton : public QPushButton { - Q_OBJECT - -private: - QTimer *glowTimer; - int glowAlpha = 100; // Current alpha of glow - int glowDelta = 10; // Change per tick - -public: - explicit ExitOffroadButton(QWidget* parent = 0); - - Params params; - bool offroad_mode; - int img_width = 100; - int horizontal_padding = 30; - QPixmap pixmap; - QLabel *mode_label; - QLabel *mode_icon; - -protected: - void paintEvent(QPaintEvent *event) override; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/offroad_home.cc b/selfdrive/ui/sunnypilot/qt/offroad/offroad_home.cc deleted file mode 100644 index cc82e6ddb9..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/offroad_home.cc +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include - -#include "selfdrive/ui/sunnypilot/qt/offroad/offroad_home.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h" - -OffroadHomeSP::OffroadHomeSP(QWidget *parent) : OffroadHome(parent) { - QFrame *left_widget = new QFrame(this); - QVBoxLayout *left_layout = new QVBoxLayout(left_widget); - left_layout->setContentsMargins(0, 0, 0, 0); - left_layout->setSpacing(30); - - btn_exit_offroad = new ExitOffroadButton(this); - QObject::connect(btn_exit_offroad, &ExitOffroadButton::clicked, [=]() { - refreshOffroadStatus(); - }); - left_layout->addWidget(btn_exit_offroad); - - left_layout->addWidget(new DriveStats(this)); - left_widget->setStyleSheet("border-radius: 10px;"); - - home_layout->insertWidget(0, left_widget); - - offroad_notif = new QPushButton(tr("ALWAYS OFFROAD ACTIVE")); - offroad_notif->setVisible(false); - offroad_notif->setStyleSheet("background-color: #E22C2C;"); - header_layout->insertWidget(0, offroad_notif, 0, Qt::AlignHCenter | Qt::AlignLeft); - - QObject::connect(deviceSP(), &DeviceSP::displayPowerChanged, this, &OffroadHomeSP::refreshOffroadStatus); - -} - -void OffroadHomeSP::showEvent(QShowEvent *event) { - refreshOffroadStatus(); - OffroadHome::showEvent(event); -} - -void OffroadHomeSP::refreshOffroadStatus() { - bool is_offroad = params.getBool("OffroadMode"); - btn_exit_offroad->setVisible(is_offroad); - offroad_notif->setVisible(is_offroad); - OffroadHome::refresh(); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/offroad_home.h b/selfdrive/ui/sunnypilot/qt/offroad/offroad_home.h deleted file mode 100644 index 30816f666c..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/offroad_home.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/offroad/offroad_home.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/exit_offroad_button.h" - -class OffroadHomeSP : public OffroadHome { - Q_OBJECT - -public: - explicit OffroadHomeSP(QWidget *parent = 0); - -private: - ExitOffroadButton *btn_exit_offroad; - QPushButton *offroad_notif; - Params params; - - void showEvent(QShowEvent *event) override; - void refreshOffroadStatus(); -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.cc deleted file mode 100644 index e9bd13485a..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.cc +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h" - -// Map of Brightness Options -const QMap Brightness::brightness_options = { - {"0", "1"}, // Auto (Dark) - {"1", "0"}, // Auto - {"2", "10"}, - {"3", "20"}, - {"4", "30"}, - {"5", "40"}, - {"6", "50"}, - {"7", "60"}, - {"8", "70"}, - {"9", "80"}, - {"10", "90"}, - {"11", "100"} -}; - -Brightness::Brightness() : OptionControlSP( - "Brightness", - tr("Global Brightness"), - tr("Overrides the brightness of the device. This applies to both onroad and offroad screens. "), - "../assets/offroad/icon_blank.png", - {0, 11}, 1, true, &brightness_options) { - - refresh(); -} - -void Brightness::refresh() { - const int brightness = QString::fromStdString(params.get("Brightness")).toInt(); - - QString label; - if (brightness == 1) { - label = tr("Auto (Dark)"); - } else if (brightness == 0) { - label = tr("Auto"); - } else { - const int value = brightness; - label = QString("%1").arg(value); - } - - setLabel(label); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h deleted file mode 100644 index 20d0a291d9..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class Brightness : public OptionControlSP { - Q_OBJECT - -public: - static const QMap brightness_options; - - Brightness(); - void refresh(); - -private: - Params params; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.cc deleted file mode 100644 index 9eb8da71ec..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.cc +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/external_storage.h" - -DeveloperPanelSP::DeveloperPanelSP(SettingsWindow *parent) : DeveloperPanel(parent) { - - #ifndef __APPLE__ - addItem(new ExternalStorageControl()); - #endif - - // Advanced Controls Toggle - showAdvancedControls = new ParamControlSP("ShowAdvancedControls", tr("Show Advanced Controls"), tr("Toggle visibility of advanced sunnypilot controls.\nThis only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state."), ""); - addItem(showAdvancedControls); - - QObject::connect(showAdvancedControls, &ParamControlSP::toggleFlipped, this, [=](bool) { - AbstractControlSP::UpdateAllAdvancedControls(); - updateToggles(!uiState()->scene.started); - }); - showAdvancedControls->showDescription(); - - // Github Runner Toggle - enableGithubRunner = new ParamControlSP("EnableGithubRunner", tr("Enable GitHub runner service"), tr("Enables or disables the github runner service."), "", this, true); - addItem(enableGithubRunner); - - // Copyparty Toggle - enableCopyparty = new ParamControlSP("EnableCopyparty", tr("Enable Copyparty service"), tr("Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP."), "", this, false); - addItem(enableCopyparty); - - // Quickboot Mode Toggle - prebuiltToggle = new ParamControlSP("QuickBootToggle", tr("Enable Quickboot Mode"), tr(""), "", this, true); - addItem(prebuiltToggle); - - QObject::connect(prebuiltToggle, &ParamControl::toggleFlipped, [=](bool state) { - QString prebuiltPath = "/data/openpilot/prebuilt"; - state ? QFile(prebuiltPath).open(QIODevice::WriteOnly) : QFile::remove(prebuiltPath); - prebuiltToggle->refresh(); - }); - prebuiltToggle->setVisible(false); - - // Error log button - errorLogBtn = new ButtonControlSP(tr("Error Log"), tr("VIEW"), tr("View the error log for sunnypilot crashes.")); - connect(errorLogBtn, &ButtonControlSP::clicked, [=]() { - QFileInfo file("/data/community/crashes/error.log"); - QString text; - if (file.exists()) { - text = "" + file.lastModified().toString("dd-MMM-yyyy hh:mm:ss ").toUpper() + "

"; - } - text += QString::fromStdString(util::read_file("/data/community/crashes/error.log")); - ConfirmationDialog::rich(text, this); - }); - addItem(errorLogBtn); - - QObject::connect(uiState(), &UIState::offroadTransition, this, &DeveloperPanelSP::updateToggles); -} - -void DeveloperPanelSP::updateToggles(bool offroad) { - bool disable_updates = params.getBool("DisableUpdates"); - bool is_release = params.getBool("IsReleaseBranch") || params.getBool("IsReleaseSpBranch"); - bool is_tested = params.getBool("IsTestedBranch"); - bool is_development = params.getBool("IsDevelopmentBranch"); - - prebuiltToggle->setVisible(!is_release && !is_tested && !is_development); - prebuiltToggle->setEnabled(disable_updates); - params.putBool("QuickBootToggle", QFile::exists("/data/openpilot/prebuilt")); - prebuiltToggle->refresh(); - - prebuiltToggle->setDescription(disable_updates - ? tr("When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, " - "it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. " - "

To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.") - : tr("Quickboot mode requires updates to be disabled.
Enable 'Disable Updates' in the Software panel first.")); - prebuiltToggle->showDescription(); - - enableGithubRunner->setVisible(!is_release); - errorLogBtn->setVisible(!is_release); - showAdvancedControls->setEnabled(true); - - joystickToggle->setVisible(!is_release); - longManeuverToggle->setVisible(!is_release); -} - -void DeveloperPanelSP::showEvent(QShowEvent *event) { - DeveloperPanel::showEvent(event); - AbstractControlSP::UpdateAllAdvancedControls(); - updateToggles(!uiState()->scene.started); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.h deleted file mode 100644 index ed64964a56..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ -#pragma once -#include -#include - -#include "selfdrive/ui/qt/offroad/developer_panel.h" - -class DeveloperPanelSP : public DeveloperPanel { - Q_OBJECT -public: - explicit DeveloperPanelSP(SettingsWindow *parent); - -private: - ParamControlSP *enableCopyparty; - ParamControlSP *enableGithubRunner; - ButtonControlSP *errorLogBtn; - ParamControlSP *prebuiltToggle; - Params params; - ParamControlSP *showAdvancedControls; - -private slots: - void updateToggles(bool offroad); - -protected: - void showEvent(QShowEvent *event) override; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc deleted file mode 100644 index 8295789f0a..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc +++ /dev/null @@ -1,203 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h" - -#include "common/watchdog.h" -#include "selfdrive/ui/qt/qt_window.h" - -DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) { - QGridLayout *device_grid_layout = new QGridLayout(); - device_grid_layout->setSpacing(30); - device_grid_layout->setHorizontalSpacing(5); - device_grid_layout->setVerticalSpacing(25); - - std::vector> device_btns = { - {"quietModeBtn", tr("Quiet Mode"), "QuietMode"}, - {"dcamBtn", tr("Driver Camera Preview"), ""}, - {"retrainingBtn", tr("Training Guide"), ""}, - {"regulatoryBtn", tr("Regulatory"), ""}, - {"translateBtn", tr("Language"), ""}, - {"resetParams", tr("Reset Settings"), ""}, - {"onroadUploadsBtn", tr("Onroad Uploads"), "OnroadUploads"} - }; - - int row = 0, col = 0; - for (const auto &[id, text, param] : device_btns) { - if (id == "regulatoryBtn" && !Hardware::TICI()) { - continue; - } - - auto *btn = new PushButtonSP(text, 750, this, param); - btn->setObjectName(id); - buttons[id] = btn; - - if (col==0) { - device_grid_layout->addWidget(btn, row, col, Qt::AlignLeft); - col++; - } else { - device_grid_layout->addWidget(btn, row, col, Qt::AlignRight); - col=0; - row++; - } - } - - connect(buttons["dcamBtn"], &PushButtonSP::clicked, [=]() { emit showDriverView(); }); - - connect(buttons["quietModeBtn"], &PushButtonSP::clicked, buttons["quietModeBtn"], &PushButtonSP::updateButton); - - connect(buttons["retrainingBtn"], &PushButtonSP::clicked, [=]() { - if (ConfirmationDialog::confirm(tr("Are you sure you want to review the training guide?"), tr("Review"), this)) { - emit reviewTrainingGuide(); - } - }); - - if (Hardware::TICI()) { - connect(buttons["regulatoryBtn"], &PushButtonSP::clicked, [=]() { - const std::string txt = util::read_file("../assets/offroad/fcc.html"); - ConfirmationDialog::rich(QString::fromStdString(txt), this); - }); - } - - connect(buttons["translateBtn"], &PushButtonSP::clicked, [=]() { - QMap langs = getSupportedLanguages(); - QString selection = MultiOptionDialog::getSelection(tr("Select a language"), langs.keys(), langs.key(uiState()->language), this); - if (!selection.isEmpty()) { - // put language setting, exit Qt UI, and trigger fast restart - params.put("LanguageSetting", langs[selection].toStdString()); - qApp->exit(18); - watchdog_kick(0); - } - }); - - connect(buttons["resetParams"], &PushButtonSP::clicked, this, &DevicePanelSP::resetSettings); - - connect(buttons["onroadUploadsBtn"], &PushButtonSP::clicked, buttons["onroadUploadsBtn"], &PushButtonSP::updateButton); - - // Max Time Offroad - maxTimeOffroad = new MaxTimeOffroad(); - connect(maxTimeOffroad, &OptionControlSP::updateLabels, maxTimeOffroad, &MaxTimeOffroad::refresh); - addItem(maxTimeOffroad); - - toggleDeviceBootMode = new ButtonParamControlSP("DeviceBootMode", tr("Wake-Up Behavior"), "", "", {"Default", "Offroad"}, 375, true); - addItem(toggleDeviceBootMode); - - connect(toggleDeviceBootMode, &ButtonParamControlSP::buttonClicked, this, [=](int index) { - params.put("DeviceBootMode", QString::number(index).toStdString()); - updateState(offroad); - }); - - addItem(device_grid_layout); - - // offroad mode and power buttons - - QHBoxLayout *power_layout = new QHBoxLayout(); - power_layout->setSpacing(25); - - PushButtonSP *rebootBtn = new PushButtonSP(tr("Reboot"), 750, this); - rebootBtn->setStyleSheet(rebootButtonStyle); - power_layout->addWidget(rebootBtn); - QObject::connect(rebootBtn, &PushButtonSP::clicked, this, &DevicePanelSP::reboot); - - PushButtonSP *poweroffBtn = new PushButtonSP(tr("Power Off"), 750, this); - poweroffBtn->setStyleSheet(powerOffButtonStyle); - power_layout->addWidget(poweroffBtn); - QObject::connect(poweroffBtn, &PushButtonSP::clicked, this, &DevicePanelSP::poweroff); - - if (!Hardware::PC()) { - connect(uiState(), &UIState::offroadTransition, poweroffBtn, &PushButtonSP::setVisible); - } - - offroadBtn = new PushButtonSP(tr("Offroad Mode")); - offroadBtn->setFixedWidth(power_layout->sizeHint().width()); - QObject::connect(offroadBtn, &PushButtonSP::clicked, this, &DevicePanelSP::setOffroadMode); - - power_group_layout = new QVBoxLayout(); - power_group_layout->setSpacing(25); - power_group_layout->addLayout(power_layout); - - addItem(power_group_layout); - - always_enabled_btns = { - rebootBtn, - poweroffBtn, - offroadBtn, - buttons["quietModeBtn"], - buttons["onroadUploadsBtn"], - }; - - QObject::connect(uiState(), &UIState::offroadTransition, this, &DevicePanelSP::updateState); -} - -void DevicePanelSP::setOffroadMode() { - if (!uiState()->engaged()) { - if (params.getBool("OffroadMode")) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to exit Always Offroad mode?"), tr("Confirm"), this)) { - // Check engaged again in case it changed while the dialog was open - if (!uiState()->engaged()) { - params.remove("OffroadMode"); - } - } - } else { - if (ConfirmationDialog::confirm(tr("Are you sure you want to enter Always Offroad mode?"), tr("Confirm"), this)) { - // Check engaged again in case it changed while the dialog was open - if (!uiState()->engaged()) { - params.putBool("OffroadMode", true); - } - } - } - } else { - ConfirmationDialog::alert(tr("Disengage to Enter Always Offroad Mode"), this); - } - - updateState(offroad); -} - -void DevicePanelSP::resetSettings() { - if (ConfirmationDialog::confirm(tr("Are you sure you want to reset all sunnypilot settings to default? Once the settings are reset, there is no going back."), tr("Reset"), this)) { - if (ConfirmationDialog::confirm(tr("The reset cannot be undone. You have been warned."), tr("Confirm"), this)) { - const std::vector keys = params.allKeys(); - for (const auto& key : keys) { - params.remove(key); - } - - Hardware::reboot(); - } - } -} - -void DevicePanelSP::showEvent(QShowEvent *event) { - updateState(offroad); -} - -void DevicePanelSP::updateState(bool _offroad) { - for (auto btn : findChildren()) { - bool always_enabled = std::find(always_enabled_btns.begin(), always_enabled_btns.end(), btn) != always_enabled_btns.end(); - - if (!always_enabled) { - btn->setEnabled(_offroad); - } - } - - bool offroad_mode_param = params.getBool("OffroadMode"); - offroadBtn->setText(offroad_mode_param ? tr("Exit Always Offroad") : tr("Enable Always Offroad")); - offroadBtn->setStyleSheet(offroad_mode_param ? alwaysOffroadStyle : autoOffroadStyle); - - DeviceSleepModeStatus currStatus = DeviceSleepModeStatus::DEFAULT; - if (params.get("DeviceBootMode") == "1") { - currStatus = DeviceSleepModeStatus::OFFROAD; - } - toggleDeviceBootMode->setDescription(deviceSleepModeDescription(currStatus)); - - if (offroad and not offroad_mode_param) { - power_group_layout->insertWidget(0, offroadBtn, 0, Qt::AlignHCenter); - } else { - AddWidgetAt(0, offroadBtn); - } - - offroad = _offroad; -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h deleted file mode 100644 index 425c4528a1..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/max_time_offroad.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -enum class DeviceSleepModeStatus { - DEFAULT, - OFFROAD, -}; - -class DevicePanelSP : public DevicePanel { - Q_OBJECT - -public: - explicit DevicePanelSP(SettingsWindowSP *parent = 0); - void showEvent(QShowEvent *event) override; - void setOffroadMode(); - void updateState(bool _offroad); - void resetSettings(); - -private: - std::map buttons; - PushButtonSP *offroadBtn; - MaxTimeOffroad *maxTimeOffroad; - ButtonParamControlSP *toggleDeviceBootMode; - QVBoxLayout *power_group_layout; - bool offroad; - - std::vector always_enabled_btns = {}; - - const QString alwaysOffroadStyle = R"( - PushButtonSP { - border-radius: 20px; - font-size: 50px; - font-weight: 450; - height: 150px; - padding: 0 25px 0 25px; - color: #FFFFFF; - background-color: #393939; - } - PushButtonSP:pressed { - background-color: #4A4A4A; - } - )"; - - const QString autoOffroadStyle = R"( - PushButtonSP { - border-radius: 20px; - font-size: 50px; - font-weight: 450; - height: 150px; - padding: 0 25px 0 25px; - color: #FFFFFF; - background-color: #E22C2C; - } - PushButtonSP:pressed { - background-color: #FF2424; - } - )"; - - const QString rebootButtonStyle = R"( - PushButtonSP { - border-radius: 20px; - font-size: 50px; - font-weight: 450; - height: 150px; - padding: 0 25px 0 25px; - color: #FFFFFF; - background-color: #393939; - } - PushButtonSP:pressed { - background-color: #4A4A4A; - } - )"; - - const QString powerOffButtonStyle = R"( - PushButtonSP { - border-radius: 20px; - font-size: 50px; - font-weight: 450; - height: 150px; - padding: 0 25px 0 25px; - color: #FFFFFF; - background-color: #E22C2C; - } - PushButtonSP:pressed { - background-color: #FF2424; - } - )"; - - static QString deviceSleepModeDescription(DeviceSleepModeStatus status = DeviceSleepModeStatus::DEFAULT) { - QString def_str = tr("⁍ Default: Device will boot/wake-up normally & will be ready to engage."); - QString offrd_str = tr("⁍ Offroad: Device will be in Always Offroad mode after boot/wake-up."); - - if (status == DeviceSleepModeStatus::DEFAULT) { - def_str = "" + def_str + ""; - } else if (status == DeviceSleepModeStatus::OFFROAD) { - offrd_str = "" + offrd_str + ""; - } - - return QString("%1

%2
%3") - .arg(tr("Controls state of the device after boot/sleep.")) - .arg(def_str) - .arg(offrd_str); - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.cc deleted file mode 100644 index e29d06cb82..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.cc +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.h" - -OnroadScreenBrightnessControl::OnroadScreenBrightnessControl(const QString ¶m, const QString &title, - const QString &description, const QString &icon, - QWidget *parent) - : ExpandableToggleRow(param, title, description, icon, parent) { - auto *mainFrame = new QFrame(this); - auto *mainFrameLayout = new QVBoxLayout(); - mainFrame->setLayout(mainFrameLayout); - mainFrameLayout->setSpacing(30); - mainFrameLayout->setContentsMargins(0, 0, 0, 0); - - onroadScreenOffTimer = new OptionControlSP( - "OnroadScreenOffTimer", - "Onroad Brightness Delay", - "", - "", - {0, 11}, 1, true, &onroadScreenOffTimerOptions); - - onroadScreenBrightness = new OptionControlSP( - "OnroadScreenOffBrightness", - "Onroad Brightness", - "", - "", - {0, 90}, 10, true); - - connect(onroadScreenOffTimer, &OptionControlSP::updateLabels, this, &OnroadScreenBrightnessControl::refresh); - connect(onroadScreenBrightness, &OptionControlSP::updateLabels, this, &OnroadScreenBrightnessControl::refresh); - mainFrameLayout->addWidget(onroadScreenBrightness); - mainFrameLayout->addWidget(onroadScreenOffTimer); - - addItem(mainFrame); - - refresh(); -} - -void OnroadScreenBrightnessControl::refresh() { - // Driving Screen Off Timer - int valTimer = std::atoi(params.get("OnroadScreenOffTimer").c_str()); - std::string labelTimer = (valTimer < 60 ? std::to_string(valTimer) + "s" : std::to_string(valTimer / 60) + "m"); - onroadScreenOffTimer->setLabel(QString::fromStdString(labelTimer)); - - // Driving Screen Off Brightness - std::string valBrightness = params.get("OnroadScreenOffBrightness"); - std::string labelBrightness = (valBrightness == "0" ? " Screen Off" : valBrightness + "%"); - onroadScreenBrightness->setLabel(QString::fromStdString(labelBrightness)); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.h deleted file mode 100644 index 02335d1ce6..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h" - -static const QMap onroadScreenOffTimerOptions = { - {"0", "15"}, - {"1", "30"}, - {"2", "60"}, - {"3", "120"}, - {"4", "180"}, - {"5", "240"}, - {"6", "300"}, - {"7", "360"}, - {"8", "420"}, - {"9", "480"}, - {"10", "540"}, - {"11", "600"} -}; - -class OnroadScreenBrightnessControl : public ExpandableToggleRow { - Q_OBJECT - -public: - OnroadScreenBrightnessControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, - QWidget *parent = nullptr); - void refresh(); - -private: - Params params; - OptionControlSP *onroadScreenOffTimer; - OptionControlSP *onroadScreenBrightness; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.cc deleted file mode 100644 index 465047f178..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.cc +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.h" - -DisplayPanel::DisplayPanel(QWidget *parent) : QWidget(parent) { - main_layout = new QStackedLayout(this); - ListWidgetSP *list = new ListWidgetSP(this, false); - - sunnypilotScreen = new QWidget(this); - QVBoxLayout* vlayout = new QVBoxLayout(sunnypilotScreen); - vlayout->setContentsMargins(50, 20, 50, 20); - - // Onroad Screen Off/Brightness - onroadScreenBrightnessControl = new OnroadScreenBrightnessControl( - "OnroadScreenOffControl", - tr("Onroad Screen: Reduced Brightness"), - tr("Turn off device screen or reduce brightness after driving starts. " - "It automatically brightens again when screen is touched or a visible alert is displayed."), - "", - this); - list->addItem(onroadScreenBrightnessControl); - list->addItem(horizontal_line()); - - // Global Brightness - brightness = new Brightness(); - connect(brightness, &OptionControlSP::updateLabels, brightness, &Brightness::refresh); - list->addItem(brightness); - list->addItem(horizontal_line()); - - // Interactivity Timeout - interactivityTimeout = new OptionControlSP("InteractivityTimeout", tr("Interactivity Timeout"), - tr("Apply a custom timeout for settings UI." - "\nThis is the time after which settings UI closes automatically if user is not interacting with the screen."), - "", {0, 120}, 10, true, nullptr, false); - - connect(interactivityTimeout, &OptionControlSP::updateLabels, [=]() { - refresh(); - }); - list->addItem(interactivityTimeout); - - sunnypilotScroller = new ScrollViewSP(list, this); - vlayout->addWidget(sunnypilotScroller); - main_layout->addWidget(sunnypilotScreen); -} - -void DisplayPanel::showEvent(QShowEvent *event) { - QWidget::showEvent(event); - refresh(); -} - -void DisplayPanel::refresh() { - onroadScreenBrightnessControl->refresh(); - - QString timeoutValue = QString::fromStdString(params.get("InteractivityTimeout")); - if (timeoutValue == "0" || timeoutValue.isEmpty()) { - interactivityTimeout->setLabel("Default"); - } else { - interactivityTimeout->setLabel(timeoutValue + "s"); - } -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.h deleted file mode 100644 index 69b440c9d3..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -class DisplayPanel : public QWidget { - Q_OBJECT - -public: - explicit DisplayPanel(QWidget *parent = nullptr); - void showEvent(QShowEvent *event) override; - void refresh(); - -private: - QStackedLayout* main_layout = nullptr; - QWidget* sunnypilotScreen = nullptr; - ScrollViewSP *sunnypilotScroller = nullptr; - Params params; - OnroadScreenBrightnessControl *onroadScreenBrightnessControl = nullptr; - Brightness *brightness; - OptionControlSP *interactivityTimeout; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.cc deleted file mode 100644 index b43c6162c6..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.cc +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.h" - -BlinkerPauseLateralSettings::BlinkerPauseLateralSettings(const QString ¶m, const QString &title, const QString &description, const QString &icon, QWidget *parent) - : ExpandableToggleRow(param, title, description, icon, parent) { - - pauseLateralSpeed = new OptionControlSP("BlinkerMinLateralControlSpeed", "", "", "", {0, 255}, 5); - connect(pauseLateralSpeed, &OptionControlSP::updateLabels, this, &BlinkerPauseLateralSettings::refresh); - addItem(pauseLateralSpeed); - - refresh(); -} - -void BlinkerPauseLateralSettings::refresh() { - const QString option = QString::fromStdString(params.get("BlinkerMinLateralControlSpeed")); - const bool is_metric = params.getBool("IsMetric"); - const QString unit = is_metric ? "km/h" : "mph"; - - pauseLateralSpeed->setLabel(option + " " + unit); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.h deleted file mode 100644 index 7f02337b9c..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h" - -class BlinkerPauseLateralSettings : public ExpandableToggleRow { - Q_OBJECT - -public: - BlinkerPauseLateralSettings(const QString ¶m, const QString &title, const QString &description, const QString &icon, QWidget *parent = nullptr); - void refresh(); - -private: - Params params; - OptionControlSP *pauseLateralSpeed; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.cc deleted file mode 100644 index 53717508bf..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.cc +++ /dev/null @@ -1,111 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - * - * Created by kumar on March 10, 2025 - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" -#include -#include -#include -#include - -LaneChangeSettings::LaneChangeSettings(QWidget* parent) : QWidget(parent) { - QVBoxLayout* main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(50, 20, 50, 20); - main_layout->setSpacing(20); - - // Back button - PanelBackButton* back = new PanelBackButton(tr("Back")); - connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); - main_layout->addWidget(back, 0, Qt::AlignLeft); - - ListWidgetSP *list = new ListWidgetSP(this, false); - // param, title, desc, icon - std::vector> toggle_defs{ - { - "AutoLaneChangeBsmDelay", - tr("Auto Lane Change: Delay with Blind Spot"), - tr("Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering."), - "../assets/offroad/icon_blank.png", - }, - }; - - // Controls: Auto Lane Change Timer - autoLaneChangeTimer = new AutoLaneChangeTimer(); - autoLaneChangeTimer->setUpdateOtherToggles(true); - autoLaneChangeTimer->showDescription(); - connect(autoLaneChangeTimer, &OptionControlSP::updateLabels, autoLaneChangeTimer, &AutoLaneChangeTimer::refresh); - connect(autoLaneChangeTimer, &AutoLaneChangeTimer::updateOtherToggles, this, &LaneChangeSettings::updateToggles); - list->addItem(autoLaneChangeTimer); - - for (auto &[param, title, desc, icon] : toggle_defs) { - auto toggle = new ParamControlSP(param, title, desc, icon, this); - list->addItem(toggle); - toggles[param.toStdString()] = toggle; - } - - main_layout->addWidget(new ScrollViewSP(list, this)); -} - -void LaneChangeSettings::showEvent(QShowEvent *event) { - updateToggles(); -} - -void LaneChangeSettings::updateToggles() { - if (!isVisible()) { - return; - } - - auto auto_lane_change_bsm_delay_toggle = toggles["AutoLaneChangeBsmDelay"]; - auto autoLaneChangeTimer_param = std::atoi(params.get("AutoLaneChangeTimer").c_str()); - - auto cp_bytes = params.get("CarParamsPersistent"); - if (!cp_bytes.empty()) { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - - if (!CP.getEnableBsm()) { - params.remove("AutoLaneChangeBsmDelay"); - } - auto_lane_change_bsm_delay_toggle->setEnabled(CP.getEnableBsm() && (autoLaneChangeTimer_param > 0)); - auto_lane_change_bsm_delay_toggle->refresh(); - } else { - auto_lane_change_bsm_delay_toggle->setEnabled(false); - } -} - -// Auto Lane Change Timer (ALCT) -AutoLaneChangeTimer::AutoLaneChangeTimer() : OptionControlSP( - "AutoLaneChangeTimer", - tr("Auto Lane Change by Blinker"), - tr("Set a timer to delay the auto lane change operation when the blinker is used. " - "No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge.\n" - "Please use caution when using this feature. Only use the blinker when traffic and road conditions permit."), - "../assets/offroad/icon_blank.png", - {-1, 5}) { - - refresh(); -} - -void AutoLaneChangeTimer::refresh() { - QString option = QString::fromStdString(params.get("AutoLaneChangeTimer")); - const QString second = tr("s"); - - static const QMap options = { - {"-1", tr("Off")}, - {"0", tr("Nudge")}, - {"1", tr("Nudgeless")}, - {"2", "0.5 " + second}, - {"3", "1 " + second}, - {"4", "2 " + second}, - {"5", "3 " + second}, - }; - - setLabel(options.value(option, tr("Nudge"))); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.h deleted file mode 100644 index 5bd458c47d..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include -#include - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class AutoLaneChangeTimer : public OptionControlSP { - Q_OBJECT - -public: - AutoLaneChangeTimer(); - - void refresh(); - -signals: - void toggleUpdated(); - -private: - Params params; -}; - - -class LaneChangeSettings : public QWidget { - Q_OBJECT - -public: - explicit LaneChangeSettings(QWidget* parent = nullptr); - void showEvent(QShowEvent *event) override; - -signals: - void backPress(); - -public slots: - void updateToggles(); - -private: - Params params; - std::map toggles; - - AutoLaneChangeTimer *autoLaneChangeTimer; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.cc deleted file mode 100644 index 749bc9e3f3..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.cc +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.h" - -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -MadsSettings::MadsSettings(QWidget *parent) : QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(50, 20, 50, 20); - main_layout->setSpacing(20); - - // Back button - PanelBackButton *back = new PanelBackButton(); - connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); - main_layout->addWidget(back, 0, Qt::AlignLeft); - - ListWidget *list = new ListWidget(this, false); - // Main cruise - madsMainCruiseToggle = new ParamControl("MadsMainCruiseAllowed", tr("Toggle with Main Cruise"), "", ""); - list->addItem(madsMainCruiseToggle); - - // Unified Engagement Mode - madsUnifiedEngagementModeToggle = new ParamControl("MadsUnifiedEngagementMode", tr("Unified Engagement Mode (UEM)"), "", ""); - list->addItem(madsUnifiedEngagementModeToggle); - - // Steering Mode On Brake - madsSteeringMode = new ButtonParamControl("MadsSteeringMode", tr("Steering Mode on Brake Pedal"), "", "", madsSteeringModeTexts(), 500); - QObject::connect(madsSteeringMode, &ButtonParamControl::buttonClicked, [=] { - updateToggles(offroad); - }); - list->addItem(madsSteeringMode); - - QObject::connect(uiState(), &UIState::offroadTransition, this, &MadsSettings::updateToggles); - - main_layout->addWidget(new ScrollViewSP(list, this)); -} - -void MadsSettings::showEvent(QShowEvent *event) { - updateToggles(offroad); -} - -void MadsSettings::updateToggles(bool _offroad) { - auto mads_steering_mode_param = std::atoi(params.get("MadsSteeringMode").c_str()); - - auto steering_mode = static_cast( - std::clamp(mads_steering_mode_param, static_cast(MadsSteeringMode::REMAIN_ACTIVE), static_cast(MadsSteeringMode::DISENGAGE)) - ); - - auto cp_bytes = params.get("CarParamsPersistent"); - auto cp_sp_bytes = params.get("CarParamsSPPersistent"); - if (!cp_bytes.empty() && !cp_sp_bytes.empty()) { - AlignedBuffer aligned_buf; - AlignedBuffer aligned_buf_sp; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); - capnp::FlatArrayMessageReader cmsg_sp(aligned_buf_sp.align(cp_sp_bytes.data(), cp_sp_bytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - cereal::CarParamsSP::Reader CP_SP = cmsg_sp.getRoot(); - - if (madsLimitedSettings(CP, CP_SP)) { - params.remove("MadsMainCruiseAllowed"); - params.putBool("MadsUnifiedEngagementMode", true); - params.put("MadsSteeringMode", std::to_string(static_cast(MadsSteeringMode::DISENGAGE))); - - madsMainCruiseToggle->setEnabled(false); - madsMainCruiseToggle->setDescription(madsDescriptionBuilder(DEFAULT_TO_OFF, MADS_MAIN_CRUISE_BASE_DESC)); - madsMainCruiseToggle->showDescription(); - - madsUnifiedEngagementModeToggle->setEnabled(false); - madsUnifiedEngagementModeToggle->setDescription(madsDescriptionBuilder(DEFAULT_TO_ON, MADS_UNIFIED_ENGAGEMENT_MODE_BASE_DESC)); - madsUnifiedEngagementModeToggle->showDescription(); - - madsSteeringModeValues = convertMadsSteeringModeValues({MadsSteeringMode::DISENGAGE}); - madsSteeringMode->setDescription(madsDescriptionBuilder(STATUS_DISENGAGE_ONLY, madsSteeringModeDescription(steering_mode))); - } else { - madsMainCruiseToggle->setEnabled(true); - madsMainCruiseToggle->setDescription(MADS_MAIN_CRUISE_BASE_DESC); - - madsUnifiedEngagementModeToggle->setEnabled(true); - madsUnifiedEngagementModeToggle->setDescription(MADS_UNIFIED_ENGAGEMENT_MODE_BASE_DESC); - - madsSteeringModeValues = convertMadsSteeringModeValues(getMadsSteeringModeValues()); - madsSteeringMode->setDescription(madsSteeringModeDescription(steering_mode)); - } - } else { - madsMainCruiseToggle->setEnabled(false); - madsMainCruiseToggle->setDescription(madsDescriptionBuilder(STATUS_CHECK_COMPATIBILITY, MADS_MAIN_CRUISE_BASE_DESC)); - madsMainCruiseToggle->showDescription(); - - madsUnifiedEngagementModeToggle->setEnabled(false); - madsUnifiedEngagementModeToggle->setDescription(madsDescriptionBuilder(STATUS_CHECK_COMPATIBILITY, MADS_UNIFIED_ENGAGEMENT_MODE_BASE_DESC)); - madsUnifiedEngagementModeToggle->showDescription(); - - madsSteeringModeValues = {}; - madsSteeringMode->setDescription(madsDescriptionBuilder(STATUS_CHECK_COMPATIBILITY, madsSteeringModeDescription(steering_mode))); - } - - madsSteeringMode->setEnableSelectedButtons(_offroad, madsSteeringModeValues); - madsSteeringMode->showDescription(); - - offroad = _offroad; -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.h deleted file mode 100644 index 9cf62a0ffe..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.h +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -inline bool madsLimitedSettings(const cereal::CarParams::Reader &CP, const cereal::CarParamsSP::Reader &CP_SP) { - if (CP.getBrand() == "rivian") { - return true; - } - if (CP.getBrand() == "tesla") { - return !(CP_SP.getFlags() & 1); // 1 == TeslaFlagsSP.HAS_VEHICLE_BUS - } - - return false; -} - -enum class MadsSteeringMode { - REMAIN_ACTIVE = 0, - PAUSE = 1, - DISENGAGE = 2, -}; - -struct MadsSteeringModeOption { - MadsSteeringMode mode; - QString display_text; - QString description; -}; - -class MadsSettings : public QWidget { - Q_OBJECT - -public: - explicit MadsSettings(QWidget *parent = nullptr); - - void showEvent(QShowEvent *event) override; - -signals: - void backPress(); - -public slots: - void updateToggles(bool _offroad); - -private: - Params params; - bool offroad; - - ParamControl *madsMainCruiseToggle; - ParamControl *madsUnifiedEngagementModeToggle; - ButtonParamControl *madsSteeringMode; - - std::vector madsSteeringModeValues = {}; - - const QString MADS_MAIN_CRUISE_BASE_DESC = tr("Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement."); - const QString MADS_UNIFIED_ENGAGEMENT_MODE_BASE_DESC = QString("%1
" - "

%2

") - .arg(tr("Engage lateral and longitudinal control with cruise control engagement.")) - .arg(tr("Note: Once lateral control is engaged via UEM, it will remain engaged until it is manually disabled via the MADS button or car shut off.")); - - const QString STATUS_CHECK_COMPATIBILITY = tr("Start the vehicle to check vehicle compatibility."); - const QString DEFAULT_TO_OFF = tr("This feature defaults to OFF, and does not allow selection due to vehicle limitations."); - const QString DEFAULT_TO_ON = tr("This feature defaults to ON, and does not allow selection due to vehicle limitations."); - const QString STATUS_DISENGAGE_ONLY = tr("This platform only supports Disengage mode due to vehicle limitations."); - - static const std::vector &madsSteeringModeOptions() { - static const std::vector options = { - {MadsSteeringMode::REMAIN_ACTIVE, tr("Remain Active"), tr("Remain Active: ALC will remain active when the brake pedal is pressed.")}, - {MadsSteeringMode::PAUSE, tr("Pause"), tr("Pause: ALC will pause when the brake pedal is pressed.")}, - {MadsSteeringMode::DISENGAGE, tr("Disengage"), tr("Disengage: ALC will disengage when the brake pedal is pressed.")}, - }; - return options; - } - - static std::vector getMadsSteeringModeValues() { - std::vector values; - for (const auto& option : madsSteeringModeOptions()) { - values.push_back(option.mode); - } - return values; - } - - static std::vector convertMadsSteeringModeValues(const std::vector &modes) { - std::vector values; - for (const auto& mode : modes) { - values.push_back(static_cast(mode)); - } - return values; - } - - static std::vector madsSteeringModeTexts() { - std::vector texts; - for (const auto& option : madsSteeringModeOptions()) { - texts.push_back(option.display_text); - } - return texts; - } - - static QString madsSteeringModeDescription(const MadsSteeringMode mode = MadsSteeringMode::REMAIN_ACTIVE) { - QString base_desc = tr("Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot."); - QString result = base_desc + "

"; - - for (const auto& option : madsSteeringModeOptions()) { - QString desc = option.description; - if (option.mode == mode) { - desc = "" + desc + ""; - } - result += desc + "
"; - } - - return result; - } - - static QString madsDescriptionBuilder(const QString &custom_description, const QString &base_description) { - return "" + custom_description + "

" + base_description; - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc deleted file mode 100644 index 02ab810c57..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h" - -NeuralNetworkLateralControl::NeuralNetworkLateralControl() : - ParamControl("NeuralNetworkLateralControl", tr("Neural Network Lateral Control (NNLC)"), "", "") { - setConfirmation(true, false); - updateToggle(offroad); -} - -void NeuralNetworkLateralControl::updateToggle(bool _offroad) { - QString statusInitText = "" + STATUS_CHECK_COMPATIBILITY + ""; - QString notLoadedText = "" + STATUS_NOT_LOADED + ""; - QString loadedText = "" + STATUS_LOADED + ""; - - bool allowed = true; - auto cp_bytes = params.get("CarParamsPersistent"); - auto cp_sp_bytes = params.get("CarParamsSPPersistent"); - if (!cp_bytes.empty() && !cp_sp_bytes.empty()) { - AlignedBuffer aligned_buf; - AlignedBuffer aligned_buf_sp; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); - capnp::FlatArrayMessageReader cmsg_sp(aligned_buf_sp.align(cp_sp_bytes.data(), cp_sp_bytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - cereal::CarParamsSP::Reader CP_SP = cmsg_sp.getRoot(); - - if (CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE) { - params.remove("NeuralNetworkLateralControl"); - setDescription(nnffDescriptionBuilder(STATUS_NOT_AVAILABLE)); - allowed = false; - } else { - QString nn_model_name = QString::fromStdString(CP_SP.getNeuralNetworkLateralControl().getModel().getName()); - QString nn_fuzzy = CP_SP.getNeuralNetworkLateralControl().getFuzzyFingerprint() ? - STATUS_MATCH_FUZZY : STATUS_MATCH_EXACT; - - if (nn_model_name.isEmpty()) { - setDescription(nnffDescriptionBuilder(statusInitText)); - } else if (nn_model_name == "MOCK") { - setDescription(nnffDescriptionBuilder( - notLoadedText + "
" + buildSupportText(SUPPORT_DONATE_LOGS) - )); - } else { - QString statusText = loadedText + " | " + STATUS_MATCH + " = " + nn_fuzzy + " | " + nn_model_name; - QString explanationText = EXPLANATION_MATCH + " " + buildSupportText(SUPPORT_ISSUES); - setDescription(nnffDescriptionBuilder(statusText + "

" + explanationText)); - } - } - } else { - setDescription(nnffDescriptionBuilder(statusInitText)); - } - - if (getDescription() != getBaseDescription()) { - showDescription(); - } - - bool enforce_torque_toggle = params.getBool("EnforceTorqueControl"); - setEnabled(_offroad && allowed && !enforce_torque_toggle); - - refresh(); - - offroad = _offroad; -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h deleted file mode 100644 index 9e872b11e9..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" - -class NeuralNetworkLateralControl : public ParamControl { - Q_OBJECT - -public: - NeuralNetworkLateralControl(); - -public slots: - void updateToggle(bool _offroad); - -private: - Params params; - bool offroad; - - // Status messages - const QString STATUS_NOT_AVAILABLE = tr("NNLC is currently not available on this platform."); - const QString STATUS_CHECK_COMPATIBILITY = tr("Start the car to check car compatibility"); - const QString STATUS_NOT_LOADED = tr("NNLC Not Loaded"); - const QString STATUS_LOADED = tr("NNLC Loaded"); - const QString STATUS_MATCH = tr("Match"); - const QString STATUS_MATCH_EXACT = tr("Exact"); - const QString STATUS_MATCH_FUZZY = tr("Fuzzy"); - - // Explanations - const QString EXPLANATION_MATCH = tr("Match: \"Exact\" is ideal, but \"Fuzzy\" is fine too."); - const QString EXPLANATION_FEATURE = tr("Formerly known as \"NNFF\", this replaces the lateral \"torque\" controller, " - "with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy."); - - // Support information - const QString SUPPORT_CHANNEL = "#tuning-nnlc"; - const QString SUPPORT_REACH_OUT = tr("Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server"); - const QString SUPPORT_FEEDBACK = tr("with feedback, or to provide log data for your car if your car is currently unsupported:"); - const QString SUPPORT_ISSUES = tr("if there are any issues:"); - const QString SUPPORT_DONATE_LOGS = tr("and donate logs to get NNLC loaded for your car:"); - - // Description builders - QString buildSupportText(const QString& context) const { - return SUPPORT_REACH_OUT + " " + context + " " + SUPPORT_CHANNEL; - } - - QString nnffDescriptionBuilder(const QString &custom_description) const { - return "" + custom_description + "

" + getBaseDescription(); - } - - QString getBaseDescription() const { - return EXPLANATION_FEATURE + "

" + buildSupportText(SUPPORT_FEEDBACK); - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.cc deleted file mode 100644 index 894fbc2ec4..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.cc +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.h" - -TorqueLateralControlCustomParams::TorqueLateralControlCustomParams(const QString ¶m, const QString &title, const QString &description, const QString &icon, QWidget *parent) - : ExpandableToggleRow(param, title, description, icon, parent) { - - QFrame *frame = new QFrame(this); - QGridLayout *frame_layout = new QGridLayout(); - frame->setLayout(frame_layout); - frame_layout->setSpacing(0); - - torqueLateralControlParamsOverride = new ParamControl( - "TorqueParamsOverrideEnabled", - tr("Manual Real-Time Tuning"), - tr("Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values."), - "../assets/offroad/icon_blank.png", - this - ); - connect(torqueLateralControlParamsOverride, &ParamControl::toggleFlipped, this, &TorqueLateralControlCustomParams::refresh); - - torqueParamsOverrideLatAccelFactor = new OptionControlSP("TorqueParamsOverrideLatAccelFactor", tr("Lateral Acceleration Factor"), "", "", {1, 500}, 1, false, nullptr, true, false); - connect(torqueParamsOverrideLatAccelFactor, &OptionControlSP::updateLabels, this, &TorqueLateralControlCustomParams::refresh); - torqueParamsOverrideLatAccelFactor->setFixedWidth(280); - - torqueParamsOverrideFriction = new OptionControlSP("TorqueParamsOverrideFriction", tr("Friction"), "", "", {1, 100}, 1, false, nullptr, true, false); - connect(torqueParamsOverrideFriction, &OptionControlSP::updateLabels, this, &TorqueLateralControlCustomParams::refresh); - torqueParamsOverrideFriction->setFixedWidth(280); - - frame_layout->addWidget(torqueLateralControlParamsOverride, 0, 0, 1, 2); - QSpacerItem *spacer = new QSpacerItem(20, 40); - frame_layout->addItem(spacer, 1, 0, 1, 2); - frame_layout->addWidget(torqueParamsOverrideLatAccelFactor, 2, 0, Qt::AlignCenter); - frame_layout->addWidget(torqueParamsOverrideFriction, 2, 1, Qt::AlignCenter); - - addItem(frame); - - refresh(); -} - -void TorqueLateralControlCustomParams::refresh() { - bool torque_override_param = params.getBool("TorqueParamsOverrideEnabled"); - float laf_param = QString::fromStdString(params.get("TorqueParamsOverrideLatAccelFactor")).toFloat(); - const QString laf_unit = "m/s²"; - - float friction_param = QString::fromStdString(params.get("TorqueParamsOverrideFriction")).toFloat(); - - torqueParamsOverrideLatAccelFactor->setTitle(tr("Lateral Acceleration Factor") + "\n(" + (torque_override_param ? tr("Real-time and Offline") : tr("Offline Only")) + ")"); - torqueParamsOverrideFriction->setTitle(tr("Friction") + "\n(" + (torque_override_param ? tr("Real-time and Offline") : tr("Offline Only")) + ")"); - - torqueParamsOverrideLatAccelFactor->setLabel(QString::number(laf_param, 'f', 2) + " " + laf_unit); - torqueParamsOverrideFriction->setLabel(QString::number(friction_param, 'f', 2)); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.h deleted file mode 100644 index 8442bd0d48..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h" - -class TorqueLateralControlCustomParams : public ExpandableToggleRow { - Q_OBJECT - -public: - TorqueLateralControlCustomParams(const QString ¶m, const QString &title, const QString &description, const QString &icon, QWidget *parent = nullptr); - void refresh(); - -private: - Params params; - ParamControl *torqueLateralControlParamsOverride; - OptionControlSP *torqueParamsOverrideFriction; - OptionControlSP *torqueParamsOverrideLatAccelFactor; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.cc deleted file mode 100644 index 914ce7a939..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.cc +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h" - -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -TorqueLateralControlSettings::TorqueLateralControlSettings(QWidget *parent) : QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(50, 20, 50, 20); - main_layout->setSpacing(20); - - // Back button - PanelBackButton *back = new PanelBackButton(); - connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); - main_layout->addWidget(back, 0, Qt::AlignLeft); - - ListWidget *list = new ListWidget(this, false); - // param, title, desc, icon - std::vector> toggle_defs{ - { - "LiveTorqueParamsToggle", - tr("Self-Tune"), - tr("Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default."), - "../assets/offroad/icon_blank.png", - }, - { - "LiveTorqueParamsRelaxedToggle", - tr("Less Restrict Settings for Self-Tune (Beta)"), - tr("Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values."), - "../assets/offroad/icon_blank.png", - } - }; - - for (auto &[param, title, desc, icon] : toggle_defs) { - auto toggle = new ParamControlSP(param, title, desc, icon, this); - list->addItem(toggle); - toggles[param.toStdString()] = toggle; - } - - torqueLateralControlCustomParams = new TorqueLateralControlCustomParams( - "CustomTorqueParams", - tr("Enable Custom Tuning"), - tr("Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within \"opendbc/car/torque_data\". " - "The values will also be used live when \"Manual Real-Time Tuning\" toggle is enabled."), - "../assets/offroad/icon_blank.png", - this); - list->addItem(torqueLateralControlCustomParams); - - QObject::connect(uiState(), &UIState::offroadTransition, this, &TorqueLateralControlSettings::updateToggles); - QObject::connect(toggles["LiveTorqueParamsToggle"], &ParamControlSP::toggleFlipped, [=](bool state) { - if (!state) { - params.remove("LiveTorqueParamsRelaxedToggle"); - toggles["LiveTorqueParamsRelaxedToggle"]->refresh(); - } - - updateToggles(offroad); - }); - - main_layout->addWidget(new ScrollViewSP(list, this)); -} - -void TorqueLateralControlSettings::showEvent(QShowEvent *event) { - updateToggles(offroad); -} - -void TorqueLateralControlSettings::updateToggles(bool _offroad) { - bool live_toggle = toggles["LiveTorqueParamsToggle"]->isToggled(); - - toggles["LiveTorqueParamsToggle"]->setEnabled(_offroad); - toggles["LiveTorqueParamsRelaxedToggle"]->setEnabled(_offroad && live_toggle); - - torqueLateralControlCustomParams->setEnabled(_offroad); - torqueLateralControlCustomParams->refresh(); - - offroad = _offroad; -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h deleted file mode 100644 index 6254073dfe..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class TorqueLateralControlSettings : public QWidget { - Q_OBJECT - -public: - explicit TorqueLateralControlSettings(QWidget *parent = nullptr); - - void showEvent(QShowEvent *event) override; - - signals: - void backPress(); - -public slots: - void updateToggles(bool _offroad); - -private: - Params params; - bool offroad; - std::map toggles; - - TorqueLateralControlCustomParams *torqueLateralControlCustomParams; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.cc deleted file mode 100644 index ac004e8856..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.cc +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.h" - -#include "common/util.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) { - main_layout = new QStackedLayout(this); - ListWidget *list = new ListWidget(this, false); - - sunnypilotScreen = new QWidget(this); - QVBoxLayout* vlayout = new QVBoxLayout(sunnypilotScreen); - vlayout->setContentsMargins(50, 20, 50, 20); - - // MADS - madsToggle = new ParamControl( - "Mads", - tr("Modular Assistive Driving System (MADS)"), - tr("Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement."), - ""); - madsToggle->setConfirmation(true, false); - list->addItem(madsToggle); - - madsSettingsButton = new PushButtonSP(tr("Customize MADS")); - madsSettingsButton->setObjectName("mads_btn"); - connect(madsSettingsButton, &QPushButton::clicked, [=]() { - sunnypilotScroller->setLastScrollPosition(); - main_layout->setCurrentWidget(madsWidget); - }); - QObject::connect(madsToggle, &ToggleControl::toggleFlipped, madsSettingsButton, &PushButtonSP::setEnabled); - - madsWidget = new MadsSettings(this); - connect(madsWidget, &MadsSettings::backPress, [=]() { - sunnypilotScroller->restoreScrollPosition(); - main_layout->setCurrentWidget(sunnypilotScreen); - }); - list->addItem(madsSettingsButton); - - list->addItem(vertical_space()); - list->addItem(horizontal_line()); - list->addItem(vertical_space()); - - // Lane Change Settings - laneChangeSettingsButton = new PushButtonSP(tr("Customize Lane Change")); - laneChangeSettingsButton->setObjectName("lane_change_btn"); - connect(laneChangeSettingsButton, &QPushButton::clicked, [=]() { - sunnypilotScroller->setLastScrollPosition(); - main_layout->setCurrentWidget(laneChangeWidget); - }); - - laneChangeWidget = new LaneChangeSettings(this); - connect(laneChangeWidget, &LaneChangeSettings::backPress, [=]() { - sunnypilotScroller->restoreScrollPosition(); - main_layout->setCurrentWidget(sunnypilotScreen); - }); - list->addItem(laneChangeSettingsButton); - - list->addItem(vertical_space(0)); - list->addItem(horizontal_line()); - - // Blinker Pause Lateral Control - blinkerPauseLateralSettings = new BlinkerPauseLateralSettings( - "BlinkerPauseLateralControl", - tr("Pause Lateral Control with Blinker"), - tr("Pause lateral control with blinker when traveling below the desired speed selected."), - "", - this); - list->addItem(blinkerPauseLateralSettings); - - list->addItem(horizontal_line()); - - // Customized Torque Lateral Control - torqueLateralControlToggle = new ParamControl( - "EnforceTorqueControl", - tr("Enforce Torque Lateral Control"), - tr("Enable this to enforce sunnypilot to steer with Torque lateral control."), - ""); - list->addItem(torqueLateralControlToggle); - - torqueLateralControlSettingsButton = new PushButtonSP(tr("Customize Params")); - torqueLateralControlSettingsButton->setObjectName("torque_btn"); - connect(torqueLateralControlSettingsButton, &QPushButton::clicked, [=]() { - sunnypilotScroller->setLastScrollPosition(); - main_layout->setCurrentWidget(torqueLateralControlWidget); - }); - QObject::connect(torqueLateralControlToggle, &ToggleControl::toggleFlipped, [=](bool state) { - torqueLateralControlSettingsButton->setEnabled(state); - nnlcToggle->updateToggle(offroad); - updateToggles(offroad); - }); - - torqueLateralControlWidget = new TorqueLateralControlSettings(this); - connect(torqueLateralControlWidget, &TorqueLateralControlSettings::backPress, [=]() { - sunnypilotScroller->restoreScrollPosition(); - main_layout->setCurrentWidget(sunnypilotScreen); - }); - list->addItem(torqueLateralControlSettingsButton); - - list->addItem(vertical_space(0)); - list->addItem(horizontal_line()); - - // Neural Network Lateral Control - nnlcToggle = new NeuralNetworkLateralControl(); - list->addItem(nnlcToggle); - - QObject::connect(nnlcToggle, &ParamControl::toggleFlipped, [=](bool state) { - if (state) { - nnlcToggle->showDescription(); - } else { - nnlcToggle->hideDescription(); - } - - nnlcToggle->updateToggle(offroad); - updateToggles(offroad); - }); - - QObject::connect(uiState(), &UIState::offroadTransition, this, &LateralPanel::updateToggles); - - sunnypilotScroller = new ScrollViewSP(list, this); - vlayout->addWidget(sunnypilotScroller); - - main_layout->addWidget(sunnypilotScreen); - main_layout->addWidget(madsWidget); - main_layout->addWidget(laneChangeWidget); - main_layout->addWidget(torqueLateralControlWidget); - - setStyleSheet(R"( - #back_btn { - font-size: 50px; - margin: 0px; - padding: 15px; - border-width: 0; - border-radius: 30px; - color: #dddddd; - background-color: #393939; - } - #back_btn:pressed { - background-color: #4a4a4a; - } - )"); - - main_layout->setCurrentWidget(sunnypilotScreen); -} - -void LateralPanel::showEvent(QShowEvent *event) { - nnlcToggle->updateToggle(offroad); - updateToggles(offroad); -} - -void LateralPanel::hideEvent(QHideEvent *event) { - main_layout->setCurrentWidget(sunnypilotScreen); -} - -void LateralPanel::updateToggles(bool _offroad) { - bool torque_allowed = true; - auto cp_bytes = params.get("CarParamsPersistent"); - auto cp_sp_bytes = params.get("CarParamsSPPersistent"); - if (!cp_bytes.empty() && !cp_sp_bytes.empty()) { - AlignedBuffer aligned_buf; - AlignedBuffer aligned_buf_sp; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); - capnp::FlatArrayMessageReader cmsg_sp(aligned_buf_sp.align(cp_sp_bytes.data(), cp_sp_bytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - cereal::CarParamsSP::Reader CP_SP = cmsg_sp.getRoot(); - - if (madsLimitedSettings(CP, CP_SP)) { - madsToggle->setDescription(descriptionBuilder(STATUS_MADS_SETTINGS_LIMITED_COMPATIBILITY, MADS_BASE_DESC)); - } else { - madsToggle->setDescription(descriptionBuilder(STATUS_MADS_SETTINGS_FULL_COMPATIBILITY, MADS_BASE_DESC)); - } - - if (CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE) { - params.remove("EnforceTorqueControl"); - torque_allowed = false; - } - } else { - madsToggle->setDescription(descriptionBuilder(STATUS_MADS_CHECK_COMPATIBILITY, MADS_BASE_DESC)); - - params.remove("EnforceTorqueControl"); - torque_allowed = false; - } - - madsToggle->setEnabled(_offroad); - madsSettingsButton->setEnabled(madsToggle->isToggled()); - - torqueLateralControlToggle->setEnabled(_offroad && torque_allowed && !nnlcToggle->isToggled()); - torqueLateralControlSettingsButton->setEnabled(torqueLateralControlToggle->isToggled()); - - blinkerPauseLateralSettings->refresh(); - - offroad = _offroad; -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.h deleted file mode 100644 index 88c4d401d0..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include -#include - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -class LateralPanel : public QFrame { - Q_OBJECT - -public: - explicit LateralPanel(SettingsWindowSP *parent = nullptr); - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent* event) override; - -public slots: - void updateToggles(bool _offroad); - -private: - Params params; - QStackedLayout* main_layout = nullptr; - QWidget* sunnypilotScreen = nullptr; - ScrollViewSP *sunnypilotScroller = nullptr; - bool offroad; - - ParamControl *madsToggle; - PushButtonSP *madsSettingsButton; - MadsSettings *madsWidget = nullptr; - PushButtonSP *laneChangeSettingsButton; - LaneChangeSettings *laneChangeWidget = nullptr; - NeuralNetworkLateralControl *nnlcToggle = nullptr; - BlinkerPauseLateralSettings *blinkerPauseLateralSettings = nullptr; - ParamControl *torqueLateralControlToggle; - PushButtonSP *torqueLateralControlSettingsButton; - TorqueLateralControlSettings *torqueLateralControlWidget = nullptr; - - const QString MADS_BASE_DESC = tr("Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC)."); - - const QString STATUS_MADS_CHECK_COMPATIBILITY = tr("Start the vehicle to check vehicle compatibility."); - const QString STATUS_MADS_SETTINGS_FULL_COMPATIBILITY = tr("This platform supports all MADS settings."); - const QString STATUS_MADS_SETTINGS_LIMITED_COMPATIBILITY = tr("This platform supports limited MADS settings."); - - static QString descriptionBuilder(const QString &custom_description, const QString &base_description) { - return "" + custom_description + "

" + base_description; - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/custom_acc_increment.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/custom_acc_increment.cc deleted file mode 100644 index 29cadeaa62..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/custom_acc_increment.cc +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/custom_acc_increment.h" - -CustomAccIncrement::CustomAccIncrement(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent) - : ExpandableToggleRow(param, title, desc, icon, parent) { - auto *accFrame = new QFrame(this); - auto *accFrameLayout = new QGridLayout(); - accFrame->setLayout(accFrameLayout); - accFrameLayout->setSpacing(0); - - auto *shortPressControl = new AccIncrementOptionControl("CustomAccShortPressIncrement", {1, 10}, 1); - connect(shortPressControl, &OptionControlSP::updateLabels, shortPressControl, &AccIncrementOptionControl::refresh); - - auto *longPressControl = new AccIncrementOptionControl("CustomAccLongPressIncrement", {1, 3}, 1, &customLongValues); - connect(longPressControl, &OptionControlSP::updateLabels, longPressControl, &AccIncrementOptionControl::refresh); - - shortPressControl->setFixedWidth(280); - longPressControl->setFixedWidth(280); - accFrameLayout->addWidget(shortPressControl, 0, 0, Qt::AlignLeft); - accFrameLayout->addWidget(longPressControl, 0, 1, Qt::AlignRight); - - addItem(accFrame); -} - -AccIncrementOptionControl::AccIncrementOptionControl(const QString ¶m, const MinMaxValue &range, const int per_value_change, const QMap *valMap) - : OptionControlSP(param, "", "", "", range, per_value_change, true, valMap) { - param_name = param.toStdString(); - refresh(); -} - -void AccIncrementOptionControl::refresh() { - std::string val = params.get(param_name); - std::string label = ""; - label += param_name == "CustomAccShortPressIncrement" ? "Short Press" : "Long Press"; - label += "
" + val; - label += param_name == "CustomAccShortPressIncrement" - ? (val == "1" ? " (Default)" : "") - : (val == "5" ? " (Default)" : ""); - label += "
"; - setLabel(QString::fromStdString(label)); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/custom_acc_increment.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/custom_acc_increment.h deleted file mode 100644 index 707d4143bc..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/custom_acc_increment.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h" - -class CustomAccIncrement : public ExpandableToggleRow { - Q_OBJECT - -public: - CustomAccIncrement(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr); - -private: - QMap customLongValues = { - {"1", "1"}, - {"2", "5"}, // Default - {"3", "10"} - }; -}; - -class AccIncrementOptionControl : public OptionControlSP { - Q_OBJECT - -public: - AccIncrementOptionControl(const QString ¶m, const MinMaxValue &range, int per_value_change, const QMap *valMap = nullptr); - void refresh(); - -protected: - std::string param_name; - -private: - Params params; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/helpers.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/helpers.h deleted file mode 100644 index 6c02d627fa..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/helpers.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ -#pragma once - -enum class SpeedLimitOffsetType { - NONE, - FIXED, - PERCENT, -}; - -inline const QString SpeedLimitOffsetTypeTexts[]{ - QT_TRANSLATE_NOOP("SpeedLimitSettings", "None"), - QT_TRANSLATE_NOOP("SpeedLimitSettings", "Fixed"), - QT_TRANSLATE_NOOP("SpeedLimitSettings", "Percent"), -}; - -enum class SpeedLimitSourcePolicy { - CAR_ONLY, - MAP_ONLY, - CAR_FIRST, - MAP_FIRST, - COMBINED, -}; - -inline const QString SpeedLimitSourcePolicyTexts[]{ - QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Car\nOnly"), - QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Map\nOnly"), - QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Car\nFirst"), - QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Map\nFirst"), - QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Combined\nData") -}; - -enum class SpeedLimitMode { - OFF, - INFORMATION, - WARNING, - ASSIST, -}; - -inline const QString SpeedLimitModeTexts[]{ - QT_TRANSLATE_NOOP("SpeedLimitSettings", "Off"), - QT_TRANSLATE_NOOP("SpeedLimitSettings", "Information"), - QT_TRANSLATE_NOOP("SpeedLimitSettings", "Warning"), - QT_TRANSLATE_NOOP("SpeedLimitSettings", "Assist"), -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.cc deleted file mode 100644 index c54ff11f69..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ -#include - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.h" - -SpeedLimitPolicy::SpeedLimitPolicy(QWidget *parent) : QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(0, 0, 0, 0); - main_layout->setSpacing(0); - - // Back button - PanelBackButton *back = new PanelBackButton(tr("Back")); - connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); - main_layout->addWidget(back, 0, Qt::AlignLeft); - - main_layout->addSpacing(10); - - ListWidgetSP *list = new ListWidgetSP(this); - - std::vector speed_limit_policy_texts{ - tr(SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::CAR_ONLY)].toStdString().c_str()), - tr(SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::MAP_ONLY)].toStdString().c_str()), - tr(SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::CAR_FIRST)].toStdString().c_str()), - tr(SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::MAP_FIRST)].toStdString().c_str()), - tr(SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::COMBINED)].toStdString().c_str()) - }; - speed_limit_policy = new ButtonParamControlSP( - "SpeedLimitPolicy", - tr("Speed Limit Source"), - "", - "", - speed_limit_policy_texts, - 250); - list->addItem(speed_limit_policy); - connect(speed_limit_policy, &ButtonParamControlSP::buttonClicked, this, &SpeedLimitPolicy::refresh); - - speedLimitPolicyScroller = new ScrollViewSP(list, this); - main_layout->addWidget(speedLimitPolicyScroller); - refresh(); -}; - -void SpeedLimitPolicy::refresh() { - SpeedLimitSourcePolicy policy_param = static_cast(std::atoi(params.get("SpeedLimitPolicy").c_str())); - speed_limit_policy->setDescription(sourceDescription(policy_param)); -} - -void SpeedLimitPolicy::showEvent(QShowEvent *event) { - speedLimitPolicyScroller->verticalScrollBar()->setValue(0); - refresh(); - speed_limit_policy->showDescription(); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.h deleted file mode 100644 index 219aa53c6e..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/helpers.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -class SpeedLimitPolicy : public QWidget { - Q_OBJECT - -public: - explicit SpeedLimitPolicy(QWidget *parent = nullptr); - void refresh(); - void showEvent(QShowEvent *event) override; - -signals: - void backPress(); - -private: - Params params; - ButtonParamControlSP *speed_limit_policy; - ScrollViewSP *speedLimitPolicyScroller; - - static QString sourceDescription(SpeedLimitSourcePolicy type = SpeedLimitSourcePolicy::CAR_ONLY) { - QString car_only = tr("⦿ Car Only: Use Speed Limit data only from Car"); - QString map_only = tr("⦿ Map Only: Use Speed Limit data only from OpenStreetMaps"); - QString car_first = tr("⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps"); - QString map_first = tr("⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car"); - QString combined = tr("⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps"); - - if (type == SpeedLimitSourcePolicy::CAR_ONLY) { - car_only = "" + car_only + ""; - } else if (type == SpeedLimitSourcePolicy::MAP_ONLY) { - map_only = "" + map_only + ""; - } else if (type == SpeedLimitSourcePolicy::CAR_FIRST) { - car_first = "" + car_first + ""; - } else if (type == SpeedLimitSourcePolicy::MAP_FIRST) { - map_first = "" + map_first + ""; - } else { - combined = "" + combined + ""; - } - - return QString("%1
%2
%3
%4
%5") - .arg(car_only) - .arg(map_only) - .arg(car_first) - .arg(map_first) - .arg(combined); - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc deleted file mode 100644 index 99c227d233..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h" - -#include "selfdrive/ui/sunnypilot/qt/util.h" - -SpeedLimitSettings::SpeedLimitSettings(QWidget *parent) : QStackedWidget(parent) { - subPanelFrame = new QFrame(); - QVBoxLayout *subPanelLayout = new QVBoxLayout(subPanelFrame); - subPanelLayout->setContentsMargins(0, 0, 0, 0); - subPanelLayout->setSpacing(0); - - // Back button - PanelBackButton *back = new PanelBackButton(tr("Back")); - connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); - subPanelLayout->addWidget(back, 0, Qt::AlignLeft); - - subPanelLayout->addSpacing(20); - - ListWidgetSP *list = new ListWidgetSP(this, false); - - speedLimitPolicyScreen = new SpeedLimitPolicy(this); - - std::vector speed_limit_mode_texts{ - tr(SpeedLimitModeTexts[static_cast(SpeedLimitMode::OFF)].toStdString().c_str()), - tr(SpeedLimitModeTexts[static_cast(SpeedLimitMode::INFORMATION)].toStdString().c_str()), - tr(SpeedLimitModeTexts[static_cast(SpeedLimitMode::WARNING)].toStdString().c_str()), - tr(SpeedLimitModeTexts[static_cast(SpeedLimitMode::ASSIST)].toStdString().c_str()) - }; - speed_limit_mode_settings = new ButtonParamControlSP( - "SpeedLimitMode", - tr("Speed Limit"), - "", - "", - speed_limit_mode_texts, - 380); - list->addItem(speed_limit_mode_settings); - - list->addItem(horizontal_line()); - list->addItem(vertical_space()); - - speedLimitSource = new PushButtonSP(tr("Customize Source")); - connect(speedLimitSource, &QPushButton::clicked, [&]() { - speedLimitScroller->setLastScrollPosition(); - setCurrentWidget(speedLimitPolicyScreen); - speedLimitPolicyScreen->refresh(); - }); - connect(speedLimitPolicyScreen, &SpeedLimitPolicy::backPress, [&]() { - speedLimitScroller->restoreScrollPosition(); - setCurrentWidget(subPanelFrame); - showEvent(new QShowEvent()); - }); - - speedLimitSource->setFixedWidth(720); - list->addItem(speedLimitSource); - - list->addItem(vertical_space(0)); - list->addItem(horizontal_line()); - - QFrame *offsetFrame = new QFrame(this); - QVBoxLayout *offsetLayout = new QVBoxLayout(offsetFrame); - - std::vector speed_limit_offset_texts{ - tr(SpeedLimitOffsetTypeTexts[static_cast(SpeedLimitOffsetType::NONE)].toStdString().c_str()), - tr(SpeedLimitOffsetTypeTexts[static_cast(SpeedLimitOffsetType::FIXED)].toStdString().c_str()), - tr(SpeedLimitOffsetTypeTexts[static_cast(SpeedLimitOffsetType::PERCENT)].toStdString().c_str()) - }; - speed_limit_offset_settings = new ButtonParamControlSP( - "SpeedLimitOffsetType", - tr("Speed Limit Offset"), - "", - "", - speed_limit_offset_texts, - 500); - - offsetLayout->addWidget(speed_limit_offset_settings); - - speed_limit_offset = new OptionControlSP( - "SpeedLimitValueOffset", - "", - "", - "", - {-30, 30} - ); - offsetLayout->addWidget(speed_limit_offset); - - list->addItem(offsetFrame); - - connect(speed_limit_mode_settings, &ButtonParamControlSP::buttonClicked, this, &SpeedLimitSettings::refresh); - connect(speed_limit_offset, &OptionControlSP::updateLabels, this, &SpeedLimitSettings::refresh); - connect(speed_limit_offset_settings, &ButtonParamControlSP::showDescriptionEvent, speed_limit_offset, &OptionControlSP::showDescription); - connect(speed_limit_offset_settings, &ButtonParamControlSP::buttonClicked, this, &SpeedLimitSettings::refresh); - - refresh(); - speedLimitScroller = new ScrollViewSP(list, this); - subPanelLayout->addWidget(speedLimitScroller); - addWidget(subPanelFrame); - addWidget(speedLimitPolicyScreen); - setCurrentWidget(subPanelFrame); -} - -void SpeedLimitSettings::refresh() { - bool is_release = params.getBool("IsReleaseSpBranch"); - bool is_metric_param = params.getBool("IsMetric"); - SpeedLimitMode speed_limit_mode_param = static_cast(std::atoi(params.get("SpeedLimitMode").c_str())); - SpeedLimitOffsetType offset_type_param = static_cast(std::atoi(params.get("SpeedLimitOffsetType").c_str())); - QString offsetLabel = QString::fromStdString(params.get("SpeedLimitValueOffset")); - - bool sla_available; - auto cp_bytes = params.get("CarParamsPersistent"); - auto cp_sp_bytes = params.get("CarParamsSPPersistent"); - if (!cp_bytes.empty() && !cp_sp_bytes.empty()) { - AlignedBuffer aligned_buf; - AlignedBuffer aligned_buf_sp; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); - capnp::FlatArrayMessageReader cmsg_sp(aligned_buf_sp.align(cp_sp_bytes.data(), cp_sp_bytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - cereal::CarParamsSP::Reader CP_SP = cmsg_sp.getRoot(); - - bool has_longitudinal_control = hasLongitudinalControl(CP); - bool has_icbm = hasIntelligentCruiseButtonManagement(CP_SP); - - /* - * Speed Limit Assist is available when: - * - has_longitudinal_control or has_icbm, and - * - is not a release branch or not a disallowed brand, and - * - is not always disallowed - */ - bool sla_disallow_in_release = CP.getBrand() == "tesla" && is_release; - bool sla_always_disallow = CP.getBrand() == "rivian"; - sla_available = (has_longitudinal_control || has_icbm) && !sla_disallow_in_release && !sla_always_disallow; - - if (!sla_available && speed_limit_mode_param == SpeedLimitMode::ASSIST) { - params.put("SpeedLimitMode", std::to_string(static_cast(SpeedLimitMode::WARNING))); - } - } else { - sla_available = false; - } - - speed_limit_mode_settings->setDescription(modeDescription(speed_limit_mode_param)); - speed_limit_offset->setDescription(offsetDescription(offset_type_param)); - - if (offset_type_param == SpeedLimitOffsetType::PERCENT) { - offsetLabel += "%"; - } else if (offset_type_param == SpeedLimitOffsetType::FIXED) { - offsetLabel += QString(" %1").arg(is_metric_param ? "km/h" : "mph"); - } - - if (offset_type_param == SpeedLimitOffsetType::NONE) { - speed_limit_offset->setVisible(false); - } else { - speed_limit_offset->setVisible(true); - speed_limit_offset->setLabel(offsetLabel); - speed_limit_offset->showDescription(); - } - - if (sla_available) { - speed_limit_mode_settings->setEnableSelectedButtons(true, convertSpeedLimitModeValues(getSpeedLimitModeValues())); - } else { - speed_limit_mode_settings->setEnableSelectedButtons(true, convertSpeedLimitModeValues( - {SpeedLimitMode::OFF, SpeedLimitMode::INFORMATION, SpeedLimitMode::WARNING})); - } - - speed_limit_mode_settings->refresh(); - speed_limit_mode_settings->showDescription(); - speed_limit_offset->showDescription(); -} - -void SpeedLimitSettings::showEvent(QShowEvent *event) { - refresh(); -} - -void SpeedLimitSettings::hideEvent(QHideEvent *event) { - setCurrentWidget(subPanelFrame); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h deleted file mode 100644 index 69e85814c2..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/helpers.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -class SpeedLimitSettings : public QStackedWidget { - Q_OBJECT - -public: - SpeedLimitSettings(QWidget *parent = nullptr); - void refresh(); - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; - -signals: - void backPress(); - -private: - Params params; - ScrollViewSP *speedLimitScroller; - QFrame *subPanelFrame; - ButtonParamControlSP *speed_limit_mode_settings; - PushButtonSP *speedLimitSource; - SpeedLimitPolicy *speedLimitPolicyScreen; - ButtonParamControlSP *speed_limit_offset_settings; - OptionControlSP *speed_limit_offset; - bool icbm_available = false; - - static QString offsetDescription(SpeedLimitOffsetType type = SpeedLimitOffsetType::NONE) { - QString none_str = tr("⦿ None: No Offset"); - QString fixed_str = tr("⦿ Fixed: Adds a fixed offset [Speed Limit + Offset]"); - QString percent_str = tr("⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)]"); - - if (type == SpeedLimitOffsetType::FIXED) { - fixed_str = "" + fixed_str + ""; - } else if (type == SpeedLimitOffsetType::PERCENT) { - percent_str = "" + percent_str + ""; - } else { - none_str = "" + none_str + ""; - } - - return QString("%1
%2
%3") - .arg(none_str) - .arg(fixed_str) - .arg(percent_str); - } - - static QString modeDescription(SpeedLimitMode mode = SpeedLimitMode::OFF) { - QString off_str = tr("⦿ Off: Disables the Speed Limit functions."); - QString info_str = tr("⦿ Information: Displays the current road's speed limit."); - QString warning_str = tr("⦿ Warning: Provides a warning when exceeding the current road's speed limit."); - QString assist_str = tr("⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons."); - - if (mode == SpeedLimitMode::ASSIST) { - assist_str = "" + assist_str + ""; - } else if (mode == SpeedLimitMode::WARNING) { - warning_str = "" + warning_str + ""; - } else if (mode == SpeedLimitMode::INFORMATION) { - info_str = "" + info_str + ""; - } else { - off_str = "" + off_str + ""; - } - - return QString("%1
%2
%3
%4") - .arg(off_str) - .arg(info_str) - .arg(warning_str) - .arg(assist_str); - } - - static std::vector getSpeedLimitModeValues() { - std::vector values; - for (int i = static_cast(SpeedLimitMode::OFF); - i <= static_cast(SpeedLimitMode::ASSIST); ++i) { - values.push_back(static_cast(i)); - } - return values; - } - - static std::vector convertSpeedLimitModeValues(const std::vector &modes) { - std::vector values; - for (const auto& mode : modes) { - values.push_back(static_cast(mode)); - } - return values; - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.cc deleted file mode 100644 index ab357a2c16..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.cc +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h" - -#include "selfdrive/ui/sunnypilot/qt/util.h" - -LongitudinalPanel::LongitudinalPanel(QWidget *parent) : QWidget(parent) { - setStyleSheet(R"( - #back_btn { - font-size: 50px; - margin: 0px; - padding: 15px; - border-width: 0; - border-radius: 30px; - color: #dddddd; - background-color: #393939; - } - #back_btn:pressed { - background-color: #4a4a4a; - } - )"); - - main_layout = new QStackedLayout(this); - ListWidget *list = new ListWidget(this, false); - - cruisePanelScreen = new QWidget(this); - QVBoxLayout *vlayout = new QVBoxLayout(cruisePanelScreen); - vlayout->setContentsMargins(0, 0, 0, 0); - - cruisePanelScroller = new ScrollViewSP(list, this); - vlayout->addWidget(cruisePanelScroller); - - intelligentCruiseButtonManagement = new ParamControlSP( - "IntelligentCruiseButtonManagement", - tr("Intelligent Cruise Button Management (ICBM) (Alpha)"), - "", - "", - this - ); - QObject::connect(intelligentCruiseButtonManagement, &ParamControlSP::toggleFlipped, this, [=](bool) { - refresh(offroad); - }); - list->addItem(intelligentCruiseButtonManagement); - - dynamicExperimentalControl = new ParamControlSP( - "DynamicExperimentalControl", - tr("Dynamic Experimental Control (DEC)"), - tr("Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal."), - "", - this - ); - list->addItem(dynamicExperimentalControl); - - SmartCruiseControlVision = new ParamControl( - "SmartCruiseControlVision", - tr("Smart Cruise Control - Vision"), - tr("Use vision path predictions to estimate the appropriate speed to drive through turns ahead."), - ""); - list->addItem(SmartCruiseControlVision); - - SmartCruiseControlMap = new ParamControl( - "SmartCruiseControlMap", - tr("Smart Cruise Control - Map"), - tr("Use map data to estimate the appropriate speed to drive through turns ahead."), - ""); - list->addItem(SmartCruiseControlMap); - - customAccIncrement = new CustomAccIncrement("CustomAccIncrementsEnabled", tr("Custom ACC Speed Increments"), "", "", this); - list->addItem(customAccIncrement); - - QObject::connect(uiState(), &UIState::offroadTransition, this, &LongitudinalPanel::refresh); - - speedLimitSettings = new PushButtonSP(tr("Speed Limit"), 750, this); - connect(speedLimitSettings, &QPushButton::clicked, [&]() { - cruisePanelScroller->setLastScrollPosition(); - main_layout->setCurrentWidget(speedLimitScreen); - }); - list->addItem(speedLimitSettings); - - speedLimitScreen = new SpeedLimitSettings(this); - connect(speedLimitScreen, &SpeedLimitSettings::backPress, [=]() { - cruisePanelScroller->restoreScrollPosition(); - main_layout->setCurrentWidget(cruisePanelScreen); - }); - - main_layout->addWidget(cruisePanelScreen); - main_layout->addWidget(speedLimitScreen); - main_layout->setCurrentWidget(cruisePanelScreen); - refresh(offroad); -} - -void LongitudinalPanel::showEvent(QShowEvent *event) { - main_layout->setCurrentWidget(cruisePanelScreen); - refresh(offroad); -} - -void LongitudinalPanel::hideEvent(QHideEvent *event) { - main_layout->setCurrentWidget(cruisePanelScreen); -} - -void LongitudinalPanel::refresh(bool _offroad) { - const QString icbm_description = tr("When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control."); - - auto cp_bytes = params.get("CarParamsPersistent"); - auto cp_sp_bytes = params.get("CarParamsSPPersistent"); - if (!cp_bytes.empty() && !cp_sp_bytes.empty()) { - AlignedBuffer aligned_buf; - AlignedBuffer aligned_buf_sp; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); - capnp::FlatArrayMessageReader cmsg_sp(aligned_buf_sp.align(cp_sp_bytes.data(), cp_sp_bytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - cereal::CarParamsSP::Reader CP_SP = cmsg_sp.getRoot(); - - has_longitudinal_control = hasLongitudinalControl(CP); - is_pcm_cruise = CP.getPcmCruise(); - has_icbm = hasIntelligentCruiseButtonManagement(CP_SP); - - if (CP_SP.getIntelligentCruiseButtonManagementAvailable() && !has_longitudinal_control) { - intelligentCruiseButtonManagement->setEnabled(offroad); - intelligentCruiseButtonManagement->setDescription(icbm_description); - } else { - params.remove("IntelligentCruiseButtonManagement"); - intelligentCruiseButtonManagement->setEnabled(false); - - const QString icbm_unavaialble = tr("Intelligent Cruise Button Management is currently unavailable on this platform."); - - QString long_desc = icbm_unavaialble; - if (has_longitudinal_control) { - if (CP.getAlphaLongitudinalAvailable()) { - long_desc = icbm_unavaialble + " " + tr("Disable the sunnypilot Longitudinal Control (alpha) toggle to allow Intelligent Cruise Button Management."); - } else { - long_desc = icbm_unavaialble + " " + tr("sunnypilot Longitudinal Control is the default longitudinal control for this platform."); - } - } - - intelligentCruiseButtonManagement->setDescription("" + long_desc + "

" + icbm_description); - intelligentCruiseButtonManagement->showDescription(); - } - - if (has_longitudinal_control || has_icbm) { - // enable Custom ACC Increments when long is available and is not PCM cruise - customAccIncrement->setEnabled(((has_longitudinal_control && !is_pcm_cruise) || has_icbm) && offroad); - dynamicExperimentalControl->setEnabled(has_longitudinal_control); - SmartCruiseControlVision->setEnabled(true); - SmartCruiseControlMap->setEnabled(true); - } else { - params.remove("CustomAccIncrementsEnabled"); - params.remove("DynamicExperimentalControl"); - params.remove("SmartCruiseControlVision"); - params.remove("SmartCruiseControlMap"); - customAccIncrement->setEnabled(false); - dynamicExperimentalControl->setEnabled(false); - SmartCruiseControlVision->setEnabled(false); - SmartCruiseControlMap->setEnabled(false); - } - - intelligentCruiseButtonManagement->refresh(); - customAccIncrement->refresh(); - dynamicExperimentalControl->refresh(); - SmartCruiseControlVision->refresh(); - SmartCruiseControlMap->refresh(); - } else { - has_longitudinal_control = false; - is_pcm_cruise = false; - has_icbm = false; - intelligentCruiseButtonManagement->setDescription("" + tr("Start the vehicle to check vehicle compatibility.") + "
" + icbm_description); - } - - QString accEnabledDescription = tr("Enable custom Short & Long press increments for cruise speed increase/decrease."); - QString accNoLongDescription = tr("This feature can only be used with sunnypilot longitudinal control enabled."); - QString accPcmCruiseDisabledDescription = tr("This feature is not supported on this platform due to vehicle limitations."); - QString onroadOnlyDescription = tr("Start the vehicle to check vehicle compatibility."); - - if (offroad) { - customAccIncrement->setDescription(onroadOnlyDescription); - customAccIncrement->showDescription(); - } else { - if (has_longitudinal_control || has_icbm) { - if (has_longitudinal_control && is_pcm_cruise) { - customAccIncrement->setDescription(accPcmCruiseDisabledDescription); - customAccIncrement->showDescription(); - } else { - customAccIncrement->setDescription(accEnabledDescription); - } - } else { - customAccIncrement->toggleFlipped(false); - customAccIncrement->setDescription(accNoLongDescription); - customAccIncrement->showDescription(); - } - } - - offroad = _offroad; -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h deleted file mode 100644 index 2b9c0b8968..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/custom_acc_increment.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -class LongitudinalPanel : public QWidget { - Q_OBJECT - -public: - explicit LongitudinalPanel(QWidget *parent = nullptr); - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; - void refresh(bool _offroad); - -private: - Params params; - bool has_longitudinal_control = false; - bool is_pcm_cruise = false; - bool has_icbm = false; - bool offroad = false; - - QStackedLayout *main_layout = nullptr; - ScrollViewSP *cruisePanelScroller = nullptr; - QWidget *cruisePanelScreen = nullptr; - CustomAccIncrement *customAccIncrement = nullptr; - ParamControl *SmartCruiseControlVision; - ParamControl *SmartCruiseControlMap; - ParamControl *intelligentCruiseButtonManagement = nullptr; - ParamControl *dynamicExperimentalControl = nullptr; - SpeedLimitSettings *speedLimitScreen; - PushButtonSP *speedLimitSettings; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/max_time_offroad.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/max_time_offroad.cc deleted file mode 100644 index 4cc7351b03..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/max_time_offroad.cc +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/max_time_offroad.h" - -// Map of Max Offroad Time Options (Minutes) -const QMap MaxTimeOffroad::offroad_time_options = { - {"0", "0"}, // Always On - {"1", "5"}, - {"2", "10"}, - {"3", "15"}, - {"4", "30"}, - {"5", "60"}, - {"6", "120"}, - {"7", "180"}, - {"8", "300"}, - {"9", "600"}, - {"10", "1440"}, - {"11", "1800"} -}; - -MaxTimeOffroad::MaxTimeOffroad() : OptionControlSP( - "MaxTimeOffroad", - tr("Max Time Offroad"), - tr("Device will automatically shutdown after set time once the engine is turned off.
(30h is the default)"), - "../assets/offroad/icon_blank.png", - {0, 11}, 1, true, &offroad_time_options) { - - refresh(); -} - -void MaxTimeOffroad::refresh() { - const int maxOffroadInMinutes = QString::fromStdString(params.get("MaxTimeOffroad")).toInt(); - const bool useHours = maxOffroadInMinutes >= 60; - - QString label; - if (maxOffroadInMinutes == 0) { - label = tr("Always On"); - } else { - const int value = useHours ? maxOffroadInMinutes / 60 : maxOffroadInMinutes; - label = QString("%1%2").arg(value).arg(useHours ? tr("h") : tr("m")); - } - - if (maxOffroadInMinutes == 1800) { - label += tr(" (default)"); - } - - setLabel(label); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/max_time_offroad.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/max_time_offroad.h deleted file mode 100644 index 31c6a335c7..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/max_time_offroad.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class MaxTimeOffroad : public OptionControlSP { - Q_OBJECT - -public: - static const QMap offroad_time_options; - - MaxTimeOffroad(); - void refresh(); - -private: - Params params; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc deleted file mode 100644 index 4d89ea58b0..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc +++ /dev/null @@ -1,517 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include -#include -#include -#include -#include - -#include "common/model.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -static const QString progressStyleActive = "QProgressBar {" - " font-size: 40px;" - " font-weight: 200;" - " padding: 1px;" - " border: 3px solid black;" - " border-radius: 10px;" - "}" - "QProgressBar::chunk {" - " background-color: #1e79e8;" - " border-radius: 10px;" - "}"; - -static const QString progressStyleInactive = progressStyleActive + - "QProgressBar::chunk {" - " background-color: transparent;" - "}"; - -static const QString progressStyleDone = progressStyleActive + - "QProgressBar {" - " color: #33ab4c;" - "}" - "QProgressBar::chunk {" - " background-color: transparent;" - "}"; - -static const QString progressStyleError = progressStyleActive + - "QProgressBar {" - " color: red;" - "}" - "QProgressBar::chunk {" - " background-color: transparent;" - "}"; - -ModelsPanel::ModelsPanel(QWidget *parent) : QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(50, 20, 50, 20); - - ListWidgetSP *list = new ListWidgetSP(this, false); - ScrollViewSP *scroller = new ScrollViewSP(list, this); - main_layout->addWidget(scroller); - - const auto current_model = GetActiveModelName(); - currentModelLblBtn = new ButtonControlSP(tr("Current Model"), tr("SELECT"), "", this); - currentModelLblBtn->setValue(current_model); - - connect(currentModelLblBtn, &ButtonControlSP::clicked, this, &ModelsPanel::handleCurrentModelLblBtnClicked); - connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { - is_onroad = !offroad; - updateLabels(); - }); - connect(uiStateSP(), &UIStateSP::uiUpdate, this, &ModelsPanel::updateLabels); - list->addItem(currentModelLblBtn); - - refreshAvailableModelsBtn = new ButtonControlSP(tr("Refresh Model List"), tr("REFRESH"), "", this); - connect(refreshAvailableModelsBtn, &ButtonControlSP::clicked, this, [=]() { - params.put("ModelManager_LastSyncTime", "0"); - ConfirmationDialog::alert(tr("Fetching Latest Models"), this); - }); - - list->addItem(refreshAvailableModelsBtn); - - clearModelCacheBtn = new ButtonControlSP(tr("Clear Model Cache"), tr("CLEAR"), "", this); - connect(clearModelCacheBtn, &ButtonControlSP::clicked, this, &ModelsPanel::clearModelCache); - - list->addItem(clearModelCacheBtn); - - // Create progress bars for downloads - supercomboProgressBar = createProgressBar(this); - QString supercomboType = tr("Driving Model"); - supercomboFrame = createModelDetailFrame(this, supercomboType, supercomboProgressBar); - list->addItem(supercomboFrame); - - navigationProgressBar = createProgressBar(this); - QString navigationType = tr("Navigation Model"); - navigationFrame = createModelDetailFrame(this, navigationType, navigationProgressBar); - list->addItem(navigationFrame); - - visionProgressBar = createProgressBar(this); - QString visionType = tr("Vision Model"); - visionFrame = createModelDetailFrame(this, visionType, visionProgressBar); - list->addItem(visionFrame); - - policyProgressBar = createProgressBar(this); - QString policyType = tr("Policy Model"); - policyFrame = createModelDetailFrame(this, policyType, policyProgressBar); - list->addItem(policyFrame); - list->addItem(horizontal_line()); - - // Lane Turn Desire toggle - lane_turn_desire_toggle = new ParamControlSP("LaneTurnDesire", tr("Use Lane Turn Desires"), - "If you’re driving at 20 mph (32 km/h) or below and have your blinker on, " - "the car will plan a turn in that direction at the nearest drivable path. " - "This prevents situations (like at red lights) where the car might plan the wrong turn direction.", - "../assets/offroad/icon_shell.png"); - list->addItem(lane_turn_desire_toggle); - - // Lane Turn Value control - int max_value_mph = 20; - bool is_metric_initial = params.getBool("IsMetric"); - const float K = 1.609344f; - int per_value_change_scaled = is_metric_initial ? static_cast(std::round((1.0f / K) * 100.0f)) : 100; // 100 -> 1 mph - lane_turn_value_control = new OptionControlSP("LaneTurnValue", tr("Adjust Lane Turn Speed"), - tr("Set the maximum speed for lane turn desires. Default is 19 %1.").arg(is_metric_initial ? "km/h" : "mph"), - "", {5 * 100, max_value_mph * 100}, per_value_change_scaled, false, nullptr, true, true); - lane_turn_value_control->showDescription(); - list->addItem(lane_turn_value_control); - - // Show based on toggle - refreshLaneTurnValueControl(); - connect(lane_turn_desire_toggle, &ParamControlSP::toggleFlipped, this, &ModelsPanel::refreshLaneTurnValueControl); - connect(lane_turn_value_control, &OptionControlSP::updateLabels, this, &ModelsPanel::refreshLaneTurnValueControl); - - // LiveDelay toggle - lagd_toggle_control = new ParamControlSP("LagdToggle", tr("Live Learning Steer Delay"), "", "../assets/offroad/icon_shell.png"); - lagd_toggle_control->showDescription(); - list->addItem(lagd_toggle_control); - - // Software delay control - delay_control = new OptionControlSP("LagdToggleDelay", tr("Adjust Software Delay"), - tr("Adjust the software delay when Live Learning Steer Delay is toggled off." - "\nThe default software delay value is 0.2"), - "", {5, 50}, 1, false, nullptr, true, true); - - connect(delay_control, &OptionControlSP::updateLabels, [=]() { - float value = QString::fromStdString(params.get("LagdToggleDelay")).toFloat(); - delay_control->setLabel(QString::number(value, 'f', 2) + "s"); - }); - connect(lagd_toggle_control, &ParamControlSP::toggleFlipped, [=](bool state) { - delay_control->setVisible(!state); - }); - delay_control->showDescription(); - list->addItem(delay_control); -} - -QProgressBar* ModelsPanel::createProgressBar(QWidget *parent) { - QProgressBar *progressBar = new QProgressBar(parent); - progressBar->setRange(0, 100); - progressBar->setValue(0); - progressBar->setTextVisible(true); - progressBar->setAlignment(Qt::AlignVCenter); - return progressBar; -} - -QFrame* ModelsPanel::createModelDetailFrame(QWidget *parent, QString &typeName, QProgressBar *progressBar) { - QFrame *frame = new QFrame(parent); - QHBoxLayout *layout = new QHBoxLayout(frame); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(50); - layout->addWidget(new QLabel(typeName)); - layout->addWidget(progressBar); - frame->setVisible(false); - return frame; -} - -void ModelsPanel::refreshLaneTurnValueControl() { - if (!lane_turn_value_control) return; - float stored_mph = QString::fromStdString(params.get("LaneTurnValue")).toFloat(); - bool is_metric = params.getBool("IsMetric"); - QString unit = is_metric ? "km/h" : "mph"; - float display_value = stored_mph; - if (is_metric) { - display_value = stored_mph * 1.609344f; - } - lane_turn_value_control->setLabel(QString::number(static_cast(std::round(display_value))) + " " + unit); - lane_turn_value_control->setVisible(params.getBool("LaneTurnDesire")); -} - -/** - * @brief Updates the UI with bundle download progress information - * Reads status from modelManagerSP cereal message and displays status for all models - */ -void ModelsPanel::handleBundleDownloadProgress() { - supercomboFrame->setVisible(false); - visionFrame->setVisible(false); - policyFrame->setVisible(false); - navigationFrame->setVisible(false); - - using DS = cereal::ModelManagerSP::DownloadStatus; - if (!model_manager.hasSelectedBundle() && !model_manager.hasActiveBundle()) { - return; - } - - const bool showSelectedBundle = model_manager.hasSelectedBundle() && (isDownloading() || model_manager.getSelectedBundle().getStatus() == DS::FAILED); - const auto &bundle = showSelectedBundle ? model_manager.getSelectedBundle() : model_manager.getActiveBundle(); - const auto &models = bundle.getModels(); - download_status = bundle.getStatus(); - const auto download_status_changed = prev_download_status != download_status; - QStringList status; - - // Get status for each model type in order - for (const auto &model: models) { - QString modelName = QString::fromStdString(bundle.getDisplayName()); - - QProgressBar *progressBar = nullptr; - QFrame *modelFrame = nullptr; - - switch (model.getType()) { - case cereal::ModelManagerSP::Model::Type::SUPERCOMBO: - progressBar = supercomboProgressBar; - modelFrame = supercomboFrame; - break; - case cereal::ModelManagerSP::Model::Type::NAVIGATION: - progressBar = navigationProgressBar; - modelFrame = navigationFrame; - break; - case cereal::ModelManagerSP::Model::Type::VISION: - progressBar = visionProgressBar; - modelFrame = visionFrame; - break; - case cereal::ModelManagerSP::Model::Type::POLICY: - progressBar = policyProgressBar; - modelFrame = policyFrame; - break; - } - - const auto &progress = model.getArtifact().getDownloadProgress(); - QString line; - - if (progress.getStatus() == cereal::ModelManagerSP::DownloadStatus::DOWNLOADING) { - progressBar->setStyleSheet(progressStyleActive); - progressBar->setValue(progress.getProgress()); - progressBar->setFormat(QString(" %1% - %2").arg(static_cast(progress.getProgress())).arg(modelName)); - device()->resetInteractiveTimeout(); - } else if (progress.getStatus() == cereal::ModelManagerSP::DownloadStatus::DOWNLOADED) { - progressBar->setStyleSheet(progressStyleDone); - progressBar->setFormat(tr(" %1 - %2").arg(modelName, download_status_changed ? tr("downloaded") : tr("ready"))); - } else if (progress.getStatus() == cereal::ModelManagerSP::DownloadStatus::CACHED) { - progressBar->setStyleSheet(progressStyleDone); - progressBar->setFormat(tr(" %1 - %2").arg(modelName, download_status_changed ? tr("from cache") : tr("ready"))); - } else if (progress.getStatus() == cereal::ModelManagerSP::DownloadStatus::FAILED) { - progressBar->setStyleSheet(progressStyleError); - progressBar->setFormat(tr(" download failed - %1").arg(modelName)); - } else { - progressBar->setStyleSheet(progressStyleInactive); - progressBar->setFormat(tr(" pending - %1").arg(modelName)); - } - // keep navigation hidden for now to avoid confusion - if (model.getType() != cereal::ModelManagerSP::Model::Type::NAVIGATION) { - modelFrame->setVisible(true); - } - } - prev_download_status = download_status; -} - -/** - * @brief Gets the name of the currently selected model bundle - * @return Display name of the selected bundle or default model name - */ -QString ModelsPanel::GetActiveModelName() { - if (model_manager.hasActiveBundle()) { - return QString::fromStdString(model_manager.getActiveBundle().getDisplayName()); - } - - return DEFAULT_MODEL; -} - -/** - * @brief Gets the short name of the currently selected model bundle - * @return Display short name of the selected bundle or default model name - */ -QString ModelsPanel::GetActiveModelInternalName() { - if (model_manager.hasActiveBundle()) { - return QString::fromStdString(model_manager.getActiveBundle().getInternalName()); - } - return DEFAULT_MODEL; -} - -/** - * @brief Gets the ref of the currently selected model bundle - * @return ref of the selected bundle or default model name - */ -QString ModelsPanel::GetActiveModelRef() { - if (model_manager.hasActiveBundle()) { - return QString::fromStdString(model_manager.getActiveBundle().getRef()); - } - - return DEFAULT_MODEL; -} - -void ModelsPanel::updateModelManagerState() { - const SubMaster &sm = *(uiStateSP()->sm); - model_manager = sm["modelManagerSP"].getModelManagerSP(); -} - -/** - * @brief Handles the model bundle selection button click - * Displays available bundles, allows selection, and initiates download - */ -void ModelsPanel::handleCurrentModelLblBtnClicked() { - currentModelLblBtn->setEnabled(false); - currentModelLblBtn->setValue(tr("Fetching models...")); - - QList sortedModels; - QSet modelFolders; - QRegularExpression re("\\(([^)]*)\\)[^(]*$"); - - for (const auto &bundle : model_manager.getAvailableBundles()) { - auto overrides = bundle.getOverrides(); - QString folder; - for (const auto &override : overrides) { - if (override.getKey() == "folder") { - folder = QString::fromStdString(override.getValue().cStr()); - } - } - - modelFolders.insert(folder); - sortedModels.append(TreeNode{ - folder, - QString::fromStdString(bundle.getDisplayName()), - QString::fromStdString(bundle.getRef()), - static_cast(bundle.getIndex()) - }); - } - - std::sort(sortedModels.begin(), sortedModels.end(), - [](const TreeNode &a, const TreeNode &b) { - return a.index > b.index; - }); - - // Create a list of folder-maxIndex pairs for sorting - QList> folderMaxIndices; - for (const auto &folder : modelFolders) { - int maxIndex = -1; - for (const auto &model : sortedModels) { - if (model.folder == folder) { - maxIndex = std::max(maxIndex, model.index); - } - } - folderMaxIndices.append(qMakePair(folder, maxIndex)); - } - - // Sort folders by their highest model index - std::sort(folderMaxIndices.begin(), folderMaxIndices.end(), - [](const QPair &a, const QPair &b) { - return a.second > b.second; - }); - - // Create the final items list using sorted folders - QList items; - for (const auto &folderPair : folderMaxIndices) { - QList folderModels; - QString folder = folderPair.first; - for (const auto &model : sortedModels) { - if (model.folder == folderPair.first) { - if (model.index == folderPair.second) { - QRegularExpressionMatch match = re.match(model.displayName); - if (match.hasMatch()) { - folder.append(" - (Updated: ").append(match.captured(1)).append(")"); - } - } - folderModels.append(model); - } - } - items.append(TreeFolder{folder, folderModels}); - } - - items.insert(0, TreeFolder{"", { - TreeNode{"", DEFAULT_MODEL, DEFAULT_MODEL, -1} - }}); - - currentModelLblBtn->setValue(GetActiveModelInternalName()); - - const QString selectedBundleRef = TreeOptionDialog::getSelection( - tr("Select a Model"), items, GetActiveModelRef(), QString("ModelManager_Favs"), this); - - if (selectedBundleRef.isEmpty() || !canContinueOnMeteredDialog()) { - return; - } - - // Handle "Stock" selection differently - if (selectedBundleRef == DEFAULT_MODEL) { - params.remove("ModelManager_ActiveBundle"); - currentModelLblBtn->setValue(tr("Default")); - showResetParamsDialog(); - } else { - // Find selected bundle and initiate download - for (const auto &bundle: model_manager.getAvailableBundles()) { - if (QString::fromStdString(bundle.getRef()) == selectedBundleRef) { - params.put("ModelManager_DownloadIndex", std::to_string(bundle.getIndex())); - if (bundle.getGeneration() != model_manager.getActiveBundle().getGeneration()) { - showResetParamsDialog(); - } - break; - } - } - } - - updateLabels(); -} - -/** - * @brief Updates the UI elements based on current state - */ -void ModelsPanel::updateLabels() { - if (!isVisible()) { - return; - } - - updateModelManagerState(); - handleBundleDownloadProgress(); - currentModelLblBtn->setEnabled(!is_onroad && !isDownloading()); - currentModelLblBtn->setValue(GetActiveModelInternalName()); - - // Update lagdToggle description with current value - QString desc = tr("Enable this for the car to learn and adapt its steering response time. " - "Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience."); - bool lagdEnabled = params.getBool("LagdToggle"); - if (lagdEnabled) { - auto liveDelayBytes = params.get("LiveDelay"); - if (!liveDelayBytes.empty()) { - auto LD = loadCerealEvent(params, "LiveDelay"); - float lateralDelay = LD->getLiveDelay().getLateralDelay(); - desc += QString("

%1 %2 s") - .arg(tr("Live Steer Delay:")).arg(QString::number(lateralDelay, 'f', 3)); - } - } else { - auto carParamsBytes = params.get("CarParamsPersistent"); - if (!carParamsBytes.empty()) { - AlignedBuffer aligned_buf_cp; - capnp::FlatArrayMessageReader cmsg(aligned_buf_cp.align(carParamsBytes.data(), carParamsBytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - - float steerDelay = CP.getSteerActuatorDelay(); - float softwareDelay = QString::fromStdString(params.get("LagdToggleDelay")).toFloat(); - float totalLag = steerDelay + softwareDelay; - desc += QString("

" - "%1 %2 s + %3 %4 s = %5 %6 s") - .arg(tr("Actuator Delay:"), QString::number(steerDelay, 'f', 2), - tr("Software Delay:"), QString::number(softwareDelay, 'f', 2), - tr("Total Delay:"), QString::number(totalLag, 'f', 2)); - } - } - lagd_toggle_control->setDescription(desc); - - delay_control->setVisible(!params.getBool("LagdToggle")); - if (delay_control->isVisible()) { - float value = QString::fromStdString(params.get("LagdToggleDelay")).toFloat(); - delay_control->setLabel(QString::number(value, 'f', 2) + "s"); - } - - // Update lane turn desire label and visibility - refreshLaneTurnValueControl(); - - clearModelCacheBtn->setValue(QString::number(calculateCacheSize(), 'f', 2) + " MB"); -} - -/** - * @brief Shows dialog prompting user to reset calibration after model download - */ -void ModelsPanel::showResetParamsDialog() { - const auto confirmMsg = QString("%1

%2

%3") - .arg(tr("Model download has started in the background.")) - .arg(tr("We STRONGLY suggest you to reset calibration.")) - .arg(tr("Would you like to do that now?")); - const auto button_text = tr("Reset Calibration"); - - QString content("

" + tr("Driving Model Selector") + "


" - "

" + confirmMsg + "

"); - - if (showConfirmationDialog(content, button_text, false)) { - params.remove("CalibrationParams"); - params.remove("LiveTorqueParameters"); - } -} - -void ModelsPanel::clearModelCache() { - QString confirmMsg = tr("This will delete ALL downloaded models from the cache" - "
except the currently active model." - "

Are you sure you want to continue?"); - QString content("

" + tr("Driving Model Selector") + "


" - "

" + confirmMsg + "

"); - if (showConfirmationDialog( - content, - tr("Clear Cache"))) { - params.putBool("ModelManager_ClearCache", true); - } -} - -double ModelsPanel::calculateCacheSize() { - QFuture future_ModelCacheSize = QtConcurrent::run([=]() { - - QDir model_dir(QString::fromStdString(Path::model_root())); - QFileInfoList model_files = model_dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot); - qint64 totalSize = 0; - for (const QFileInfo &model_file : model_files) { - if (model_file.isFile()) { - totalSize += model_file.size(); - } - } - return totalSize; - }); - return static_cast(future_ModelCacheSize) / (1024.0 * 1024.0); -} - -void ModelsPanel::showEvent(QShowEvent *event) { - lagd_toggle_control->showDescription(); - if (delay_control->isVisible()) { - delay_control->showDescription(); - } -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h deleted file mode 100644 index 1a39800dde..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include - -#include "selfdrive/ui/sunnypilot/qt/util.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" - -class ModelsPanel : public QWidget { - Q_OBJECT - -public: - explicit ModelsPanel(QWidget *parent = nullptr); - -private: - QString GetActiveModelName(); - QString GetActiveModelInternalName(); - QString GetActiveModelRef(); - void updateModelManagerState(); - void showEvent(QShowEvent *event) override; - - bool isDownloading() const { - if (!model_manager.hasSelectedBundle()) { - return false; - } - - const auto &selected_bundle = model_manager.getSelectedBundle(); - return selected_bundle.getStatus() == cereal::ModelManagerSP::DownloadStatus::DOWNLOADING; - } - - // UI update related methods - void updateLabels(); - void handleCurrentModelLblBtnClicked(); - void handleBundleDownloadProgress(); - void refreshLaneTurnValueControl(); - void showResetParamsDialog(); - QProgressBar* createProgressBar(QWidget *parent); - QFrame* createModelDetailFrame(QWidget *parent, QString &typeName, QProgressBar *progressBar); - cereal::ModelManagerSP::Reader model_manager; - cereal::ModelManagerSP::DownloadStatus download_status{}; - cereal::ModelManagerSP::DownloadStatus prev_download_status{}; - void clearModelCache(); - double calculateCacheSize(); - - bool canContinueOnMeteredDialog() { - if (!is_metered) return true; - return showConfirmationDialog(QString(), QString(), is_metered); - } - - inline bool showConfirmationDialog(const QString &message = QString(), const QString &confirmButtonText = QString(), const bool show_metered_warning = false) { - return showConfirmationDialog(this, message, confirmButtonText, show_metered_warning); - } - - static inline bool showConfirmationDialog(QWidget *parent, const QString &message = QString(), const QString &confirmButtonText = QString(), const bool show_metered_warning = false) { - const QString warning_message = show_metered_warning ? tr("Warning: You are on a metered connection!") : QString(); - const QString final_message = QString("%1%2").arg(!message.isEmpty() ? message + "\n" : QString(), warning_message); - const QString final_buttonText = !confirmButtonText.isEmpty() ? confirmButtonText : QString(tr("Continue") + " %1").arg(show_metered_warning ? tr("on Metered") : ""); - - return ConfirmationDialog(final_message, final_buttonText, tr("Cancel"), true, parent).exec(); - } - - bool is_metered{}; - bool is_wifi{}; - bool is_onroad = false; - - ButtonControlSP *currentModelLblBtn; - ParamControlSP *lagd_toggle_control; - OptionControlSP *delay_control; - QProgressBar *supercomboProgressBar; - QFrame *supercomboFrame; - QProgressBar *navigationProgressBar; - QFrame *navigationFrame; - QProgressBar *visionProgressBar; - QFrame *visionFrame; - QProgressBar *policyProgressBar; - QFrame *policyFrame; - Params params; - ButtonControlSP *clearModelCacheBtn; - ButtonControlSP *refreshAvailableModelsBtn; - ParamControlSP *lane_turn_desire_toggle; - OptionControlSP *lane_turn_value_control; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/locations_fetcher.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/locations_fetcher.h deleted file mode 100644 index 32d169ad15..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/locations_fetcher.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include // for std::sort -#include -#include -#include - -#include -#include - -#include "selfdrive/ui/sunnypilot/qt/common/json_fetcher.h" - -static const std::tuple defaultLocation = std::make_tuple("== None ==", ""); - -// New class LocationsFetcher that handles web requests and JSON parsing -class LocationsFetcher { -public: - inline std::vector > - getLocationsFromURL(const QUrl &url, const std::tuple &customLocation = defaultLocation) const { - // Initialize an empty vector to hold the locations - std::vector > locations; - - JsonFetcher fetcher; - QJsonObject json = fetcher.getJsonFromURL(url.toString()); - - for (auto it = json.begin(); it != json.end(); ++it) { - QString code = it.key(); - QJsonObject obj = it.value().toObject(); - QString fullName = obj["full_name"].toString(); - - locations.push_back(std::make_tuple(fullName, code, QString(), QString())); - } - // Sort locations by full name - std::sort(locations.begin(), locations.end(), [](const auto &lhs, const auto &rhs) { - return std::get<0>(lhs) < std::get<0>(rhs); // Compare full names - }); - // Optionally, you can now add defaultName entry at the beginning - locations.insert(locations.begin(), std::tuple_cat(customLocation, std::make_tuple("", ""))); - return locations; - } - - inline std::vector > - getLocationsFromURL(const QString &url, const std::tuple &customLocation = defaultLocation) const { - return getLocationsFromURL(QUrl(url), customLocation); - } - - inline std::vector > - getOsmLocations(const std::tuple &customLocation = defaultLocation) const { - return getLocationsFromURL( "https://raw.githubusercontent.com/pfeiferj/openpilot-mapd/main/nation_bounding_boxes.json", customLocation); - } - - inline std::vector > - getUsStatesLocations(const std::tuple &customLocation = defaultLocation) const { - return getLocationsFromURL( "https://raw.githubusercontent.com/pfeiferj/openpilot-mapd/main/us_states_bounding_boxes.json", customLocation); - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.cc deleted file mode 100644 index b67e41e09d..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.cc +++ /dev/null @@ -1,158 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.h" - -#include - -ModelsFetcher::ModelsFetcher(QObject *parent) : QObject(parent) { - manager = new QNetworkAccessManager(this); -} - -QByteArray ModelsFetcher::verifyFileHash(const QString &filePath, const QString &expectedHash, bool &hashMatches) { - hashMatches = false; // Default to false - QByteArray fileData; - - if (expectedHash.isEmpty()) { - // If no hash is provided, assume verification isn't required but return the file data - hashMatches = true; - } else { - QFile file(filePath); - if (file.open(QIODevice::ReadOnly)) { - QCryptographicHash hash(QCryptographicHash::Sha256); // Or your chosen algorithm - fileData = file.readAll(); // Read the file data once - hash.addData(fileData); - file.close(); - - QString currentHash = QString(hash.result().toHex()); - hashMatches = (currentHash == expectedHash); - } - } - - // Return the file data if hash matches or no hash was provided; empty otherwise - return hashMatches ? fileData : QByteArray(); -} - - -void ModelsFetcher::download(const DownloadInfo &downloadInfo, const QString &filename, const QString &destinationPath) { - QString fullPath = destinationPath + "/" + filename; - QFileInfo fileInfo(fullPath); - bool hashMatches = false; - QByteArray data = verifyFileHash(fullPath, downloadInfo.sha256, hashMatches); - - if (fileInfo.exists() && hashMatches) { - // Hash matches or no hash provided, and we have the file data - LOGD("File already downloaded and verified: %s", filename.toStdString().c_str()); - emit downloadProgress(100); - emit downloadComplete(data, true); // Use the data returned from verifyFileHash - return; // Exit early - } - - // Proceed with download if file does not exist or hash verification failed - QNetworkRequest request(downloadInfo.url); - QNetworkReply *reply = manager->get(request); - connect(reply, &QNetworkReply::downloadProgress, this, &ModelsFetcher::onDownloadProgress); - connect(reply, &QNetworkReply::finished, this, [this, reply, destinationPath, filename, downloadInfo]() { - onFinished(reply, destinationPath, filename, downloadInfo.sha256); - }); -} - -QString extractFileName(const QString &contentDisposition) { - const QString filenameTag = "filename="; - const int idx = contentDisposition.indexOf(filenameTag); - if (idx < 0) { - return QString(); - } - - QString filename = contentDisposition.mid(idx + filenameTag.length()); - if (filename.startsWith("\"") && filename.endsWith("\"")) { - return filename.mid(1, filename.size() - 2); - } - - return filename; -} - -void ModelsFetcher::onFinished(QNetworkReply *reply, const QString &destinationPath, const QString &filename, const QString &expectedHash) { - // Handle download error - if (reply->error()) { - return; // Possibly emit a signal or log an error as per your error handling policy - } - - const QByteArray data = reply->readAll(); - - QString finalFilename = filename; - if (finalFilename.isEmpty()) { - finalFilename = extractFileName(reply->header(QNetworkRequest::ContentDispositionHeader).toString()); - } - - QString finalPath = QDir(destinationPath).filePath(finalFilename); - - // Save the downloaded file - QFile file(finalPath); - //ensure if the path exists and if not create it - if (!QDir().mkpath(destinationPath)) { - LOGE("Unable to create directory: %s", destinationPath.toStdString().c_str()); - emit downloadFailed(filename); - return; // Stop further processing - } - - //Retry the file open and write 3 times with a little delay between each retry - for (int i = 0; i < 3; i++) { - if (file.isOpen()) break; - - file.open(QIODevice::WriteOnly); - if (!file.isOpen()) QThread::msleep(100); - } - - // If the file is still not open, log an error and emit a failure signal - if (!file.isOpen()) { - LOGE("Unable to open file for writing: %s", finalPath.toStdString().c_str()); - emit downloadFailed(filename); - return; // Stop further processing - } - - file.write(data); - file.close(); - - bool hashMatches = false; - verifyFileHash(finalPath, expectedHash, hashMatches); - - // Verify the file hash if expectedHash is provided - if (!expectedHash.isEmpty() && !hashMatches) { - LOGE("The downloaded file didn't pass the hash validation!: %s", filename.toStdString().c_str()); - // Hash verification failed, handle accordingly - // This could involve deleting the file, logging an error, or emitting a failure signal - QFile::remove(finalPath); // Example action: Remove the invalid file - emit downloadFailed(filename); - return; // Stop further processing - } - - emit downloadComplete(data, false); // Emit your success signal -} - -void ModelsFetcher::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - const double progress = (bytesReceived * 100.0) / bytesTotal; - emit downloadProgress(progress); -} - -std::vector ModelsFetcher::getModelsFromURL(const QUrl &url) { - std::vector models; - JsonFetcher fetcher; - QJsonObject json = fetcher.getJsonFromURL(url.toString()); - for (auto it = json.begin(); it != json.end(); ++it) { - models.push_back(Model(it.value().toObject())); - } - return models; -} - -std::vector ModelsFetcher::getModelsFromURL(const QString &url) { - return getModelsFromURL(QUrl(url)); -} - -std::vector ModelsFetcher::getModelsFromURL() { - return getModelsFromURL("https://docs.sunnypilot.ai/models_v5.json"); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.h deleted file mode 100644 index 73890e9d5a..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.h +++ /dev/null @@ -1,143 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include // for std::sort -#include -#include -#include - -#include -#include -#include - -#include "common/swaglog.h" -#include "common/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/qt/common/json_fetcher.h" -#ifdef SUNNYPILOT -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" -#else -#include "selfdrive/ui/qt/widgets/controls.h" -#endif -#include "system/hardware/hw.h" - -static const QString MODELS_PATH = Hardware::PC() ? QDir::homePath() + "/.comma/media/0/models/" : "/data/media/0/models/"; - -struct DownloadInfo { - QString url; - QString sha256; -}; - -// New class ModelsFetcher with a new function that handles web requests and JSON parsing for the new JSON structure -class Model { -public: - explicit Model(const QJsonObject &json) { - displayName = json["display_name"].toString(); - fullName = json["full_name"].toString(); - fileName = json["file_name"].toString(); - - // Parse downloadUri as an object - QJsonObject downloadUriObj = json["download_uri"].toObject(); - downloadUri.url = downloadUriObj["url"].toString(); - downloadUri.sha256 = downloadUriObj["sha256"].toString(); - - fullNameNav = json["full_name_nav"].toString(); - fileNameNav = json["file_name_nav"].toString(); - - // Parse downloadUriNav as an object - QJsonObject downloadUriNavObj = json["download_uri_nav"].toObject(); - downloadUriNav.url = downloadUriNavObj["url"].toString(); - downloadUriNav.sha256 = downloadUriNavObj["sha256"].toString(); - - fullNameMetadata = json["full_name_metadata"].toString(); - fileNameMetadata = json["file_name_metadata"].toString(); - - // Parse downloadUriMetadata as an object - QJsonObject downloadUriMetadataObj = json["download_uri_metadata"].toObject(); - downloadUriMetadata.url = downloadUriMetadataObj["url"].toString(); - downloadUriMetadata.sha256 = downloadUriMetadataObj["sha256"].toString(); - - index = json["index"].toString(); - environment = json["environment"].toString(); - generation = json["generation"].toString(); - } - - // Method to convert model back to QJsonObject, if needed - QJsonObject toJson() const { - QJsonObject json; - json["display_name"] = displayName; - json["full_name"] = fullName; - json["file_name"] = fileName; - - QJsonObject uriObj; - uriObj["url"] = downloadUri.url; - uriObj["sha256"] = downloadUri.sha256; - json["download_uri"] = uriObj; - - QJsonObject uriNavObj; - uriNavObj["url"] = downloadUriNav.url; - uriNavObj["sha256"] = downloadUriNav.sha256; - json["download_uri_nav"] = uriNavObj; - - QJsonObject uriMetadataObj; - uriMetadataObj["url"] = downloadUriMetadata.url; - uriMetadataObj["sha256"] = downloadUriMetadata.sha256; - json["download_uri_metadata"] = uriMetadataObj; - - json["full_name_nav"] = fullNameNav; - json["file_name_nav"] = fileNameNav; - json["full_name_metadata"] = fullNameMetadata; - json["file_name_metadata"] = fileNameMetadata; - json["index"] = index; - json["environment"] = environment; - json["generation"] = generation; - return json; - } - - QString displayName; - QString fullName; - QString fileName; - DownloadInfo downloadUri; - DownloadInfo downloadUriNav; - DownloadInfo downloadUriMetadata; - - QString fullNameNav; - QString fileNameNav; - QString fullNameMetadata; - QString fileNameMetadata; - QString index; - QString environment; - QString generation; -}; - -class ModelsFetcher : public QObject { - Q_OBJECT - -public: - explicit ModelsFetcher(QObject *parent = nullptr); - void download(const DownloadInfo &url, const QString &filename = "", const QString &destinationPath = MODELS_PATH); - static std::vector getModelsFromURL(const QUrl &url); - static std::vector getModelsFromURL(const QString &url); - static std::vector getModelsFromURL(); - -signals: - void downloadProgress(double percentage); - void downloadComplete(const QByteArray &data, bool fromCache = false); - void downloadFailed(const QString &filename); - -private: - // static bool verifyFileHash(const QString& filePath, const QString& expectedHash); - static QByteArray verifyFileHash(const QString &filePath, const QString &expectedHash, bool &hashMatches); - void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); - void onFinished(QNetworkReply *reply, const QString &destinationPath, const QString &filename, - const QString &expectedHash); - - QNetworkAccessManager *manager; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.cc deleted file mode 100644 index e946d7870f..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.cc +++ /dev/null @@ -1,307 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.h" - -#include -#include -#include - -#include "common/swaglog.h" -#include "selfdrive/ui/sunnypilot/qt/util.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -OsmPanel::OsmPanel(QWidget *parent) : QFrame(parent) { - main_layout = new QStackedLayout(this); - - const auto list = new ListWidgetSP(this, false); - list->addItem(mapdVersion = new LabelControlSP(tr("Mapd Version"), "Loading...")); - list->addItem(setupOsmDeleteMapsButton(parent)); - list->addItem(offlineMapsETA = new LabelControlSP(tr("Offline Maps ETA"), "")); - list->addItem(offlineMapsElapsed = new LabelControlSP(tr("Time Elapsed"), "")); - list->addItem(setupOsmUpdateButton(parent)); - list->addItem(setupOsmDownloadButton(parent)); - list->addItem(setupUsStatesButton(parent)); - - connect(uiStateSP(), &UIStateSP::offroadTransition, [=](bool offroad) { - updateLabels(); - }); - - timer = new QTimer(this); - connect(timer, &QTimer::timeout, this, QOverload<>::of(&OsmPanel::updateLabels)); - timer->start(FAST_REFRESH_INTERVAL); // Time specified in milliseconds. - updateLabels(); - - osmScreen = new QWidget(this); - auto *vlayout = new QVBoxLayout(osmScreen); - vlayout->setContentsMargins(50, 20, 50, 20); - vlayout->addWidget(new ScrollViewSP(list, this), 1); - main_layout->addWidget(osmScreen); -} - -ButtonControlSP *OsmPanel::setupOsmDeleteMapsButton(QWidget *parent) { - osmDeleteMapsBtn = new ButtonControlSP(tr("Downloaded Maps"), tr("DELETE")); // Updated on updateLabels() - connect(osmDeleteMapsBtn, &ButtonControlSP::clicked, [=]() { - if (showConfirmationDialog(parent, tr("This will delete ALL downloaded maps\n\nAre you sure you want to delete all the maps?"), tr("Yes, delete all the maps."))) { - QtConcurrent::run([=]() { - QDir dir(MAP_PATH); - osmDeleteMapsBtn->setEnabled(false); - osmDeleteMapsBtn->setText("⌛"); - dir.removeRecursively(); - updateMapSize(); - osmDeleteMapsBtn->setEnabled(true); - osmDeleteMapsBtn->setText(tr("DELETE")); - }); - updateLabels(); - } - }); - return osmDeleteMapsBtn; -} - -ButtonControlSP *OsmPanel::setupOsmUpdateButton(QWidget *parent) { - osmUpdateBtn = new ButtonControlSP(tr("Database Update"), tr("CHECK")); // Updated on updateLabels() - connect(osmUpdateBtn, &ButtonControlSP::clicked, [=]() { - if (osm_download_in_progress && !download_failed_state) { - updateLabels(); - } else if (showConfirmationDialog(parent)) { - osm_download_in_progress = true; - params.putBool("OsmDbUpdatesCheck", true); - updateLabels(); - } - }); - return osmUpdateBtn; -} - -ButtonControlSP *OsmPanel::setupOsmDownloadButton(QWidget *parent) { - osmDownloadBtn = new ButtonControlSP(tr("Country"), tr("SELECT")); - connect(osmDownloadBtn, &ButtonControlSP::clicked, [=]() { - osmDownloadBtn->setEnabled(false); - osmDownloadBtn->setValue(tr("Fetching Country list...")); - const std::vector > locations = getOsmLocations(); - osmDownloadBtn->setEnabled(true); - osmDownloadBtn->setValue(""); - const QString initTitle = QString::fromStdString(params.get("OsmLocationTitle")); - const QString currentTitle = ((initTitle == "== None ==") || (initTitle.length() == 0)) ? "== None ==" : initTitle; - - QStringList locationTitles; - for (auto &loc: locations) { - locationTitles.push_back(std::get<0>(loc)); - } - - InputDialog d(tr("Search Country"), this, tr("Enter search keywords, or leave blank to list all countries."), false); - d.setMinLength(0); - const int ret = d.exec(); - if (ret) { - const QString selection = search(d.text(), locationTitles, tr("Select Country")); - if (!selection.isEmpty()) { - params.put("OsmLocal", "1"); - params.put("OsmLocationTitle", selection.toStdString()); - for (auto &loc: locations) { - if (std::get<0>(loc) == selection) { - params.put("OsmLocationName", std::get<1>(loc).toStdString()); - break; - } - } - if (params.get("OsmLocationName") == "US") { - usStatesBtn->click(); - return; - } - if (selection != "== None ==") { - if (showConfirmationDialog(parent)) { - osm_download_in_progress = true; - params.putBool("OsmDbUpdatesCheck", true); - updateLabels(); - } - } - } - } - updateLabels(); - }); - return osmDownloadBtn; -} - -ButtonControlSP *OsmPanel::setupUsStatesButton(QWidget *parent) { - usStatesBtn = new ButtonControlSP(tr("State"), tr("SELECT")); - connect(usStatesBtn, &ButtonControlSP::clicked, [=]() { - const std::tuple allStatesOption = std::make_tuple("All States (~4.8 GB)", "All"); - usStatesBtn->setEnabled(false); - usStatesBtn->setValue(tr("Fetching State list...")); - const std::vector > locations = - getUsStatesLocations(allStatesOption); - usStatesBtn->setEnabled(true); - usStatesBtn->setValue(""); - const QString initTitle = QString::fromStdString(params.get("OsmStateTitle")); - const QString currentTitle = ((initTitle == std::get<0>(allStatesOption)) || (initTitle.length() == 0)) ? tr("All") : initTitle; - - QStringList locationTitles; - for (auto &loc: locations) { - locationTitles.push_back(std::get<0>(loc)); - } - - InputDialog d(tr("Search State"), this, tr("Enter search keywords, or leave blank to list all states."), false); - d.setMinLength(0); - const int ret = d.exec(); - if (ret) { - const QString selection = search(d.text(), locationTitles, tr("Select State")); - if (!selection.isEmpty()) { - params.put("OsmStateTitle", selection.toStdString()); - for (auto &loc: locations) { - if (std::get<0>(loc) == selection) { - params.put("OsmStateName", std::get<1>(loc).toStdString()); - break; - } - } - usStatesBtn->setValue(selection); - if (showConfirmationDialog(parent)) { - osm_download_in_progress = true; - params.putBool("OsmDbUpdatesCheck", true); - updateLabels(); - } - } - } - updateLabels(); - }); - usStatesBtn->setVisible(false); // initially hidden - return usStatesBtn; -} - -void OsmPanel::showEvent(QShowEvent *event) { - updateLabels(); // For snappier feeling - if (!timer->isActive()) { - timer->start(FAST_REFRESH_INTERVAL); - } -} - -void OsmPanel::hideEvent(QHideEvent *event) { - if (timer->isActive()) { - timer->stop(); - } -} - - -void OsmPanel::updateLabels() { - if (!isVisible()) { - return; - } - mapd_version = params.get("MapdVersion"); - mapdVersion->setText(mapd_version.c_str()); - - updateMapSize(); - osm_download_locations = mem_params.get("OSMDownloadLocations"); - osm_download_in_progress = !osm_download_locations.empty(); - - timer->setInterval(osm_download_in_progress ? FAST_REFRESH_INTERVAL : SLOW_REFRESH_INTERVAL); - LOGT("Timer Interval %d", timer->interval()); - - const std::string osmLastDownloadTimeStr = params.get("OsmDownloadedDate"); - if (!lastDownloadedTimePoint.has_value() && !osmLastDownloadTimeStr.empty()) { - const double osmLastDownloadTime = std::stod(osmLastDownloadTimeStr); - lastDownloadedTimePoint = std::chrono::system_clock::from_time_t(static_cast(osmLastDownloadTime)); - } - - osmDownloadBtn->setEnabled(!osm_download_in_progress); - usStatesBtn->setEnabled(!osm_download_in_progress); - - updateDownloadProgress(); - - const QString locationName = QString::fromStdString(params.get("OsmLocationName")); - const bool isUs = !locationName.isEmpty() && locationName == "US"; - usStatesBtn->setVisible(isUs); - - if (!locationName.isEmpty()) { - if (!isUs) { - params.remove("OsmStateName"); - params.remove("OsmStateTitle"); - } - osmUpdateBtn->setVisible(true); - } else { - params.remove("OsmLocal"); - params.remove("OsmLocationName"); - params.remove("OsmLocationTitle"); - params.remove("OsmStateName"); - params.remove("OsmStateTitle"); - osmUpdateBtn->setVisible(false); - usStatesBtn->setVisible(false); - } - - osmDownloadBtn->setValue(QString::fromStdString(params.get("OsmLocationTitle"))); - usStatesBtn->setValue(QString::fromStdString(params.get("OsmStateTitle"))); - update(); -} - -void OsmPanel::updateDownloadProgress() { - const auto pending_update_check = params.getBool("OsmDbUpdatesCheck"); - const QJsonObject osmDownloadProgress = QJsonDocument::fromJson(params.get("OSMDownloadProgress").c_str()).object(); - if (osm_download_in_progress && lastDownloadedTimePoint.has_value()) { - offlineMapsETA->setVisible(true); - offlineMapsElapsed->setVisible(true); - offlineMapsETA->setText(calculateETA(osmDownloadProgress, lastDownloadedTimePoint.value())); - offlineMapsElapsed->setText(calculateElapsedTime(osmDownloadProgress, lastDownloadedTimePoint.value())); - } else { - offlineMapsETA->setVisible(false); - offlineMapsElapsed->setVisible(false); - } - - const int total_files = extractIntFromJson(osmDownloadProgress, "total_files"); - const int downloaded_files = extractIntFromJson(osmDownloadProgress, "downloaded_files"); - download_failed_state = total_files && osm_download_in_progress && !lastDownloadedTimePoint.has_value() && downloaded_files < total_files; - - QString updateButtonText = processUpdateStatus(pending_update_check, total_files, downloaded_files, osmDownloadProgress, download_failed_state); - - osmUpdateBtn->setValue(updateButtonText); - osmUpdateBtn->setText(osm_download_in_progress && !download_failed_state ? tr("REFRESH") : tr("UPDATE")); - osmDeleteMapsBtn->setValue(formatSize(mapsDirSize)); -} - -int OsmPanel::extractIntFromJson(const QJsonObject &json, const QString &key) { - return (json.contains(key)) ? json[key].toInt() : 0; -} - -QString OsmPanel::processUpdateStatus(bool pending_update, int total_files, int downloaded_files, const QJsonObject &json, bool failed_state) { - if (pending_update && !osm_download_in_progress && !total_files) { - lastDownloadedTimePoint.reset(); - return tr("Download starting..."); - } else if (failed_state) { - return tr("Error: Invalid download. Retry."); - } else if (osm_download_in_progress && total_files > downloaded_files) { - return formatDownloadStatus(json); - } else if (osm_download_in_progress && downloaded_files >= total_files) { - osm_download_in_progress = false; - lastDownloadedTimePoint.reset(); - return tr("Download complete!"); - } - - if (lastDownloadedTimePoint.has_value()) { - QDateTime dateTime = QDateTime::fromTime_t(std::chrono::system_clock::to_time_t(lastDownloadedTimePoint.value())); //fromMSecsSinceEpoch(duration); - dateTime = dateTime.toLocalTime(); - return QString("%1").arg(dateTime.toString("yyyy-MM-dd HH:mm:ss")); - } - - return ""; -} - -void OsmPanel::updateMapSize() { - if (mapSizeFuture.has_value() && mapSizeFuture.value().isFinished()) { - mapsDirSize = mapSizeFuture.value().result(); - } - - if (!mapSizeFuture.has_value() || !mapSizeFuture.value().isRunning()) { - mapSizeFuture = QtConcurrent::run(getDirSize, MAP_PATH); - } -} - -QString OsmPanel::search(const QString &query, const QStringList &list, const QString &prompt_text) { - QStringList lst_results = searchFromList(query, list); - QString selection; - - if (lst_results.isEmpty()) { - ConfirmationDialog::alert(tr("No results found for keywords: %1").arg(query), this); - return selection; - } - selection = MultiOptionDialog::getSelection(prompt_text, lst_results, "", this); - return selection; -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.h deleted file mode 100644 index e4067d415f..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.h +++ /dev/null @@ -1,233 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "selfdrive/ui/qt/network/wifi_manager.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/osm/locations_fetcher.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "system/hardware/hw.h" - -constexpr int FAST_REFRESH_INTERVAL = 1000; // ms -constexpr int SLOW_REFRESH_INTERVAL = 5000; // ms - -static const QString MAP_PATH = Hardware::PC() ? QDir::homePath() + "/.comma/media/0/osm/offline/" : "/data/media/0/osm/offline/"; - -class OsmPanel : public QFrame { - Q_OBJECT - -public: - explicit OsmPanel(QWidget *parent = nullptr); - -private: - QStackedLayout *main_layout = nullptr; - QWidget *osmScreen = nullptr; - Params params; - Params mem_params{Hardware::PC() ? "" : "/dev/shm/params"}; - std::map toggles; - std::optional > mapSizeFuture; - const SubMaster &sm = *uiStateSP()->sm; - - - bool is_onroad = false; - std::string mapd_version; - - bool isWifi() const { return sm["deviceState"].getDeviceState().getNetworkType() == cereal::DeviceState::NetworkType::WIFI; } - bool isMetered() const { return sm["deviceState"].getDeviceState().getNetworkMetered(); } - bool osm_download_in_progress = false; - bool download_failed_state = false; - quint64 mapsDirSize = 0; - - QLabel *osmUpdateLbl; - ButtonControlSP *osmDownloadBtn; - ButtonControlSP *osmUpdateBtn; - ButtonControlSP *usStatesBtn; - ButtonControlSP *osmDeleteMapsBtn; - - ButtonControlSP *setupOsmDeleteMapsButton(QWidget *parent);; - ButtonControlSP *setupOsmUpdateButton(QWidget *parent); - ButtonControlSP *setupOsmDownloadButton(QWidget *parent); - ButtonControlSP *setupUsStatesButton(QWidget *parent); - - QTimer *timer; - std::string osm_download_locations; - // void updateButtonControlSP(ButtonControlSP *btnControl, QWidget *parent, const QString &initTitle, const QString &allStatesOption); - - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; - void updateLabels(); - void updateDownloadProgress(); - static int extractIntFromJson(const QJsonObject &json, const QString &key); - QString processUpdateStatus(bool pending_update_check, int total_files, int downloaded_files, const QJsonObject &json, bool failed_state); - QString search(const QString &query, const QStringList &list, const QString &prompt_text); - - ConfirmationDialog *confirmationDialog; - LabelControlSP *mapdVersion; - LabelControlSP *offlineMapsStatus; - LabelControlSP *offlineMapsETA; - LabelControlSP *offlineMapsElapsed; - std::optional lastDownloadedTimePoint; - LocationsFetcher locationsFetcher; - - void updateMapSize(); - - bool showConfirmationDialog(QWidget *parent, - const QString &message = QString(), - const QString &confirmButtonText = QString()) const { - const auto _is_metered = isMetered(); - const QString warning_message = _is_metered ? tr("\n\nWarning: You are on a metered connection!") : QString(); - QString final_message = message.isEmpty() ? tr("This will start the download process and it might take a while to complete.") : message; - final_message += warning_message; // Append the warning message if the connection is metered - - const QString final_buttonText = confirmButtonText.isEmpty() ? (_is_metered ? tr("Continue on Metered") : tr("Start Download")) : confirmButtonText; - - return ConfirmationDialog::confirm(final_message, final_buttonText, parent); - } - - // Refactored methods - std::vector > getOsmLocations(const std::tuple &customLocation = defaultLocation) const { - return locationsFetcher.getOsmLocations(customLocation); - } - - std::vector > getUsStatesLocations(const std::tuple &customLocation = defaultLocation) const { - return locationsFetcher.getUsStatesLocations(customLocation); - } - - static QString formatTime(const long timeInSeconds) { - const long minutes = timeInSeconds / 60; - const long seconds = timeInSeconds % 60; - - QString formattedTime; - if (minutes > 0) { - formattedTime = QString::number(minutes) + tr("m "); - } - formattedTime += QString::number(seconds) + tr("s"); - return formattedTime; - } - - static QString calculateElapsedTime(const QJsonObject &jsonData, const std::chrono::system_clock::time_point &startTime) { - using namespace std::chrono; - if (!jsonData.contains("total_files") || !jsonData.contains("downloaded_files")) - return tr("Calculating..."); - - const int totalFiles = jsonData["total_files"].toInt(); - const int downloadedFiles = jsonData["downloaded_files"].toInt(); - - if (downloadedFiles >= totalFiles || totalFiles <= 0) return tr("Downloaded"); - - const long elapsed = duration_cast(system_clock::now() - startTime).count(); - - if (elapsed == 0 || downloadedFiles == 0) return tr("Calculating..."); - - return formatTime(elapsed); - } - - static QString calculateETA(const QJsonObject &jsonData, const std::chrono::system_clock::time_point &startTime) { - using namespace std::chrono; - static steady_clock::time_point lastUpdateTime = steady_clock::now(); - static std::deque rateHistory; - - constexpr int minDataPoints = 3; - constexpr int historySize = 10; - - static QString lastETA = tr("Calculating ETA..."); - - if (duration_cast(steady_clock::now() - lastUpdateTime).count() < 1) { - return lastETA; - } - - if (!jsonData.contains("total_files") || !jsonData.contains("downloaded_files")) - return lastETA; - - const int totalFiles = jsonData["total_files"].toInt(); - const int downloadedFiles = jsonData["downloaded_files"].toInt(); - - if (totalFiles <= 0 || downloadedFiles >= totalFiles) { - return totalFiles <= 0 ? tr("Ready") : tr("Downloaded"); - } - - const long elapsed = duration_cast(system_clock::now() - startTime).count(); - if (elapsed == 0 || downloadedFiles == 0) return lastETA; - - const double rate = downloadedFiles / static_cast(elapsed); - if (rateHistory.size() >= historySize) rateHistory.pop_front(); - rateHistory.push_back(rate); - - if (rateHistory.size() < minDataPoints) return lastETA; - - double weightedSum = 0; - for (int i = 0, weight = 1; i < rateHistory.size(); ++i, ++weight) { - weightedSum += rateHistory[i] * weight; - } - const double avgRate = 2 * weightedSum / (rateHistory.size() * (rateHistory.size() + 1)); - - const long remainingTime = static_cast((totalFiles - downloadedFiles) / avgRate); - if (remainingTime <= 0) return lastETA; - - lastETA = tr("Time remaining: ") + formatTime(remainingTime); - lastUpdateTime = steady_clock::now(); - return lastETA; - } - - static QString formatDownloadStatus(const QJsonObject &json) { - if (!json.contains("total_files") || !json.contains("downloaded_files")) - return ""; - - const int total_files = json["total_files"].toInt(); - const int downloaded_files = json["downloaded_files"].toInt(); - - if (total_files <= 0) return tr("Ready"); - if (downloaded_files >= total_files) return tr("Downloaded"); - - const int percentage = static_cast(100.0 * downloaded_files / total_files); - return QString::asprintf("%d/%d (%d%%)", downloaded_files, total_files, percentage); - } - - QString formatSize(quint64 size) const { - if (size == 0 && (!mapSizeFuture.has_value() || mapSizeFuture.value().isRunning())) { - return tr("Calculating..."); - } - - constexpr qint64 kb = 1024; - constexpr qint64 mb = 1024 * kb; - constexpr qint64 gb = 1024 * mb; - - if (size < gb) { - const double sizeMB = size / static_cast(mb); - return QString::number(sizeMB, 'f', 2) + " MB"; - } else { - const double sizeGB = size / static_cast(gb); - return QString::number(sizeGB, 'f', 2) + " GB"; - } - } - - static quint64 getDirSize(QString dirPath) { - quint64 size = 0; - const QString actualDirPath = dirPath.startsWith("~") ? dirPath.replace(0, 1, QDir::homePath()) : dirPath; - QDirIterator it(actualDirPath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks, QDirIterator::Subdirectories); - while (it.hasNext()) { - it.next(); - if (it.fileInfo().isFile()) { - size += it.fileInfo().size(); - } - } - return size; - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/settings.cc deleted file mode 100644 index c712442df3..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/settings.cc +++ /dev/null @@ -1,171 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" - -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" -#include "selfdrive/ui/qt/offroad/firehose.h" -#include "selfdrive/ui/sunnypilot/qt/network/networking.h" - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/trips_panel.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h" - -TogglesPanelSP::TogglesPanelSP(SettingsWindowSP *parent) : TogglesPanel(parent) { - QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &TogglesPanelSP::updateState); -} - -void TogglesPanelSP::updateState(const UIStateSP &s) { - TogglesPanel::updateState(s); -} - -SettingsWindowSP::SettingsWindowSP(QWidget *parent) : SettingsWindow(parent) { - // setup two main layouts - sidebar_widget = new QWidget; - QVBoxLayout *sidebar_layout = new QVBoxLayout(sidebar_widget); - panel_widget = new QStackedWidget(); - - // setup layout for close button - QVBoxLayout *close_btn_layout = new QVBoxLayout; - close_btn_layout->setContentsMargins(0, 0, 0, 20); - - // close button - QPushButton *close_btn = new QPushButton(tr("×")); - close_btn->setStyleSheet(R"( - QPushButton { - font-size: 140px; - padding-bottom: 20px; - border-radius: 76px; - background-color: #292929; - font-weight: 400; - } - QPushButton:pressed { - background-color: #3B3B3B; - } - )"); - close_btn->setFixedSize(152, 152); - close_btn_layout->addWidget(close_btn, 0, Qt::AlignLeft); - QObject::connect(close_btn, &QPushButton::clicked, this, &SettingsWindowSP::closeSettings); - - // setup buttons widget - QWidget *buttons_widget = new QWidget; - QVBoxLayout *buttons_layout = new QVBoxLayout(buttons_widget); - buttons_layout->setMargin(0); - buttons_layout->addSpacing(10); - - // setup panels - DevicePanelSP *device = new DevicePanelSP(this); - QObject::connect(device, &DevicePanelSP::reviewTrainingGuide, this, &SettingsWindowSP::reviewTrainingGuide); - QObject::connect(device, &DevicePanelSP::showDriverView, this, &SettingsWindowSP::showDriverView); - - TogglesPanelSP *toggles = new TogglesPanelSP(this); - QObject::connect(this, &SettingsWindowSP::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription); - QObject::connect(this, &SettingsWindowSP::scrollToToggle, toggles, &TogglesPanel::scrollToToggle); - - auto networking = new NetworkingSP(this); - QObject::connect(uiState()->prime_state, &PrimeState::changed, networking, &NetworkingSP::setPrimeType); - - QList panels = { - PanelInfo(" " + tr("Device"), device, "../../sunnypilot/selfdrive/assets/offroad/icon_home.svg"), - PanelInfo(" " + tr("Network"), networking, "../assets/icons/network.png"), - PanelInfo(" " + tr("sunnylink"), new SunnylinkPanel(this), "../assets/icons/wifi_strength_full.svg"), - PanelInfo(" " + tr("Toggles"), toggles, "../../sunnypilot/selfdrive/assets/offroad/icon_toggle.png"), - PanelInfo(" " + tr("Software"), new SoftwarePanelSP(this), "../../sunnypilot/selfdrive/assets/offroad/icon_software.png"), - PanelInfo(" " + tr("Models"), new ModelsPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_models.png"), - PanelInfo(" " + tr("Steering"), new LateralPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_lateral.png"), - PanelInfo(" " + tr("Cruise"), new LongitudinalPanel(this), "../assets/icons/speed_limit.png"), - PanelInfo(" " + tr("Visuals"), new VisualsPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_visuals.png"), - PanelInfo(" " + tr("Display"), new DisplayPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_display.png"), - PanelInfo(" " + tr("OSM"), new OsmPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_map.png"), - PanelInfo(" " + tr("Trips"), new TripsPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_trips.png"), - PanelInfo(" " + tr("Vehicle"), new VehiclePanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_vehicle.png"), - PanelInfo(" " + tr("Firehose"), new FirehosePanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_firehose.svg"), - PanelInfo(" " + tr("Developer"), new DeveloperPanelSP(this), "../assets/icons/shell.png"), - }; - - nav_btns = new QButtonGroup(this); - for (auto &[name, panel, icon] : panels) { - QPushButton *btn = new QPushButton(name); - btn->setCheckable(true); - btn->setChecked(nav_btns->buttons().size() == 0); - btn->setIcon(QIcon(QPixmap(icon))); - btn->setIconSize(QSize(70, 70)); - btn->setStyleSheet(R"( - QPushButton { - border-radius: 20px; - width: 400px; - height: 98px; - color: #bdbdbd; - border: none; - background: none; - font-size: 50px; - font-weight: 500; - text-align: left; - padding-left: 22px; - } - QPushButton:checked { - background-color: #696868; - color: white; - } - QPushButton:pressed { - color: #ADADAD; - } - )"); - btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); - nav_btns->addButton(btn); - buttons_layout->addWidget(btn, 0, Qt::AlignLeft | Qt::AlignBottom); - - const int lr_margin = (name != (" " + tr("Network"))) ? 50 : 0; // Network panel handles its own margins - panel->setContentsMargins(lr_margin, 25, lr_margin, 25); - - ScrollViewSP *panel_frame = new ScrollViewSP(panel, this); - panel_widget->addWidget(panel_frame); - - QObject::connect(btn, &QPushButton::clicked, [=, w = panel_frame]() { - btn->setChecked(true); - panel_widget->setCurrentWidget(w); - }); - } - sidebar_layout->setContentsMargins(50, 50, 25, 50); - - // main settings layout, sidebar + main panel - QHBoxLayout *main_layout = new QHBoxLayout(this); - - // add layout for close button - sidebar_layout->addLayout(close_btn_layout); - - // add layout for buttons scrolling - ScrollViewSP *buttons_scrollview = new ScrollViewSP(buttons_widget, this); - sidebar_layout->addWidget(buttons_scrollview); - - sidebar_widget->setFixedWidth(500); - main_layout->addWidget(sidebar_widget); - main_layout->addWidget(panel_widget); - - setStyleSheet(R"( - * { - color: white; - font-size: 50px; - } - SettingsWindow { - background-color: black; - } - QStackedWidget, ScrollViewSP { - background-color: black; - border-radius: 30px; - } - )"); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h deleted file mode 100644 index ff25d3b64f..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include -#include - -#include "selfdrive/ui/qt/offroad/settings.h" - -inline bool isBrandInList(const std::string &brand, const std::vector &list) { - return std::find(list.begin(), list.end(), brand) != list.end(); -} - -class SettingsWindowSP : public SettingsWindow { - Q_OBJECT - -public: - explicit SettingsWindowSP(QWidget *parent = nullptr); - -protected: - struct PanelInfo { - QString name; - QWidget *widget; - QString icon; - - PanelInfo(const QString &name, QWidget *widget, const QString &icon) : name(name), widget(widget), icon(icon) {} - }; -}; - -class TogglesPanelSP : public TogglesPanel { - Q_OBJECT - -public: - explicit TogglesPanelSP(SettingsWindowSP *parent); - -private slots: - void updateState(const UIStateSP &s); -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.cc deleted file mode 100644 index 8bdb7703f2..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.cc +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.h" - -SoftwarePanelSP::SoftwarePanelSP(QWidget *parent) : SoftwarePanel(parent) { - // branch selector - QObject::disconnect(targetBranchBtn, nullptr, nullptr, nullptr); - connect(targetBranchBtn, &ButtonControlSP::clicked, [=]() { - if (Hardware::get_device_type() == cereal::InitData::DeviceType::TICI) { - auto current = params.get("GitBranch"); - QStringList allBranches = QString::fromStdString(params.get("UpdaterAvailableBranches")).split(","); - QStringList branches; - for (const QString &b : allBranches) { - if (b.endsWith("-tici")) { - branches.append(b); - } - } - - for (QString b : {current.c_str(), "master-tici", "staging-tici", "release-tici"}) { - auto i = branches.indexOf(b); - if (i >= 0) { - branches.removeAt(i); - branches.insert(0, b); - } - } - - QString cur = QString::fromStdString(params.get("UpdaterTargetBranch")); - QString selection = MultiOptionDialog::getSelection(tr("Select a branch"), branches, cur, this); - if (!selection.isEmpty()) { - params.put("UpdaterTargetBranch", selection.toStdString()); - targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch"))); - checkForUpdates(); - } - } else { - InputDialog d(tr("Search Branch"), this, tr("Enter search keywords, or leave blank to list all branches."), false); - d.setMinLength(0); - const int ret = d.exec(); - if (ret) { - searchBranches(d.text()); - } - } - }); - - // Disable Updates toggle - disableUpdatesToggle = new ParamControl("DisableUpdates", - tr("Disable Updates"), - tr("When enabled, software updates will be disabled. This requires a reboot to take effect."), - "../assets/icons/icon_warning.png", - this, true); - disableUpdatesToggle->showDescription(); - addItem(disableUpdatesToggle); - connect(disableUpdatesToggle, &ParamControl::toggleFlipped, this, &SoftwarePanelSP::handleDisableUpdatesToggled); - connect(uiState(), &UIState::offroadTransition, this, &SoftwarePanelSP::updateDisableUpdatesToggle); - updateDisableUpdatesToggle(!uiState()->scene.started); -} - -/** - * @brief Searches for available branches based on a query string, presents the results in a dialog, - * and updates the target branch if a selection is made. - * - * This function filters the list of branches based on the provided query, and displays the filtered branches in a selection dialog. - * If a branch is selected, the "UpdaterTargetBranch" parameter is updated and a check for updates is triggered. - * If no branches are found matching the query, an alert dialog is displayed. - * - * @param query The search query string. - */ -void SoftwarePanelSP::searchBranches(const QString &query) { - - QStringList branches = QString::fromStdString(params.get("UpdaterAvailableBranches")).split(","); - QStringList results = searchFromList(query, branches); - results.sort(); - - if (results.isEmpty()) { - ConfirmationDialog::alert(tr("No branches found for keywords: %1").arg(query), this); - return; - } - - QString selected_branch = MultiOptionDialog::getSelection(tr("Select a branch"), results, "", this); - - if (!selected_branch.isEmpty()) { - params.put("UpdaterTargetBranch", selected_branch.toStdString()); - targetBranchBtn->setValue(selected_branch); - checkForUpdates(); - } -} - -void SoftwarePanelSP::handleDisableUpdatesToggled(bool state) { - if (ConfirmationDialog::confirm(tr("%1 updates requires a reboot.
Reboot now?") - .arg(state ? "Disabling" : "Enabling"), tr("Reboot"), this)) { - params.putBool("DoReboot", true); - } else { - params.putBool("DisableUpdates", !state); - disableUpdatesToggle->refresh(); - } -} - -void SoftwarePanelSP::updateDisableUpdatesToggle(bool offroad) { - bool enabled = offroad; - disableUpdatesToggle->setEnabled(enabled); - disableUpdatesToggle->setDescription(enabled - ? tr("When enabled, software updates will be disabled.
This requires a reboot to take effect.") - : tr("Please enable always offroad mode or turn off vehicle to adjust these toggles")); -} - -void SoftwarePanelSP::showEvent(QShowEvent *event) { - SoftwarePanel::showEvent(event); - updateDisableUpdatesToggle(!uiState()->scene.started); - disableUpdatesToggle->showDescription(); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.h deleted file mode 100644 index efaa836a21..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/util.h" -#include "selfdrive/ui/qt/offroad/settings.h" - -class SoftwarePanelSP final : public SoftwarePanel { - Q_OBJECT - -public: - explicit SoftwarePanelSP(QWidget *parent = nullptr); - -private: - void searchBranches(const QString &query); - ParamControl *disableUpdatesToggle = nullptr; - void handleDisableUpdatesToggled(bool state); -private slots: - void updateDisableUpdatesToggle(bool offroad); -protected: - void showEvent(QShowEvent *event) override; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/community_widget.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/community_widget.cc deleted file mode 100644 index e29e89ee98..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/community_widget.cc +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright (c) 2025-, sunnypilot contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/community_widget.h" - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/util.h" - -using qrcodegen::QrCode; - -// --- SunnylinkCommunityQRWidget --- - -SunnylinkCommunityQRWidget::SunnylinkCommunityQRWidget(QWidget* parent) - : QWidget(parent) {} - -void SunnylinkCommunityQRWidget::showEvent(QShowEvent *event) { - updateQrCode(SUNNYLINK_COMMUNITY_URL); - update(); -} - -void SunnylinkCommunityQRWidget::updateQrCode(const QString &text) { - QrCode qr = QrCode::encodeText(text.toUtf8().data(), QrCode::Ecc::LOW); - qint32 sz = qr.getSize(); - QImage im(sz, sz, QImage::Format_RGB32); - - QRgb black = qRgb(0, 0, 0); - QRgb white = qRgb(255, 255, 255); - for (int y = 0; y < sz; y++) { - for (int x = 0; x < sz; x++) { - im.setPixel(x, y, qr.getModule(x, y) ? black : white); - } - } - - int final_sz = ((width() / sz) - 1) * sz; - img = QPixmap::fromImage(im.scaled(final_sz, final_sz, Qt::KeepAspectRatio), Qt::MonoOnly); -} - -void SunnylinkCommunityQRWidget::paintEvent(QPaintEvent *e) { - QPainter p(this); - p.fillRect(rect(), Qt::white); - - if (!img.isNull()) { - QSize s = (size() - img.size()) / 2; - p.drawPixmap(s.width(), s.height(), img); - } -} - -// --- SunnylinkCommunityPopup --- - -QStringList SunnylinkCommunityPopup::getInstructions() { - QStringList instructions; - instructions << tr("Scan the QR code and join us!"); - return instructions; -} - -SunnylinkCommunityPopup::SunnylinkCommunityPopup(QWidget* parent) - : DialogBase(parent) { - auto *mainLayout = new QVBoxLayout(this); - mainLayout->setContentsMargins(0, 0, 0, 0); - mainLayout->setSpacing(0); - - // Solarized Light base3 background - setStyleSheet("SunnylinkCommunityPopup { background-color: #FDF6E3; }"); - - // Header spanning full width - auto headerWidget = new QWidget(this); - auto headerLayout = new QHBoxLayout(headerWidget); - headerLayout->setContentsMargins(85, 50, 85, 30); - headerLayout->setSpacing(30); - - auto close = new QPushButton(QIcon(":/icons/close.svg"), "", this); - close->setIconSize(QSize(80, 80)); - close->setStyleSheet("border: none;"); - connect(close, &QPushButton::clicked, this, &QDialog::reject); - headerLayout->addWidget(close, 0, Qt::AlignLeft | Qt::AlignVCenter); - - const auto title = new QLabel(tr("Join the sunnypilot Community Forum"), this); - // Solarized base02 for text - title->setStyleSheet("font-size: 65px; color: #073642;"); - title->setWordWrap(false); - title->setAlignment(Qt::AlignCenter); - headerLayout->addWidget(title, 1); - - // Spacer to balance the close button on the right - auto spacer = new QWidget(this); - spacer->setFixedSize(80, 80); - headerLayout->addWidget(spacer, 0); - - mainLayout->addWidget(headerWidget); - - // Two-column content layout - auto contentLayout = new QHBoxLayout(); - contentLayout->setContentsMargins(0, 0, 0, 0); - contentLayout->setSpacing(0); - mainLayout->addLayout(contentLayout, 66); - - // Left side: description - auto leftLayout = new QVBoxLayout(); - leftLayout->setContentsMargins(85, 40, 50, 70); - leftLayout->setSpacing(35); - contentLayout->addLayout(leftLayout, 40); - - // Hype / intro paragraph - const auto desc = new QLabel(tr( - "We're excited to announce our sunnypilot Community Forum

" - "Over the years, Discord just hasn't scaled well for our growing community.
" - "It's noisy, unsearchable, and great discussions disappear too easily.
" - "Our new community forum aims to fix that by making it easier to find answers, share ideas, track feedback, report bugs, help newcomers and more!

" - "Here's what's waiting for you:
" - "• Fully indexable and discoverable through search engines 🔎
" - "• AI-powered🤖 topic and chat summaries, spam detection, and more
" - "• A trust-level system✅ that rewards meaningful contributions
" - "• Designed to work on your own time.🧘

" - "Scan the QR code on the right and join the discussion!" - ), this); - // Solarized base01 for body text - desc->setStyleSheet("font-size: 40px; color: #586E75;"); - desc->setWordWrap(true); - leftLayout->addWidget(desc); - - leftLayout->addStretch(); - - // Right side: QR code and instructions - auto rightLayout = new QVBoxLayout(); - rightLayout->setContentsMargins(50, 40, 85, 70); - rightLayout->setSpacing(40); - contentLayout->addLayout(rightLayout, 1); - - // QR code (smaller, fixed size) - auto *qr = new SunnylinkCommunityQRWidget(this); - qr->setFixedSize(500, 500); - rightLayout->addStretch(); - rightLayout->addWidget(qr, 0, Qt::AlignCenter); - rightLayout->addStretch(); -} \ No newline at end of file diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/community_widget.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/community_widget.h deleted file mode 100644 index 613375d12c..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/community_widget.h +++ /dev/null @@ -1,40 +0,0 @@ -/** -* Copyright (c) 2025-, sunnypilot contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include -#include - -#include "common/util.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -const QString SUNNYLINK_COMMUNITY_URL = "https://community.sunnypilot.ai/sp-qr"; - -class SunnylinkCommunityQRWidget : public QWidget { - Q_OBJECT - -public: - explicit SunnylinkCommunityQRWidget(QWidget* parent = nullptr); - void paintEvent(QPaintEvent*) override; - -private: - QPixmap img; - void updateQrCode(const QString &text); - void showEvent(QShowEvent *event) override; -}; - -// Popup widget -class SunnylinkCommunityPopup : public DialogBase { - Q_OBJECT - -public: - explicit SunnylinkCommunityPopup(QWidget* parent = nullptr); - -private: - static QStringList getInstructions(); -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/sponsor_widget.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/sponsor_widget.cc deleted file mode 100644 index a014eddacb..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/sponsor_widget.cc +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/sponsor_widget.h" - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/api.h" -#include "selfdrive/ui/sunnypilot/qt/util.h" -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.h" - -// Sponsor Upsell -using qrcodegen::QrCode; - -SunnylinkSponsorQRWidget::SunnylinkSponsorQRWidget(bool sponsor_pair, QWidget* parent) : QWidget(parent), sponsor_pair(sponsor_pair) { - timer = new QTimer(this); - connect(timer, &QTimer::timeout, this, &SunnylinkSponsorQRWidget::refresh); -} - -void SunnylinkSponsorQRWidget::showEvent(QShowEvent *event) { - refresh(); - timer->start(5 * 60 * 1000); - device()->setOffroadBrightness(100); -} - -void SunnylinkSponsorQRWidget::hideEvent(QHideEvent *event) { - timer->stop(); - device()->setOffroadBrightness(BACKLIGHT_OFFROAD); -} - -void SunnylinkSponsorQRWidget::refresh() { - QString qrString; - - if (sponsor_pair) { - QString token = SunnylinkApi::create_jwt({}, 3600, true); - auto sl_dongle_id = getSunnylinkDongleId(); - QByteArray payload = QString("1|" + sl_dongle_id.value_or("") + "|" + token).toUtf8().toBase64(); - qrString = SUNNYLINK_BASE_URL + "/sso?state=" + payload; - } else { - qrString = "https://github.com/sponsors/sunnyhaibin"; - } - - this->updateQrCode(qrString); - update(); -} - -void SunnylinkSponsorQRWidget::updateQrCode(const QString &text) { - QrCode qr = QrCode::encodeText(text.toUtf8().data(), QrCode::Ecc::LOW); - qint32 sz = qr.getSize(); - QImage im(sz, sz, QImage::Format_RGB32); - - QRgb black = qRgb(0, 0, 0); - QRgb white = qRgb(255, 255, 255); - for (int y = 0; y < sz; y++) { - for (int x = 0; x < sz; x++) { - im.setPixel(x, y, qr.getModule(x, y) ? black : white); - } - } - - // Integer division to prevent anti-aliasing - int final_sz = ((width() / sz) - 1) * sz; - img = QPixmap::fromImage(im.scaled(final_sz, final_sz, Qt::KeepAspectRatio), Qt::MonoOnly); -} - -void SunnylinkSponsorQRWidget::paintEvent(QPaintEvent *e) { - QPainter p(this); - p.fillRect(rect(), Qt::white); - - QSize s = (size() - img.size()) / 2; - p.drawPixmap(s.width(), s.height(), img); -} - -QStringList SunnylinkSponsorPopup::getInstructions(bool sponsor_pair) { - QStringList instructions; - if (sponsor_pair) { - instructions << tr("Scan the QR code to login to your GitHub account") - << tr("Follow the prompts to complete the pairing process") - << tr("Re-enter the \"sunnylink\" panel to verify sponsorship status") - << tr("If sponsorship status was not updated, please contact a moderator on our forum at https://community.sunnypilot.ai"); - } else { - instructions << tr("Scan the QR code to visit sunnyhaibin's GitHub Sponsors page") - << tr("Choose your sponsorship tier and confirm your support") - << tr("Join our Community Forum at https://community.sunnypilot.ai and reach out to a moderator if you have issues"); - } - return instructions; -} - -SunnylinkSponsorPopup::SunnylinkSponsorPopup(bool sponsor_pair, QWidget *parent) : DialogBase(parent), sponsor_pair(sponsor_pair) { - auto *hlayout = new QHBoxLayout(this); - auto sunnylink_client = new SunnylinkClient(this); - hlayout->setContentsMargins(0, 0, 0, 0); - hlayout->setSpacing(0); - - setStyleSheet("SunnylinkSponsorPopup { background-color: #E0E0E0; }"); - - // text - auto vlayout = new QVBoxLayout(); - vlayout->setContentsMargins(85, 70, 50, 70); - vlayout->setSpacing(50); - hlayout->addLayout(vlayout, 1); - { - auto close = new QPushButton(QIcon(":/icons/close.svg"), "", this); - close->setIconSize(QSize(80, 80)); - close->setStyleSheet("border: none;"); - vlayout->addWidget(close, 0, Qt::AlignLeft); - connect(close, &QPushButton::clicked, this, [=] { - sunnylink_client->role_service->load(); - sunnylink_client->user_service->load(); - QDialog::reject(); - }); - - //vlayout->addSpacing(30); - - const QString titleText = sponsor_pair ? tr("Pair your GitHub account") : tr("Early Access: Become a sunnypilot Sponsor"); - const auto title = new QLabel(titleText, this); - title->setStyleSheet("font-size: 75px; color: black;"); - title->setWordWrap(true); - vlayout->addWidget(title); - - QStringList instructions = getInstructions(sponsor_pair); - QString instructionsHtml = "
    "; - for (const auto & instruction : instructions) { - instructionsHtml += QString("
  1. %1
  2. ").arg(instruction); - } - instructionsHtml += "
"; - const auto instructionsLabel = new QLabel(instructionsHtml, this); - - - instructionsLabel->setStyleSheet("font-size: 47px; font-weight: bold; color: black;"); - instructionsLabel->setWordWrap(true); - vlayout->addWidget(instructionsLabel); - - vlayout->addStretch(); - } - - // QR code - auto *qr = new SunnylinkSponsorQRWidget(sponsor_pair, this); - hlayout->addWidget(qr, 1); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/sponsor_widget.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/sponsor_widget.h deleted file mode 100644 index 9f15a6084f..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/sponsor_widget.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include -#include - -#include "common/util.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -const QString SUNNYLINK_BASE_URL = util::getenv("SUNNYLINK_API_HOST", "https://stg.api.sunnypilot.ai").c_str(); - -class SunnylinkSponsorQRWidget : public QWidget { - Q_OBJECT - -public: - explicit SunnylinkSponsorQRWidget(bool sponsor_pair = false, QWidget* parent = 0); - void paintEvent(QPaintEvent*) override; - -private: - QPixmap img; - QTimer *timer; - void updateQrCode(const QString &text); - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; - - bool sponsor_pair = false; - -private slots: - void refresh(); -}; - -// sponsor popup widget -class SunnylinkSponsorPopup : public DialogBase { - Q_OBJECT - -public: - explicit SunnylinkSponsorPopup(bool sponsor_pair = false, QWidget* parent = 0); - -private: - static QStringList getInstructions(bool sponsor_pair); - bool sponsor_pair = false; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.cc deleted file mode 100644 index 1b170bb0c2..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.cc +++ /dev/null @@ -1,305 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.h" - -#include "common/watchdog.h" -#include "selfdrive/ui/sunnypilot/qt/util.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" -#include - -SunnylinkPanel::SunnylinkPanel(QWidget *parent) : QFrame(parent) { - main_layout = new QStackedLayout(this); - sunnylink_client = new SunnylinkClient(this); - param_watcher = new ParamWatcher(this); - param_watcher->addParam("SunnylinkEnabled"); - connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { - paramsRefresh(param_name, param_value); - }); - - is_sunnylink_enabled = params.getBool("SunnylinkEnabled"); - connect(uiStateSP(), &UIStateSP::sunnylinkRolesChanged, this, &SunnylinkPanel::updatePanel); - connect(uiStateSP(), &UIStateSP::sunnylinkDeviceUsersChanged, this, &SunnylinkPanel::updatePanel); - connect(uiStateSP(), &UIStateSP::offroadTransition, [=](bool offroad) { - is_onroad = !offroad; - updatePanel(); - }); - - sunnylinkScreen = new QWidget(this); - auto vlayout = new QVBoxLayout(sunnylinkScreen); - vlayout->setContentsMargins(50, 20, 50, 20); - - auto *list = new ListWidget(this, false); - - QVBoxLayout *titleLayout = new QVBoxLayout; - QLabel *title = new QLabel(tr("🚀 sunnylink 🚀")); - title->setStyleSheet("font-size: 90px; font-weight: 500; font-family: 'Noto Color Emoji';"); - titleLayout->addWidget(title, 0, Qt::AlignCenter); - - QLabel *sunnylinkDesc = new QLabel("
"+ - tr("For secure backup, restore, and remote configuration")+ "
"); - - QLabel *sponsorMsg = new QLabel("
"+ - tr("Sponsorship isn't required for basic backup/restore") + "
" + - tr("Click the sponsor button for more details")+ "
"); - - sunnylinkDesc->setStyleSheet("font-size: 40px; font-weight: 100; font-family: 'Noto';"); - sponsorMsg->setStyleSheet("font-size: 35px; font-weight: 100; font-family: 'Noto';"); - - titleLayout->addWidget(sunnylinkDesc, 0, Qt::AlignCenter); - titleLayout->addWidget(sponsorMsg, 0, Qt::AlignCenter); - - list->addItem(titleLayout); - - QString sunnylinkEnabledBtnDesc = tr("This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that."); - sunnylinkEnabledBtn = new ParamControl( - "SunnylinkEnabled", - tr("Enable sunnylink"), - sunnylinkEnabledBtnDesc, - ""); - list->addItem(sunnylinkEnabledBtn); - - status_popup = new SunnylinkSponsorPopup(false, this); - sponsorBtn = new ButtonControlSP( - tr("Sponsor Status"), tr("SPONSOR"), - tr("Become a sponsor of sunnypilot to get early access to sunnylink features when they become available.")); - list->addItem(sponsorBtn); - connect(sponsorBtn, &ButtonControlSP::clicked, [=]() { - status_popup->exec(); - }); - list->addItem(horizontal_line()); - - pair_popup = new SunnylinkSponsorPopup(true, this); - pairSponsorBtn = new ButtonControlSP( - tr("Pair GitHub Account"), tr("PAIR"), - tr("Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink.") + "🌟"); - list->addItem(pairSponsorBtn); - connect(pairSponsorBtn, &ButtonControlSP::clicked, [=]() { - if (getSunnylinkDongleId().value_or(tr("N/A")) == "N/A") { - ConfirmationDialog::alert(tr("sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again."), this); - } else { - pair_popup->exec(); - } - }); - list->addItem(horizontal_line()); - - QString sunnylinkUploaderDesc = tr("Enable sunnylink uploader to allow sunnypilot to upload your driving data to sunnypilot servers. (only for highest tiers, and does NOT bring ANY benefit to you. We are just testing data volume.)"); - sunnylinkUploaderEnabledBtn = new ParamControlSP( - "EnableSunnylinkUploader", - tr("Enable sunnylink uploader (infrastructure test)"), - sunnylinkUploaderDesc, - "", nullptr, true); - list->addItem(sunnylinkUploaderEnabledBtn); - - connect(sunnylinkEnabledBtn, &ParamControl::showDescriptionEvent, [=]() { - // resets the description to the default one for the Easter egg - sunnylinkEnabledBtn->setDescription(sunnylinkEnabledBtnDesc); - }); - - connect(sunnylinkEnabledBtn, &ParamControl::toggleFlipped, [=](bool enabled) { - QString description; - if (enabled) { - description = ""+ tr("🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀")+ ""; - } else { - description = ""+ tr("👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.")+ ""; - } - sunnylinkEnabledBtn->showDescription(); - sunnylinkEnabledBtn->setDescription(description); - - updatePanel(); - }); - - // Backup Settings - backupSettings = new PushButtonSP(tr("Backup Settings"), 750, this); - backupSettings->setObjectName("backup_btn"); - connect(backupSettings, &QPushButton::clicked, [=]() { - backupSettings->setEnabled(false); - if (ConfirmationDialog::confirm(tr("Are you sure you want to backup sunnypilot settings?"), tr("Back Up"), this)) { - params.putBool("BackupManager_CreateBackup", true); - backup_request_pending = true; - } - }); - - // Restore Settings - restoreSettings = new PushButtonSP(tr("Restore Settings"), 750, this); - restoreSettings->setObjectName("restore_btn"); - connect(restoreSettings, &QPushButton::clicked, [=]() { - restoreSettings->setEnabled(false); - if (ConfirmationDialog::confirm(tr("Are you sure you want to restore the last backed up sunnypilot settings?"), tr("Restore"), this)) { - params.put("BackupManager_RestoreVersion", "latest"); - restore_request_pending = true; - } - }); - // Settings Restore and Settings Backup in the same horizontal space - auto settings_layout = new QHBoxLayout; - settings_layout->setContentsMargins(0, 0, 0, 30); - settings_layout->addWidget(backupSettings, 0, Qt::AlignLeft); - settings_layout->addSpacing(10); - settings_layout->addWidget(restoreSettings, 0, Qt::AlignRight); - list->addItem(settings_layout); - - QObject::connect(uiState(), &UIState::offroadTransition, this, &SunnylinkPanel::updatePanel); - QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &SunnylinkPanel::updatePanel); - - sunnylinkScroller = new ScrollViewSP(list, this); - vlayout->addWidget(sunnylinkScroller); - - main_layout->addWidget(sunnylinkScreen); - - if (is_sunnylink_enabled) { - startSunnylink(); - } -} - -void SunnylinkPanel::updateBackupManagerState() { - const SubMaster &sm = *(uiStateSP()->sm); - backup_manager = sm["backupManagerSP"].getBackupManagerSP(); -} - -void SunnylinkPanel::handleBackupProgress() { - auto backup_status = backup_manager.getBackupStatus(); - auto restore_status = backup_manager.getRestoreStatus(); - auto backup_progress = backup_manager.getBackupProgress(); - auto restore_progress = backup_manager.getRestoreProgress(); - - switch (backup_status) { - case cereal::BackupManagerSP::Status::IN_PROGRESS: - backup_request_pending = false; - backup_request_started = true; - backupSettings->setEnabled(false); - backupSettings->setText(QString(tr("Backup in progress %1%").arg(backup_progress))); - break; - case cereal::BackupManagerSP::Status::FAILED: - backup_request_pending = false; - backup_request_started = false; - backupSettings->setEnabled(!is_onroad); - backupSettings->setText(tr("Backup Failed")); - break; - case cereal::BackupManagerSP::Status::COMPLETED: - backup_request_pending = false; - break; - default: - if (!backup_request_pending && backup_request_started) { - backup_request_started = false; - ConfirmationDialog::alert(tr("Settings backup completed."), this); - } else { - backupSettings->setEnabled(!is_onroad && !backup_request_pending && is_sunnylink_enabled); - } - backupSettings->setText(tr("Backup Settings")); - break; - } - - switch (restore_status) { - case cereal::BackupManagerSP::Status::IN_PROGRESS: - restore_request_pending = false; - restore_request_started = true; - restoreSettings->setEnabled(false); - restoreSettings->setText(QString(tr("Restore in progress %1%").arg(restore_progress))); - break; - case cereal::BackupManagerSP::Status::FAILED: - restore_request_pending = false; - restore_request_started = false; - restoreSettings->setEnabled(!is_onroad); - restoreSettings->setText(tr("Restore Failed")); - ConfirmationDialog::alert(tr("Unable to restore the settings, try again later."), this); - break; - case cereal::BackupManagerSP::Status::COMPLETED: - restore_request_pending = false; - break; - default: - if (!restore_request_pending && restore_request_started) { - restore_request_started = false; - if (ConfirmationDialog::alert(tr("Settings restored. Confirm to restart the interface."), this)) { - qApp->exit(18); - watchdog_kick(0); - } - } else { - restoreSettings->setEnabled(!is_onroad && !restore_request_pending && is_sunnylink_enabled); - } - restoreSettings->setText(tr("Restore Settings")); - break; - } -} - -void SunnylinkPanel::paramsRefresh(const QString ¶m_name, const QString ¶m_value) { - // We do it on paramsRefresh because the toggleEvent happens before the value is updated - if (param_name == "SunnylinkEnabled" && param_value == "1") { - startSunnylink(); - } else if (param_name == "SunnylinkEnabled" && param_value == "0") { - stopSunnylink(); - } - - updatePanel(); -} - -void SunnylinkPanel::startSunnylink() const { - if (!sunnylink_client->role_service->isCurrentyPolling()) { - sunnylink_client->role_service->startPolling(); - } else { - sunnylink_client->role_service->load(); - } - - if (!sunnylink_client->user_service->isCurrentyPolling()) { - sunnylink_client->user_service->startPolling(); - } else { - sunnylink_client->user_service->load(); - } -} - -void SunnylinkPanel::stopSunnylink() const { - sunnylink_client->role_service->stopPolling(); - sunnylink_client->user_service->stopPolling(); -} - -void SunnylinkPanel::showEvent(QShowEvent *event) { - updatePanel(); - if (is_sunnylink_enabled) { - startSunnylink(); - } -} - -void SunnylinkPanel::updatePanel() { - if (!isVisible()) { - return; - } - - updateBackupManagerState(); - handleBackupProgress(); - const auto sunnylinkDongleId = getSunnylinkDongleId().value_or(tr("N/A")); - sunnylinkEnabledBtn->setEnabled(!is_onroad); - - is_sunnylink_enabled = params.getBool("SunnylinkEnabled"); - bool is_sub = uiStateSP()->isSunnylinkSponsor() && is_sunnylink_enabled; - auto max_current_sponsor_rule = uiStateSP()->sunnylinkSponsorRole(); - auto role_name = max_current_sponsor_rule.getSponsorTierString(); - std::optional role_color = max_current_sponsor_rule.getSponsorTierColor(); - bool is_paired = uiStateSP()->isSunnylinkPaired(); - auto paired_users = uiStateSP()->sunnylinkDeviceUsers(); - - sunnylinkEnabledBtn->setEnabled(!is_onroad); - sunnylinkEnabledBtn->setValue(tr("Device ID") + " " + sunnylinkDongleId); - - sponsorBtn->setEnabled(!is_onroad && is_sunnylink_enabled); - sponsorBtn->setText(is_sub ? tr("THANKS ♥") : tr("SPONSOR")); - sponsorBtn->setValue(is_sub ? tr(role_name.toStdString().c_str()) : tr("Not Sponsor"), role_color); - - pairSponsorBtn->setEnabled(!is_onroad && is_sunnylink_enabled); - pairSponsorBtn->setValue(is_paired ? tr("Paired") : tr("Not Paired")); - - bool can_do_uploads = max_current_sponsor_rule.roleTier >= SponsorTier::Novice && is_sunnylink_enabled; - sunnylinkUploaderEnabledBtn->setVisible(can_do_uploads); - sunnylinkUploaderEnabledBtn->setEnabled(can_do_uploads); - - - if (!is_sunnylink_enabled) { - sunnylinkEnabledBtn->setValue(""); - sponsorBtn->setValue(""); - pairSponsorBtn->setValue(""); - } - - update(); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.h deleted file mode 100644 index c56d8ebd1a..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.h" - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/sponsor_widget.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -class SunnylinkPanel : public QFrame { - Q_OBJECT - -public: - explicit SunnylinkPanel(QWidget *parent = nullptr); - void showEvent(QShowEvent *event) override; - void paramsRefresh(const QString ¶m_name, const QString ¶m_value); - void updateBackupManagerState(); - void handleBackupProgress(); - -public slots: - void updatePanel(); - -private: - Params params; - QStackedLayout *main_layout = nullptr; - QWidget *sunnylinkScreen = nullptr; - ScrollViewSP *sunnylinkScroller = nullptr; - SunnylinkSponsorPopup *status_popup; - SunnylinkSponsorPopup *pair_popup; - ButtonControlSP *sponsorBtn; - ButtonControlSP *pairSponsorBtn; - SunnylinkClient *sunnylink_client; - cereal::BackupManagerSP::Reader backup_manager; - - ParamControl *sunnylinkEnabledBtn; - bool is_onroad = false; - bool is_sunnylink_enabled = false; - bool backup_request_pending = false; - bool backup_request_started = false; - bool restore_request_pending = false; - bool restore_request_started = false; - ParamWatcher *param_watcher; - QString sunnylinkBtnDescription; - PushButtonSP *restoreSettings; - PushButtonSP *backupSettings; - ParamControlSP * sunnylinkUploaderEnabledBtn; - - void stopSunnylink() const; - void startSunnylink() const; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/trips_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/trips_panel.cc deleted file mode 100644 index dcb16d168d..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/trips_panel.cc +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/trips_panel.h" - -TripsPanel::TripsPanel(QWidget* parent) : QFrame(parent) { - QVBoxLayout* main_layout = new QVBoxLayout(this); - main_layout->setMargin(0); - - // main content - main_layout->addSpacing(25); - center_layout = new QStackedLayout(); - - driveStatsWidget = new DriveStats; - driveStatsWidget->setStyleSheet(R"( - QLabel[type="title"] { font-size: 51px; font-weight: 500; } - QLabel[type="number"] { font-size: 78px; font-weight: 500; } - QLabel[type="unit"] { font-size: 51px; font-weight: 300; color: #A0A0A0; } - )"); - center_layout->addWidget(driveStatsWidget); - - main_layout->addLayout(center_layout, 1); - - setStyleSheet(R"( - * { - color: white; - } - TripsPanel > QLabel { - font-size: 55px; - } - )"); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/trips_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/trips_panel.h deleted file mode 100644 index 67a49e21a4..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/trips_panel.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -#include "selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h" - -class TripsPanel : public QFrame { - Q_OBJECT - -public: - explicit TripsPanel(QWidget* parent = 0); - -private: - Params params; - - QStackedLayout* center_layout; - DriveStats *driveStatsWidget; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_factory.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_factory.cc deleted file mode 100644 index bebc6c3032..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_factory.cc +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_factory.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brands.h" - -static const QStringList supportedBrands = { - "chrysler", - "ford", - "gm", - "honda", - "hyundai", - "mazda", - "nissan", - "rivian", - "subaru", - "tesla", - "toyota", - "volkswagen", -}; - -BrandSettingsInterface* BrandSettingsFactory::createBrandSettings(const QString& brand, QWidget* parent) { - if (brand == "chrysler") - return new ChryslerSettings(parent); - if (brand == "ford") - return new FordSettings(parent); - if (brand == "gm") - return new GMSettings(parent); - if (brand == "honda") - return new HondaSettings(parent); - if (brand == "hyundai") - return new HyundaiSettings(parent); - if (brand == "mazda") - return new MazdaSettings(parent); - if (brand == "nissan") - return new NissanSettings(parent); - if (brand == "rivian") - return new RivianSettings(parent); - if (brand == "subaru") - return new SubaruSettings(parent); - if (brand == "tesla") - return new TeslaSettings(parent); - if (brand == "toyota") - return new ToyotaSettings(parent); - if (brand == "volkswagen") - return new VolkswagenSettings(parent); - - // Default empty settings if brand not supported - return nullptr; -} - -bool BrandSettingsFactory::isBrandSupported(const QString& brand) { - return supportedBrands.contains(brand); -} - -QStringList BrandSettingsFactory::getSupportedBrands() { - return supportedBrands; -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_factory.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_factory.h deleted file mode 100644 index b4dc9fc81b..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_factory.h +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -class BrandSettingsFactory { - -public: - static BrandSettingsInterface* createBrandSettings(const QString &brand, QWidget *parent = nullptr); - static bool isBrandSupported(const QString& brand); - static QStringList getSupportedBrands(); -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.cc deleted file mode 100644 index 03921c01a3..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.cc +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -BrandSettingsInterface::BrandSettingsInterface(QWidget *parent) : QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(0, 0, 0, 0); - - list = new ListWidget(this, false); - main_layout->addWidget(list); -} - -void BrandSettingsInterface::updatePanel(bool _offroad) { - offroad = _offroad; - updateSettings(); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h deleted file mode 100644 index 4aff123177..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class BrandSettingsInterface : public QWidget { - Q_OBJECT - -public: - explicit BrandSettingsInterface(QWidget *parent = nullptr); - virtual ~BrandSettingsInterface() = default; - - void updatePanel(bool _offroad); - virtual void updateSettings() = 0; - -protected: - ListWidget *list = nullptr; - Params params; - bool offroad = false; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brands.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brands.h deleted file mode 100644 index 795dba5739..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brands.h +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/chrysler_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/ford_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/gm_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/honda_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/mazda_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/nissan_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/rivian_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/tesla_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/toyota_settings.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/volkswagen_settings.h" diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/chrysler_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/chrysler_settings.cc deleted file mode 100644 index fd8fc423fe..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/chrysler_settings.cc +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/chrysler_settings.h" - -ChryslerSettings::ChryslerSettings(QWidget *parent) : BrandSettingsInterface(parent) { -} - -void ChryslerSettings::updateSettings() { -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/chrysler_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/chrysler_settings.h deleted file mode 100644 index ab84bec16a..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/chrysler_settings.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class ChryslerSettings : public BrandSettingsInterface { - Q_OBJECT - -public: - explicit ChryslerSettings(QWidget *parent = nullptr); - void updateSettings() override; - -private: - bool offroad = false; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/ford_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/ford_settings.cc deleted file mode 100644 index 96564cb8a9..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/ford_settings.cc +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/ford_settings.h" - -FordSettings::FordSettings(QWidget *parent) : BrandSettingsInterface(parent) { -} - -void FordSettings::updateSettings() { -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/ford_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/ford_settings.h deleted file mode 100644 index 468bd6b7dd..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/ford_settings.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class FordSettings : public BrandSettingsInterface { - Q_OBJECT - -public: - explicit FordSettings(QWidget *parent = nullptr); - void updateSettings() override; - -private: - bool offroad = false; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/gm_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/gm_settings.cc deleted file mode 100644 index 060a28424b..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/gm_settings.cc +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/gm_settings.h" - -GMSettings::GMSettings(QWidget *parent) : BrandSettingsInterface(parent) { -} - -void GMSettings::updateSettings() { -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/gm_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/gm_settings.h deleted file mode 100644 index 211563ab61..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/gm_settings.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class GMSettings : public BrandSettingsInterface { - Q_OBJECT - -public: - explicit GMSettings(QWidget *parent = nullptr); - void updateSettings() override; - -private: - bool offroad = false; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/honda_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/honda_settings.cc deleted file mode 100644 index ca18fa7240..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/honda_settings.cc +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/honda_settings.h" - -HondaSettings::HondaSettings(QWidget *parent) : BrandSettingsInterface(parent) { -} - -void HondaSettings::updateSettings() { -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/honda_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/honda_settings.h deleted file mode 100644 index e41602dc11..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/honda_settings.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class HondaSettings : public BrandSettingsInterface { - Q_OBJECT - -public: - explicit HondaSettings(QWidget *parent = nullptr); - void updateSettings() override; - -private: - bool offroad = false; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.cc deleted file mode 100644 index 01ea64f0cb..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.cc +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.h" - -HyundaiSettings::HyundaiSettings(QWidget *parent) : BrandSettingsInterface(parent) { - std::vector tuning_texts{ tr("Off"), tr("Dynamic"), tr("Predictive") }; - longitudinalTuningToggle = new ButtonParamControl( - "HyundaiLongitudinalTuning", - tr("Custom Longitudinal Tuning"), - "", - "", - tuning_texts, - 500 - ); - QObject::connect(longitudinalTuningToggle, &ButtonParamControlSP::buttonClicked, this, &HyundaiSettings::updateSettings); - list->addItem(longitudinalTuningToggle); - longitudinalTuningToggle->showDescription(); -} - -void HyundaiSettings::updateSettings() { - auto longitudinal_tuning_param = std::atoi(params.get("HyundaiLongitudinalTuning").c_str()); - - auto cp_bytes = params.get("CarParamsPersistent"); - if (!cp_bytes.empty()) { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - - has_longitudinal_control = hasLongitudinalControl(CP); - } else { - has_longitudinal_control = false; - } - - LongitudinalTuningOption longitudinal_tuning_option; - if (longitudinal_tuning_param == int(LongitudinalTuningOption::PREDICTIVE)) { - longitudinal_tuning_option = LongitudinalTuningOption::PREDICTIVE; - } else if (longitudinal_tuning_param == int(LongitudinalTuningOption::DYNAMIC)) { - longitudinal_tuning_option = LongitudinalTuningOption::DYNAMIC; - } else { - longitudinal_tuning_option = LongitudinalTuningOption::OFF; - } - - bool longitudinal_tuning_disabled = !offroad || !has_longitudinal_control; - QString longitudinal_tuning_description = longitudinalTuningDescription(longitudinal_tuning_option); - if (longitudinal_tuning_disabled) { - longitudinal_tuning_description = toggleDisableMsg(offroad, has_longitudinal_control); - } - - longitudinalTuningToggle->setEnabled(!longitudinal_tuning_disabled); - longitudinalTuningToggle->setDescription(longitudinal_tuning_description); - longitudinalTuningToggle->showDescription(); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.h deleted file mode 100644 index b1ae95a01e..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -enum class LongitudinalTuningOption { - OFF, - DYNAMIC, - PREDICTIVE, -}; - -class HyundaiSettings : public BrandSettingsInterface { - Q_OBJECT - -public: - explicit HyundaiSettings(QWidget *parent = nullptr); - void updateSettings() override; - -private: - bool has_longitudinal_control = false; - ButtonParamControl *longitudinalTuningToggle = nullptr; - - static QString toggleDisableMsg(bool _offroad, bool _has_longitudinal_control) { - if (!_has_longitudinal_control) { - return tr("This feature can only be used with sunnypilot longitudinal control enabled."); - } - - if (!_offroad) { - return tr("Enable \"Always Offroad\" in Device panel, or turn vehicle off to select an option."); - } - - return QString(); - } - - static QString longitudinalTuningDescription(LongitudinalTuningOption option = LongitudinalTuningOption::OFF) { - QString off_str = tr("Off: Uses default tuning"); - QString dynamic_str = tr("Dynamic: Adjusts acceleration limits based on current speed"); - QString predictive_str = tr("Predictive: Uses future trajectory data to anticipate needed adjustments"); - - if (option == LongitudinalTuningOption::PREDICTIVE) { - predictive_str = "" + predictive_str + ""; - } else if (option == LongitudinalTuningOption::DYNAMIC) { - dynamic_str = "" + dynamic_str + ""; - } else { - off_str = "" + off_str + ""; - } - - return QString("%1

%2
%3
%4
") - .arg(tr("Fine-tune your driving experience by adjusting acceleration smoothness with sunnypilot longitudinal control.")) - .arg(off_str) - .arg(dynamic_str) - .arg(predictive_str); - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/mazda_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/mazda_settings.cc deleted file mode 100644 index b8b8825f27..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/mazda_settings.cc +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/mazda_settings.h" - -MazdaSettings::MazdaSettings(QWidget *parent) : BrandSettingsInterface(parent) { -} - -void MazdaSettings::updateSettings() { -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/mazda_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/mazda_settings.h deleted file mode 100644 index cbbc38de7f..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/mazda_settings.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class MazdaSettings : public BrandSettingsInterface { - Q_OBJECT - -public: - explicit MazdaSettings(QWidget *parent = nullptr); - void updateSettings() override; - -private: - bool offroad = false; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/nissan_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/nissan_settings.cc deleted file mode 100644 index 3c21943622..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/nissan_settings.cc +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/nissan_settings.h" - -NissanSettings::NissanSettings(QWidget *parent) : BrandSettingsInterface(parent) { -} - -void NissanSettings::updateSettings() { -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/nissan_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/nissan_settings.h deleted file mode 100644 index d6eabac0bf..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/nissan_settings.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class NissanSettings : public BrandSettingsInterface { - Q_OBJECT - -public: - explicit NissanSettings(QWidget *parent = nullptr); - void updateSettings() override; - -private: - bool offroad = false; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.cc deleted file mode 100644 index 0d4dde681f..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.cc +++ /dev/null @@ -1,235 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.h" - -#include -#include -#include -#include - -#include "selfdrive/ui/sunnypilot/qt/util.h" - -QVariant PlatformSelector::getPlatformBundle(const QString &key) { - QString platform_bundle = QString::fromStdString(params.get("CarPlatformBundle")); - if (!platform_bundle.isEmpty()) { - QJsonDocument json = QJsonDocument::fromJson(platform_bundle.toUtf8()); - if (!json.isNull() && json.isObject()) { - return json.object().value(key).toVariant(); - } - } - return {}; -} - -PlatformSelector::PlatformSelector() : ButtonControl(tr("Vehicle"), "", "") { - platforms = loadPlatformList(); - - QObject::connect(this, &ButtonControl::clicked, [=]() { - if (text() == tr("SEARCH")) { - QString query = InputDialog::getText(tr("Search your vehicle"), this, tr("Enter model year (e.g., 2021) and model name (Toyota Corolla):"), false); - if (query.length() > 0) { - setText(tr("SEARCHING")); - setEnabled(false); - searchPlatforms(query); - refresh(offroad); - } - } else { - params.remove("CarPlatformBundle"); - refresh(offroad); - } - }); - - main_layout->addStretch(0); - refresh(offroad); -} - -void PlatformSelector::refresh(bool _offroad) { - QString name = getPlatformBundle("name").toString(); - platform = unrecognized_str; - QString platform_color = YELLOW_PLATFORM; - - if (!name.isEmpty()) { - platform = name; - platform_color = BLUE_PLATFORM; - brand = getPlatformBundle("brand").toString(); - setText(tr("REMOVE")); - } else { - setText(tr("SEARCH")); - - platform = unrecognized_str; - brand = ""; - auto cp_bytes = params.get("CarParamsPersistent"); - if (!cp_bytes.empty()) { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - - platform = QString::fromStdString(CP.getCarFingerprint().cStr()); - - for (auto it = platforms.constBegin(); it != platforms.constEnd(); ++it) { - if (it.value()["platform"].toString() == platform) { - brand = it.value()["brand"].toString(); - break; - } - } - - if (platform == "MOCK") { - platform = unrecognized_str; - } else { - platform_color = GREEN_PLATFORM; - } - } - } - setValue(platform, platform_color); - setEnabled(true); - emit refreshPanel(); - - offroad = _offroad; - - FingerprintStatus cur_status; - if (platform_color == GREEN_PLATFORM) { - cur_status = FingerprintStatus::AUTO_FINGERPRINT; - } else if (platform_color == BLUE_PLATFORM) { - cur_status = FingerprintStatus::MANUAL_FINGERPRINT; - } else { - cur_status = FingerprintStatus::UNRECOGNIZED; - } - - setDescription(platformDescription(cur_status)); - showDescription(); -} - -void PlatformSelector::setPlatform(const QString &_platform) { - QVariantMap platform_data = platforms[_platform]; - - const QString offroad_msg = offroad ? tr("This setting will take effect immediately.") : - tr("This setting will take effect once the device enters offroad state."); - const QString msg = QString("%1

%2") - .arg(_platform, offroad_msg); - - QString content("

" + tr("Vehicle Selector") + "


" - "

" + msg + "

"); - - if (ConfirmationDialog(content, tr("Confirm"), tr("Cancel"), true, this).exec()) { - QJsonObject json_bundle; - json_bundle["platform"] = platform_data["platform"].toString(); - json_bundle["name"] = _platform; - json_bundle["make"] = platform_data["make"].toString(); - json_bundle["brand"] = platform_data["brand"].toString(); - json_bundle["model"] = platform_data["model"].toString(); - json_bundle["package"] = platform_data["package"].toString(); - - QVariantList yearList = platform_data["year"].toList(); - QJsonArray yearArray; - for (const QVariant &year : yearList) { - yearArray.append(year.toString()); - } - json_bundle["year"] = yearArray; - - QString json_bundle_str = QString::fromUtf8(QJsonDocument(json_bundle).toJson(QJsonDocument::Compact)); - - params.put("CarPlatformBundle", json_bundle_str.toStdString()); - } -} - -void PlatformSelector::searchPlatforms(const QString &query) { - if (query.isEmpty()) { - return; - } - - QSet matched_cars; - - QString normalized_query = query.simplified().toLower(); - QStringList tokens = normalized_query.split(" ", QString::SkipEmptyParts); - - int search_year = -1; - QStringList search_terms; - - for (const QString &token : tokens) { - bool ok; - int year = token.toInt(&ok); - if (ok && year >= 1900 && year <= 2100) { - search_year = year; - } else { - search_terms << token; - } - } - - for (auto it = platforms.constBegin(); it != platforms.constEnd(); ++it) { - QString platform_name = it.key(); - QVariantMap platform_data = it.value(); - - if (search_year != -1) { - QVariantList year_list = platform_data["year"].toList(); - bool year_match = false; - for (const QVariant &year_var : year_list) { - int year = year_var.toString().toInt(); - if (year == search_year) { - year_match = true; - break; - } - } - if (!year_match) continue; - } - - QString normalized_make = platform_data["make"].toString().normalized(QString::NormalizationForm_KD).toLower(); - QString normalized_model = platform_data["model"].toString().normalized(QString::NormalizationForm_KD).toLower(); - normalized_make.remove(QRegExp("[^a-zA-Z0-9\\s]")); - normalized_model.remove(QRegExp("[^a-zA-Z0-9\\s]")); - - bool all_terms_match = true; - for (const QString &term : search_terms) { - QString normalized_term = term.normalized(QString::NormalizationForm_KD).toLower(); - normalized_term.remove(QRegExp("[^a-zA-Z0-9\\s]")); - - bool term_matched = false; - - if (normalized_make.contains(normalized_term, Qt::CaseInsensitive)) { - term_matched = true; - } - - if (!term_matched) { - if (term.contains(QRegExp("[a-z]\\d|\\d[a-z]", Qt::CaseInsensitive))) { - QString clean_model = normalized_model; - QString clean_term = normalized_term; - clean_model.remove(" "); - clean_term.remove(" "); - if (clean_model.contains(clean_term, Qt::CaseInsensitive)) { - term_matched = true; - } - } else { - if (normalized_model.contains(normalized_term, Qt::CaseInsensitive)) { - term_matched = true; - } - } - } - - if (!term_matched) { - all_terms_match = false; - break; - } - } - - if (all_terms_match) { - matched_cars.insert(platform_name); - } - } - - QStringList results = matched_cars.toList(); - results.sort(); - - if (results.isEmpty()) { - ConfirmationDialog::alert(tr("No vehicles found for query: %1").arg(query), this); - return; - } - - QString selected_platform = MultiOptionDialog::getSelection(tr("Select a vehicle"), results, "", this); - - if (!selected_platform.isEmpty()) { - setPlatform(selected_platform); - } -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.h deleted file mode 100644 index 9867371ef6..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" - -static const QString GREEN_PLATFORM = "#00F100"; -static const QString BLUE_PLATFORM = "#0086E9"; -static const QString YELLOW_PLATFORM = "#FFD500"; - -enum class FingerprintStatus { - AUTO_FINGERPRINT, - MANUAL_FINGERPRINT, - UNRECOGNIZED, -}; - -class PlatformSelector : public ButtonControl { - Q_OBJECT - -public: - PlatformSelector(); - QVariant getPlatformBundle(const QString &key); - - QString platform; - QString brand; - -public slots: - void refresh(bool _offroad); - -signals: - void refreshPanel(); - -private: - void searchPlatforms(const QString &query); - void setPlatform(const QString &platform = ""); - QMap platforms; - - Params params; - bool offroad; - - QString unrecognized_str = tr("Unrecognized Vehicle"); - - static QString platformDescription(FingerprintStatus status = FingerprintStatus::UNRECOGNIZED) { - QString auto_str = "🟢 - " + tr("Fingerprinted automatically"); - QString manual_str = "🔵 - " + tr("Manually selected"); - QString unrecognized_str = "🟡 - " + tr("Not fingerprinted or manually selected"); - - if (status == FingerprintStatus::AUTO_FINGERPRINT) { - auto_str = "" + auto_str + ""; - } else if (status == FingerprintStatus::MANUAL_FINGERPRINT) { - manual_str = "" + manual_str + ""; - } else { - unrecognized_str = "" + unrecognized_str + ""; - } - - return QString("%1
%2

%3
%4
%5") - .arg(tr("Select vehicle to force fingerprint manually.")) - .arg(tr("Colors represent fingerprint status:")) - .arg(auto_str) - .arg(manual_str) - .arg(unrecognized_str); - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/rivian_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/rivian_settings.cc deleted file mode 100644 index 92cf3dcd6c..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/rivian_settings.cc +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/rivian_settings.h" - -RivianSettings::RivianSettings(QWidget *parent) : BrandSettingsInterface(parent) { -} - -void RivianSettings::updateSettings() { -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/rivian_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/rivian_settings.h deleted file mode 100644 index be25d01b37..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/rivian_settings.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class RivianSettings : public BrandSettingsInterface { - Q_OBJECT - -public: - explicit RivianSettings(QWidget *parent = nullptr); - void updateSettings() override; - -private: - bool offroad = false; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.cc deleted file mode 100644 index 302740a94a..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.cc +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.h" - -SubaruSettings::SubaruSettings(QWidget *parent) : BrandSettingsInterface(parent) { - stopAndGoToggle = new ParamControl("SubaruStopAndGo", tr("Stop and Go (Beta)"), "", ""); - stopAndGoToggle->setConfirmation(true, false); - list->addItem(stopAndGoToggle); - - stopAndGoManualParkingBrakeToggle = new ParamControl( - "SubaruStopAndGoManualParkingBrake", - tr("Stop and Go for Manual Parking Brake (Beta)"), - "", - "" - ); - stopAndGoManualParkingBrakeToggle->setConfirmation(true, false); - list->addItem(stopAndGoManualParkingBrakeToggle); -} - -void SubaruSettings::updateSettings() { - auto cp_bytes = params.get("CarParamsPersistent"); - if (!cp_bytes.empty()) { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - - is_subaru = CP.getBrand() == "subaru"; - - if (is_subaru) { - if (!(CP.getFlags() & (SUBARU_FLAG_GLOBAL_GEN2 | SUBARU_FLAG_HYBRID))) { - has_stop_and_go = true; - } - } - } else { - is_subaru = false; - has_stop_and_go = false; - } - - bool stop_and_go_disabled = !offroad || !has_stop_and_go; - QString stop_and_go_desc = stopAndGoDescriptionBuilder(stopAndGoDesc); - QString stop_and_go_manual_parking_brake_desc = stopAndGoDescriptionBuilder(stopAndGoManualParkingBrakeDesc); - if (stop_and_go_disabled) { - stop_and_go_desc = stopAndGoDescriptionBuilder(stopAndGoDesc, stopAndGoDisabledMsg()); - stop_and_go_manual_parking_brake_desc = stopAndGoDescriptionBuilder(stopAndGoManualParkingBrakeDesc, stopAndGoDisabledMsg()); - } - - stopAndGoToggle->setEnabled(has_stop_and_go); - stopAndGoToggle->setDescription(stop_and_go_desc); - stopAndGoToggle->showDescription(); - - stopAndGoManualParkingBrakeToggle->setEnabled(has_stop_and_go); - stopAndGoManualParkingBrakeToggle->setDescription(stop_and_go_manual_parking_brake_desc); - stopAndGoManualParkingBrakeToggle->showDescription(); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.h deleted file mode 100644 index 2bb160beba..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -const int SUBARU_FLAG_GLOBAL_GEN2 = 4; -const int SUBARU_FLAG_HYBRID = 32; - -class SubaruSettings : public BrandSettingsInterface { - Q_OBJECT - -public: - explicit SubaruSettings(QWidget *parent = nullptr); - void updateSettings() override; - -private: - bool offroad = false; - bool is_subaru; - bool has_stop_and_go; - - ParamControl* stopAndGoToggle; - ParamControl* stopAndGoManualParkingBrakeToggle; - - QString stopAndGoDesc = tr("Experimental feature to enable auto-resume during stop-and-go for certain supported Subaru platforms."); - QString stopAndGoManualParkingBrakeDesc = tr("Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation!"); - - QString stopAndGoDisabledMsg() const { - if (is_subaru && !has_stop_and_go) { - return tr("This feature is currently not available on this platform."); - } - - if (!is_subaru) { - return tr("Start the car to check car compatibility."); - } - - if (!offroad) { - return tr("Enable \"Always Offroad\" in Device panel, or turn vehicle off to toggle."); - } - - return QString(); - } - - static QString stopAndGoDescriptionBuilder(const QString &base_description, const QString &custom_description = "") { - return "" + custom_description + "

" + base_description; - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/tesla_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/tesla_settings.cc deleted file mode 100644 index 2fffdb8ad4..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/tesla_settings.cc +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/tesla_settings.h" - -TeslaSettings::TeslaSettings(QWidget *parent) : BrandSettingsInterface(parent) { - constexpr int coopSteeringMinKmh = 23; // minimum speed for cooperative steering (enforced by Tesla firmware) - constexpr int oemSteeringMinKmh = 48; // minimum speed for OEM lane departure avoidance (enforced by Tesla firmware) - bool is_metric = params.getBool("IsMetric"); - QString unit = is_metric ? "km/h" : "mph"; - int display_value_coop; - int display_value_oem; - if (is_metric) { - display_value_coop = coopSteeringMinKmh; - display_value_oem = oemSteeringMinKmh; - } else { - display_value_coop = static_cast(std::round(coopSteeringMinKmh * KM_TO_MILE)); - display_value_oem = static_cast(std::round(oemSteeringMinKmh * KM_TO_MILE)); - } - const QString coop_desc = QString("%1

" - "%2
" - "%3
") - .arg(tr("Warning: May experience steering oscillations below %5 %6 during turns, recommend disabling this feature if you experience these.")) - .arg(tr("Allows the driver to provide limited steering input while openpilot is engaged.")) - .arg(tr("Only works above %4 %6.")) - .arg(display_value_coop) - .arg(display_value_oem) - .arg(unit); - - coopSteeringToggle = new ParamControlSP( - "TeslaCoopSteering", - tr("Cooperative Steering (Beta)"), - coop_desc, - "", - this - ); - list->addItem(coopSteeringToggle); - coopSteeringToggle->showDescription(); - coopSteeringToggle->setConfirmation(true, false); -} - -void TeslaSettings::updateSettings() { - coopSteeringToggle->setEnabled(offroad); -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/tesla_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/tesla_settings.h deleted file mode 100644 index a1294513ee..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/tesla_settings.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class TeslaSettings : public BrandSettingsInterface { - Q_OBJECT - -public: - explicit TeslaSettings(QWidget *parent = nullptr); - void updateSettings() override; - -private: - ParamControlSP *coopSteeringToggle = nullptr; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/toyota_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/toyota_settings.cc deleted file mode 100644 index c416177916..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/toyota_settings.cc +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/toyota_settings.h" - -ToyotaSettings::ToyotaSettings(QWidget *parent) : BrandSettingsInterface(parent) { -} - -void ToyotaSettings::updateSettings() { -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/toyota_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/toyota_settings.h deleted file mode 100644 index 9fc18a2a65..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/toyota_settings.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class ToyotaSettings : public BrandSettingsInterface { - Q_OBJECT - -public: - explicit ToyotaSettings(QWidget *parent = nullptr); - void updateSettings() override; - -private: - bool offroad = false; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/volkswagen_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/volkswagen_settings.cc deleted file mode 100644 index 59f0aab727..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/volkswagen_settings.cc +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/volkswagen_settings.h" - -VolkswagenSettings::VolkswagenSettings(QWidget *parent) : BrandSettingsInterface(parent) { -} - -void VolkswagenSettings::updateSettings() { -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/volkswagen_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/volkswagen_settings.h deleted file mode 100644 index 25d3a07faf..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/volkswagen_settings.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class VolkswagenSettings : public BrandSettingsInterface { - Q_OBJECT - -public: - explicit VolkswagenSettings(QWidget *parent = nullptr); - void updateSettings() override; - -private: - bool offroad = false; -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.cc deleted file mode 100644 index 5c00e746f8..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.cc +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h" - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_factory.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brands.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -VehiclePanel::VehiclePanel(QWidget *parent) : QFrame(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(50, 20, 50, 20); - - ListWidget *list = new ListWidget(this); - - platformSelector = new PlatformSelector(); - QObject::connect(platformSelector, &PlatformSelector::refreshPanel, this, &VehiclePanel::updateBrandSettings); - list->addItem(platformSelector); - - brandSettingsContainer = new QWidget(this); - brandSettingsContainerLayout = new QVBoxLayout(brandSettingsContainer); - brandSettingsContainerLayout->setContentsMargins(0, 0, 0, 0); - brandSettingsContainerLayout->setSpacing(0); - list->addItem(brandSettingsContainer); - - ScrollViewSP *scroller = new ScrollViewSP(list, this); - main_layout->addWidget(scroller); - - currentBrandSettings = nullptr; - - QObject::connect(uiState(), &UIState::offroadTransition, this, &VehiclePanel::updatePanel); -} - -void VehiclePanel::showEvent(QShowEvent *event) { - updatePanel(offroad); -} - -void VehiclePanel::updatePanel(bool _offroad) { - offroad = _offroad; - platformSelector->refresh(_offroad); - updateBrandSettings(); -} - -void VehiclePanel::updateBrandSettings() { - if (!isVisible()) { - return; - } - - if (currentBrandSettings) { - brandSettingsContainerLayout->removeWidget(currentBrandSettings); - delete currentBrandSettings; - currentBrandSettings = nullptr; - } - - if (BrandSettingsFactory::isBrandSupported(platformSelector->brand)) { - currentBrandSettings = BrandSettingsFactory::createBrandSettings(platformSelector->brand, this); - if (currentBrandSettings) { - currentBrandSettings->setContentsMargins(0, 0, 0, 0); - brandSettingsContainerLayout->addWidget(currentBrandSettings); - currentBrandSettings->updatePanel(offroad); - } - } -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h deleted file mode 100644 index a170aa87c3..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/brand_settings_interface.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.h" - -class VehiclePanel : public QFrame { - Q_OBJECT - -public: - explicit VehiclePanel(QWidget *parent = nullptr); - void showEvent(QShowEvent *event) override; - -public slots: - void updatePanel(bool _offroad); - -private: - PlatformSelector* platformSelector = nullptr; - BrandSettingsInterface* currentBrandSettings = nullptr; - QWidget* brandSettingsContainer = nullptr; - QVBoxLayout* brandSettingsContainerLayout = nullptr; - bool offroad = false; - -private slots: - void updateBrandSettings(); -}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc deleted file mode 100644 index 37e982a982..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc +++ /dev/null @@ -1,194 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h" - -VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) { - param_watcher = new ParamWatcher(this); - connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { - paramsRefresh(); - }); - - main_layout = new QStackedLayout(this); - ListWidgetSP *list = new ListWidgetSP(this, false); - - sunnypilotScreen = new QWidget(this); - QVBoxLayout* vlayout = new QVBoxLayout(sunnypilotScreen); - vlayout->setContentsMargins(50, 20, 50, 20); - - std::vector > toggle_defs{ - { - "BlindSpot", - tr("Show Blind Spot Warnings"), - tr("Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported."), - "", - false, - }, - { - "RainbowMode", - tr("Enable Tesla Rainbow Mode"), - RainbowizeWords(tr("A beautiful rainbow effect on the path the model wants to take.")) + "
" + tr("It")+ " " + tr("does not") + " " + tr("affect driving in any way.") + "", - "", - false, - }, - { - "StandstillTimer", - tr("Enable Standstill Timer"), - tr("Show a timer on the HUD when the car is at a standstill."), - "", - false, - }, - { - "RoadNameToggle", - tr("Display Road Name"), - tr("Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name."), - "", - false, - }, - { - "GreenLightAlert", - tr("Green Traffic Light Alert (Beta)"), - QString("%1
" - "

%2


") - .arg(tr("A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you.")) - .arg(tr("Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly.")), - "", - false, - }, - { - "LeadDepartAlert", - tr("Lead Departure Alert (Beta)"), - QString("%1
" - "

%2


") - .arg(tr("A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving.")) - .arg(tr("Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly.")), - "", - false, - }, - { - "TrueVEgoUI", - tr("Speedometer: Always Display True Speed"), - tr("Always display the true vehicle current speed from wheel speed sensors."), - "", - false, - }, - { - "HideVEgoUI", - tr("Speedometer: Hide from Onroad Screen"), - tr("When enabled, the speedometer on the onroad screen is not displayed."), - "", - false, - }, - { - "ShowTurnSignals", - tr("Display Turn Signals"), - tr("When enabled, visual turn indicators are drawn on the HUD."), - "", - false, - }, - }; - - // Add regular toggles first - for (auto &[param, title, desc, icon, needs_restart] : toggle_defs) { - auto toggle = new ParamControlSP(param, title, desc, icon, this); - - bool locked = params.getBool((param + "Lock").toStdString()); - toggle->setEnabled(!locked); - - if (needs_restart && !locked) { - toggle->setDescription(toggle->getDescription() + tr(" Changing this setting will restart openpilot if the car is powered on.")); - - QObject::connect(uiState(), &UIState::engagedChanged, [toggle](bool engaged) { - toggle->setEnabled(!engaged); - }); - - QObject::connect(toggle, &ParamControlSP::toggleFlipped, [=](bool state) { - params.putBool("OnroadCycleRequested", true); - }); - } - - list->addItem(toggle); - toggles[param.toStdString()] = toggle; - param_watcher->addParam(param); - } - - // Visuals: Display Metrics below Chevron - std::vector chevron_info_settings_texts{tr("Off"), tr("Distance"), tr("Speed"), tr("Time"), tr("All")}; - chevron_info_settings = new ButtonParamControlSP( - "ChevronInfo", tr("Display Metrics Below Chevron"), tr("Display useful metrics below the chevron that tracks the lead car (only applicable to cars with sunnypilot longitudinal control)."), - "", - chevron_info_settings_texts, - 200); - chevron_info_settings->showDescription(); - list->addItem(chevron_info_settings); - param_watcher->addParam("ChevronInfo"); - - // Visuals: Developer UI Info (Dev UI) - std::vector dev_ui_settings_texts{tr("Off"), tr("Right"), tr("Right &&\nBottom")}; - dev_ui_settings = new ButtonParamControlSP( - "DevUIInfo", tr("Developer UI"), tr("Display real-time parameters and metrics from various sources."), - "", - dev_ui_settings_texts, - 380); - list->addItem(dev_ui_settings); - - sunnypilotScroller = new ScrollViewSP(list, this); - vlayout->addWidget(sunnypilotScroller); - - main_layout->addWidget(sunnypilotScreen); - - QObject::connect(uiState(), &UIState::offroadTransition, this, &VisualsPanel::refreshLongitudinalStatus); - - refreshLongitudinalStatus(); -} - -void VisualsPanel::refreshLongitudinalStatus() { - auto cp_bytes = params.get("CarParamsPersistent"); - if (!cp_bytes.empty()) { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - - has_longitudinal_control = hasLongitudinalControl(CP); - } else { - has_longitudinal_control = false; - } - - if (chevron_info_settings) { - QString chevronEnabledDescription = tr("Display useful metrics below the chevron that tracks the lead car (only applicable to cars with sunnypilot longitudinal control)."); - QString chevronNoLongDescription = tr("This feature requires sunnypilot longitudinal control to be available."); - - if (has_longitudinal_control) { - chevron_info_settings->setDescription(chevronEnabledDescription); - } else { - // Reset to "Off" when longitudinal not available - params.put("ChevronInfo", "0"); - chevron_info_settings->setDescription(chevronNoLongDescription); - } - - // Enable only when longitudinal is available - chevron_info_settings->setEnabled(has_longitudinal_control); - chevron_info_settings->refresh(); - } -} - -void VisualsPanel::paramsRefresh() { - if (!isVisible()) { - return; - } - - for (auto toggle : toggles) { - toggle.second->refresh(); - } - - if (chevron_info_settings) { - chevron_info_settings->refresh(); - } - if (dev_ui_settings) { - dev_ui_settings->refresh(); - } -} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h deleted file mode 100644 index 76a846dd45..0000000000 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -class ScrollViewSP; - -class VisualsPanel : public QWidget { - Q_OBJECT - -public: - explicit VisualsPanel(QWidget *parent = nullptr); - - void paramsRefresh(); - void refreshLongitudinalStatus(); - -protected: - QStackedLayout* main_layout = nullptr; - QWidget* sunnypilotScreen = nullptr; - ScrollViewSP *sunnypilotScroller = nullptr; - Params params; - std::map toggles; - ParamWatcher * param_watcher; - ButtonParamControlSP *chevron_info_settings; - ButtonParamControlSP *dev_ui_settings; - - bool has_longitudinal_control = false; -}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/alerts.cc b/selfdrive/ui/sunnypilot/qt/onroad/alerts.cc deleted file mode 100644 index 695f6d2ce8..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/alerts.cc +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/onroad/alerts.h" - -#include -#include -#include -#include - -OnroadAlerts::Alert OnroadAlertsSP::getAlert(const SubMaster &sm, uint64_t started_frame) { - OnroadAlerts::Alert alert = OnroadAlerts::getAlert(sm, started_frame); - alert.text1.replace("openpilot", "sunnypilot"); - alert.text2.replace("openpilot", "sunnypilot"); - return alert; -} - -void OnroadAlertsSP::paintEvent(QPaintEvent *event) { - if (alert.size == cereal::SelfdriveState::AlertSize::NONE) { - return; - } else if (alert.size == cereal::SelfdriveState::AlertSize::FULL) { - OnroadAlerts::paintEvent(event); - return; - } - static std::map alert_heights = { - {cereal::SelfdriveState::AlertSize::SMALL, 271}, - {cereal::SelfdriveState::AlertSize::MID, 420} - }; - int h = alert_heights[alert.size]; - - QPainter p(this); - QFont topFont; - QFont bottomFont; - QRect topTextBoundingRect; - QRect bottomTextBoundingRect; - QRect rect; - - int margin = 40; - int radius = 30; - - const int dev_ui_info = uiStateSP()->scene.dev_ui_info; - const int v_adjustment = dev_ui_info > 1 && alert.size != cereal::SelfdriveState::AlertSize::FULL ? 40 : 0; - const int h_adjustment = dev_ui_info > 0 && alert.size != cereal::SelfdriveState::AlertSize::FULL ? 230 : 0; - - if (alert.size == cereal::SelfdriveState::AlertSize::SMALL) { - topFont = InterFont(74, QFont::DemiBold); - QFontMetrics fmTop(topFont); - topTextBoundingRect = fmTop.boundingRect( - QRect(0 + margin, height() - h + margin - v_adjustment, width() - margin * 2 - h_adjustment, 0), Qt::TextWordWrap, - alert.text1); - h = topTextBoundingRect.height(); - rect = QRect(0 + margin, height() - h - margin * 2 - v_adjustment, width() - margin * 2 - h_adjustment, h + margin); - } else if (alert.size == cereal::SelfdriveState::AlertSize::MID) { - topFont = InterFont(88, QFont::Bold); - bottomFont = InterFont(66); - QFontMetrics fmTop(topFont); - QFontMetrics fmBotton(bottomFont); - topTextBoundingRect = fmTop.boundingRect( - QRect(0 + margin, height() - h + margin - v_adjustment, width() - margin * 2 - h_adjustment, 0), Qt::TextWordWrap, - alert.text1); - bottomTextBoundingRect = fmBotton.boundingRect( - QRect(0 + margin, height() - h + margin - v_adjustment + topTextBoundingRect.height(), - width() - margin * 2 - h_adjustment, 0), Qt::TextWordWrap, alert.text2); - h = topTextBoundingRect.height() + bottomTextBoundingRect.height() + margin * 2; - rect = QRect(0 + margin, height() - h - margin * 2 - v_adjustment, width() - margin * 2 - h_adjustment, h + margin); - } - - - // draw background + gradient - // draw background + gradient - p.setPen(Qt::NoPen); - p.setCompositionMode(QPainter::CompositionMode_SourceOver); - p.setBrush(QBrush(alert_colors[alert.status])); - p.drawRoundedRect(rect, radius, radius); - - QLinearGradient g(0, rect.y(), 0, rect.bottom()); - g.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.05)); - g.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0.35)); - - p.setCompositionMode(QPainter::CompositionMode_DestinationOver); - p.setBrush(QBrush(g)); - p.drawRoundedRect(rect, radius, radius); - p.setCompositionMode(QPainter::CompositionMode_SourceOver); - - // text - p.setPen(QColor(0xff, 0xff, 0xff)); - p.setRenderHint(QPainter::TextAntialiasing); - p.setFont(topFont); - if (alert.size == cereal::SelfdriveState::AlertSize::SMALL) { - p.drawText(rect, Qt::AlignCenter | Qt::TextWordWrap, alert.text1); - } else if (alert.size == cereal::SelfdriveState::AlertSize::MID) { - QRect topText = QRect(rect.x(), rect.top() + margin, rect.width(), topTextBoundingRect.height()); - p.drawText(topText, Qt::AlignHCenter | Qt::AlignTop | Qt::TextWordWrap | Qt::AlignCenter, alert.text1); - p.setFont(bottomFont); - p.drawText(QRect(rect.x(), topText.bottom() + margin, rect.width(), bottomTextBoundingRect.height()), - Qt::AlignHCenter | Qt::TextWordWrap | Qt::AlignCenter, alert.text2); - } -} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/alerts.h b/selfdrive/ui/sunnypilot/qt/onroad/alerts.h deleted file mode 100644 index 8b65309f46..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/alerts.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/onroad/alerts.h" -#include "selfdrive/ui/sunnypilot/ui.h" - -class OnroadAlertsSP : public OnroadAlerts { - Q_OBJECT - -public: - OnroadAlertsSP(QWidget *parent = 0) : OnroadAlerts(parent) {} - -protected: - void paintEvent(QPaintEvent *) override; - Alert getAlert(const SubMaster &sm, uint64_t started_frame); -}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.cc b/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.cc deleted file mode 100644 index f9b62b0ae7..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.cc +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h" - -AnnotatedCameraWidgetSP::AnnotatedCameraWidgetSP(VisionStreamType type, QWidget *parent) - : AnnotatedCameraWidget(type, parent) { -} - -void AnnotatedCameraWidgetSP::updateState(const UIState &s) { - AnnotatedCameraWidget::updateState(s); -} - -void AnnotatedCameraWidgetSP::showEvent(QShowEvent *event) { - AnnotatedCameraWidget::showEvent(event); - ui_update_params_sp(uiState()); - uiStateSP()->reset_onroad_sleep_timer(OnroadTimerStatusToggle::RESUME); -} - -void AnnotatedCameraWidgetSP::hideEvent(QHideEvent *event) { - AnnotatedCameraWidget::hideEvent(event); - uiStateSP()->reset_onroad_sleep_timer(OnroadTimerStatusToggle::PAUSE); -} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h b/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h deleted file mode 100644 index 2e7609dae0..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/onroad/annotated_camera.h" - -class AnnotatedCameraWidgetSP : public AnnotatedCameraWidget { - Q_OBJECT - -public: - explicit AnnotatedCameraWidgetSP(VisionStreamType type, QWidget *parent = nullptr); - void updateState(const UIState &s) override; - -protected: - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent* event) override; -}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/buttons.cc b/selfdrive/ui/sunnypilot/qt/onroad/buttons.cc deleted file mode 100644 index 97f6a391ce..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/buttons.cc +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/onroad/buttons.h" - -#include - -ExperimentalButtonSP::ExperimentalButtonSP(QWidget *parent) : ExperimentalButton(parent) { - QObject::disconnect(uiState(), &UIState::uiUpdate, this, &ExperimentalButton::updateState); - QObject::connect(uiState(), &UIState::uiUpdate, this, &ExperimentalButtonSP::updateState); -} - -void ExperimentalButtonSP::updateState(const UIState &s) { - ExperimentalButton::updateState(s); - const auto long_plan_sp = (*s.sm)["longitudinalPlanSP"].getLongitudinalPlanSP(); - - int mode = int(long_plan_sp.getDec().getState()); - if ((long_plan_sp.getDec().getActive() != dynamic_experimental_control) || (mode != dec_mpc_mode)) { - dynamic_experimental_control = long_plan_sp.getDec().getActive(); - dec_mpc_mode = mode; - update(); - } -} - -void ExperimentalButtonSP::drawButton(QPainter &p) { - if (dynamic_experimental_control) { - QPixmap left_half = engage_img.copy(0, 0, engage_img.width() / 2, engage_img.height()); - QPixmap right_half = experimental_img.copy(experimental_img.width() / 2, 0, experimental_img.width() / 2, experimental_img.height()); - - QPixmap combined_img(engage_img.width(), engage_img.height()); - combined_img.fill(Qt::transparent); - - QPainter combined_painter(&combined_img); - - combined_painter.setOpacity(dec_mpc_mode == 1 ? 0.1 : 1.0); - combined_painter.drawPixmap(0, 0, left_half); - - combined_painter.setOpacity(dec_mpc_mode == 1 ? 1.0 : 0.1); - combined_painter.drawPixmap(engage_img.width() / 2, 0, right_half); - - combined_painter.end(); - - drawIcon(p, QPoint(btn_size / 2, btn_size / 2), combined_img, QColor(0, 0, 0, 166), (isDown() || !engageable) ? 0.6 : 1.0); - } else { - ExperimentalButton::drawButton(p); - } -} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/buttons.h b/selfdrive/ui/sunnypilot/qt/onroad/buttons.h deleted file mode 100644 index ce62a69e2d..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/buttons.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/onroad/buttons.h" - -class ExperimentalButtonSP : public ExperimentalButton { - Q_OBJECT - -public: - explicit ExperimentalButtonSP(QWidget *parent = nullptr); - void updateState(const UIState &s) override; - -private: - void drawButton(QPainter &p) override; - - bool dynamic_experimental_control; - int dec_mpc_mode; -}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.cc b/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.cc deleted file mode 100644 index 292ba6f7bb..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.cc +++ /dev/null @@ -1,227 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ -#include - -#include "common/util.h" -#include "selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h" - - -// Add Relative Distance to Primary Lead Car -// Unit: Meters -UiElement DeveloperUi::getDRel(bool lead_status, float lead_d_rel) { - QString value = lead_status ? QString::number(lead_d_rel, 'f', 0) : "-"; - QColor color = QColor(255, 255, 255, 255); - - if (lead_status) { - // Orange if close, Red if very close - if (lead_d_rel < 5) { - color = QColor(255, 0, 0, 255); - } else if (lead_d_rel < 15) { - color = QColor(255, 188, 0, 255); - } - } - - return UiElement(value, "REL DIST", "m", color); -} - -// Add Relative Velocity vs Primary Lead Car -// Unit: kph if metric, else mph -UiElement DeveloperUi::getVRel(bool lead_status, float lead_v_rel, bool is_metric, const QString &speed_unit) { - QString value = lead_status ? QString::number(lead_v_rel * (is_metric ? MS_TO_KPH : MS_TO_MPH), 'f', 0) : "-"; - QColor color = QColor(255, 255, 255, 255); - - if (lead_status) { - // Red if approaching faster than 10mph - // Orange if approaching (negative) - if (lead_v_rel < -4.4704) { - color = QColor(255, 0, 0, 255); - } else if (lead_v_rel < 0) { - color = QColor(255, 188, 0, 255); - } - } - - return UiElement(value, "REL SPEED", speed_unit, color); -} - -// Add Real Steering Angle -// Unit: Degrees -UiElement DeveloperUi::getSteeringAngleDeg(float angle_steers, bool lat_active, bool steer_override) { - QString value = QString("%1%2%3").arg(QString::number(angle_steers, 'f', 1)).arg("°").arg(""); - QColor color = lat_active ? (steer_override ? QColor(0x91, 0x9b, 0x95, 0xff) : QColor(0, 255, 0, 255)) : QColor(255, 255, 255, 255); - - // Red if large steering angle - // Orange if moderate steering angle - if (std::fabs(angle_steers) > 180) { - color = QColor(255, 0, 0, 255); - } else if (std::fabs(angle_steers) > 90) { - color = QColor(255, 188, 0, 255); - } - - return UiElement(value, "REAL STEER", "", color); -} - -// Add Actual Lateral Acceleration (roll compensated) when using Torque -// Unit: m/s² -UiElement DeveloperUi::getActualLateralAccel(float curvature, float v_ego, float roll, bool lat_active, bool steer_override) { - double actualLateralAccel = (curvature * pow(v_ego, 2)) - (roll * 9.81); - - QString value = QString::number(actualLateralAccel, 'f', 2); - QColor color = lat_active ? (steer_override ? QColor(0x91, 0x9b, 0x95, 0xff) : QColor(0, 255, 0, 255)) : QColor(255, 255, 255, 255); - - return UiElement(value, "ACTUAL L.A.", "m/s²", color); -} - -// Add Desired Steering Angle when using PID -// Unit: Degrees -UiElement DeveloperUi::getSteeringAngleDesiredDeg(bool lat_active, float steer_angle_desired, float angle_steers) { - QString value = lat_active ? QString("%1%2%3").arg(QString::number(steer_angle_desired, 'f', 1)).arg("°").arg("") : "-"; - QColor color = QColor(255, 255, 255, 255); - - if (lat_active) { - // Red if large steering angle - // Orange if moderate steering angle - if (std::fabs(angle_steers) > 180) { - color = QColor(255, 0, 0, 255); - } else if (std::fabs(angle_steers) > 90) { - color = QColor(255, 188, 0, 255); - } else { - color = QColor(0, 255, 0, 255); - } - } - - return UiElement(value, "DESIRED STEER", "", color); -} - -// Add Device Memory (RAM) Usage -// Unit: Percent -UiElement DeveloperUi::getMemoryUsagePercent(int memory_usage_percent) { - QString value = QString("%1%2").arg(QString::number(memory_usage_percent, 'd', 0)).arg("%"); - QColor color = (memory_usage_percent > 85) ? QColor(255, 188, 0, 255) : QColor(255, 255, 255, 255); - - return UiElement(value, "RAM", "", color); -} - -// Add Vehicle Current Acceleration -// Unit: m/s² -UiElement DeveloperUi::getAEgo(float a_ego) { - QString value = QString::number(a_ego, 'f', 1); - QColor color = QColor(255, 255, 255, 255); - - return UiElement(value, "ACC.", "m/s²", color); -} - -// Add Relative Velocity to Primary Lead Car -// Unit: kph if metric, else mph -UiElement DeveloperUi::getVEgoLead(bool lead_status, float lead_v_rel, float v_ego, bool is_metric, const QString &speed_unit) { - QString value = lead_status ? QString::number((lead_v_rel + v_ego) * (is_metric ? MS_TO_KPH : MS_TO_MPH), 'f', 0) : "-"; - QColor color = QColor(255, 255, 255, 255); - - if (lead_status) { - // Red if approaching faster than 10mph - // Orange if approaching (negative) - if (lead_v_rel < -4.4704) { - color = QColor(255, 0, 0, 255); - } else if (lead_v_rel < 0) { - color = QColor(255, 188, 0, 255); - } - } - - return UiElement(value, "L.S.", speed_unit, color); -} - -// Add Friction Coefficient Raw from torqued -// Unit: None -UiElement DeveloperUi::getFrictionCoefficientFiltered(float friction_coefficient_filtered, bool live_valid) { - QString value = QString::number(friction_coefficient_filtered, 'f', 3); - QColor color = live_valid ? QColor(0, 255, 0, 255) : QColor(255, 255, 255, 255); - - return UiElement(value, "FRIC.", "", color); -} - -// Add Lateral Acceleration Factor Raw from torqued -// Unit: m/s² -UiElement DeveloperUi::getLatAccelFactorFiltered(float lat_accel_factor_filtered, bool live_valid) { - QString value = QString::number(lat_accel_factor_filtered, 'f', 3); - QColor color = live_valid ? QColor(0, 255, 0, 255) : QColor(255, 255, 255, 255); - - return UiElement(value, "L.A.", "m/s²", color); -} - -// Add Steering Torque from Car EPS -// Unit: Newton Meters -UiElement DeveloperUi::getSteeringTorqueEps(float steering_torque_eps) { - QString value = QString::number(std::fabs(steering_torque_eps), 'f', 1); - QColor color = QColor(255, 255, 255, 255); - - return UiElement(value, "E.T.", "N·dm", color); -} - -// Add Bearing Degree and Direction from Car (Compass) -// Unit: Meters -UiElement DeveloperUi::getBearingDeg(float bearing_accuracy_deg, float bearing_deg) { - QString value = (bearing_accuracy_deg != 180.00) ? QString("%1%2%3").arg(QString::number(bearing_deg, 'd', 0)).arg("°").arg("") : "-"; - QColor color = QColor(255, 255, 255, 255); - QString dir_value; - - if (bearing_accuracy_deg != 180.00) { - if (((bearing_deg >= 337.5) && (bearing_deg <= 360)) || ((bearing_deg >= 0) && (bearing_deg <= 22.5))) { - dir_value = "N"; - } else if ((bearing_deg > 22.5) && (bearing_deg < 67.5)) { - dir_value = "NE"; - } else if ((bearing_deg >= 67.5) && (bearing_deg <= 112.5)) { - dir_value = "E"; - } else if ((bearing_deg > 112.5) && (bearing_deg < 157.5)) { - dir_value = "SE"; - } else if ((bearing_deg >= 157.5) && (bearing_deg <= 202.5)) { - dir_value = "S"; - } else if ((bearing_deg > 202.5) && (bearing_deg < 247.5)) { - dir_value = "SW"; - } else if ((bearing_deg >= 247.5) && (bearing_deg <= 292.5)) { - dir_value = "W"; - } else if ((bearing_deg > 292.5) && (bearing_deg < 337.5)) { - dir_value = "NW"; - } - } else { - dir_value = "OFF"; - } - - return UiElement(QString("%1 | %2").arg(dir_value).arg(value), "B.D.", "", color); -} - -// Add Altitude of Current Location -// Unit: Meters -UiElement DeveloperUi::getAltitude(float gps_accuracy, float altitude) { - QString value = (gps_accuracy != 0.00) ? QString::number(altitude, 'f', 1) : "-"; - QColor color = QColor(255, 255, 255, 255); - - return UiElement(value, "ALT.", "m", color); -} - -// Add Actuators Output -// Unit: Degree (angle) or m/s² (torque) -UiElement DeveloperUi::getActuatorsOutputLateral(cereal::CarParams::SteerControlType steerControlType, - cereal::CarControl::Actuators::Reader &actuators, - float desiredCurvature, float v_ego, float roll, bool lat_active, bool steer_override) { - QString label; - QString value; - QString unit; - - if (steerControlType == cereal::CarParams::SteerControlType::ANGLE) { - label = "DESIRED STEER"; - value = QString("%1%2%3").arg(QString::number(actuators.getSteeringAngleDeg(), 'f', 1)).arg("°").arg(""); - } else { - label = "DESIRED L.A."; - double desiredLateralAccel = (desiredCurvature * pow(v_ego, 2)) - (roll * 9.81); - value = QString::number(desiredLateralAccel, 'f', 2); - unit = "m/s²"; - } - - value = lat_active ? value : "-"; - QColor color = lat_active ? (steer_override ? QColor(0x91, 0x9b, 0x95, 0xff) : QColor(0, 255, 0, 255)) : QColor(255, 255, 255, 255); - - return UiElement(value, label, unit, color); -} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h b/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h deleted file mode 100644 index 0c5c472209..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ -#pragma once - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/qt/onroad/developer_ui/ui_elements.h" - -class DeveloperUi { - -public: - static UiElement getDRel(bool lead_status, float lead_d_rel); - static UiElement getVRel(bool lead_status, float lead_v_rel, bool is_metric, const QString &speed_unit); - static UiElement getSteeringAngleDeg(float angle_steers, bool lat_active, bool steer_override); - static UiElement getActualLateralAccel(float curvature, float v_ego, float roll, bool lat_active, bool steer_override); - static UiElement getSteeringAngleDesiredDeg(bool lat_active, float steer_angle_desired, float angle_steers); - static UiElement getMemoryUsagePercent(int memory_usage_percent); - static UiElement getAEgo(float a_ego); - static UiElement getVEgoLead(bool lead_status, float lead_v_rel, float v_ego, bool is_metric, const QString &speed_unit); - static UiElement getFrictionCoefficientFiltered(float friction_coefficient_filtered, bool live_valid); - static UiElement getLatAccelFactorFiltered(float lat_accel_factor_filtered, bool live_valid); - static UiElement getSteeringTorqueEps(float steering_torque_eps); - static UiElement getBearingDeg(float bearing_accuracy_deg, float bearing_deg); - static UiElement getAltitude(float gps_accuracy, float altitude); - static UiElement getActuatorsOutputLateral(cereal::CarParams::SteerControlType steerControlType, - cereal::CarControl::Actuators::Reader &actuators, - float desiredCurvature, float v_ego, float roll, bool lat_active, bool steer_override); -}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/ui_elements.h b/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/ui_elements.h deleted file mode 100644 index 3711e5ac05..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/ui_elements.h +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ -#pragma once - -#include - -struct UiElement { - QString value{}; - QString label{}; - QString units{}; - QColor color{}; - - explicit UiElement(const QString &value = "", const QString &label = "", const QString &units = "", const QColor &color = QColor(255, 255, 255, 255)) - : value(value), label(label), units(units), color(color) {} -}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/hud.cc b/selfdrive/ui/sunnypilot/qt/onroad/hud.cc deleted file mode 100644 index 2fc9eb98fc..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/hud.cc +++ /dev/null @@ -1,887 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ -#include - -#include "selfdrive/ui/sunnypilot/qt/onroad/hud.h" - -#include "selfdrive/ui/qt/util.h" - - -HudRendererSP::HudRendererSP() { - plus_arrow_up_img = loadPixmap("../../sunnypilot/selfdrive/assets/img_plus_arrow_up", {90, 90}); - minus_arrow_down_img = loadPixmap("../../sunnypilot/selfdrive/assets/img_minus_arrow_down", {90, 90}); - - int size = e2e_alert_size * 2 - 40; - green_light_alert_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/green_light.png", {size, size}); - lead_depart_alert_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/lead_depart.png", {size, size}); -} - -void HudRendererSP::updateState(const UIState &s) { - HudRenderer::updateState(s); - - float speedConv = is_metric ? MS_TO_KPH : MS_TO_MPH; - devUiInfo = s.scene.dev_ui_info; - roadName = s.scene.road_name; - showTurnSignals = s.scene.turn_signals; - speedLimitMode = static_cast(s.scene.speed_limit_mode); - speedUnit = is_metric ? tr("km/h") : tr("mph"); - standstillTimer = s.scene.standstill_timer; - - const SubMaster &sm = *(s.sm); - const auto cs = sm["controlsState"].getControlsState(); - const auto car_state = sm["carState"].getCarState(); - const auto car_control = sm["carControl"].getCarControl(); - const auto radar_state = sm["radarState"].getRadarState(); - const auto is_gps_location_external = sm.rcv_frame("gpsLocationExternal") > 1; - const char *gps_source = is_gps_location_external ? "gpsLocationExternal" : "gpsLocation"; - const auto gpsLocation = is_gps_location_external ? sm[gps_source].getGpsLocationExternal() : sm[gps_source].getGpsLocation(); - const auto ltp = sm["liveTorqueParameters"].getLiveTorqueParameters(); - const auto car_params = sm["carParams"].getCarParams(); - const auto car_params_sp = sm["carParamsSP"].getCarParamsSP(); - const auto lp_sp = sm["longitudinalPlanSP"].getLongitudinalPlanSP(); - const auto lmd = sm["liveMapDataSP"].getLiveMapDataSP(); - - if (sm.updated("carParams")) { - steerControlType = car_params.getSteerControlType(); - } - - if (sm.updated("carParamsSP")) { - pcmCruiseSpeed = car_params_sp.getPcmCruiseSpeed(); - } - - if (sm.updated("longitudinalPlanSP")) { - speedLimit = lp_sp.getSpeedLimit().getResolver().getSpeedLimit() * speedConv; - speedLimitLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLast() * speedConv; - speedLimitOffset = lp_sp.getSpeedLimit().getResolver().getSpeedLimitOffset() * speedConv; - speedLimitValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitValid(); - speedLimitLastValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLastValid(); - speedLimitFinalLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitFinalLast() * speedConv; - speedLimitSource = lp_sp.getSpeedLimit().getResolver().getSource(); - speedLimitAssistState = lp_sp.getSpeedLimit().getAssist().getState(); - speedLimitAssistActive = lp_sp.getSpeedLimit().getAssist().getActive(); - smartCruiseControlVisionEnabled = lp_sp.getSmartCruiseControl().getVision().getEnabled(); - smartCruiseControlVisionActive = lp_sp.getSmartCruiseControl().getVision().getActive(); - smartCruiseControlMapEnabled = lp_sp.getSmartCruiseControl().getMap().getEnabled(); - smartCruiseControlMapActive = lp_sp.getSmartCruiseControl().getMap().getActive(); - } - greenLightAlert = lp_sp.getE2eAlerts().getGreenLightAlert(); - leadDepartAlert = lp_sp.getE2eAlerts().getLeadDepartAlert(); - - if (sm.updated("liveMapDataSP")) { - roadNameStr = QString::fromStdString(lmd.getRoadName()); - speedLimitAheadValid = lmd.getSpeedLimitAheadValid(); - speedLimitAhead = lmd.getSpeedLimitAhead() * speedConv; - speedLimitAheadDistance = lmd.getSpeedLimitAheadDistance(); - if (speedLimitAheadDistance < speedLimitAheadDistancePrev && speedLimitAheadValidFrame < SPEED_LIMIT_AHEAD_VALID_FRAME_THRESHOLD) { - speedLimitAheadValidFrame++; - } else if (speedLimitAheadDistance > speedLimitAheadDistancePrev && speedLimitAheadValidFrame > 0) { - speedLimitAheadValidFrame--; - } - } - speedLimitAheadDistancePrev = speedLimitAheadDistance; - - static int reverse_delay = 0; - bool reverse_allowed = false; - if (car_state.getGearShifter() != cereal::CarState::GearShifter::REVERSE) { - reverse_delay = 0; - reverse_allowed = false; - } else { - reverse_delay += 50; - if (reverse_delay >= 1000) { - reverse_allowed = true; - } - } - - reversing = reverse_allowed; - - if (sm.updated("liveParameters")) { - roll = sm["liveParameters"].getLiveParameters().getRoll(); - } - - if (sm.updated("deviceState")) { - memoryUsagePercent = sm["deviceState"].getDeviceState().getMemoryUsagePercent(); - } - - if (sm.updated(gps_source)) { - gpsAccuracy = is_gps_location_external ? gpsLocation.getHorizontalAccuracy() : 1.0; // External reports accuracy, internal does not. - altitude = gpsLocation.getAltitude(); - bearingAccuracyDeg = gpsLocation.getBearingAccuracyDeg(); - bearingDeg = gpsLocation.getBearingDeg(); - } - - if (sm.updated("liveTorqueParameters")) { - torquedUseParams = ltp.getUseParams(); - latAccelFactorFiltered = ltp.getLatAccelFactorFiltered(); - frictionCoefficientFiltered = ltp.getFrictionCoefficientFiltered(); - liveValid = ltp.getLiveValid(); - } - - latActive = car_control.getLatActive(); - actuators = car_control.getActuators(); - longOverride = car_control.getCruiseControl().getOverride(); - carControlEnabled = car_control.getEnabled(); - - steerOverride = car_state.getSteeringPressed(); - lead_d_rel = radar_state.getLeadOne().getDRel(); - lead_v_rel = radar_state.getLeadOne().getVRel(); - lead_status = radar_state.getLeadOne().getStatus(); - torqueLateral = steerControlType == cereal::CarParams::SteerControlType::TORQUE; - angleSteers = car_state.getSteeringAngleDeg(); - desiredCurvature = cs.getDesiredCurvature(); - curvature = cs.getCurvature(); - vEgo = car_state.getVEgo(); - aEgo = car_state.getAEgo(); - steeringTorqueEps = car_state.getSteeringTorqueEps(); - - isStandstill = car_state.getStandstill(); - if (!s.scene.started) standstillElapsedTime = 0.0; - - // override stock current speed values - float v_ego = (v_ego_cluster_seen && !s.scene.trueVEgoUI) ? car_state.getVEgoCluster() : car_state.getVEgo(); - speed = std::max(0.0f, v_ego * (is_metric ? MS_TO_KPH : MS_TO_MPH)); - hideVEgoUI = s.scene.hideVEgoUI; - - leftBlinkerOn = car_state.getLeftBlinker(); - rightBlinkerOn = car_state.getRightBlinker(); - leftBlindspot = car_state.getLeftBlindspot(); - rightBlindspot = car_state.getRightBlindspot(); - - speedCluster = car_state.getCruiseState().getSpeedCluster() * speedConv; - - allow_e2e_alerts = sm["selfdriveState"].getSelfdriveState().getAlertSize() == cereal::SelfdriveState::AlertSize::NONE && - sm.rcv_frame("driverStateV2") > s.scene.started_frame && !reversing; -} - -void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) { - HudRenderer::draw(p, surface_rect); - - e2eAlertDisplayTimer = std::max(0, e2eAlertDisplayTimer - 1); - - p.save(); - - if (is_cruise_available) { - drawSetSpeedSP(p, surface_rect); - } - - if (!hideVEgoUI) { - drawCurrentSpeedSP(p, surface_rect); - } - - if (!reversing) { - // Smart Cruise Control - int x_offset = -260; - int y1_offset = -80; - int y2_offset = -140; - - int y_scc_v = 0, y_scc_m = 0; - const int orders[2] = {y1_offset, y2_offset}; - int i = 0; - // SCC-V takes first order - if (smartCruiseControlVisionEnabled) y_scc_v = orders[i++]; - if (smartCruiseControlMapEnabled) y_scc_m = orders[i++]; - - // Smart Cruise Control - Vision - bool scc_vision_active_pulse = pulseElement(smartCruiseControlVisionFrame); - if ((smartCruiseControlVisionEnabled && !smartCruiseControlVisionActive) || (smartCruiseControlVisionActive && scc_vision_active_pulse)) { - drawSmartCruiseControlOnroadIcon(p, surface_rect, x_offset, y_scc_v, "SCC-V"); - } - smartCruiseControlVisionFrame = smartCruiseControlVisionActive ? (smartCruiseControlVisionFrame + 1) : 0; - - // Smart Cruise Control - Map - bool scc_map_active_pulse = pulseElement(smartCruiseControlMapFrame); - if ((smartCruiseControlMapEnabled && !smartCruiseControlMapActive) || (smartCruiseControlMapActive && scc_map_active_pulse)) { - drawSmartCruiseControlOnroadIcon(p, surface_rect, x_offset, y_scc_m, "SCC-M"); - } - smartCruiseControlMapFrame = smartCruiseControlMapActive ? (smartCruiseControlMapFrame + 1) : 0; - - // Bottom Dev UI - if (devUiInfo == 2) { - QRect rect_bottom(surface_rect.left(), surface_rect.bottom() - 60, surface_rect.width(), 61); - p.setPen(Qt::NoPen); - p.setBrush(QColor(0, 0, 0, 100)); - p.drawRect(rect_bottom); - drawBottomDevUI(p, rect_bottom.left(), rect_bottom.center().y()); - } - - // Right Dev UI - if (devUiInfo != 0) { - QRect rect_right(surface_rect.right() - (UI_BORDER_SIZE * 2), UI_BORDER_SIZE * 1.5, 184, 170); - drawRightDevUI(p, surface_rect.right() - 184 - UI_BORDER_SIZE * 2, UI_BORDER_SIZE * 2 + rect_right.height()); - } - - // Speed Limit - bool showSpeedLimit; - bool speed_limit_assist_pre_active_pulse = pulseElement(speedLimitAssistFrame); - - // Position speed limit sign next to set speed box - const int sign_width = is_metric ? 200 : 172; - const int sign_x = is_metric ? 280 : 272; - const int sign_y = 45; - const int sign_height = 204; - QRect sign_rect(sign_x, sign_y, sign_width, sign_height); - - if (speedLimitAssistState == cereal::LongitudinalPlanSP::SpeedLimit::AssistState::PRE_ACTIVE) { - speedLimitAssistFrame++; - showSpeedLimit = speed_limit_assist_pre_active_pulse; - drawSpeedLimitPreActiveArrow(p, sign_rect); - } else { - speedLimitAssistFrame = 0; - showSpeedLimit = speedLimitMode != SpeedLimitMode::OFF; - } - - if (showSpeedLimit) { - drawSpeedLimitSigns(p, sign_rect); - - // do not show during SLA's preActive state - if (speedLimitAssistState != cereal::LongitudinalPlanSP::SpeedLimit::AssistState::PRE_ACTIVE) { - drawUpcomingSpeedLimit(p); - } - } - - // Road Name - drawRoadName(p, surface_rect); - - // Green Light & Lead Depart Alerts - if (greenLightAlert || leadDepartAlert) { - e2eAlertDisplayTimer = 3 * UI_FREQ; - // reset onroad sleep timer for e2e alerts - uiStateSP()->reset_onroad_sleep_timer(); - } - - if (e2eAlertDisplayTimer > 0) { - e2eAlertFrame++; - if (greenLightAlert) { - alert_text = tr("GREEN\nLIGHT"); - alert_img = green_light_alert_img; - } - else if (leadDepartAlert) { - alert_text = tr("LEAD VEHICLE\nDEPARTING"); - alert_img = lead_depart_alert_img; - } - drawE2eAlert(p, surface_rect); - } - // Standstill Timer - else if (standstillTimer && isStandstill) { - alert_img = QPixmap(); - - standstillElapsedTime += 1.0 / UI_FREQ; - int minute = static_cast(standstillElapsedTime / 60); - int second = static_cast(standstillElapsedTime - (minute * 60)); - alert_text = QString("%1:%2").arg(minute, 1, 10, QChar('0')).arg(second, 2, 10, QChar('0')); - drawE2eAlert(p, surface_rect, tr("STOPPED")); - e2eAlertFrame++; - } - // No Alerts displayed - else { - e2eAlertFrame = 0; - if (!isStandstill) standstillElapsedTime = 0.0; - } - - // Blinker - if (showTurnSignals) { - drawBlinker(p, surface_rect); - } - } - - p.restore(); -} - -void HudRendererSP::drawText(QPainter &p, int x, int y, const QString &text, QColor color) { - QRect real_rect = p.fontMetrics().boundingRect(text); - real_rect.moveCenter({x, y - real_rect.height() / 2}); - p.setPen(color); - p.drawText(real_rect.x(), real_rect.bottom(), text); -} - -bool HudRendererSP::pulseElement(int frame) { - if (frame % UI_FREQ < (UI_FREQ / 2.5)) { - return false; - } - - return true; -} - -void HudRendererSP::drawSmartCruiseControlOnroadIcon(QPainter &p, const QRect &surface_rect, int x_offset, int y_offset, std::string name) { - int x = surface_rect.center().x(); - int y = surface_rect.height() / 4; - - QString text = QString::fromStdString(name); - QFont font = InterFont(36, QFont::Bold); - p.setFont(font); - - QFontMetrics fm(font); - - int padding_v = 5; - int box_width = 160; - int box_height = fm.height() + padding_v * 2; - - QRectF bg_rect(x - (box_width / 2) + x_offset, - y - (box_height / 2) + y_offset, - box_width, box_height); - - QPainterPath boxPath; - boxPath.addRoundedRect(bg_rect, 10, 10); - - int text_w = fm.horizontalAdvance(text); - qreal baseline_y = bg_rect.top() + padding_v + fm.ascent(); - qreal text_x = bg_rect.center().x() - (text_w / 2.0); - - QPainterPath textPath; - textPath.addText(QPointF(text_x, baseline_y), font, text); - boxPath = boxPath.subtracted(textPath); - - p.setPen(Qt::NoPen); - p.setBrush(longOverride ? QColor(0x91, 0x9b, 0x95, 0xf1) : QColor(0, 0xff, 0, 0xff)); - p.drawPath(boxPath); -} - -int HudRendererSP::drawRightDevUIElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color) { - - p.setFont(InterFont(28, QFont::Bold)); - x += 92; - y += 80; - drawText(p, x, y, label); - - p.setFont(InterFont(30 * 2, QFont::Bold)); - y += 65; - drawText(p, x, y, value, color); - - p.setFont(InterFont(28, QFont::Bold)); - - if (units.length() > 0) { - p.save(); - x += 120; - y -= 25; - p.translate(x, y); - p.rotate(-90); - drawText(p, 0, 0, units); - p.restore(); - } - - return 130; -} - -void HudRendererSP::drawRightDevUI(QPainter &p, int x, int y) { - int rh = 5; - int ry = y; - - UiElement dRelElement = DeveloperUi::getDRel(lead_status, lead_d_rel); - rh += drawRightDevUIElement(p, x, ry, dRelElement.value, dRelElement.label, dRelElement.units, dRelElement.color); - ry = y + rh; - - UiElement vRelElement = DeveloperUi::getVRel(lead_status, lead_v_rel, is_metric, speedUnit); - rh += drawRightDevUIElement(p, x, ry, vRelElement.value, vRelElement.label, vRelElement.units, vRelElement.color); - ry = y + rh; - - UiElement steeringAngleDegElement = DeveloperUi::getSteeringAngleDeg(angleSteers, latActive, steerOverride); - rh += drawRightDevUIElement(p, x, ry, steeringAngleDegElement.value, steeringAngleDegElement.label, steeringAngleDegElement.units, steeringAngleDegElement.color); - ry = y + rh; - - UiElement actuatorsOutputLateralElement = DeveloperUi::getActuatorsOutputLateral(steerControlType, actuators, desiredCurvature, vEgo, roll, latActive, steerOverride); - rh += drawRightDevUIElement(p, x, ry, actuatorsOutputLateralElement.value, actuatorsOutputLateralElement.label, actuatorsOutputLateralElement.units, actuatorsOutputLateralElement.color); - ry = y + rh; - - UiElement actualLateralAccelElement = DeveloperUi::getActualLateralAccel(curvature, vEgo, roll, latActive, steerOverride); - rh += drawRightDevUIElement(p, x, ry, actualLateralAccelElement.value, actualLateralAccelElement.label, actualLateralAccelElement.units, actualLateralAccelElement.color); -} - -int HudRendererSP::drawBottomDevUIElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color) { - p.setFont(InterFont(38, QFont::Bold)); - QFontMetrics fm(p.font()); - QRect init_rect = fm.boundingRect(label + " "); - QRect real_rect = fm.boundingRect(init_rect, 0, label + " "); - real_rect.moveCenter({x, y}); - - QRect init_rect2 = fm.boundingRect(value); - QRect real_rect2 = fm.boundingRect(init_rect2, 0, value); - real_rect2.moveTop(real_rect.top()); - real_rect2.moveLeft(real_rect.right() + 10); - - QRect init_rect3 = fm.boundingRect(units); - QRect real_rect3 = fm.boundingRect(init_rect3, 0, units); - real_rect3.moveTop(real_rect.top()); - real_rect3.moveLeft(real_rect2.right() + 10); - - p.setPen(Qt::white); - p.drawText(real_rect, Qt::AlignLeft | Qt::AlignVCenter, label); - - p.setPen(color); - p.drawText(real_rect2, Qt::AlignRight | Qt::AlignVCenter, value); - p.drawText(real_rect3, Qt::AlignLeft | Qt::AlignVCenter, units); - return 430; -} - -void HudRendererSP::drawBottomDevUI(QPainter &p, int x, int y) { - int rw = 90; - - UiElement aEgoElement = DeveloperUi::getAEgo(aEgo); - rw += drawBottomDevUIElement(p, rw, y, aEgoElement.value, aEgoElement.label, aEgoElement.units, aEgoElement.color); - - UiElement vEgoLeadElement = DeveloperUi::getVEgoLead(lead_status, lead_v_rel, vEgo, is_metric, speedUnit); - rw += drawBottomDevUIElement(p, rw, y, vEgoLeadElement.value, vEgoLeadElement.label, vEgoLeadElement.units, vEgoLeadElement.color); - - if (torqueLateral && torquedUseParams) { - UiElement frictionCoefficientFilteredElement = DeveloperUi::getFrictionCoefficientFiltered(frictionCoefficientFiltered, liveValid); - rw += drawBottomDevUIElement(p, rw, y, frictionCoefficientFilteredElement.value, frictionCoefficientFilteredElement.label, frictionCoefficientFilteredElement.units, frictionCoefficientFilteredElement.color); - - UiElement latAccelFactorFilteredElement = DeveloperUi::getLatAccelFactorFiltered(latAccelFactorFiltered, liveValid); - rw += drawBottomDevUIElement(p, rw, y, latAccelFactorFilteredElement.value, latAccelFactorFilteredElement.label, latAccelFactorFilteredElement.units, latAccelFactorFilteredElement.color); - } else { - UiElement steeringTorqueEpsElement = DeveloperUi::getSteeringTorqueEps(steeringTorqueEps); - rw += drawBottomDevUIElement(p, rw, y, steeringTorqueEpsElement.value, steeringTorqueEpsElement.label, steeringTorqueEpsElement.units, steeringTorqueEpsElement.color); - - UiElement bearingDegElement = DeveloperUi::getBearingDeg(bearingAccuracyDeg, bearingDeg); - rw += drawBottomDevUIElement(p, rw, y, bearingDegElement.value, bearingDegElement.label, bearingDegElement.units, bearingDegElement.color); - } - - UiElement altitudeElement = DeveloperUi::getAltitude(gpsAccuracy, altitude); - rw += drawBottomDevUIElement(p, rw, y, altitudeElement.value, altitudeElement.label, altitudeElement.units, altitudeElement.color); -} - -void HudRendererSP::drawSpeedLimitSigns(QPainter &p, QRect &sign_rect) { - bool speedLimitWarningEnabled = speedLimitMode >= SpeedLimitMode::WARNING; // TODO-SP: update to include SpeedLimitMode::ASSIST - bool hasSpeedLimit = speedLimitValid || speedLimitLastValid; - bool overspeed = hasSpeedLimit && std::nearbyint(speedLimitFinalLast) < std::nearbyint(speed); - QString speedLimitStr = hasSpeedLimit ? QString::number(std::nearbyint(speedLimitLast)) : "---"; - - // Offset display text - QString speedLimitSubText = ""; - if (speedLimitOffset != 0) { - speedLimitSubText = (speedLimitOffset > 0 ? "" : "-") + QString::number(std::nearbyint(speedLimitOffset)); - } - - float speedLimitSubTextFactor = is_metric ? 0.5 : 0.6; - if (speedLimitSubText.size() >= 3) { - speedLimitSubTextFactor = 0.475; - } - - int alpha = 255; - QColor red_color = QColor(255, 0, 0, alpha); - QColor speed_color = (speedLimitWarningEnabled && overspeed) ? red_color : - (!speedLimitValid && speedLimitLastValid ? QColor(0x91, 0x9b, 0x95, 0xf1) : QColor(0, 0, 0, alpha)); - - if (is_metric) { - // EU Vienna Convention style circular sign - QRect vienna_rect = sign_rect; - int circle_size = std::min(vienna_rect.width(), vienna_rect.height()); - QRect circle_rect(vienna_rect.x(), vienna_rect.y(), circle_size, circle_size); - - if (vienna_rect.width() > vienna_rect.height()) { - circle_rect.moveLeft(vienna_rect.x() + (vienna_rect.width() - circle_size) / 2); - } else if (vienna_rect.height() > vienna_rect.width()) { - circle_rect.moveTop(vienna_rect.y() + (vienna_rect.height() - circle_size) / 2); - } - - // White background circle - p.setPen(Qt::NoPen); - p.setBrush(QColor(255, 255, 255, alpha)); - p.drawEllipse(circle_rect); - - // Red border ring with color coding - QRect red_ring = circle_rect; - - p.setBrush(red_color); - p.drawEllipse(red_ring); - - // Center white circle for text - int ring_size = circle_size * 0.12; - QRect center_circle = red_ring.adjusted(ring_size, ring_size, -ring_size, -ring_size); - p.setBrush(QColor(255, 255, 255, alpha)); - p.drawEllipse(center_circle); - - // Speed value, smaller font for 3+ digits - int font_size = (speedLimitStr.size() >= 3) ? 70 : 85; - p.setFont(InterFont(font_size, QFont::Bold)); - - p.setPen(speed_color); - p.drawText(center_circle, Qt::AlignCenter, speedLimitStr); - - // Offset value in small circular box - if (!speedLimitSubText.isEmpty() && hasSpeedLimit) { - int offset_circle_size = circle_size * 0.4; - int overlap = offset_circle_size * 0.25; - QRect offset_circle_rect( - circle_rect.right() - offset_circle_size/1.25 + overlap, - circle_rect.top() - offset_circle_size/1.75 + overlap, - offset_circle_size, - offset_circle_size - ); - - p.setPen(QPen(QColor(77, 77, 77, 255), 6)); - p.setBrush(QColor(0, 0, 0, alpha)); - p.drawEllipse(offset_circle_rect); - - p.setFont(InterFont(offset_circle_size * speedLimitSubTextFactor, QFont::Bold)); - p.setPen(QColor(255, 255, 255, alpha)); - p.drawText(offset_circle_rect, Qt::AlignCenter, speedLimitSubText); - } - } else { - // US/Canada MUTCD style sign - p.setPen(Qt::NoPen); - p.setBrush(QColor(255, 255, 255, alpha)); - p.drawRoundedRect(sign_rect, 32, 32); - - // Inner border with violation color coding - QRect inner_rect = sign_rect.adjusted(10, 10, -10, -10); - QColor border_color = QColor(0, 0, 0, alpha); - - p.setPen(QPen(border_color, 4)); - p.setBrush(QColor(255, 255, 255, alpha)); - p.drawRoundedRect(inner_rect, 22, 22); - - // "SPEED LIMIT" text - p.setFont(InterFont(40, QFont::DemiBold)); - p.setPen(QColor(0, 0, 0, alpha)); - p.drawText(inner_rect.adjusted(0, 10, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("SPEED")); - p.drawText(inner_rect.adjusted(0, 50, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("LIMIT")); - - // Speed value with color coding - p.setFont(InterFont(90, QFont::Bold)); - - p.setPen(speed_color); - p.drawText(inner_rect.adjusted(0, 80, 0, 0), Qt::AlignTop | Qt::AlignHCenter, speedLimitStr); - - // Offset value in small box - if (!speedLimitSubText.isEmpty() && hasSpeedLimit) { - int offset_box_size = sign_rect.width() * 0.4; - int overlap = offset_box_size * 0.25; - QRect offset_box_rect( - sign_rect.right() - offset_box_size/1.5 + overlap, - sign_rect.top() - offset_box_size/1.25 + overlap, - offset_box_size, - offset_box_size - ); - - int corner_radius = offset_box_size * 0.2; - p.setPen(QPen(QColor(77, 77, 77, 255), 6)); - p.setBrush(QColor(0, 0, 0, alpha)); - p.drawRoundedRect(offset_box_rect, corner_radius, corner_radius); - - p.setFont(InterFont(offset_box_size * speedLimitSubTextFactor, QFont::Bold)); - p.setPen(QColor(255, 255, 255, alpha)); - p.drawText(offset_box_rect, Qt::AlignCenter, speedLimitSubText); - } - } -} - -void HudRendererSP::drawUpcomingSpeedLimit(QPainter &p) { - bool speed_limit_ahead = speedLimitAheadValid && speedLimitAhead > 0 && speedLimitAhead != speedLimit && speedLimitAheadValidFrame > 0 && - speedLimitSource == cereal::LongitudinalPlanSP::SpeedLimit::Source::MAP; - if (!speed_limit_ahead) { - return; - } - - auto roundToInterval = [&](float distance, int interval, int threshold) { - int base = static_cast(distance / interval) * interval; - return (distance - base >= threshold) ? base + interval : base; - }; - - auto outputDistance = [&] { - if (is_metric) { - if (speedLimitAheadDistance < 50) return tr("Near"); - if (speedLimitAheadDistance >= 1000) return QString::number(speedLimitAheadDistance * METER_TO_KM, 'f', 1) + tr("km"); - - int rounded = (speedLimitAheadDistance < 200) ? std::max(10, roundToInterval(speedLimitAheadDistance, 10, 5)) : roundToInterval(speedLimitAheadDistance, 100, 50); - return QString::number(rounded) + tr("m"); - } else { - float distance_ft = speedLimitAheadDistance * METER_TO_FOOT; - if (distance_ft < 100) return tr("Near"); - if (distance_ft >= 900) return QString::number(speedLimitAheadDistance * METER_TO_MILE, 'f', 1) + tr("mi"); - - int rounded = (distance_ft < 500) ? std::max(50, roundToInterval(distance_ft, 50, 25)) : roundToInterval(distance_ft, 100, 50); - return QString::number(rounded) + tr("ft"); - } - }; - - QString speedStr = QString::number(std::nearbyint(speedLimitAhead)); - QString distanceStr = outputDistance(); - - // Position below current speed limit sign - const int sign_width = is_metric ? 200 : 172; - const int sign_x = is_metric ? 280 : 272; - const int sign_y = 45; - const int sign_height = 204; - - const int ahead_width = 170; - const int ahead_height = 160; - const int ahead_x = sign_x + (sign_width - ahead_width) / 2; - const int ahead_y = sign_y + sign_height + 10; - - QRect ahead_rect(ahead_x, ahead_y, ahead_width, ahead_height); - p.setPen(QPen(QColor(255, 255, 255, 100), 3)); - p.setBrush(QColor(0, 0, 0, 180)); - p.drawRoundedRect(ahead_rect, 16, 16); - - // "AHEAD" label - p.setFont(InterFont(40, QFont::DemiBold)); - p.setPen(QColor(200, 200, 200, 255)); - p.drawText(ahead_rect.adjusted(0, 4, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("AHEAD")); - - // Speed value - p.setFont(InterFont(70, QFont::Bold)); - p.setPen(QColor(255, 255, 255, 255)); - p.drawText(ahead_rect.adjusted(0, 38, 0, 0), Qt::AlignTop | Qt::AlignHCenter, speedStr); - - // Distance - p.setFont(InterFont(40, QFont::Normal)); - p.setPen(QColor(180, 180, 180, 255)); - p.drawText(ahead_rect.adjusted(0, 110, 0, 0), Qt::AlignTop | Qt::AlignHCenter, distanceStr); -} - -void HudRendererSP::drawRoadName(QPainter &p, const QRect &surface_rect) { - if (!roadName || roadNameStr.isEmpty()) return; - - // Measure text to size container - p.setFont(InterFont(46, QFont::DemiBold)); - QFontMetrics fm(p.font()); - - int text_width = fm.horizontalAdvance(roadNameStr); - int padding = 40; - int rect_width = text_width + padding; - - // Constrain to reasonable bounds - int min_width = 200; - int max_width = surface_rect.width() - 40; - rect_width = std::max(min_width, std::min(rect_width, max_width)); - - // Center at top of screen - QRect road_rect(surface_rect.width() / 2 - rect_width / 2, -4, rect_width, 60); - - p.setPen(Qt::NoPen); - p.setBrush(QColor(0, 0, 0, 120)); - p.drawRoundedRect(road_rect, 12, 12); - - p.setPen(QColor(255, 255, 255, 200)); - - // Truncate if still too long - QString truncated = fm.elidedText(roadNameStr, Qt::ElideRight, road_rect.width() - 20); - p.drawText(road_rect, Qt::AlignCenter, truncated); -} - -void HudRendererSP::drawSpeedLimitPreActiveArrow(QPainter &p, QRect &sign_rect) { - const int sign_margin = 12; - const int arrow_spacing = sign_margin * 1.4; - int arrow_x = sign_rect.right() + arrow_spacing; - - int _set_speed = std::nearbyint(set_speed); - int _speed_limit_final_last = std::nearbyint(speedLimitFinalLast); - - // Calculate the vertical offset using a sinusoidal function for smooth bouncing - double bounce_frequency = 2.0 * M_PI / UI_FREQ; // 20 frames for one full oscillation - int bounce_offset = 20 * sin(speedLimitAssistFrame * bounce_frequency); // Adjust the amplitude (20 pixels) as needed - - if (_set_speed < _speed_limit_final_last) { - QPoint iconPosition(arrow_x, sign_rect.center().y() - plus_arrow_up_img.height() / 2 + bounce_offset); - p.drawPixmap(iconPosition, plus_arrow_up_img); - } else if (_set_speed > _speed_limit_final_last) { - QPoint iconPosition(arrow_x, sign_rect.center().y() - minus_arrow_down_img.height() / 2 - bounce_offset); - p.drawPixmap(iconPosition, minus_arrow_down_img); - } -} - -void HudRendererSP::drawSetSpeedSP(QPainter &p, const QRect &surface_rect) { - // Draw outer box + border to contain set speed - const QSize default_size = {172, 204}; - QSize set_speed_size = is_metric ? QSize(200, 204) : default_size; - QRect set_speed_rect(QPoint(60 + (default_size.width() - set_speed_size.width()) / 2, 45), set_speed_size); - - // Draw set speed box - p.setPen(QPen(QColor(255, 255, 255, 75), 6)); - p.setBrush(QColor(0, 0, 0, 166)); - p.drawRoundedRect(set_speed_rect, 32, 32); - - // Colors based on status - QColor max_color = QColor(0xa6, 0xa6, 0xa6, 0xff); - QColor set_speed_color = QColor(0x72, 0x72, 0x72, 0xff); - if (is_cruise_set) { - set_speed_color = QColor(255, 255, 255); - if (speedLimitAssistActive) { - set_speed_color = longOverride ? QColor(0x91, 0x9b, 0x95, 0xff) : QColor(0, 0xff, 0, 0xff); - max_color = longOverride ? QColor(0x91, 0x9b, 0x95, 0xff) : QColor(0x80, 0xd8, 0xa6, 0xff); - } else { - if (status == STATUS_DISENGAGED) { - max_color = QColor(255, 255, 255); - } else if (status == STATUS_OVERRIDE) { - max_color = QColor(0x91, 0x9b, 0x95, 0xff); - } else { - max_color = QColor(0x80, 0xd8, 0xa6, 0xff); - } - } - } - - // Draw "MAX" or carState.cruiseState.speedCluster (when ICBM is active) text - if (!pcmCruiseSpeed && carControlEnabled) { - if (std::nearbyint(set_speed) != std::nearbyint(speedCluster)) { - icbm_active_counter = 3 * UI_FREQ; - } else if (icbm_active_counter > 0) { - icbm_active_counter--; - } - } else { - icbm_active_counter = 0; - } - int max_str_size = (icbm_active_counter != 0) ? 60 : 40; - int max_str_y = (icbm_active_counter != 0) ? 15 : 27; - QString max_str = (icbm_active_counter != 0) ? QString::number(std::nearbyint(speedCluster)) : tr("MAX"); - - p.setFont(InterFont(max_str_size, QFont::DemiBold)); - p.setPen(max_color); - p.drawText(set_speed_rect.adjusted(0, max_str_y, 0, 0), Qt::AlignTop | Qt::AlignHCenter, max_str); - - // Draw set speed - QString setSpeedStr = is_cruise_set ? QString::number(std::nearbyint(set_speed)) : "–"; - p.setFont(InterFont(90, QFont::Bold)); - p.setPen(set_speed_color); - p.drawText(set_speed_rect.adjusted(0, 77, 0, 0), Qt::AlignTop | Qt::AlignHCenter, setSpeedStr); -} - -void HudRendererSP::drawE2eAlert(QPainter &p, const QRect &surface_rect, const QString &alert_alt_text) { - if (!allow_e2e_alerts) return; - - int x = surface_rect.right() - e2e_alert_size - (devUiInfo > 0 ? 180 : 100) - (UI_BORDER_SIZE * 3); - int y = surface_rect.center().y() + 20; - QRect alertRect(x - e2e_alert_size, y - e2e_alert_size, e2e_alert_size * 2, e2e_alert_size * 2); - - // Alert Circle - QPoint center = alertRect.center(); - QColor frameColor; - if (!alert_alt_text.isEmpty()) frameColor = QColor(255, 255, 255, 75); - else frameColor = pulseElement(e2eAlertFrame) ? QColor(255, 255, 255, 75) : QColor(0, 255, 0, 75); - p.setPen(QPen(frameColor, 15)); - p.setBrush(QColor(0, 0, 0, 190)); - p.drawEllipse(center, e2e_alert_size, e2e_alert_size); - - // Alert Text - QColor txtColor; - QFont font; - int alert_bottom_adjustment; - if (!alert_alt_text.isEmpty()) { - font = InterFont(100, QFont::Bold); - alert_bottom_adjustment = 5; - txtColor = QColor(255, 255, 255, 255); - } else { - font = InterFont(48, QFont::Bold); - alert_bottom_adjustment = 7; - txtColor = pulseElement(e2eAlertFrame) ? QColor(255, 255, 255, 255) : QColor(0, 255, 0, 190); - } - p.setPen(txtColor); - p.setFont(font); - QFontMetrics fm(p.font()); - QRect textRect = fm.boundingRect(alertRect, Qt::TextWordWrap, alert_text); - textRect.moveCenter({alertRect.center().x(), alertRect.center().y()}); - textRect.moveBottom(alertRect.bottom() - alertRect.height() / alert_bottom_adjustment); - p.drawText(textRect, Qt::AlignCenter, alert_text); - - if (!alert_alt_text.isEmpty()) { - // Alert Alternate Text - p.setFont(InterFont(80, QFont::Bold)); - p.setPen(QColor(255, 175, 3, 240)); - QFontMetrics fmt(p.font()); - QRect topTextRect = fmt.boundingRect(alertRect, Qt::TextWordWrap, alert_alt_text); - topTextRect.moveCenter({alertRect.center().x(), alertRect.center().y()}); - topTextRect.moveTop(alertRect.top() + alertRect.height() / 3.5); - p.drawText(topTextRect, Qt::AlignCenter, alert_alt_text); - } else { - // Alert Image instead of Top Text - QPointF pixmapCenterOffset = QPointF(alert_img.width() / 2.0, alert_img.height() / 2.0); - QPointF drawPoint = center - pixmapCenterOffset; - p.drawPixmap(drawPoint, alert_img); - } -} - -void HudRendererSP::drawCurrentSpeedSP(QPainter &p, const QRect &surface_rect) { - QString speedStr = QString::number(std::nearbyint(speed)); - - p.setFont(InterFont(176, QFont::Bold)); - HudRenderer::drawText(p, surface_rect.center().x(), 210, speedStr); - - p.setFont(InterFont(66)); - HudRenderer::drawText(p, surface_rect.center().x(), 290, is_metric ? tr("km/h") : tr("mph"), 200); -} - -void HudRendererSP::drawBlinker(QPainter &p, const QRect &surface_rect) { - const bool hazard = leftBlinkerOn && rightBlinkerOn; - int blinkerStatus = hazard ? 2 : (leftBlinkerOn || rightBlinkerOn) ? 1 : 0; - - if (!leftBlinkerOn && !rightBlinkerOn) { - blinkerFrameCounter = 0; - lastBlinkerStatus = 0; - return; - } - - if (blinkerStatus != lastBlinkerStatus) { - blinkerFrameCounter = 0; - lastBlinkerStatus = blinkerStatus; - } - - ++blinkerFrameCounter; - - const int BLINKER_COOLDOWN_FRAMES = UI_FREQ / 10; - if (blinkerFrameCounter < BLINKER_COOLDOWN_FRAMES) { - return; - } - - const int circleRadius = 60; - const int arrowLength = 60; - const int x_gap = 160; - const int y_offset = 272; - - const int centerX = surface_rect.center().x(); - - const QPen bgBorder(Qt::white, 5); - const QPen arrowPen(Qt::NoPen); - - p.save(); - - auto drawArrow = [&](int cx, int cy, int dir, const QBrush &arrowBrush) { - const int bodyLength = arrowLength / 2; - const int bodyWidth = arrowLength / 2; - const int headLength = arrowLength / 2; - const int headWidth = arrowLength; - - QPolygon arrow; - arrow.reserve(7); - arrow << QPoint(cx - dir * bodyLength, cy - bodyWidth / 2) - << QPoint(cx, cy - bodyWidth / 2) - << QPoint(cx, cy - headWidth / 2) - << QPoint(cx + dir * headLength, cy) - << QPoint(cx, cy + headWidth / 2) - << QPoint(cx, cy + bodyWidth / 2) - << QPoint(cx - dir * bodyLength, cy + bodyWidth / 2); - - p.setPen(arrowPen); - p.setBrush(arrowBrush); - p.drawPolygon(arrow); - }; - - auto drawCircle = [&](int cx, int cy, const QBrush &bgBrush) { - p.setPen(bgBorder); - p.setBrush(bgBrush); - p.drawEllipse(QPoint(cx, cy), circleRadius, circleRadius); - }; - - struct BlinkerSide { bool on; int dir; bool blocked; int cx; }; - const std::array sides = {{ - {leftBlinkerOn, -1, hazard ? true : (leftBlinkerOn && leftBlindspot), centerX - x_gap}, - {rightBlinkerOn, 1, hazard ? true : (rightBlinkerOn && rightBlindspot), centerX + x_gap}, - }}; - - for (const auto &s: sides) { - if (!s.on) continue; - - QColor bgColor = s.blocked ? QColor(135, 23, 23) : QColor(23, 134, 68); - QColor arrowColor = s.blocked ? QColor(66, 12, 12) : QColor(12, 67, 34); - if (pulseElement(blinkerFrameCounter)) arrowColor = Qt::white; - - const QBrush bgBrush(bgColor); - const QBrush arrowBrush(arrowColor); - - drawCircle(s.cx, y_offset, bgBrush); - drawArrow(s.cx, y_offset, s.dir, arrowBrush); - } - - p.restore(); -} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/hud.h b/selfdrive/ui/sunnypilot/qt/onroad/hud.h deleted file mode 100644 index f021a949e4..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/hud.h +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/onroad/hud.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/helpers.h" -#include "selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h" - -constexpr int SPEED_LIMIT_AHEAD_VALID_FRAME_THRESHOLD = 5; - -class HudRendererSP : public HudRenderer { - Q_OBJECT - -public: - HudRendererSP(); - void updateState(const UIState &s) override; - void draw(QPainter &p, const QRect &surface_rect) override; - -private: - Params params; - void drawText(QPainter &p, int x, int y, const QString &text, QColor color = Qt::white); - void drawRightDevUI(QPainter &p, int x, int y); - int drawRightDevUIElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color); - int drawBottomDevUIElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color); - void drawBottomDevUI(QPainter &p, int x, int y); - void drawStandstillTimer(QPainter &p, int x, int y); - bool pulseElement(int frame); - void drawSmartCruiseControlOnroadIcon(QPainter &p, const QRect &surface_rect, int x_offset, int y_offset, std::string name); - void drawSpeedLimitSigns(QPainter &p, QRect &sign_rect); - void drawUpcomingSpeedLimit(QPainter &p); - void drawRoadName(QPainter &p, const QRect &surface_rect); - void drawSpeedLimitPreActiveArrow(QPainter &p, QRect &sign_rect); - void drawSetSpeedSP(QPainter &p, const QRect &surface_rect); - void drawE2eAlert(QPainter &p, const QRect &surface_rect, const QString &alert_alt_text = ""); - void drawCurrentSpeedSP(QPainter &p, const QRect &surface_rect); - void drawBlinker(QPainter &p, const QRect &surface_rect); - - bool lead_status; - float lead_d_rel; - float lead_v_rel; - bool torqueLateral; - float angleSteers; - float desiredCurvature; - float curvature; - float roll; - int memoryUsagePercent; - int devUiInfo; - float gpsAccuracy; - float altitude; - float vEgo; - float aEgo; - float steeringTorqueEps; - float bearingAccuracyDeg; - float bearingDeg; - bool torquedUseParams; - float latAccelFactorFiltered; - float frictionCoefficientFiltered; - bool liveValid; - QString speedUnit; - bool latActive; - bool steerOverride; - bool reversing; - cereal::CarParams::SteerControlType steerControlType; - cereal::CarControl::Actuators::Reader actuators; - bool standstillTimer; - bool isStandstill; - float standstillElapsedTime; - bool longOverride; - bool smartCruiseControlVisionEnabled; - bool smartCruiseControlVisionActive; - int smartCruiseControlVisionFrame; - bool smartCruiseControlMapEnabled; - bool smartCruiseControlMapActive; - int smartCruiseControlMapFrame; - float speedLimit; - float speedLimitLast; - float speedLimitOffset; - bool speedLimitValid; - bool speedLimitLastValid; - float speedLimitFinalLast; - cereal::LongitudinalPlanSP::SpeedLimit::Source speedLimitSource; - bool speedLimitAheadValid; - float speedLimitAhead; - float speedLimitAheadDistance; - float speedLimitAheadDistancePrev; - int speedLimitAheadValidFrame; - SpeedLimitMode speedLimitMode = SpeedLimitMode::OFF; - bool roadName; - QString roadNameStr; - cereal::LongitudinalPlanSP::SpeedLimit::AssistState speedLimitAssistState; - bool speedLimitAssistActive; - int speedLimitAssistFrame; - QPixmap plus_arrow_up_img; - QPixmap minus_arrow_down_img; - int e2e_alert_size = 250; - QPixmap green_light_alert_img; - bool greenLightAlert; - int e2eAlertFrame; - int e2eAlertDisplayTimer = 0; - bool allow_e2e_alerts; - bool leadDepartAlert; - QPixmap lead_depart_alert_img; - QString alert_text; - QPixmap alert_img; - bool hideVEgoUI; - bool leftBlinkerOn; - bool rightBlinkerOn; - bool leftBlindspot; - bool rightBlindspot; - int blinkerFrameCounter; - int lastBlinkerStatus; - bool showTurnSignals; - - bool carControlEnabled; - float speedCluster = 0; - int icbm_active_counter = 0; - bool pcmCruiseSpeed = true; -}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/model.cc b/selfdrive/ui/sunnypilot/qt/onroad/model.cc deleted file mode 100644 index 590ade24a1..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/model.cc +++ /dev/null @@ -1,254 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/onroad/model.h" - - -void ModelRendererSP::update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead) { - ModelRenderer::update_model(model, lead); - const auto &model_position = model.getPosition(); - const auto &lane_lines = model.getLaneLines(); - float max_distance = std::clamp(*(model_position.getX().end() - 1), MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE); - int max_idx = get_path_length_idx(lane_lines[0], max_distance); - // update blindspot vertices - float max_distance_barrier = 100; - int max_idx_barrier = std::min(max_idx, get_path_length_idx(lane_lines[0], max_distance_barrier)); - mapLineToPolygon(model.getLaneLines()[1], 0.2, -0.05, &left_blindspot_vertices, max_idx_barrier); - mapLineToPolygon(model.getLaneLines()[2], 0.2, -0.05, &right_blindspot_vertices, max_idx_barrier); -} - -void ModelRendererSP::draw(QPainter &painter, const QRect &surface_rect) { - auto *s = uiState(); - auto &sm = *(s->sm); - - if (sm.rcv_frame("liveCalibration") < s->scene.started_frame || - sm.rcv_frame("modelV2") < s->scene.started_frame) { - return; - } - - clip_region = surface_rect.adjusted(-CLIP_MARGIN, -CLIP_MARGIN, CLIP_MARGIN, CLIP_MARGIN); - experimental_mode = sm["selfdriveState"].getSelfdriveState().getExperimentalMode(); - longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl(); - path_offset_z = sm["liveCalibration"].getLiveCalibration().getHeight()[0]; - - painter.save(); - - const auto &model = sm["modelV2"].getModelV2(); - const auto &radar_state = sm["radarState"].getRadarState(); - const auto &lead_one = radar_state.getLeadOne(); - const auto &car_state = sm["carState"].getCarState(); - - update_model(model, lead_one); - drawLaneLines(painter); - - if (s->scene.rainbow_mode) { - drawRainbowPath(painter, surface_rect); - } else { - ModelRenderer::drawPath(painter, model, surface_rect.height()); - } - - if (longitudinal_control && sm.alive("radarState")) { - update_leads(radar_state, model.getPosition()); - const auto &lead_two = radar_state.getLeadTwo(); - if (lead_one.getStatus()) { - drawLead(painter, lead_one, lead_vertices[0], surface_rect); - } - if (lead_two.getStatus() && (std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0)) { - drawLead(painter, lead_two, lead_vertices[1], surface_rect); - } - } - - if (s->scene.blindspot_ui) { - const bool left_blindspot = car_state.getLeftBlindspot(); - const bool right_blindspot = car_state.getRightBlindspot(); - drawBlindspot(painter, surface_rect, left_blindspot, right_blindspot); - } - drawLeadStatus(painter, surface_rect.height(), surface_rect.width()); - - painter.restore(); -} - -void ModelRendererSP::drawBlindspot(QPainter &painter, const QRect &surface_rect, bool left_blindspot, bool right_blindspot) { - if (left_blindspot && !left_blindspot_vertices.isEmpty()) { - QLinearGradient gradient(0, 0, surface_rect.width(), 0); // Horizontal gradient from left to right - gradient.setColorAt(0.0, QColor(255, 165, 0, 102)); // Orange with alpha - gradient.setColorAt(1.0, QColor(255, 255, 0, 102)); // Yellow with alpha - painter.setBrush(gradient); - painter.drawPolygon(left_blindspot_vertices); - } - - if (right_blindspot && !right_blindspot_vertices.isEmpty()) { - QLinearGradient gradient(surface_rect.width(), 0, 0, 0); // Horizontal gradient from right to left - gradient.setColorAt(0.0, QColor(255, 165, 0, 102)); // Orange with alpha - gradient.setColorAt(1.0, QColor(255, 255, 0, 102)); // Yellow with alpha - painter.setBrush(gradient); - painter.drawPolygon(right_blindspot_vertices); - } -} - -void ModelRendererSP::drawLeadStatus(QPainter &painter, int height, int width) { - auto *s = uiState(); - auto &sm = *(s->sm); - - bool longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl(); - if (!longitudinal_control) { - lead_status_alpha = std::max(0.0f, lead_status_alpha - 0.05f); - return; - } - - if (!sm.alive("radarState")) { - lead_status_alpha = std::max(0.0f, lead_status_alpha - 0.05f); - return; - } - - const auto &radar_state = sm["radarState"].getRadarState(); - const auto &lead_one = radar_state.getLeadOne(); - const auto &lead_two = radar_state.getLeadTwo(); - - bool has_lead_one = lead_one.getStatus(); - bool has_lead_two = lead_two.getStatus(); - - if (!has_lead_one && !has_lead_two) { - lead_status_alpha = std::max(0.0f, lead_status_alpha - 0.05f); - if (lead_status_alpha <= 0.0f) return; - } else { - lead_status_alpha = std::min(1.0f, lead_status_alpha + 0.1f); - } - - if (has_lead_one) { - drawLeadStatusPosition(painter, lead_one, lead_vertices[0], height, width); - } - - if (has_lead_two && std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0) { - drawLeadStatusPosition(painter, lead_two, lead_vertices[1], height, width); - } -} - -void ModelRendererSP::drawLeadStatusPosition(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, - const QPointF &chevron_pos, int height, int width) { - float d_rel = lead_data.getDRel(); - float v_rel = lead_data.getVRel(); - auto *s = uiState(); - auto &sm = *(s->sm); - float v_ego = sm["carState"].getCarState().getVEgo(); - - int chevron_data = s->scene.chevron_info; - float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), 15.0f, 30.0f) * 2.35; - - QFont content_font = painter.font(); - content_font.setPixelSize(50); - content_font.setBold(true); - painter.setFont(content_font); - - bool is_metric = s->scene.is_metric; - QStringList text_lines; - const int chevron_all = 4; - QStringList chevron_text[3]; - - // Distance display - if (chevron_data == 1 || chevron_data == chevron_all) { - int pos = 0; - float val = std::max(0.0f, d_rel); - QString unit = is_metric ? "m" : "ft"; - if (!is_metric) val *= 3.28084f; - chevron_text[pos].append(QString::number(val, 'f', 0) + " " + unit); - } - - // Speed display - if (chevron_data == 2 || chevron_data == chevron_all) { - int pos = (chevron_data == 2) ? 0 : 1; - float multiplier = is_metric ? static_cast(MS_TO_KPH) : static_cast(MS_TO_MPH); - float val = std::max(0.0f, (v_rel + v_ego) * multiplier); - QString unit = is_metric ? "km/h" : "mph"; - chevron_text[pos].append(QString::number(val, 'f', 0) + " " + unit); - } - - // Time to contact - if (chevron_data == 3 || chevron_data == chevron_all) { - int pos = (chevron_data == 3) ? 0 : 2; - float val = (d_rel > 0 && v_ego > 0) ? std::max(0.0f, d_rel / v_ego) : 0.0f; - QString ttc = (val > 0 && val < 200) ? QString::number(val, 'f', 1) + "s" : "---"; - chevron_text[pos].append(ttc); - } - - for (int i = 0; i < 3; ++i) { - if (!chevron_text[i].isEmpty()) text_lines.append(chevron_text[i]); - } - - if (text_lines.isEmpty()) return; - - QFontMetrics fm(content_font); - float text_width = 120.0f; - for (const QString &line : text_lines) { - text_width = std::max(text_width, fm.horizontalAdvance(line) + 20.0f); - } - text_width = std::min(text_width, 250.0f); - - float line_height = 50.0f; - float total_height = text_lines.size() * line_height; - float margin = 20.0f; - - float text_y = chevron_pos.y() + sz + 15; - if (text_y + total_height > height - margin) { - float y_max = chevron_pos.y() > (height - margin) ? (height - margin) : chevron_pos.y(); - text_y = y_max - 15 - total_height; - text_y = std::max(margin, text_y); - } - - float text_x = chevron_pos.x() - text_width / 2; - text_x = std::clamp(text_x, margin, (float)width - text_width - margin); - - QPoint shadow_offset(2, 2); - QColor text_color = QColor(255, 255, 255, (int)(255 * lead_status_alpha)); - for (int i = 0; i < text_lines.size(); ++i) { - float y = text_y + (i * line_height); - if (y + line_height > height - margin) break; - - QRect rect(text_x, y, text_width, line_height); - - // Draw shadow - painter.setPen(QColor(0, 0, 0, (int)(200 * lead_status_alpha))); - painter.drawText(rect.translated(shadow_offset), Qt::AlignCenter, text_lines[i]); - painter.setPen(text_color); - painter.drawText(rect, Qt::AlignCenter, text_lines[i]); - } - - painter.setPen(Qt::NoPen); -} - -void ModelRendererSP::drawRainbowPath(QPainter &painter, const QRect &surface_rect) { - // Simple time-based animation - float time_offset = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()).count() / 1000.0f; - - // simple linear gradient from bottom to top - QLinearGradient bg(0, surface_rect.height(), 0, 0); - - // evenly spaced colors across the spectrum - // The animation shifts the entire spectrum smoothly - float animation_speed = 40.0f; // speed vroom vroom - float hue_offset = fmod(time_offset * animation_speed, 360.0f); - - // 6-8 color stops for smooth transitions more color makes it laggy - const int num_stops = 7; - for (int i = 0; i < num_stops; i++) { - float position = static_cast(i) / (num_stops - 1); - - float hue = fmod(hue_offset + position * 360.0f, 360.0f); - float saturation = 0.9f; - float lightness = 0.6f; - - // Alpha fades out towards the far end of the path - float alpha = 0.8f * (1.0f - position * 0.3f); - - QColor color = QColor::fromHslF(hue / 360.0f, saturation, lightness, alpha); - bg.setColorAt(position, color); - } - - painter.setBrush(bg); - painter.drawPolygon(track_vertices); -} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/model.h b/selfdrive/ui/sunnypilot/qt/onroad/model.h deleted file mode 100644 index 68068f2068..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/model.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/onroad/model.h" - -class ModelRendererSP : public ModelRenderer { -public: - ModelRendererSP() = default; - - void draw(QPainter &painter, const QRect &surface_rect); - -private: - void update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead) override; - void drawLeadStatus(QPainter &painter, int height, int width); - void drawLeadStatusPosition(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, - const QPointF &chevron_pos, int height, int width); - void drawBlindspot(QPainter &painter, const QRect &surface_rect, bool left_blindspot, bool right_blindspot); - void drawRainbowPath(QPainter &painter, const QRect &surface_rect); - - QPolygonF left_blindspot_vertices; - QPolygonF right_blindspot_vertices; - - // Lead status animation - float lead_status_alpha = 0.0f; -}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.cc b/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.cc deleted file mode 100644 index b26d1b828a..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.cc +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h" - -#include "common/swaglog.h" -#include "selfdrive/ui/qt/util.h" - -OnroadWindowSP::OnroadWindowSP(QWidget *parent) : OnroadWindow(parent) { - QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &OnroadWindowSP::updateState); - QObject::connect(uiStateSP(), &UIStateSP::offroadTransition, this, &OnroadWindowSP::offroadTransition); -} - -void OnroadWindowSP::updateState(const UIStateSP &s) { - if (!s.scene.started) { - return; - } - - OnroadWindow::updateState(s); -} - -void OnroadWindowSP::mousePressEvent(QMouseEvent *e) { - OnroadWindow::mousePressEvent(e); -} - -void OnroadWindowSP::offroadTransition(bool offroad) { - OnroadWindow::offroadTransition(offroad); -} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h b/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h deleted file mode 100644 index 193fdae0dc..0000000000 --- a/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/onroad/onroad_home.h" - -class OnroadWindowSP : public OnroadWindow { - Q_OBJECT - -public: - OnroadWindowSP(QWidget *parent = 0); - -private: - void mousePressEvent(QMouseEvent *e) override; - -protected slots: - void offroadTransition(bool offroad) override; - void updateState(const UIStateSP &s) override; -}; diff --git a/selfdrive/ui/sunnypilot/qt/request_repeater.cc b/selfdrive/ui/sunnypilot/qt/request_repeater.cc deleted file mode 100644 index e137d56172..0000000000 --- a/selfdrive/ui/sunnypilot/qt/request_repeater.cc +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/request_repeater.h" - -RequestRepeaterSP::RequestRepeaterSP(QObject *parent, const QString &requestURL, const QString &cacheKey, - int period, bool whileOnroad, bool sunnylink) : HttpRequestSP(parent, true, 20000, sunnylink) { - request_url = requestURL; - while_onroad = whileOnroad; - timer = new QTimer(this); - timer->setTimerType(Qt::VeryCoarseTimer); - connect(timer, &QTimer::timeout, [=]() { this->timerTick(); }); - timer->start(period * 1000); - - if (!cacheKey.isEmpty()) { - prevResp = QString::fromStdString(params.get(cacheKey.toStdString())); - if (!prevResp.isEmpty()) { - QTimer::singleShot(500, [=]() { emit requestDone(prevResp, true, QNetworkReply::NoError); }); - } - connect(this, &HttpRequest::requestDone, [=](const QString &resp, bool success) { - if (success && resp != prevResp) { - params.put(cacheKey.toStdString(), resp.toStdString()); - prevResp = resp; - } - }); - } - - // Don't wait for the timer to fire to send the first request - ForceUpdate(); -} - -void RequestRepeaterSP::timerTick() { - if ((!uiState()->scene.started || while_onroad) && device()->isAwake() && !active()) { - LOGD("Sending request for %s", qPrintable(request_url)); - sendRequest(request_url); - } -} diff --git a/selfdrive/ui/sunnypilot/qt/request_repeater.h b/selfdrive/ui/sunnypilot/qt/request_repeater.h deleted file mode 100644 index 0cdb370f9b..0000000000 --- a/selfdrive/ui/sunnypilot/qt/request_repeater.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/request_repeater.h" - -#include "common/swaglog.h" -#include "common/util.h" -#include "selfdrive/ui/sunnypilot/ui.h" -#include "selfdrive/ui/sunnypilot/qt/api.h" - -class RequestRepeaterSP : public HttpRequestSP { - -private: - Params params; - QTimer *timer; - QString prevResp; - QString request_url; - bool while_onroad; - void timerTick(); - -public: - RequestRepeaterSP(QObject *parent, const QString &requestURL, const QString &cacheKey = "", int period = 0, bool whileOnroad=false, bool sunnylink = false); - void ForceUpdate() { - LOGD("Forcing update for %s", qPrintable(request_url)); - timerTick(); - } -}; diff --git a/selfdrive/ui/sunnypilot/qt/sidebar.cc b/selfdrive/ui/sunnypilot/qt/sidebar.cc deleted file mode 100644 index a4dc1d6763..0000000000 --- a/selfdrive/ui/sunnypilot/qt/sidebar.cc +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/sidebar.h" - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/sunnypilot/qt/util.h" -#include "common/params.h" - -SidebarSP::SidebarSP(QWidget *parent) : Sidebar(parent) { - // Redirect uiUpdate signal to SidebarSP::updateState instead of Sidebar::updateState - QObject::disconnect(uiState(), &UIState::uiUpdate, this, &Sidebar::updateState); - QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &SidebarSP::updateState); -} - -void SidebarSP::updateState(const UIStateSP &s) { - if (!isVisible()) return; - Sidebar::updateState(s); - - ItemStatus sunnylinkStatus; - auto sl_dongle_id = getSunnylinkDongleId(); - auto last_sunnylink_ping_str = params.get("LastSunnylinkPingTime"); - auto last_sunnylink_ping = std::stoull(last_sunnylink_ping_str.empty() ? "0" : last_sunnylink_ping_str); - auto elapsed_sunnylink_ping = nanos_since_boot() - last_sunnylink_ping; - auto sunnylink_enabled = params.getBool("SunnylinkEnabled"); - - QString status = tr("DISABLED"); - QColor color = disabled_color; - - if (sunnylink_enabled && last_sunnylink_ping == 0) { - // If sunnylink is enabled, but we don't have a dongle id, and we haven't received a ping yet, we are registering - status = sl_dongle_id.has_value() ? tr("OFFLINE") : tr("REGIST..."); - color = sl_dongle_id.has_value() ? warning_color : progress_color; - } else if (sunnylink_enabled) { - // If sunnylink is enabled, we are considered online if we have received a ping in the last 80 seconds, else error. - status = elapsed_sunnylink_ping < 80000000000ULL ? tr("ONLINE") : tr("ERROR"); - color = elapsed_sunnylink_ping < 80000000000ULL ? good_color : danger_color; - } - sunnylinkStatus = ItemStatus{{tr("SUNNYLINK"), status}, color}; - setProperty("sunnylinkStatus", QVariant::fromValue(sunnylinkStatus)); -} - -void SidebarSP::drawSidebar(QPainter &p) { - Sidebar::drawSidebar(p); - // metrics - drawMetric(p, temp_status.first, temp_status.second, 310); - drawMetric(p, panda_status.first, panda_status.second, 440); - drawMetric(p, connect_status.first, connect_status.second, 570); - drawMetric(p, sunnylink_status.first, sunnylink_status.second, 700); -} diff --git a/selfdrive/ui/sunnypilot/qt/sidebar.h b/selfdrive/ui/sunnypilot/qt/sidebar.h deleted file mode 100644 index 133106cfdf..0000000000 --- a/selfdrive/ui/sunnypilot/qt/sidebar.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include - -#include "selfdrive/ui/qt/sidebar.h" - -#include "selfdrive/ui/sunnypilot/ui.h" - -class SidebarSP : public Sidebar { - Q_OBJECT - Q_PROPERTY(ItemStatus sunnylinkStatus MEMBER sunnylink_status NOTIFY valueChanged); - Q_PROPERTY(QString sidebarTemp MEMBER sidebar_temp_str NOTIFY valueChanged); - -public slots: - void updateState(const UIStateSP &s); - -public: - explicit SidebarSP(QWidget *parent = 0); - -private: - void drawSidebar(QPainter &p) override; - - Params params; - QString sidebar_temp = "0"; - QString sidebar_temp_str = "0"; - -protected: - const QColor progress_color = QColor(3, 132, 252); - const QColor disabled_color = QColor(128, 128, 128); - - ItemStatus sunnylink_status; -}; diff --git a/selfdrive/ui/sunnypilot/qt/util.cc b/selfdrive/ui/sunnypilot/qt/util.cc deleted file mode 100644 index eaa1f4bd12..0000000000 --- a/selfdrive/ui/sunnypilot/qt/util.cc +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/util.h" -#include "selfdrive/ui/qt/util.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "system/hardware/hw.h" - -std::optional getParamIgnoringDefault(const std::string ¶m_name, const std::string &default_value) { - std::string value = Params().get(param_name); - - if (!value.empty() && value != default_value) - return QString::fromStdString(value); - - return {}; -} - -QString getUserAgent(bool sunnylink) { - return (sunnylink ? "sunnypilot-" : "openpilot-") + getVersion(); -} - -std::optional getSunnylinkDongleId() { - return getParamIgnoringDefault("SunnylinkDongleId", "UnregisteredDevice"); -} - -QMap loadPlatformList() { - QMap _platforms; - - std::string json_data = util::read_file("../../sunnypilot/selfdrive/car/car_list.json"); - - if (json_data.empty()) { - return _platforms; - } - - QJsonParseError json_error{}; - QJsonDocument doc = QJsonDocument::fromJson(QString::fromStdString(json_data).toUtf8(), &json_error); - if (doc.isNull()) { - return _platforms; - } - - if (doc.isObject()) { - QJsonObject obj = doc.object(); - for (const QString &key : obj.keys()) { - QJsonObject attributes = obj.value(key).toObject(); - QVariantMap platform_data; - - QJsonArray yearArray = attributes.value("year").toArray(); - QVariantList yearList; - for (const QJsonValue &year : yearArray) { - yearList.append(year.toString()); - } - - platform_data["year"] = yearList; - platform_data["make"] = attributes.value("make").toString(); - platform_data["brand"] = attributes.value("brand").toString(); - platform_data["model"] = attributes.value("model").toString(); - platform_data["platform"] = attributes.value("platform").toString(); - platform_data["package"] = attributes.value("package").toString(); - - _platforms[key] = platform_data; - } - } - - return _platforms; -} - -/** - * @brief Searches a list of strings for elements containing all search terms in a query. - * - * The search is case-insensitive and normalizes both the query and the list elements - * using Unicode KD normalization before comparison. Non-alphanumeric characters are - * removed from the search terms before comparison. - * - * @param query The search query string. Multiple words can be separated by spaces. - * @param list The source list of strings to search. - * @return A list of strings from the input list that contain all of the search terms. - */ -QStringList searchFromList(const QString &query, const QStringList &list) { - if (query.isEmpty()) { - return list; - } - - QStringList search_terms = query.simplified().toLower().replace(QRegularExpression("[^a-zA-Z0-9\\s]"), " ").split(" ", QString::SkipEmptyParts); - QStringList search_results; - - for (const QString &element : list) { - if (std::all_of(search_terms.begin(), search_terms.end(), [&](const QString &term) { - QString normalized_term = term.normalized(QString::NormalizationForm_KD).toLower(); - QString normalized_element = element.normalized(QString::NormalizationForm_KD).toLower(); - return normalized_element.contains(normalized_term, Qt::CaseInsensitive); - })) { - search_results << element; - } - } - return search_results; -} - -std::optional loadCerealEvent(Params& params, const std::string& _param) { - std::string bytes = params.get(_param); - - try { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(bytes.data(), bytes.size())); - return cmsg.getRoot(); - } catch (kj::Exception& e) { - qInfo() << "invalid " << QString::fromStdString(_param) << ":" << e.getDescription().cStr(); - return std::nullopt; - } -} - -bool hasIntelligentCruiseButtonManagement(const cereal::CarParamsSP::Reader &car_params_sp) { - return car_params_sp.getIntelligentCruiseButtonManagementAvailable() && Params().getBool("IntelligentCruiseButtonManagement"); -} diff --git a/selfdrive/ui/sunnypilot/qt/util.h b/selfdrive/ui/sunnypilot/qt/util.h deleted file mode 100644 index 60a73615ba..0000000000 --- a/selfdrive/ui/sunnypilot/qt/util.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include - -#include "selfdrive/ui/sunnypilot/ui.h" - -QString getUserAgent(bool sunnylink = false); -std::optional getSunnylinkDongleId(); -std::optional getParamIgnoringDefault(const std::string ¶m_name, const std::string &default_value); -QMap loadPlatformList(); -QStringList searchFromList(const QString &query, const QStringList &list); -std::optional loadCerealEvent(Params& params, const std::string& _param); -bool hasIntelligentCruiseButtonManagement(const cereal::CarParamsSP::Reader &car_params_sp); diff --git a/selfdrive/ui/sunnypilot/qt/widgets/controls.cc b/selfdrive/ui/sunnypilot/qt/widgets/controls.cc deleted file mode 100644 index 28374f3a9f..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/controls.cc +++ /dev/null @@ -1,271 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -#include -#include - -QFrame *horizontal_line(QWidget *parent) { - QFrame *line = new QFrame(parent); - line->setFrameShape(QFrame::StyledPanel); - line->setStyleSheet(R"( - border-width: 2px; - border-bottom-style: solid; - border-color: gray; - )"); - line->setFixedHeight(10); - return line; -} - -QFrame *vertical_space(int height, QWidget *parent) { - QFrame *v_space = new QFrame(parent); - v_space->setFrameShape(QFrame::StyledPanel); - v_space->setFixedHeight(height); - return v_space; -} - -// AbstractControlSP -std::vector AbstractControlSP::advanced_controls_; -AbstractControlSP::~AbstractControlSP() { UnregisterAdvancedControl(this); } - -void AbstractControlSP::RegisterAdvancedControl(AbstractControlSP *ctrl) { advanced_controls_.push_back(ctrl); } - -void AbstractControlSP::UnregisterAdvancedControl(AbstractControlSP *ctrl) { - advanced_controls_.erase(std::remove(advanced_controls_.begin(), advanced_controls_.end(), ctrl), advanced_controls_.end()); -} - -void AbstractControlSP::UpdateAllAdvancedControls() { - bool visibility = Params().getBool("ShowAdvancedControls"); - advanced_controls_.erase(std::remove(advanced_controls_.begin(), advanced_controls_.end(), nullptr), advanced_controls_.end()); - for (auto *ctrl : advanced_controls_) ctrl->setVisible(visibility); -} - -AbstractControlSP::AbstractControlSP(const QString &title, const QString &desc, const QString &icon, QWidget *parent, bool advancedControl) - : AbstractControl(title, desc, icon, parent), isAdvancedControl(advancedControl) { - if (isAdvancedControl) RegisterAdvancedControl(this); - - main_layout = new QVBoxLayout(this); - main_layout->setMargin(0); - - hlayout = new QHBoxLayout; - hlayout->setMargin(0); - hlayout->setSpacing(20); - - // title - title_label = new QPushButton(title); - title_label->setFixedHeight(120); - title_label->setStyleSheet("font-size: 50px; font-weight: 450; text-align: left; border: none;"); - hlayout->addWidget(title_label, 1); - - // value next to control button - value = new ElidedLabelSP(); - value->setAlignment(Qt::AlignRight | Qt::AlignVCenter); - value->setStyleSheet("color: #aaaaaa"); - hlayout->addWidget(value); - - main_layout->addLayout(hlayout); - - // description - description = new QLabel(desc); - description->setContentsMargins(40, 20, 40, 20); - description->setStyleSheet("font-size: 40px; color: grey"); - description->setWordWrap(true); - description->setVisible(false); - main_layout->addWidget(description); - - connect(title_label, &QPushButton::clicked, [=]() { - if (!description->isVisible()) { - emit showDescriptionEvent(); - } - - if (!description->text().isEmpty()) { - description->setVisible(!description->isVisible()); - } - }); - - main_layout->addStretch(); -} - -void AbstractControlSP::hideEvent(QHideEvent *e) { - if (description != nullptr) { - description->hide(); - } -} - -AbstractControlSP_SELECTOR::AbstractControlSP_SELECTOR(const QString &title, const QString &desc, const QString &icon, QWidget *parent, bool advancedControl) - : AbstractControlSP(title, desc, icon, parent, advancedControl) { - - if (title_label != nullptr) { - delete title_label; - title_label = nullptr; - } - - if (description != nullptr) { - delete description; - description = nullptr; - } - - if (value != nullptr) { - ReplaceWidget(value, new QWidget()); - value = nullptr; - } - - QLayoutItem *item; - while ((item = main_layout->takeAt(0)) != nullptr) { - if (item->widget()) { - delete item->widget(); - } - delete item; - } - - main_layout->setMargin(0); - - hlayout = new QHBoxLayout; - hlayout->setMargin(0); - hlayout->setSpacing(0); - - // title - if (!title.isEmpty()) { - title_label = new QPushButton(title); - title_label->setFixedHeight(120); - title_label->setStyleSheet("font-size: 50px; font-weight: 450; text-align: left; border: none; padding: 0 0 0 0"); - main_layout->addWidget(title_label, 1); - - connect(title_label, &QPushButton::clicked, [=]() { - if (!description->isVisible()) { - emit showDescriptionEvent(); - } - - if (!description->text().isEmpty()) { - bool isVisible = !description->isVisible(); - description->setVisible(isVisible); - - if (isVisible && spacingItem) { - main_layout->removeItem(spacingItem); - } else if (!isVisible && spacingItem != nullptr && main_layout->indexOf(spacingItem) == -1) { - main_layout->insertItem(main_layout->indexOf(description), spacingItem); - } - } - }); - } else { - main_layout->addSpacing(20); - } - - main_layout->addLayout(hlayout); - if (!desc.isEmpty() && spacingItem != nullptr && main_layout->indexOf(spacingItem) == -1) { - main_layout->insertItem(main_layout->count(), spacingItem); - } - - // description - description = new QLabel(desc); - description->setContentsMargins(40, 20, 40, 20); - description->setStyleSheet("font-size: 40px; color: grey"); - description->setWordWrap(true); - description->setVisible(false); - main_layout->addWidget(description); - - main_layout->addStretch(); -} - -void AbstractControlSP_SELECTOR::hideEvent(QHideEvent *e) { - if (description != nullptr) { - description->hide(); - } - - if (spacingItem != nullptr && main_layout->indexOf(spacingItem) == -1) { - main_layout->insertItem(main_layout->indexOf(description), spacingItem); - } -} - -// controls - -ButtonControlSP::ButtonControlSP(const QString &title, const QString &text, const QString &desc, QWidget *parent, bool advancedControl) - : AbstractControlSP(title, desc, "", parent, advancedControl) { - - btn.setText(text); - btn.setStyleSheet(R"( - QPushButton { - padding: 0; - border-radius: 50px; - font-size: 35px; - font-weight: 500; - color: #E4E4E4; - background-color: #393939; - } - QPushButton:pressed { - background-color: #4a4a4a; - } - QPushButton:disabled { - color: #33E4E4E4; - } - )"); - btn.setFixedSize(250, 100); - QObject::connect(&btn, &QPushButton::clicked, this, &ButtonControlSP::clicked); - hlayout->addWidget(&btn); -} - -// ElidedLabelSP - -ElidedLabelSP::ElidedLabelSP(QWidget *parent) : ElidedLabelSP({}, parent) { -} - -ElidedLabelSP::ElidedLabelSP(const QString &text, QWidget *parent) : QLabel(text.trimmed(), parent) { - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - setMinimumWidth(1); -} - -void ElidedLabelSP::resizeEvent(QResizeEvent *event) { - QLabel::resizeEvent(event); - lastText_ = elidedText_ = ""; -} - -void ElidedLabelSP::paintEvent(QPaintEvent *event) { - const QString curText = text(); - if (curText != lastText_) { - elidedText_ = fontMetrics().elidedText(curText, Qt::ElideRight, contentsRect().width()); - lastText_ = curText; - } - - QPainter painter(this); - drawFrame(&painter); - QStyleOption opt; - opt.initFrom(this); - style()->drawItemText(&painter, contentsRect(), alignment(), opt.palette, isEnabled(), elidedText_, foregroundRole()); -} - -// ParamControlSP - -ParamControlSP::ParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent, bool advancedControl) - : ToggleControlSP(title, desc, icon, false, parent, advancedControl){ - - key = param.toStdString(); - QObject::connect(this, &ParamControlSP::toggleFlipped, this, &ParamControlSP::toggleClicked); - - hlayout->removeWidget(&toggle); - hlayout->insertWidget(0, &toggle); - - hlayout->removeWidget(this->icon_label); - hlayout->insertWidget(1, this->icon_label); -} - -void ParamControlSP::toggleClicked(bool state) { - auto do_confirm = [this]() { - QString content("

" + title_label->text() + "


" - "

" + getDescription() + "

"); - return ConfirmationDialog(content, tr("Enable"), tr("Cancel"), true, this).exec(); - }; - - bool confirmed = store_confirm && params.getBool(key + "Confirmed"); - if (!confirm || confirmed || !state || do_confirm()) { - if (store_confirm && state) params.putBool(key + "Confirmed", true); - params.putBool(key, state); - setIcon(state); - } else { - toggle.togglePosition(); - } -} diff --git a/selfdrive/ui/sunnypilot/qt/widgets/controls.h b/selfdrive/ui/sunnypilot/qt/widgets/controls.h deleted file mode 100644 index 71041556b7..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/controls.h +++ /dev/null @@ -1,772 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include "common/params.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/input.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/toggle.h" - -QFrame *horizontal_line(QWidget *parent = nullptr); -QFrame *vertical_space(int height = 10, QWidget *parent = nullptr); - -inline void ReplaceWidget(QWidget *old_widget, QWidget *new_widget) { - if (old_widget && old_widget->parentWidget() && old_widget->parentWidget()->layout()) { - old_widget->parentWidget()->layout()->replaceWidget(old_widget, new_widget); - old_widget->hide(); - old_widget->deleteLater(); - } -} - -class ElidedLabelSP : public QLabel { - Q_OBJECT - -public: - explicit ElidedLabelSP(QWidget *parent = 0); - explicit ElidedLabelSP(const QString &text, QWidget *parent = 0); - - void setColor(const QString &color) { - setStyleSheet("QLabel { color : " + color + "; }"); - } - -signals: - void clicked(); - -protected: - void paintEvent(QPaintEvent *event) override; - void resizeEvent(QResizeEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override { - if (rect().contains(event->pos())) { - emit clicked(); - } - } - QString lastText_, elidedText_; -}; - -class AbstractControlSP : public AbstractControl { - Q_OBJECT - -public: - ~AbstractControlSP(); - void setDescription(const QString &desc) override { - if (description) description->setText(desc); - } - - void setValue(const QString &val, std::optional color = std::nullopt) { - value->setText(val); - if (color.has_value()) { - value->setColor(color.value()); - } - } - - const QString getDescription() override { - return description->text(); - } - - void hideDescription() { - description->setVisible(false); - } - -public slots: - void showDescription() override { - description->setVisible(true); - } - - void setVisible(bool visible) override { - bool _visible = visible; - if (isAdvancedControl && !params.getBool("ShowAdvancedControls")) { - _visible = false; - } - AbstractControl::setVisible(_visible); - } - - static void RegisterAdvancedControl(AbstractControlSP *ctrl); - static void UnregisterAdvancedControl(AbstractControlSP *ctrl); - static void UpdateAllAdvancedControls(); - -protected: - AbstractControlSP(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr, bool advancedControl = false); - void hideEvent(QHideEvent *e) override; - - QVBoxLayout *main_layout; - ElidedLabelSP *value; - QLabel *description = nullptr; - bool isAdvancedControl; - -private: - Params params; - static std::vector advanced_controls_; -}; - -// AbstractControlSP_SELECTOR - -class AbstractControlSP_SELECTOR : public AbstractControlSP { - Q_OBJECT - -protected: - QSpacerItem *spacingItem = new QSpacerItem(44, 44, QSizePolicy::Minimum, QSizePolicy::Fixed); - AbstractControlSP_SELECTOR(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr, bool advancedControl = false); - void hideEvent(QHideEvent *e) override; - -}; - -// widget to display a value -class LabelControlSP : public AbstractControlSP { - Q_OBJECT - -public: - LabelControlSP(const QString &title, const QString &text = "", const QString &desc = "", QWidget *parent = nullptr) : AbstractControlSP(title, desc, "", parent) { - label.setText(text); - label.setAlignment(Qt::AlignRight | Qt::AlignVCenter); - hlayout->addWidget(&label); - } - void setText(const QString &text) { label.setText(text); } - -private: - ElidedLabelSP label; -}; - -// widget for a button with a label -class ButtonControlSP : public AbstractControlSP { - Q_OBJECT - -public: - ButtonControlSP(const QString &title, const QString &text, const QString &desc = "", QWidget *parent = nullptr, bool advancedControl = false); - inline void setText(const QString &text) { btn.setText(text); } - inline QString text() const { return btn.text(); } - inline void click() { btn.click(); } - -signals: - void clicked(); - -public slots: - void setEnabled(bool enabled) { btn.setEnabled(enabled); } - -private: - QPushButton btn; -}; - -class ToggleControlSP : public AbstractControlSP { - Q_OBJECT - -public: - ToggleControlSP(const QString &title, const QString &desc = "", const QString &icon = "", const bool state = false, QWidget *parent = nullptr, bool advancedControl = false) : AbstractControlSP(title, desc, icon, parent, advancedControl) { - // space between toggle and title - icon_label = new QLabel(this); - hlayout->addWidget(icon_label); - - toggle.setFixedSize(150, 100); - if (state) { - toggle.togglePosition(); - } - hlayout->insertWidget(0, &toggle); - hlayout->insertWidget(1, this->icon_label); - QObject::connect(&toggle, &ToggleSP::stateChanged, this, &ToggleControlSP::toggleFlipped); - } - - void setEnabled(bool enabled) { - toggle.setEnabled(enabled); - toggle.update(); - } - -signals: - void toggleFlipped(bool state); - -protected: - ToggleSP toggle; -}; - -// widget to toggle params -class ParamControlSP : public ToggleControlSP { - Q_OBJECT - -public: - ParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr, bool advancedControl = false); - void setConfirmation(bool _confirm, bool _store_confirm) { - confirm = _confirm; - store_confirm = _store_confirm; - } - - void setActiveIcon(const QString &icon) { - active_icon_pixmap = QPixmap(icon).scaledToWidth(80, Qt::SmoothTransformation); - } - - void refresh() { - bool state = params.getBool(key); - if (state != toggle.on) { - toggle.togglePosition(); - setIcon(state); - } - } - - void showEvent(QShowEvent *event) override { - refresh(); - } - - bool isToggled() { return params.getBool(key); } - -private: - void toggleClicked(bool state); - void setIcon(bool state) { - if (state && !active_icon_pixmap.isNull()) { - icon_label->setPixmap(active_icon_pixmap); - } else if (!icon_pixmap.isNull()) { - icon_label->setPixmap(icon_pixmap); - } - } - - std::string key; - Params params; - QPixmap active_icon_pixmap; - bool confirm = false; - bool store_confirm = false; -}; - -class MultiButtonControlSP : public AbstractControlSP_SELECTOR { - Q_OBJECT - -public: - MultiButtonControlSP(const QString &title, const QString &desc, const QString &icon, - const std::vector &button_texts, const int minimum_button_width = 225, const bool inline_layout = false, bool advancedControl = false) : AbstractControlSP_SELECTOR(title, desc, icon, nullptr, advancedControl), button_texts(button_texts), is_inline_layout(inline_layout) { - const QString style = R"( - QPushButton { - border-radius: 20px; - font-size: 50px; - font-weight: 450; - height:150px; - padding: 0 25 0 25; - color: #FFFFFF; - } - QPushButton:pressed { - background-color: #4a4a4a; - } - QPushButton:checked:enabled { - background-color: #696868; - } - QPushButton:disabled { - color: #33FFFFFF; - } - QPushButton:checked:disabled { - background-color: #121212; - color: #33FFFFFF; - } - )"; - - if (inline_layout) { - button_param_layout->setMargin(0); - button_param_layout->setSpacing(0); - spacingItem = nullptr; - if (!title.isEmpty()) { - main_layout->removeWidget(title_label); - hlayout->addWidget(title_label, 1); - } - } - - button_group = new QButtonGroup(this); - button_group->setExclusive(true); - for (int i = 0; i < button_texts.size(); i++) { - QPushButton *button = new QPushButton(button_texts[i], this); - button->setCheckable(true); - button->setStyleSheet(style); - button->setMinimumWidth(minimum_button_width); - if (i == 0) button_param_layout->addSpacing(2); - button_param_layout->addWidget(button); - button_group->addButton(button, i); - } - - button_param_layout->setAlignment(Qt::AlignLeft); - if (is_inline_layout) { - QFrame *container = new QFrame; - container->setLayout(button_param_layout); - container->setStyleSheet("background-color: #393939; border-radius: 20px;"); - hlayout->addWidget(container); - } - - QObject::connect(button_group, QOverload::of(&QButtonGroup::buttonClicked), this, &MultiButtonControlSP::buttonClicked); - } - - void setEnabled(bool enable) { - for (auto btn: button_group->buttons()) { - btn->setEnabled(enable); - } - button_group_enabled = enable; - - update(); - } - - void setCheckedButton(int id) { - button_group->button(id)->setChecked(true); - } - - void refresh() { - int value = atoi(params.get(key).c_str()); - - if (value >= button_texts.size()) { - value = button_texts.size() - 1; - } - if (value < 0) { - value = 0; - } - - button_group->button(value)->setChecked(true); - } - - void showEvent(QShowEvent *event) override { - refresh(); - } - - void setButton(QString param) { - key = param.toStdString(); - int value = atoi(params.get(key).c_str()); - for (int i = 0; i < button_group->buttons().size(); i++) { - button_group->buttons()[i]->setChecked(i == value); - } - } - - void setEnableSelectedButtons(bool enable, const std::vector& enabled_btns = {}) const { - for (int i = 0; i < button_group->buttons().size(); i++) { - // Enable the button if its index is in the enabled list - bool should_enable = std::find(enabled_btns.begin(), enabled_btns.end(), i) != enabled_btns.end(); - button_group->buttons()[i]->setEnabled(enable && should_enable); - } - } - -protected: - QButtonGroup *button_group; - void paintEvent(QPaintEvent *event) override { - if (is_inline_layout) { - return; - } - - QPainter p(this); - p.setRenderHint(QPainter::Antialiasing); - - // Calculate the total width and height for the background rectangle - int w = 0; - int h = 150; - - for (int i = 0; i < hlayout->count(); ++i) { - QPushButton *button = qobject_cast(hlayout->itemAt(i)->widget()); - if (button) { - w += button->width(); - } - } - - // Draw the rectangle -#ifdef __APPLE__ - QRect rect(0 + 2, h - 16, w, h); -#else - QRect rect(0 + 2, h - 24, w, h); -#endif - p.setPen(QPen(QColor(button_group_enabled ? "#696868" : "#121212"), 3)); - p.drawRoundedRect(rect, 20, 20); - } - -signals: - void buttonClicked(int id); - -private: - std::string key; - Params params; - std::vector button_texts; - - bool button_group_enabled = true; - bool is_inline_layout; - QHBoxLayout *button_param_layout = is_inline_layout ? new QHBoxLayout() : hlayout; -}; - -class ButtonParamControlSP : public MultiButtonControlSP { - Q_OBJECT -public: - ButtonParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, - const std::vector &button_texts, const int minimum_button_width = 380, const bool inline_layout = false, bool advancedControl = false) : MultiButtonControlSP(title, desc, icon, - button_texts, minimum_button_width, inline_layout, advancedControl) { - key = param.toStdString(); - int value = atoi(params.get(key).c_str()); - - if (value > 0 && value < button_group->buttons().size()) { - button_group->button(value)->setChecked(true); - } - - QObject::connect(this, QOverload::of(&MultiButtonControlSP::buttonClicked), [=](int id) { - params.put(key, std::to_string(id)); - }); - } - - void refresh() { - int value = atoi(params.get(key).c_str()); - button_group->button(value)->setChecked(true); - } - - void showEvent(QShowEvent *event) override { - refresh(); - } - -private: - std::string key; - Params params; -}; - -class ListWidgetSP : public QWidget { - Q_OBJECT - -public: - explicit ListWidgetSP(QWidget *parent = 0, const bool split_line = true) : QWidget(parent), _split_line(split_line), outer_layout(this) { - outer_layout.setMargin(0); - outer_layout.setSpacing(0); - outer_layout.addLayout(&inner_layout); - inner_layout.setMargin(0); - inner_layout.setSpacing(25); // default spacing is 25 - outer_layout.addStretch(1); - } - inline void addItem(QWidget *w) { inner_layout.addWidget(w); } - inline void addItem(QLayout *layout) { inner_layout.addLayout(layout); } - inline void setSpacing(int spacing) { inner_layout.setSpacing(spacing); } - - inline void AddWidgetAt(const int index, QWidget *new_widget) { inner_layout.insertWidget(index, new_widget); } - inline void RemoveWidgetAt(const int index) { - if (QLayoutItem *item; (item = inner_layout.takeAt(index)) != nullptr) { - if (item->widget()) delete item->widget(); - delete item; - } - } - - inline void ReplaceOrAddWidget(QWidget *old_widget, QWidget *new_widget) { - if (const int index = inner_layout.indexOf(old_widget); index != -1) { - RemoveWidgetAt(index); - AddWidgetAt(index, new_widget); - } else { - addItem(new_widget); - } - } - -private: - void paintEvent(QPaintEvent *) override { - QPainter p(this); - p.setPen(Qt::gray); - for (int i = 0; i < inner_layout.count() - 1; ++i) { - QWidget *widget = inner_layout.itemAt(i)->widget(); - if ((widget == nullptr || widget->isVisible()) && _split_line) { - QRect r = inner_layout.itemAt(i)->geometry(); - int bottom = r.bottom() + inner_layout.spacing() / 2; - p.drawLine(r.left(), bottom, r.right(), bottom); - } - } - } - QVBoxLayout outer_layout; - QVBoxLayout inner_layout; - - bool _split_line; -}; - -// convenience class for wrapping layouts -class LayoutWidgetSP : public QWidget { - Q_OBJECT - -public: - LayoutWidgetSP(QLayout *l, QWidget *parent = nullptr) : QWidget(parent) { - setLayout(l); - } -}; - -class OptionControlSP : public AbstractControlSP_SELECTOR { - Q_OBJECT - -protected: - struct MinMaxValue { - int min_value; - int max_value; - }; - -private: - bool is_inline_layout; - QHBoxLayout *optionSelectorLayout = is_inline_layout ? new QHBoxLayout() : hlayout; - - int getParamValue() { - const auto param_value = QString::fromStdString(params.get(key)); - const auto result = valueMap != nullptr ? valueMap->key(param_value) : param_value; - return result.toInt(); - } - - int getParamValueScaled() { - const auto param_value = QString::fromStdString(params.get(key)); - return std::nearbyint(param_value.toFloat() * 100.0f); - } - - void setParamValueScaled(const int new_value) { - const float scaled_value = new_value / 100.0f; - params.put(key, QString::number(scaled_value, 'f', 2).toStdString()); - } - - // Although the method is not static, and thus has access to the value property, I prefer to be explicit about the value. - void setParamValue(const int new_value) { - const auto value_str = valueMap != nullptr ? valueMap->value(QString::number(new_value)) : QString::number(new_value); - params.put(key, value_str.toStdString()); - } - -public: - OptionControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, - const MinMaxValue &range, const int per_value_change = 1, const bool inline_layout = false, - const QMap *valMap = nullptr, bool scale_float = false, bool advancedControl = false) : AbstractControlSP_SELECTOR(title, desc, icon, nullptr, advancedControl), _title(title), valueMap(valMap), is_inline_layout(inline_layout), use_float_scaling(scale_float) { - const QString style = R"( - QPushButton { - border-radius: 20px; - font-size: 60px; - font-weight: 500; - width: 150px; - height: 150px; - padding: -3 25 3 25; - color: #FFFFFF; - font-weight: bold; - } - QPushButton:pressed { - color: #5C5C5C; - } - QPushButton:disabled { - color: #5C5C5C; - } - )"; - - if (inline_layout) { - optionSelectorLayout->setMargin(0); - optionSelectorLayout->setSpacing(0); - if (!title.isEmpty()) { - main_layout->removeWidget(title_label); - hlayout->addWidget(title_label, 1); - } - main_layout->removeItem(spacingItem); - spacingItem = nullptr; - } - - label.setStyleSheet(label_enabled_style); - label.setFixedWidth(inline_layout ? 350 : 300); - label.setAlignment(Qt::AlignCenter); - - const std::vector button_texts{"-", "+"}; - - key = param.toStdString(); - value = use_float_scaling ? getParamValueScaled() : getParamValue(); - - button_group = new QButtonGroup(this); - button_group->setExclusive(true); - for (int i = 0; i < button_texts.size(); i++) { - QPushButton *button = new QPushButton(button_texts[i], this); - button->setStyleSheet(style + ((i == 0) ? "QPushButton { text-align: left; }" : - "QPushButton { text-align: right; }")); - optionSelectorLayout->addWidget(button, 0, ((i == 0) ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignVCenter); - if (i == 0) { - optionSelectorLayout->addWidget(&label, 0, Qt::AlignCenter); - } - button->setEnabled((i == 0) ? !(value <= range.min_value) : !(value >= range.max_value)); - button->setFocusPolicy(Qt::NoFocus); // This prevents unintended scroll due to loss of focus when the button gets disabled based on min/max values - button_group->addButton(button, i); - - QObject::connect(button, &QPushButton::clicked, [=]() { - int change_value = (i == 0) ? -per_value_change : per_value_change; - value = use_float_scaling ? getParamValueScaled() : getParamValue(); - value += change_value; - value = std::clamp(value, range.min_value, range.max_value); - - if (use_float_scaling) { - setParamValueScaled(value); - } else { - setParamValue(value); - } - - button_group->button(0)->setEnabled(!(value <= range.min_value)); - button_group->button(1)->setEnabled(!(value >= range.max_value)); - - updateLabels(); - - if (request_update) { - emit updateOtherToggles(); - } - }); - } - - optionSelectorLayout->setAlignment(Qt::AlignLeft); - if (is_inline_layout) { - QFrame *container = new QFrame; - container->setLayout(optionSelectorLayout); - container->setStyleSheet("background-color: #393939; border-radius: 20px;"); - hlayout->addWidget(container); - } - } - - void setUpdateOtherToggles(bool _update) { - request_update = _update; - } - - void setFixedWidth(int width) { - label.setFixedWidth(width); - } - - inline void setLabel(const QString &text) { label.setText(text); } - - void setEnabled(bool enabled) { - for (auto btn: button_group->buttons()) { - btn->setEnabled(enabled); - } - label.setEnabled(enabled); - label.setStyleSheet(enabled ? label_enabled_style : label_disabled_style); - button_enabled = enabled; - - update(); - } - -protected: - void paintEvent(QPaintEvent *event) override { - if (is_inline_layout) { - return; - } - - QPainter p(this); - p.setRenderHint(QPainter::Antialiasing); - - // Calculate the total width and height for the background rectangle - int w = 0; - int h = 150; - - for (int i = 0; i < optionSelectorLayout->count(); ++i) { - QWidget *widget = qobject_cast(optionSelectorLayout->itemAt(i)->widget()); - if (widget) { - w += widget->width(); - } - } - - // Draw the rectangle -#ifdef __APPLE__ - QRect rect(0, !_title.isEmpty() ? (h - 16) : 20, w, h); -#else - QRect rect(0, !_title.isEmpty() ? (h - 24) : 20, w, h); -#endif - p.setBrush(QColor(button_enabled ? "#b24a4a4a" : "#121212")); // Background color - p.setPen(QPen(Qt::NoPen)); - p.drawRoundedRect(rect, 20, 20); - } - -signals: - void updateLabels(); - void updateOtherToggles(); - -private: - std::string key; - int value; - QButtonGroup *button_group; - QLabel label; - Params params; - std::map option_label = {}; - bool request_update = false; - QString _title = ""; - const QMap *valueMap; - - const QString label_enabled_style = "font-size: 50px; font-weight: 450; color: #FFFFFF;"; - const QString label_disabled_style = "font-size: 50px; font-weight: 450; color: #5C5C5C;"; - - bool button_enabled = true; - bool use_float_scaling = false; -}; - -class PushButtonSP : public QPushButton { - Q_OBJECT - -public: - PushButtonSP(const QString &text, const int minimum_button_width = 800, QWidget *parent = nullptr, const QString ¶m = "") : QPushButton(text, parent) { - buttonStyle = R"( - QPushButton { - border-radius: 20px; - font-size: 50px; - font-weight: 450; - height: 150px; - padding: 0 25px 0 25px; - color: #FFFFFF; - } - )"; - - if (!param.isEmpty()) { - key = param.toStdString(); - refresh(); - } else { - updateStyle(false); - } - - setFixedWidth(minimum_button_width); - } - - void refresh() { - if (!key.empty()) { - bool state = params.getBool(key); - if (state != is_enabled) { - is_enabled = state; - } - updateStyle(is_enabled); - } - } - - void updateButton() { - if (!key.empty()) { - params.putBool(key, !is_enabled); - refresh(); - } - } - -private: - std::string key = ""; - Params params; - bool is_enabled; - QString buttonStyle; - - QString btn_enabled_off_style = "QPushButton:enabled { background-color: #393939; }"; - QString btn_enabled_on_style = "QPushButton:enabled { background-color: #1e79e8; }"; - QString btn_off_pressed_style = "QPushButton:pressed { background-color: #4A4A4A; }"; - QString btn_on_pressed_style = "QPushButton:pressed { background-color: #1E8FFF; }"; - QString btn_disabled_style = "QPushButton:disabled { background-color: #121212; color: #5C5C5C; }"; - - void updateStyle(bool enabled) { - QString enabled_style = enabled ? btn_enabled_on_style : btn_enabled_off_style; - QString pressed_style = enabled ? btn_on_pressed_style : btn_off_pressed_style; - setStyleSheet(buttonStyle + enabled_style + pressed_style + btn_disabled_style); - } -}; - -class PanelBackButton : public QPushButton { - Q_OBJECT - -public: - PanelBackButton(const QString &label = "Back", QWidget *parent = nullptr) : QPushButton(label, parent) { - setObjectName("back_btn"); - setFixedSize(400, 100); - } -}; - -inline QString RainbowizeWords(const QString &text) { - const QStringList colors = { - "#FF6F61", // soft coral red - "#FFA177", // warm peach - "#FFD966", // soft golden yellow - "#88D498", // mint green - "#6EC6FF", // sky blue - "#A78BFA", // soft lavender - "#F78FB3" // rose pink - }; - - QString result; - QStringList words = text.split(' '); - - for (int i = 0; i < words.size(); ++i) { - result += QString("%2 ").arg(colors[i % colors.size()]).arg(words[i].toHtmlEscaped()); - } - - return result.trimmed(); - } diff --git a/selfdrive/ui/sunnypilot/qt/widgets/drive_stats.cc b/selfdrive/ui/sunnypilot/qt/widgets/drive_stats.cc deleted file mode 100644 index bfdcac2564..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/drive_stats.cc +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h" - -#include -#include -#include - -#include "common/params.h" -#include "selfdrive/ui/qt/request_repeater.h" -#include "selfdrive/ui/qt/util.h" - -static QLabel* newLabel(const QString& text, const QString &type) { - QLabel* label = new QLabel(text); - label->setProperty("type", type); - return label; -} - -DriveStats::DriveStats(QWidget* parent) : QFrame(parent) { - metric_ = Params().getBool("IsMetric"); - - QVBoxLayout* main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(50, 50, 50, 60); - - auto add_stats_layouts = [=](const QString &title, StatsLabels& labels) { - QGridLayout* grid_layout = new QGridLayout; - grid_layout->setVerticalSpacing(10); - grid_layout->setContentsMargins(0, 10, 0, 10); - - int row = 0; - grid_layout->addWidget(newLabel(title, "title"), row++, 0, 1, 3); - grid_layout->addItem(new QSpacerItem(0, 30), row++, 0, 1, 1); - - grid_layout->addWidget(labels.routes = newLabel("0", "number"), row, 0, Qt::AlignLeft); - grid_layout->addWidget(labels.distance = newLabel("0", "number"), row, 1, Qt::AlignLeft); - 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(newLabel(tr("Hours"), "unit"), row + 1, 2, Qt::AlignLeft); - - main_layout->addLayout(grid_layout); - }; - - add_stats_layouts(tr("ALL TIME"), all_); - main_layout->addStretch(); - add_stats_layouts(tr("PAST WEEK"), week_); - - if (auto dongleId = getDongleId()) { - QString url = CommaApi::BASE_URL + "/v1.1/devices/" + *dongleId + "/stats"; - RequestRepeater* repeater = new RequestRepeater(this, url, "ApiCache_DriveStats", 30); - QObject::connect(repeater, &RequestRepeater::requestDone, this, &DriveStats::parseResponse); - } - - setStyleSheet(R"( - DriveStats { - background-color: #333333; - border-radius: 10px; - } - - QLabel[type="title"] { font-size: 51px; font-weight: 500; } - QLabel[type="number"] { font-size: 78px; font-weight: 500; } - QLabel[type="unit"] { font-size: 51px; font-weight: 300; color: #A0A0A0; } - )"); -} - -void DriveStats::updateStats() { - auto update = [=](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))); - }; - - QJsonObject json = stats_.object(); - update(json["all"].toObject(), all_); - update(json["week"].toObject(), week_); -} - -void DriveStats::parseResponse(const QString& response, bool success) { - if (!success) return; - - QJsonDocument doc = QJsonDocument::fromJson(response.trimmed().toUtf8()); - if (doc.isNull()) { - qDebug() << "JSON Parse failed on getting past drives statistics"; - return; - } - stats_ = doc; - updateStats(); -} - -void DriveStats::showEvent(QShowEvent* event) { - bool metric = Params().getBool("IsMetric"); - if (metric_ != metric) { - metric_ = metric; - updateStats(); - } -} diff --git a/selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h b/selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h deleted file mode 100644 index 0b2802ed8c..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include -#include - -class DriveStats : public QFrame { - Q_OBJECT - -public: - explicit DriveStats(QWidget* parent = 0); - -private: - void showEvent(QShowEvent *event) override; - void updateStats(); - inline QString getDistanceUnit() const { return metric_ ? tr("KM") : tr("Miles"); } - - bool metric_; - QJsonDocument stats_; - struct StatsLabels { - QLabel *routes, *distance, *distance_unit, *hours; - } all_, week_; - -private slots: - void parseResponse(const QString &response, bool success); -}; diff --git a/selfdrive/ui/sunnypilot/qt/widgets/expandable_row.cc b/selfdrive/ui/sunnypilot/qt/widgets/expandable_row.cc deleted file mode 100644 index b22684a295..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/expandable_row.cc +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h" - -ExpandableToggleRow::ExpandableToggleRow(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent) - : ToggleControlSP(title, desc, icon, false, parent) { - - key = param.toStdString(); - QObject::connect(this, &ExpandableToggleRow::toggleFlipped, this, &ExpandableToggleRow::toggleClicked); - - collapsibleWidget = new QFrame(this); - collapsibleWidget->setVisible(false); - QVBoxLayout *collapsible_layout = new QVBoxLayout(); - collapsibleWidget->setLayout(collapsible_layout); - collapsible_layout->setContentsMargins(0, 0, 0, 0); - - list = new ListWidgetSP(this, false); - - main_layout->addWidget(collapsibleWidget); - collapsible_layout->addWidget(list); -} - -void ExpandableToggleRow::toggleClicked(bool state) { - params.putBool(key, state); - collapsibleWidget->setVisible(state); -} diff --git a/selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h b/selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h deleted file mode 100644 index 4bfcb9ef55..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" - -class ExpandableToggleRow : public ToggleControlSP { - Q_OBJECT - -public: - ExpandableToggleRow(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr); - - void addItem(QWidget *widget) { - list->addItem(widget); - } - - ListWidgetSP *innerList() { - return list; - } - - void refresh() { - bool state = params.getBool(key); - if (state != toggle.on) { - toggle.togglePosition(); - } - collapsibleWidget->setVisible(state); - } - - bool isToggled() { - return params.getBool(key); - } - - void showEvent(QShowEvent *event) override { - refresh(); - } - -private: - void toggleClicked(bool state); - - std::string key; - Params params; - - ListWidgetSP *list; - QFrame *collapsibleWidget = nullptr; -}; diff --git a/selfdrive/ui/sunnypilot/qt/widgets/external_storage.cc b/selfdrive/ui/sunnypilot/qt/widgets/external_storage.cc deleted file mode 100644 index f951187511..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/external_storage.cc +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/widgets/external_storage.h" - -#include -#include -#include -#include -#include - -#include "common/params.h" -#include "selfdrive/ui/qt/api.h" -#include "selfdrive/ui/qt/widgets/input.h" -#include "selfdrive/ui/sunnypilot/ui.h" - -ExternalStorageControl::ExternalStorageControl() : - ButtonControl(tr("External Storage"), "", tr("Extend your comma device's storage by inserting a USB drive into the aux port.")) { - - QObject::connect(this, &ButtonControl::clicked, [=]() { - if (text() == tr("CHECK") || text() == tr("MOUNT")) { - mountStorage(); - } else if (text() == tr("UNMOUNT")) { - unmountStorage(); - } else if (text() == tr("FORMAT")) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to format this drive? This will erase all data."), tr("Format"), this)) { - formatStorage(); - } - } - }); - - QObject::connect(uiState(), &UIState::offroadTransition, this, &ExternalStorageControl::updateState); - updateState(!uiState()->scene.started); - - refresh(); -} - -void ExternalStorageControl::updateState(bool offroad) { - setEnabled(offroad); -} - -void ExternalStorageControl::debouncedRefresh() { - if (refreshPending) return; - refreshPending = true; - - QTimer::singleShot(250, this, [=]() { - refreshPending = false; - refresh(); - }); -} - -void ExternalStorageControl::refresh() { - QtConcurrent::run([=]() { - auto run = [](const QString &cmd) { - QProcess p; - p.start("sh", QStringList() << "-c" << cmd); - p.waitForFinished(); - return p.exitCode() == 0; - }; - - bool isMounted = run("findmnt -n /mnt/external_realdata"); - bool hasDrive = run("lsblk -f /dev/sdg"); - bool hasFs = run("lsblk -f /dev/sdg1 | grep -q ext4"); - bool hasLabel = run("sudo blkid /dev/sdg1 | grep -q 'LABEL=\"openpilot\"'"); - - QString info; - if (isMounted && hasLabel) { - QProcess df; - df.start("sh", QStringList() << "-c" << "df -h /mnt/external_realdata | awk 'NR==2 {print $3 \"/\" $2}'"); - df.waitForFinished(); - info = df.readAllStandardOutput().trimmed(); - } - - QMetaObject::invokeMethod(this, [=]() { - if (formatting) { - setValue(tr("formatting")); - setText(tr("FORMAT")); - setEnabled(false); - } else { - if (!hasDrive) { - setValue(tr("insert drive")); - setText(tr("CHECK")); - } else if (!hasFs || !hasLabel) { - setValue(tr("needs format")); - setText(tr("FORMAT")); - } else if (isMounted) { - setValue(info); - setText(tr("UNMOUNT")); - } else { - setValue("drive detected"); - setText(tr("MOUNT")); - } - updateState(!uiState()->scene.started); - } - }, Qt::QueuedConnection); - }); -} - -void ExternalStorageControl::mountStorage() { - setValue(tr("mounting")); - setEnabled(false); - - QtConcurrent::run([=]() { - QProcess process; - process.start("sh", QStringList() << "-c" << - "sudo mount -o remount,rw / && " - "sudo mkdir -p /mnt/external_realdata && " - "grep -q '/dev/sdg1 /mnt/external_realdata' /etc/fstab || " - "echo '/dev/sdg1 /mnt/external_realdata ext4 defaults,nofail 0 2' | sudo tee -a /etc/fstab && " - "sudo systemctl daemon-reexec && " - "sudo mount /mnt/external_realdata && " - "sudo chown -R comma:comma /mnt/external_realdata && " - "sudo chmod -R 775 /mnt/external_realdata && " - "sudo mount -o remount,ro /"); - process.waitForFinished(); - - QMetaObject::invokeMethod(this, [=]() { - debouncedRefresh(); - }, Qt::QueuedConnection); - }); -} - -void ExternalStorageControl::unmountStorage() { - setValue(tr("unmounting")); - setEnabled(false); - - QtConcurrent::run([=]() { - QProcess process; - process.start("sh", QStringList() << "-c" << "sudo umount /mnt/external_realdata"); - process.waitForFinished(); - - QMetaObject::invokeMethod(this, [=]() { - debouncedRefresh(); - }, Qt::QueuedConnection); - }); -} - -void ExternalStorageControl::formatStorage() { - unmountStorage(); - formatting = true; - setValue(tr("formatting")); - setEnabled(false); - - QProcess *process = new QProcess(this); - connect(process, static_cast(&QProcess::finished), - this, [=](int exitCode, QProcess::ExitStatus status) { - process->deleteLater(); - formatting = false; - if (exitCode == 0 && status == QProcess::NormalExit) { - mountStorage(); - } else { - setValue(tr("needs format")); - updateState(!uiState()->scene.started); - } - }); - process->start("sh", QStringList() << "-c" << - "sudo wipefs -a /dev/sdg && " - "sudo parted -s /dev/sdg mklabel gpt mkpart primary ext4 0% 100% && " - "sudo mkfs.ext4 -F -L openpilot /dev/sdg1" - ); -} - -void ExternalStorageControl::showEvent(QShowEvent *event) { - ButtonControl::showEvent(event); - QTimer::singleShot(100, this, &ExternalStorageControl::debouncedRefresh); -} diff --git a/selfdrive/ui/sunnypilot/qt/widgets/external_storage.h b/selfdrive/ui/sunnypilot/qt/widgets/external_storage.h deleted file mode 100644 index d26eefd18c..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/external_storage.h +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "system/hardware/hw.h" -#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" -#define ButtonControl ButtonControlSP - -class ExternalStorageControl : public ButtonControl { - Q_OBJECT - -public: - ExternalStorageControl(); - -protected: - void showEvent(QShowEvent *event) override; - -private: - Params params; - - bool refreshPending = false; - bool formatting = false; - void updateState(bool offroad); - void refresh(); - void debouncedRefresh(); - void mountStorage(); - void unmountStorage(); - void formatStorage(); -}; diff --git a/selfdrive/ui/sunnypilot/qt/widgets/prime.cc b/selfdrive/ui/sunnypilot/qt/widgets/prime.cc deleted file mode 100644 index a1bb85c787..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/prime.cc +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/widgets/prime.h" - -SetupWidgetSP::SetupWidgetSP(QWidget *parent) : SetupWidget(parent) { - PrimeUserWidget *primeUser = new PrimeUserWidget; - content_layout->insertWidget(0, primeUser); - - primeUser->setVisible(uiState()->prime_state->isSubscribed()); - - QObject::connect(uiState()->prime_state, &PrimeState::changed, [=]() { - primeUser->setVisible(uiState()->prime_state->isSubscribed()); - }); -} diff --git a/selfdrive/ui/sunnypilot/qt/widgets/prime.h b/selfdrive/ui/sunnypilot/qt/widgets/prime.h deleted file mode 100644 index 598b0e62eb..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/prime.h +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/widgets/prime.h" - -#include "selfdrive/ui/sunnypilot/ui.h" - -class SetupWidgetSP : public SetupWidget { - Q_OBJECT - -public: - explicit SetupWidgetSP(QWidget *parent = nullptr); -}; diff --git a/selfdrive/ui/sunnypilot/qt/widgets/scrollview.cc b/selfdrive/ui/sunnypilot/qt/widgets/scrollview.cc deleted file mode 100644 index ba9a367b0e..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/scrollview.cc +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" - -#include - -void ScrollViewSP::setLastScrollPosition() { - lastScrollPosition = verticalScrollBar()->value(); -} - -void ScrollViewSP::restoreScrollPosition() { - verticalScrollBar()->setValue(lastScrollPosition); -} diff --git a/selfdrive/ui/sunnypilot/qt/widgets/scrollview.h b/selfdrive/ui/sunnypilot/qt/widgets/scrollview.h deleted file mode 100644 index 5c20bce2f2..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/scrollview.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/widgets/scrollview.h" - -class ScrollViewSP : public ScrollView { - Q_OBJECT - -public: - explicit ScrollViewSP(QWidget *w = nullptr, QWidget *parent = nullptr) : ScrollView(w, parent) {} - -public slots: - void setLastScrollPosition(); - void restoreScrollPosition(); - -private: - int lastScrollPosition = 0; -}; diff --git a/selfdrive/ui/sunnypilot/qt/widgets/toggle.cc b/selfdrive/ui/sunnypilot/qt/widgets/toggle.cc deleted file mode 100644 index 601c8f94c1..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/toggle.cc +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/widgets/toggle.h" - -#include - -ToggleSP::ToggleSP(QWidget *parent) : Toggle(parent) { - _height_rect = 80; -} - -void ToggleSP::paintEvent(QPaintEvent *e) { - this->setFixedHeight(100); - QPainter p(this); - p.setPen(Qt::NoPen); - p.setRenderHint(QPainter::Antialiasing, true); - - // Draw toggle background - enabled ? green.setRgb(0x1e79e8) : green.setRgb(0x125db8); - p.setBrush(on ? green : QColor(0x292929)); - p.drawRoundedRect(QRect(0, 10, width(), _height_rect), _height_rect / 2, _height_rect / 2); - - // Draw toggle circle - p.setBrush(circleColor); - p.drawEllipse(QRectF(_x_circle - _radius + 6, 16, 68, 68)); -} diff --git a/selfdrive/ui/sunnypilot/qt/widgets/toggle.h b/selfdrive/ui/sunnypilot/qt/widgets/toggle.h deleted file mode 100644 index e98dea39af..0000000000 --- a/selfdrive/ui/sunnypilot/qt/widgets/toggle.h +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/widgets/toggle.h" - -class ToggleSP : public Toggle { - Q_OBJECT - -public: - explicit ToggleSP(QWidget *parent = nullptr); - -protected: - void paintEvent(QPaintEvent *) override; -}; diff --git a/selfdrive/ui/sunnypilot/qt/window.cc b/selfdrive/ui/sunnypilot/qt/window.cc deleted file mode 100644 index f332e1ed8e..0000000000 --- a/selfdrive/ui/sunnypilot/qt/window.cc +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/qt/window.h" - -MainWindowSP::MainWindowSP(QWidget *parent) - : MainWindow(parent, new HomeWindowSP(parent), new SettingsWindowSP(parent)) { - - homeWindow = dynamic_cast(MainWindow::homeWindow); - settingsWindow = dynamic_cast(MainWindow::settingsWindow); -} - -void MainWindowSP::closeSettings() { - MainWindow::closeSettings(); -} diff --git a/selfdrive/ui/sunnypilot/qt/window.h b/selfdrive/ui/sunnypilot/qt/window.h deleted file mode 100644 index d4c0900901..0000000000 --- a/selfdrive/ui/sunnypilot/qt/window.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include "selfdrive/ui/qt/window.h" -#include "selfdrive/ui/sunnypilot/qt/home.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" - -class MainWindowSP : public MainWindow { - Q_OBJECT - -public: - explicit MainWindowSP(QWidget *parent = 0); - -private: - HomeWindowSP *homeWindow; - SettingsWindowSP *settingsWindow; - void closeSettings() override; -}; diff --git a/selfdrive/ui/sunnypilot/quiet_mode.py b/selfdrive/ui/sunnypilot/quiet_mode.py deleted file mode 100644 index 893df95033..0000000000 --- a/selfdrive/ui/sunnypilot/quiet_mode.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - -This file is part of sunnypilot and is licensed under the MIT License. -See the LICENSE.md file in the root directory for more details. -""" -from cereal import car - -from openpilot.common.params import Params - -AudibleAlert = car.CarControl.HUDControl.AudibleAlert - -ALERTS_ALWAYS_PLAY = { - AudibleAlert.warningSoft, - AudibleAlert.warningImmediate, - AudibleAlert.promptDistracted, - AudibleAlert.promptRepeat, -} - -class QuietMode: - def __init__(self): - self.params = Params() - self.enabled: bool = self.params.get_bool("QuietMode") - self._frame = 0 - - def load_param(self) -> None: - self._frame += 1 - if self._frame % 50 == 0: # 2.5 seconds - self.enabled = self.params.get_bool("QuietMode") - - def should_play_sound(self, current_alert: int) -> bool: - """ - Check if a sound should be played based on the Quiet Mode setting - and the current alert. - """ - if not self.enabled: - return bool(current_alert != AudibleAlert.none) - - return current_alert in ALERTS_ALWAYS_PLAY diff --git a/selfdrive/ui/sunnypilot/ui.cc b/selfdrive/ui/sunnypilot/ui.cc deleted file mode 100644 index df7b3ce5ca..0000000000 --- a/selfdrive/ui/sunnypilot/ui.cc +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#include "selfdrive/ui/sunnypilot/ui.h" - -#include "common/watchdog.h" - -void UIStateSP::updateStatus() { - UIState::updateStatus(); - - if (scene.started && scene.onroadScreenOffControl) { - auto selfdriveState = (*sm)["selfdriveState"].getSelfdriveState(); - if (selfdriveState.getAlertSize() != cereal::SelfdriveState::AlertSize::NONE) { - reset_onroad_sleep_timer(); - } else if (scene.onroadScreenOffTimer > 0) { - scene.onroadScreenOffTimer--; - } - } -} - -UIStateSP::UIStateSP(QObject *parent) : UIState(parent) { - sm = std::make_unique(std::vector{ - "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", - "pandaStates", "carParams", "driverMonitoringState", "carState", "driverStateV2", - "wideRoadCameraState", "managerState", "selfdriveState", "longitudinalPlan", - "modelManagerSP", "selfdriveStateSP", "longitudinalPlanSP", "backupManagerSP", - "carControl", "gpsLocationExternal", "gpsLocation", "liveTorqueParameters", - "carStateSP", "liveParameters", "liveMapDataSP", "carParamsSP" - }); - - // update timer - timer = new QTimer(this); - QObject::connect(timer, &QTimer::timeout, this, &UIStateSP::update); - timer->start(1000 / UI_FREQ); - - // Param watcher for UIScene param updates - param_watcher = new ParamWatcher(this); - connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { - ui_update_params_sp(this); - }); - param_watcher->addParam("DevUIInfo"); - param_watcher->addParam("StandstillTimer"); -} - -// This method overrides completely the update method from the parent class intentionally. -void UIStateSP::update() { - update_sockets(this); - update_state(this); - updateStatus(); - - if (sm->frame % UI_FREQ == 0) { - watchdog_kick(nanos_since_boot()); - } - emit uiUpdate(*this); -} - -void ui_update_params_sp(UIStateSP *s) { - auto params = Params(); - s->scene.dev_ui_info = std::atoi(params.get("DevUIInfo").c_str()); - s->scene.standstill_timer = params.getBool("StandstillTimer"); - s->scene.speed_limit_mode = std::atoi(params.get("SpeedLimitMode").c_str()); - s->scene.road_name = params.getBool("RoadNameToggle"); - s->scene.trueVEgoUI = params.getBool("TrueVEgoUI"); - s->scene.hideVEgoUI = params.getBool("HideVEgoUI"); - - // Onroad Screen Brightness - s->scene.onroadScreenOffBrightness = std::atoi(params.get("OnroadScreenOffBrightness").c_str()); - s->scene.onroadScreenOffControl = params.getBool("OnroadScreenOffControl"); - s->scene.onroadScreenOffTimerParam = std::atoi(params.get("OnroadScreenOffTimer").c_str()); - - s->scene.turn_signals = params.getBool("ShowTurnSignals"); - s->scene.chevron_info = std::atoi(params.get("ChevronInfo").c_str()); - s->scene.blindspot_ui = params.getBool("BlindSpot"); - s->scene.rainbow_mode = params.getBool("RainbowMode"); -} - -void UIStateSP::reset_onroad_sleep_timer(OnroadTimerStatusToggle toggleTimerStatus) { - // Toggling from active state to inactive - if (toggleTimerStatus == OnroadTimerStatusToggle::PAUSE and scene.onroadScreenOffTimer != -1) { - scene.onroadScreenOffTimer = -1; - } - // Toggling from a previously inactive state or resetting an active timer - else if ((scene.onroadScreenOffTimerParam >= 0 and scene.onroadScreenOffControl and scene.onroadScreenOffTimer != -1) or toggleTimerStatus == OnroadTimerStatusToggle::RESUME) { - scene.onroadScreenOffTimer = scene.onroadScreenOffTimerParam * UI_FREQ; - } -} - -DeviceSP::DeviceSP(QObject *parent) : Device(parent) { - QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &DeviceSP::update); - QObject::connect(this, &Device::displayPowerChanged, this, &DeviceSP::handleDisplayPowerChanged); -} - -UIStateSP *uiStateSP() { - static UIStateSP ui_state; - return &ui_state; -} - -void UIStateSP::setSunnylinkRoles(const std::vector& roles) { - sunnylinkRoles = roles; - emit sunnylinkRolesChanged(roles); -} - -void UIStateSP::setSunnylinkDeviceUsers(const std::vector& users) { - sunnylinkUsers = users; - emit sunnylinkDeviceUsersChanged(users); -} - -DeviceSP *deviceSP() { - static DeviceSP _device; - return &_device; -} - -void DeviceSP::handleDisplayPowerChanged(bool on) { - // if enabled, trigger offroad mode when device goes to sleep - if (params.get("DeviceBootMode") == "1" && not on) { - params.putBool("OffroadMode", true); - } -} diff --git a/selfdrive/ui/sunnypilot/ui.h b/selfdrive/ui/sunnypilot/ui.h deleted file mode 100644 index ba5de83ef6..0000000000 --- a/selfdrive/ui/sunnypilot/ui.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -#include - -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/user_model.h" -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h" -#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/sponsor_role_model.h" -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/util.h" - -enum OnroadTimerStatusToggle { - NONE, - PAUSE, - RESUME -}; - -class UIStateSP : public UIState { - Q_OBJECT - -public: - UIStateSP(QObject *parent = 0); - void updateStatus() override; - inline bool engaged() const override { - return scene.started && ( - (*sm)["selfdriveState"].getSelfdriveState().getEnabled() || (*sm)["selfdriveStateSP"].getSelfdriveStateSP().getMads().getEnabled() - ); - } - void setSunnylinkRoles(const std::vector &roles); - void setSunnylinkDeviceUsers(const std::vector &users); - - inline std::vector sunnylinkDeviceRoles() const { return sunnylinkRoles; } - inline bool isSunnylinkAdmin() const { - return std::any_of(sunnylinkRoles.begin(), sunnylinkRoles.end(), [](const RoleModel &role) { - return role.roleType == RoleType::Admin; - }); - } - inline bool isSunnylinkSponsor() const { - return std::any_of(sunnylinkRoles.begin(), sunnylinkRoles.end(), [](const RoleModel &role) { - return role.roleType == RoleType::Sponsor && role.as().roleTier != SponsorTier::Free; - }); - } - inline SponsorRoleModel sunnylinkSponsorRole() const { - std::optional sponsorRoleWithHighestTier = std::nullopt; - for (const auto &role : sunnylinkRoles) { - if(role.roleType != RoleType::Sponsor) - continue; - - if (auto sponsorRole = role.as(); !sponsorRoleWithHighestTier.has_value() || sponsorRoleWithHighestTier->roleTier < sponsorRole.roleTier) { - sponsorRoleWithHighestTier = sponsorRole; - } - } - return sponsorRoleWithHighestTier.value_or(SponsorRoleModel(RoleType::Sponsor, SponsorTier::Free)); - } - inline SponsorTier sunnylinkSponsorTier() const { - return sunnylinkSponsorRole().roleTier; - } - inline std::vector sunnylinkDeviceUsers() const { return sunnylinkUsers; } - inline bool isSunnylinkPaired() const { - return std::any_of(sunnylinkUsers.begin(), sunnylinkUsers.end(), [](const UserModel &user) { - return user.user_id.toLower() != "unregisteredsponsor" && user.user_id.toLower() != "temporarysponsor"; - }); - } - void reset_onroad_sleep_timer(OnroadTimerStatusToggle toggleTimerStatus = OnroadTimerStatusToggle::NONE); - -signals: - void sunnylinkRoleChanged(bool subscriber); - void sunnylinkRolesChanged(std::vector roles); - void sunnylinkDeviceUsersChanged(std::vector users); - void uiUpdate(const UIStateSP &s); - -private slots: - void update() override; - -private: - std::vector sunnylinkRoles = {}; - std::vector sunnylinkUsers = {}; - ParamWatcher *param_watcher; -}; - -UIStateSP *uiStateSP(); -inline UIStateSP *uiState() { return uiStateSP(); }; - -// device management class -class DeviceSP : public Device { - Q_OBJECT - -public: - DeviceSP(QObject *parent = 0); - -private: - Params params; - void handleDisplayPowerChanged(bool on); -}; - -DeviceSP *deviceSP(); -inline DeviceSP *device() { return deviceSP(); } - -void ui_update_params_sp(UIStateSP *s); diff --git a/selfdrive/ui/sunnypilot/ui_scene.h b/selfdrive/ui/sunnypilot/ui_scene.h deleted file mode 100644 index da98931e6b..0000000000 --- a/selfdrive/ui/sunnypilot/ui_scene.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - * - * This file is part of sunnypilot and is licensed under the MIT License. - * See the LICENSE.md file in the root directory for more details. - */ - -#pragma once - -typedef struct UISceneSP : UIScene { - int dev_ui_info = 0; - bool standstill_timer = false; - int speed_limit_mode = 0; - bool road_name = false; - int onroadScreenOffBrightness, onroadScreenOffTimer = 0; - bool onroadScreenOffControl; - int onroadScreenOffTimerParam; - bool trueVEgoUI; - bool hideVEgoUI; - bool turn_signals = false; - int chevron_info; - bool blindspot_ui; - bool rainbow_mode; -} UISceneSP;