mirror of
https://github.com/infiniteCable2/openpilot.git
synced 2026-08-06 00:36:29 +08:00
UI: Add Exit Offfroad button on the home screen (#872)
* exit offroad btn on offroad-home * Remove alert for Always-Offroad. Replaced with header "Always Offroad Active" * refresh state when device wakes up * cleanup * cleaning * Add pulsing glow effect to ExitOffroadButton Introduced a QTimer-based mechanism to create a pulsing glow effect around the ExitOffroadButton. This enhances visual feedback by animating the outline with varying alpha transparency, improving UI responsiveness and aesthetics. * move custom asset to sunnypilot --------- Co-authored-by: DevTekVE <devtekve@gmail.com>
This commit is contained in:
@@ -137,7 +137,6 @@ inline static std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"Brightness", PERSISTENT | BACKUP},
|
||||
{"ModelRunnerTypeCache", CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"OffroadMode", CLEAR_ON_MANAGER_START},
|
||||
{"OffroadMode_Status", CLEAR_ON_MANAGER_START},
|
||||
{"QuietMode", PERSISTENT | BACKUP},
|
||||
|
||||
// MADS params
|
||||
|
||||
@@ -45,10 +45,6 @@
|
||||
"text": "sunnypilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.",
|
||||
"severity": 0
|
||||
},
|
||||
"OffroadMode_Status": {
|
||||
"text": "sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to \"Settings\" -> \"Device\" to exit Always Offroad mode.",
|
||||
"severity": 1
|
||||
},
|
||||
"Offroad_OSMUpdateRequired": {
|
||||
"text": "OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display.\n\n%1",
|
||||
"severity": 0
|
||||
|
||||
@@ -18,7 +18,7 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
|
||||
main_layout->setContentsMargins(40, 40, 40, 40);
|
||||
|
||||
// top header
|
||||
QHBoxLayout* header_layout = new QHBoxLayout();
|
||||
header_layout = new QHBoxLayout();
|
||||
header_layout->setContentsMargins(0, 0, 0, 0);
|
||||
header_layout->setSpacing(16);
|
||||
|
||||
|
||||
@@ -39,11 +39,13 @@ public:
|
||||
|
||||
protected:
|
||||
QHBoxLayout *home_layout;
|
||||
QHBoxLayout *header_layout;
|
||||
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
void refresh();
|
||||
|
||||
Params params;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ qt_src = [
|
||||
"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/device_panel.cc",
|
||||
"sunnypilot/qt/offroad/settings/lateral_panel.cc",
|
||||
@@ -80,6 +81,7 @@ brand_settings_qt_src = [
|
||||
"sunnypilot/qt/offroad/settings/vehicle/volkswagen_settings.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 + osm_panel_qt_src
|
||||
sp_qt_util = qt_util
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
#include <QDebug>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QStyle>
|
||||
|
||||
#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());
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
|
||||
#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;
|
||||
};
|
||||
@@ -5,16 +5,45 @@
|
||||
* See the LICENSE.md file in the root directory for more details.
|
||||
*/
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/offroad_home.h"
|
||||
|
||||
#include <QStackedWidget>
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/offroad_home.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h"
|
||||
|
||||
OffroadHomeSP::OffroadHomeSP(QWidget *parent) : OffroadHome(parent) {
|
||||
QStackedWidget *left_widget = new QStackedWidget(this);
|
||||
left_widget->addWidget(new DriveStats(this));
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -8,10 +8,19 @@
|
||||
#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();
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@ DriveStats::DriveStats(QWidget* parent) : QFrame(parent) {
|
||||
|
||||
int row = 0;
|
||||
grid_layout->addWidget(newLabel(title, "title"), row++, 0, 1, 3);
|
||||
grid_layout->addItem(new QSpacerItem(0, 50), row++, 0, 1, 1);
|
||||
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);
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d44f71f7603b106986fff7835f35c4c18c4c619a29e6292f8626ae3eedd85e57
|
||||
size 7811
|
||||
@@ -323,7 +323,6 @@ def hardware_thread(end_event, hw_queue) -> None:
|
||||
offroad_mode = params.get_bool("OffroadMode")
|
||||
startup_conditions["not_always_offroad"] = not offroad_mode
|
||||
onroad_conditions["not_always_offroad"] = not offroad_mode
|
||||
set_offroad_alert("OffroadMode_Status", offroad_mode)
|
||||
|
||||
# if the temperature enters the danger zone, go offroad to cool down
|
||||
onroad_conditions["device_temp_good"] = thermal_status < ThermalStatus.danger
|
||||
|
||||
Reference in New Issue
Block a user