mirror of
https://github.com/infiniteCable2/openpilot.git
synced 2026-07-25 19:32:03 +08:00
ui: sunnypilot offroad UI (#512)
* Revert "Revert "ui: sunnypilot offroad UI" (#511)"
This reverts commit 0e264e1b05.
* Revert "move files to sp dir"
This reverts commit c72d732259d35872fca92b90289785e7b4086140.
* remove drive stats for now
* update translation
* update onboarding
* remove sp onboarding for now
* rearrange
* remove more
* shorter license
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Wen
|
||||
+10
@@ -74,6 +74,12 @@ AddOption('--minimal',
|
||||
default=os.path.exists(File('#.lfsconfig').abspath), # minimal by default on release branch (where there's no LFS)
|
||||
help='the minimum build to run openpilot. no tests, tools, etc.')
|
||||
|
||||
AddOption('--stock-ui',
|
||||
action='store_true',
|
||||
dest='stock_ui',
|
||||
default=False,
|
||||
help='Build stock openpilot UI instead of sunnypilot UI')
|
||||
|
||||
## Architecture name breakdown (arch)
|
||||
## - larch64: linux tici aarch64
|
||||
## - aarch64: linux pc aarch64
|
||||
@@ -172,6 +178,10 @@ else:
|
||||
if arch != "Darwin":
|
||||
ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"]
|
||||
|
||||
if not GetOption('stock_ui'):
|
||||
cflags += ["-DSUNNYPILOT"]
|
||||
cxxflags += ["-DSUNNYPILOT"]
|
||||
|
||||
ccflags_option = GetOption('ccflags')
|
||||
if ccflags_option:
|
||||
ccflags += ccflags_option.split(' ')
|
||||
|
||||
@@ -57,7 +57,7 @@ function run_tests() {
|
||||
|
||||
if [[ -z "$FAST" ]]; then
|
||||
run "mypy" mypy $PYTHON_FILES
|
||||
run "codespell" codespell $ALL_FILES
|
||||
run "codespell" codespell $ALL_FILES --ignore-words=$ROOT/.codespellignore
|
||||
fi
|
||||
|
||||
return $FAILED
|
||||
|
||||
@@ -12,6 +12,12 @@ if arch == "Darwin":
|
||||
del base_libs[base_libs.index('OpenCL')]
|
||||
qt_env['FRAMEWORKS'] += ['OpenCL']
|
||||
|
||||
sp_widgets_src = []
|
||||
sp_qt_src = []
|
||||
if not GetOption('stock_ui'):
|
||||
SConscript(['sunnypilot/SConscript'])
|
||||
Import('sp_widgets_src', 'sp_qt_src')
|
||||
|
||||
# FIXME: remove this once we're on 5.15 (24.04)
|
||||
qt_env['CXXFLAGS'] += ["-Wno-deprecated-declarations"]
|
||||
|
||||
@@ -20,7 +26,7 @@ widgets_src = ["qt/widgets/input.cc", "qt/widgets/wifi.cc", "qt/prime_state.cc",
|
||||
"qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc",
|
||||
"qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc",
|
||||
"qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc",
|
||||
"qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc"]
|
||||
"qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc"] + sp_widgets_src
|
||||
|
||||
widgets = qt_env.Library("qt_widgets", widgets_src, LIBS=base_libs)
|
||||
Export('widgets')
|
||||
@@ -31,7 +37,7 @@ qt_src = ["main.cc", "ui.cc", "qt/sidebar.cc", "qt/body.cc",
|
||||
"qt/offroad/software_settings.cc", "qt/offroad/developer_panel.cc", "qt/offroad/onboarding.cc",
|
||||
"qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc",
|
||||
"qt/onroad/onroad_home.cc", "qt/onroad/annotated_camera.cc", "qt/onroad/model.cc",
|
||||
"qt/onroad/buttons.cc", "qt/onroad/alerts.cc", "qt/onroad/driver_monitoring.cc", "qt/onroad/hud.cc"]
|
||||
"qt/onroad/buttons.cc", "qt/onroad/alerts.cc", "qt/onroad/driver_monitoring.cc", "qt/onroad/hud.cc"] + sp_qt_src
|
||||
|
||||
# build translation files
|
||||
with open(File("translations/languages.json").abspath) as f:
|
||||
|
||||
@@ -4,10 +4,16 @@
|
||||
#include <QTranslator>
|
||||
|
||||
#include "system/hardware/hw.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/window.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/window.h"
|
||||
#define MainWindow MainWindowSP
|
||||
#else
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
setpriority(PRIO_PROCESS, 0, -20);
|
||||
|
||||
|
||||
@@ -5,7 +5,13 @@
|
||||
#include <QPushButton>
|
||||
|
||||
#include "common/util.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#define UIState UIStateSP
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
|
||||
class RecordButton : public QPushButton {
|
||||
Q_OBJECT
|
||||
|
||||
+16
-6
@@ -9,12 +9,23 @@
|
||||
|
||||
#include "common/params.h"
|
||||
#include "selfdrive/ui/qt/body.h"
|
||||
#include "selfdrive/ui/qt/onroad/onroad_home.h"
|
||||
#include "selfdrive/ui/qt/sidebar.h"
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/widgets/offroad_alerts.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/sidebar.h"
|
||||
#define OnroadWindow OnroadWindowSP
|
||||
#define LayoutWidget LayoutWidgetSP
|
||||
#define Sidebar SidebarSP
|
||||
#define ElidedLabel ElidedLabelSP
|
||||
#else
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/onroad/onroad_home.h"
|
||||
#include "selfdrive/ui/qt/sidebar.h"
|
||||
#endif
|
||||
|
||||
class OffroadHome : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -58,13 +69,12 @@ protected:
|
||||
void mousePressEvent(QMouseEvent* e) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent* e) override;
|
||||
|
||||
private:
|
||||
Sidebar *sidebar;
|
||||
OffroadHome *home;
|
||||
OnroadWindow *onroad;
|
||||
BodyWindow *body;
|
||||
QStackedLayout *slayout;
|
||||
|
||||
private slots:
|
||||
void updateState(const UIState &s);
|
||||
protected slots:
|
||||
virtual void updateState(const UIState &s);
|
||||
};
|
||||
|
||||
@@ -8,8 +8,14 @@
|
||||
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||
#else
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
#endif
|
||||
|
||||
static const int ICON_WIDTH = 49;
|
||||
|
||||
|
||||
@@ -8,6 +8,17 @@
|
||||
#include "selfdrive/ui/qt/widgets/ssh_keys.h"
|
||||
#include "selfdrive/ui/qt/widgets/toggle.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#define ButtonControl ButtonControlSP
|
||||
#define ElidedLabel ElidedLabelSP
|
||||
#define LabelControl LabelControlSP
|
||||
#define ListWidget ListWidgetSP
|
||||
#define ToggleControl ToggleControlSP
|
||||
#else
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#endif
|
||||
|
||||
class WifiItem : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
@@ -2,9 +2,14 @@
|
||||
|
||||
#include "selfdrive/ui/qt/offroad/developer_panel.h"
|
||||
#include "selfdrive/ui/qt/widgets/ssh_keys.h"
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#else
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#endif
|
||||
|
||||
DeveloperPanel::DeveloperPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
// SSH keys
|
||||
addItem(new SshToggle());
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||
#else
|
||||
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||
#endif
|
||||
|
||||
class DeveloperPanel : public ListWidget {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -71,6 +71,7 @@ public slots:
|
||||
private:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
protected:
|
||||
QPushButton *accept_btn;
|
||||
|
||||
signals:
|
||||
@@ -97,10 +98,10 @@ class OnboardingWindow : public QStackedWidget {
|
||||
public:
|
||||
explicit OnboardingWindow(QWidget *parent = 0);
|
||||
inline void showTrainingGuide() { setCurrentIndex(1); }
|
||||
inline bool completed() const { return accepted_terms && training_done; }
|
||||
virtual inline bool completed() const { return accepted_terms && training_done; }
|
||||
|
||||
private:
|
||||
void updateActiveScreen();
|
||||
protected:
|
||||
virtual void updateActiveScreen();
|
||||
|
||||
Params params;
|
||||
bool accepted_terms = false, training_done = false;
|
||||
|
||||
@@ -100,7 +100,9 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
}
|
||||
|
||||
// Toggles with confirmation dialogs
|
||||
#ifndef SUNNYPILOT
|
||||
toggles["ExperimentalMode"]->setActiveIcon("../assets/img_experimental.svg");
|
||||
#endif
|
||||
toggles["ExperimentalMode"]->setConfirmation(true, true);
|
||||
toggles["ExperimentalLongitudinalEnabled"]->setConfirmation(true, false);
|
||||
|
||||
@@ -354,6 +356,7 @@ void SettingsWindow::setCurrentPanel(int index, const QString ¶m) {
|
||||
}
|
||||
|
||||
SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
RETURN_IF_SUNNYPILOT
|
||||
|
||||
// setup two main layouts
|
||||
sidebar_widget = new QWidget;
|
||||
|
||||
@@ -10,9 +10,21 @@
|
||||
#include <QStackedWidget>
|
||||
#include <QWidget>
|
||||
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#define ListWidget ListWidgetSP
|
||||
#define ParamControl ParamControlSP
|
||||
#define ButtonControl ButtonControlSP
|
||||
#define ButtonParamControl ButtonParamControlSP
|
||||
#define ToggleControl ToggleControlSP
|
||||
#define LabelControl LabelControlSP
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#endif
|
||||
|
||||
// ********** settings window + top-level panels **********
|
||||
class SettingsWindow : public QFrame {
|
||||
@@ -30,7 +42,7 @@ signals:
|
||||
void reviewTrainingGuide();
|
||||
void expandToggleDescription(const QString ¶m);
|
||||
|
||||
private:
|
||||
protected:
|
||||
QPushButton *sidebar_alert_widget;
|
||||
QWidget *sidebar_widget;
|
||||
QButtonGroup *nav_btns;
|
||||
@@ -45,12 +57,12 @@ public:
|
||||
signals:
|
||||
void reviewTrainingGuide();
|
||||
|
||||
private slots:
|
||||
protected slots:
|
||||
void poweroff();
|
||||
void reboot();
|
||||
void updateCalibDescription();
|
||||
|
||||
private:
|
||||
protected:
|
||||
Params params;
|
||||
ButtonControl *pair_device;
|
||||
};
|
||||
@@ -64,15 +76,15 @@ public:
|
||||
public slots:
|
||||
void expandToggleDescription(const QString ¶m);
|
||||
|
||||
private slots:
|
||||
void updateState(const UIState &s);
|
||||
protected slots:
|
||||
virtual void updateState(const UIState &s);
|
||||
|
||||
private:
|
||||
protected:
|
||||
Params params;
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
ButtonParamControl *long_personality_setting;
|
||||
|
||||
void updateToggles();
|
||||
virtual void updateToggles();
|
||||
};
|
||||
|
||||
class SoftwarePanel : public ListWidget {
|
||||
@@ -80,7 +92,7 @@ class SoftwarePanel : public ListWidget {
|
||||
public:
|
||||
explicit SoftwarePanel(QWidget* parent = nullptr);
|
||||
|
||||
private:
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void updateLabels();
|
||||
void checkForUpdates();
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
|
||||
const int btn_size = 192;
|
||||
const int img_size = (btn_size / 4) * 3;
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
#include <QPainter>
|
||||
#include <QPolygonF>
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
|
||||
class ModelRenderer {
|
||||
public:
|
||||
|
||||
@@ -35,8 +35,12 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
|
||||
alerts->raise();
|
||||
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
||||
// We handle the connection of the signals on the derived class
|
||||
#ifndef SUNNYPILOT
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &OnroadWindow::updateState);
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &OnroadWindow::offroadTransition);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnroadWindow::updateState(const UIState &s) {
|
||||
|
||||
@@ -3,20 +3,24 @@
|
||||
#include "selfdrive/ui/qt/onroad/alerts.h"
|
||||
#include "selfdrive/ui/qt/onroad/annotated_camera.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#define UIState UIStateSP
|
||||
#endif
|
||||
|
||||
class OnroadWindow : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OnroadWindow(QWidget* parent = 0);
|
||||
|
||||
private:
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
OnroadAlerts *alerts;
|
||||
AnnotatedCameraWidget *nvg;
|
||||
QColor bg = bg_colors[STATUS_DISENGAGED];
|
||||
QHBoxLayout* split;
|
||||
|
||||
private slots:
|
||||
void offroadTransition(bool offroad);
|
||||
void updateState(const UIState &s);
|
||||
protected slots:
|
||||
virtual void offroadTransition(bool offroad);
|
||||
virtual void updateState(const UIState &s);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
|
||||
#include "common/util.h"
|
||||
#include "selfdrive/ui/qt/api.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
|
||||
class RequestRepeater : public HttpRequest {
|
||||
public:
|
||||
|
||||
@@ -110,6 +110,10 @@ void Sidebar::updateState(const UIState &s) {
|
||||
|
||||
void Sidebar::paintEvent(QPaintEvent *event) {
|
||||
QPainter p(this);
|
||||
paintSidebar(p);
|
||||
}
|
||||
|
||||
void Sidebar::paintSidebar(QPainter &p) {
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
|
||||
@@ -5,9 +5,14 @@
|
||||
#include <QFrame>
|
||||
#include <QMap>
|
||||
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/network/networking.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
|
||||
typedef QPair<QPair<QString, QString>, QColor> ItemStatus;
|
||||
Q_DECLARE_METATYPE(ItemStatus);
|
||||
|
||||
@@ -35,6 +40,7 @@ protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void drawMetric(QPainter &p, const QPair<QString, QString> &label, QColor c, int y);
|
||||
virtual void paintSidebar(QPainter &p);
|
||||
|
||||
QPixmap home_img, flag_img, settings_img;
|
||||
bool onroad, flag_pressed, settings_pressed;
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
#include "cereal/gen/cpp/car.capnp.h"
|
||||
#include "common/params.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#define RETURN_IF_SUNNYPILOT return;
|
||||
#else
|
||||
#define RETURN_IF_SUNNYPILOT // Do nothing
|
||||
#endif
|
||||
|
||||
QString getVersion();
|
||||
QString getBrand();
|
||||
QString getUserAgent();
|
||||
|
||||
@@ -23,7 +23,12 @@
|
||||
#endif
|
||||
|
||||
#include "msgq/visionipc/visionipc_client.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
|
||||
const int FRAME_BUFFER_SIZE = 5;
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
#include <QPainter>
|
||||
#include <QStyleOption>
|
||||
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
AbstractControl::AbstractControl(const QString &title, const QString &desc, const QString &icon, QWidget *parent) : QFrame(parent) {
|
||||
RETURN_IF_SUNNYPILOT
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
||||
main_layout->setMargin(0);
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ class AbstractControl : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
void setDescription(const QString &desc) {
|
||||
virtual void setDescription(const QString &desc) {
|
||||
if (description) description->setText(desc);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
value->setText(val);
|
||||
}
|
||||
|
||||
const QString getDescription() {
|
||||
virtual const QString getDescription() {
|
||||
return description->text();
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
QPixmap icon_pixmap;
|
||||
|
||||
public slots:
|
||||
void showDescription() {
|
||||
virtual void showDescription() {
|
||||
description->setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,14 @@
|
||||
#include <QPushButton>
|
||||
|
||||
#include "system/hardware/hw.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#define ButtonControl ButtonControlSP
|
||||
#define ToggleControl ToggleControlSP
|
||||
#else
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#endif
|
||||
|
||||
// SSH enable toggle
|
||||
class SshToggle : public ToggleControl {
|
||||
|
||||
@@ -23,14 +23,13 @@ public:
|
||||
update();
|
||||
}
|
||||
bool getEnabled();
|
||||
void setEnabled(bool value);
|
||||
virtual void setEnabled(bool value);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
void mouseReleaseEvent(QMouseEvent*) override;
|
||||
void enterEvent(QEvent*) override;
|
||||
|
||||
private:
|
||||
QColor circleColor;
|
||||
QColor green;
|
||||
bool enabled = true;
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
#include <QStackedLayout>
|
||||
#include <QWidget>
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#define UIState UIStateSP
|
||||
#else
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#endif
|
||||
|
||||
class WiFiPromptWidget : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -4,16 +4,19 @@
|
||||
|
||||
#include "system/hardware/hw.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) : QWidget(parent) {
|
||||
// We have this constructor so that we can provide custom implementations of the windows. By default (stock_ui) would receive them as nullptr, so they'll be instantiated with stock. Otherwise they'd be SP instances
|
||||
MainWindow::MainWindow(QWidget *parent, HomeWindow *hw, SettingsWindow *sw) :
|
||||
QWidget(parent),
|
||||
homeWindow(hw ? hw : new HomeWindow(this)),
|
||||
settingsWindow(sw ? sw : new SettingsWindow(this)) {
|
||||
|
||||
main_layout = new QStackedLayout(this);
|
||||
main_layout->setMargin(0);
|
||||
|
||||
homeWindow = new HomeWindow(this);
|
||||
main_layout->addWidget(homeWindow);
|
||||
QObject::connect(homeWindow, &HomeWindow::openSettings, this, &MainWindow::openSettings);
|
||||
QObject::connect(homeWindow, &HomeWindow::closeSettings, this, &MainWindow::closeSettings);
|
||||
|
||||
settingsWindow = new SettingsWindow(this);
|
||||
main_layout->addWidget(settingsWindow);
|
||||
QObject::connect(settingsWindow, &SettingsWindow::closeSettings, this, &MainWindow::closeSettings);
|
||||
QObject::connect(settingsWindow, &SettingsWindow::reviewTrainingGuide, [=]() {
|
||||
|
||||
@@ -11,15 +11,18 @@ class MainWindow : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
explicit MainWindow(QWidget *parent = 0) : MainWindow(parent, nullptr, nullptr) {}
|
||||
|
||||
protected:
|
||||
explicit MainWindow(QWidget *parent, HomeWindow *hw = nullptr, SettingsWindow *sw = nullptr);
|
||||
HomeWindow *homeWindow;
|
||||
SettingsWindow *settingsWindow;
|
||||
virtual void closeSettings();
|
||||
|
||||
private:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
void openSettings(int index = 0, const QString ¶m = "");
|
||||
void closeSettings();
|
||||
|
||||
QStackedLayout *main_layout;
|
||||
HomeWindow *homeWindow;
|
||||
SettingsWindow *settingsWindow;
|
||||
OnboardingWindow *onboardingWindow;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
widgets_src = [
|
||||
"sunnypilot/qt/widgets/toggle.cc",
|
||||
"sunnypilot/qt/widgets/controls.cc",
|
||||
"sunnypilot/qt/widgets/scrollview.cc",
|
||||
]
|
||||
|
||||
qt_src = [
|
||||
"sunnypilot/ui.cc",
|
||||
"sunnypilot/qt/sidebar.cc",
|
||||
"sunnypilot/qt/window.cc",
|
||||
"sunnypilot/qt/home.cc",
|
||||
"sunnypilot/qt/offroad/settings/settings.cc",
|
||||
"sunnypilot/qt/onroad/onroad_home.cc",
|
||||
]
|
||||
|
||||
sp_widgets_src = widgets_src
|
||||
sp_qt_src = qt_src
|
||||
|
||||
Export('sp_widgets_src', 'sp_qt_src')
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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"
|
||||
|
||||
HomeWindowSP::HomeWindowSP(QWidget *parent) : HomeWindow(parent) {
|
||||
}
|
||||
|
||||
void HomeWindowSP::updateState(const UIState &s) {
|
||||
HomeWindow::updateState(s);
|
||||
}
|
||||
|
||||
void HomeWindowSP::mousePressEvent(QMouseEvent *e) {
|
||||
HomeWindow::mousePressEvent(e);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 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 <QFrame>
|
||||
#include <QWidget>
|
||||
|
||||
#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;
|
||||
};
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* 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/qt/network/networking.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||
#include "selfdrive/ui/qt/offroad/developer_panel.h"
|
||||
|
||||
TogglesPanelSP::TogglesPanelSP(SettingsWindow *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, &SettingsWindow::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
|
||||
DevicePanel *device = new DevicePanel(this);
|
||||
QObject::connect(device, &DevicePanel::reviewTrainingGuide, this, &SettingsWindow::reviewTrainingGuide);
|
||||
|
||||
TogglesPanelSP *toggles = new TogglesPanelSP(this);
|
||||
QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription);
|
||||
|
||||
auto networking = new Networking(this);
|
||||
QObject::connect(uiState()->prime_state, &PrimeState::changed, networking, &Networking::setPrimeType);
|
||||
|
||||
QList<PanelInfo> panels = {
|
||||
PanelInfo(" " + tr("Device"), device, "../../sunnypilot/selfdrive/assets/offroad/icon_home.svg"),
|
||||
PanelInfo(" " + tr("Network"), networking, "../assets/offroad/icon_network.png"),
|
||||
PanelInfo(" " + tr("Toggles"), toggles, "../../sunnypilot/selfdrive/assets/offroad/icon_toggle.png"),
|
||||
PanelInfo(" " + tr("Software"), new SoftwarePanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_software.png"),
|
||||
PanelInfo(" " + tr("Developer"), new DeveloperPanel(this), "../assets/offroad/icon_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")) || (name != (" " + tr("sunnypilot")))) ? 50 : 0; // Network and sunnypilot 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;
|
||||
}
|
||||
)");
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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 <map>
|
||||
#include <string>
|
||||
|
||||
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||
|
||||
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(SettingsWindow *parent);
|
||||
|
||||
private slots:
|
||||
void updateState(const UIStateSP &s);
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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 <cmath>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
SidebarSP::SidebarSP(QWidget *parent) : Sidebar(parent) {
|
||||
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);
|
||||
}
|
||||
|
||||
void SidebarSP::paintSidebar(QPainter &p) {
|
||||
Sidebar::paintSidebar(p);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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 <memory>
|
||||
|
||||
#include "selfdrive/ui/qt/sidebar.h"
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
|
||||
class SidebarSP : public Sidebar {
|
||||
Q_OBJECT
|
||||
|
||||
public slots:
|
||||
void updateState(const UIStateSP &s);
|
||||
|
||||
public:
|
||||
explicit SidebarSP(QWidget *parent = 0);
|
||||
|
||||
private:
|
||||
void paintSidebar(QPainter &p) override;
|
||||
};
|
||||
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* 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 <QPainter>
|
||||
#include <QStyleOption>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// AbstractControlSP
|
||||
|
||||
AbstractControlSP::AbstractControlSP(const QString &title, const QString &desc, const QString &icon, QWidget *parent)
|
||||
: AbstractControl(title, desc, icon, parent) {
|
||||
|
||||
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)
|
||||
: AbstractControlSP(title, desc, icon, parent) {
|
||||
|
||||
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: 20 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);
|
||||
delete spacingItem;
|
||||
spacingItem = nullptr;
|
||||
} else if (!isVisible && spacingItem == nullptr) {
|
||||
spacingItem = new QSpacerItem(44, 44, QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
main_layout->insertItem(main_layout->indexOf(description), spacingItem);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
main_layout->addSpacing(20);
|
||||
}
|
||||
|
||||
main_layout->addLayout(hlayout);
|
||||
if (!desc.isEmpty() && spacingItem == nullptr) {
|
||||
spacingItem = new QSpacerItem(44, 44, QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
main_layout->insertItem(main_layout->count(), spacingItem);
|
||||
}
|
||||
|
||||
// description
|
||||
description = new QLabel(desc);
|
||||
description->setContentsMargins(0, 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) {
|
||||
spacingItem = new QSpacerItem(44, 44, QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
main_layout->insertItem(main_layout->indexOf(description), spacingItem);
|
||||
}
|
||||
}
|
||||
|
||||
// controls
|
||||
|
||||
ButtonControlSP::ButtonControlSP(const QString &title, const QString &text, const QString &desc, QWidget *parent)
|
||||
: AbstractControlSP(title, desc, "", parent) {
|
||||
|
||||
btn.setText(text);
|
||||
btn.setStyleSheet(R"(
|
||||
QPushButton {
|
||||
padding: 0;
|
||||
border-radius: 50px;
|
||||
font-size: 35px;
|
||||
font-weight: 500;
|
||||
color: #E4E4E4;
|
||||
background-color: #393939;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #4a4a4a;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
color: #33E4E4E4;
|
||||
}
|
||||
)");
|
||||
btn.setFixedSize(250, 100);
|
||||
QObject::connect(&btn, &QPushButton::clicked, this, &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)
|
||||
: ToggleControlSP(title, desc, icon, false, parent) {
|
||||
|
||||
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("<body><h2 style=\"text-align: center;\">" + title_label->text() + "</h2><br>"
|
||||
"<p style=\"text-align: center; margin: 0 128px; font-size: 50px;\">" + getDescription() + "</p></body>");
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,588 @@
|
||||
/**
|
||||
* 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 <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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);
|
||||
|
||||
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:
|
||||
void setDescription(const QString &desc) override {
|
||||
if (description) description->setText(desc);
|
||||
}
|
||||
|
||||
void setValue(const QString &val, std::optional<QString> 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);
|
||||
}
|
||||
|
||||
protected:
|
||||
AbstractControlSP(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr);
|
||||
void hideEvent(QHideEvent *e) override;
|
||||
|
||||
QVBoxLayout *main_layout;
|
||||
ElidedLabelSP *value;
|
||||
QLabel *description = nullptr;
|
||||
};
|
||||
|
||||
// AbstractControlSP_SELECTOR
|
||||
|
||||
class AbstractControlSP_SELECTOR : public AbstractControlSP {
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
AbstractControlSP_SELECTOR(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr);
|
||||
void hideEvent(QHideEvent *e) override;
|
||||
|
||||
private:
|
||||
QSpacerItem *spacingItem = nullptr;
|
||||
};
|
||||
|
||||
// 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);
|
||||
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) : AbstractControlSP(title, desc, icon, parent) {
|
||||
// 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);
|
||||
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 ButtonParamControlSP : public AbstractControlSP_SELECTOR {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ButtonParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon,
|
||||
const std::vector<QString> &button_texts, const int minimum_button_width = 300) : AbstractControlSP_SELECTOR(title, desc, icon), button_texts(button_texts) {
|
||||
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;
|
||||
}
|
||||
)";
|
||||
key = param.toStdString();
|
||||
int value = atoi(params.get(key).c_str());
|
||||
|
||||
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->setChecked(i == value);
|
||||
button->setStyleSheet(style);
|
||||
button->setMinimumWidth(minimum_button_width);
|
||||
if (i == 0) hlayout->addSpacing(2);
|
||||
hlayout->addWidget(button);
|
||||
button_group->addButton(button, i);
|
||||
}
|
||||
|
||||
hlayout->setAlignment(Qt::AlignLeft);
|
||||
|
||||
QObject::connect(button_group, QOverload<int>::of(&QButtonGroup::buttonClicked), [=](int id) {
|
||||
params.put(key, std::to_string(id));
|
||||
emit buttonToggled(id);
|
||||
});
|
||||
}
|
||||
|
||||
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 setDisabledSelectedButton(std::string val) {
|
||||
int value = atoi(val.c_str());
|
||||
for (int i = 0; i < button_group->buttons().size(); i++) {
|
||||
button_group->buttons()[i]->setEnabled(i != value);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override {
|
||||
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<QPushButton *>(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 buttonToggled(int btn_id);
|
||||
|
||||
private:
|
||||
std::string key;
|
||||
Params params;
|
||||
QButtonGroup *button_group;
|
||||
std::vector<QString> button_texts;
|
||||
|
||||
bool button_group_enabled = true;
|
||||
};
|
||||
|
||||
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();
|
||||
}
|
||||
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
|
||||
|
||||
private:
|
||||
struct MinMaxValue {
|
||||
int min_value;
|
||||
int max_value;
|
||||
};
|
||||
|
||||
public:
|
||||
OptionControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon,
|
||||
const MinMaxValue &range, const int per_value_change = 1) : _title(title), AbstractControlSP_SELECTOR(title, desc, icon) {
|
||||
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;
|
||||
}
|
||||
)";
|
||||
|
||||
label.setStyleSheet(label_enabled_style);
|
||||
label.setFixedWidth(300);
|
||||
label.setAlignment(Qt::AlignCenter);
|
||||
|
||||
const std::vector<QString> button_texts{"-", "+"};
|
||||
|
||||
key = param.toStdString();
|
||||
value = atoi(params.get(key).c_str());
|
||||
|
||||
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; }"));
|
||||
hlayout->addWidget(button, 0, ((i == 0) ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignVCenter);
|
||||
if (i == 0) {
|
||||
hlayout->addWidget(&label, 0, Qt::AlignCenter);
|
||||
}
|
||||
button_group->addButton(button, i);
|
||||
|
||||
QObject::connect(button, &QPushButton::clicked, [=]() {
|
||||
int change_value = (i == 0) ? -per_value_change : per_value_change;
|
||||
key = param.toStdString();
|
||||
value = atoi(params.get(key).c_str());
|
||||
value += change_value;
|
||||
value = std::clamp(value, range.min_value, range.max_value);
|
||||
params.put(key, QString::number(value).toStdString());
|
||||
|
||||
button_group->button(0)->setEnabled(!(value <= range.min_value));
|
||||
button_group->button(1)->setEnabled(!(value >= range.max_value));
|
||||
|
||||
updateLabels();
|
||||
|
||||
if (request_update) {
|
||||
emit updateOtherToggles();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
hlayout->setAlignment(Qt::AlignLeft);
|
||||
}
|
||||
|
||||
void setUpdateOtherToggles(bool _update) {
|
||||
request_update = _update;
|
||||
}
|
||||
|
||||
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 {
|
||||
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) {
|
||||
QWidget *widget = qobject_cast<QWidget *>(hlayout->itemAt(i)->widget());
|
||||
if (widget) {
|
||||
w += widget->width();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the rectangle
|
||||
QRect rect(0, !_title.isEmpty() ? (h - 24) : 20, w, h);
|
||||
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<QString, QString> option_label = {};
|
||||
bool request_update = false;
|
||||
QString _title = "";
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
class SubPanelButton : public QPushButton {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SubPanelButton(const QString &text, const int minimum_button_width = 800, QWidget *parent = nullptr) : QPushButton(text, parent) {
|
||||
const QString buttonStyle = R"(
|
||||
QPushButton {
|
||||
border-radius: 20px;
|
||||
font-size: 50px;
|
||||
font-weight: 450;
|
||||
height: 150px;
|
||||
padding: 0 25px 0 25px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
QPushButton:enabled {
|
||||
background-color: #393939;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #4A4A4A;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
background-color: #121212;
|
||||
color: #5C5C5C;
|
||||
}
|
||||
)";
|
||||
|
||||
setStyleSheet(buttonStyle);
|
||||
setFixedWidth(minimum_button_width);
|
||||
}
|
||||
};
|
||||
|
||||
class PanelBackButton : public QPushButton {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PanelBackButton(const QString &label = "Back", QWidget *parent = nullptr) : QPushButton(label, parent) {
|
||||
setObjectName("back_btn");
|
||||
setFixedSize(400, 100);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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 <QScrollBar>
|
||||
|
||||
void ScrollViewSP::setLastScrollPosition() {
|
||||
lastScrollPosition = verticalScrollBar()->value();
|
||||
}
|
||||
|
||||
void ScrollViewSP::restoreScrollPosition() {
|
||||
verticalScrollBar()->setValue(lastScrollPosition);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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 <QPainter>
|
||||
|
||||
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));
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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<HomeWindowSP *>(MainWindow::homeWindow);
|
||||
settingsWindow = dynamic_cast<SettingsWindowSP *>(MainWindow::settingsWindow);
|
||||
}
|
||||
|
||||
void MainWindowSP::closeSettings() {
|
||||
MainWindow::closeSettings();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
UIStateSP::UIStateSP(QObject *parent) : UIState(parent) {
|
||||
sm = std::make_unique<SubMaster>(std::vector<const char*>{
|
||||
"modelV2", "controlsState", "liveCalibration", "radarState", "deviceState",
|
||||
"pandaStates", "carParams", "driverMonitoringState", "carState", "driverStateV2",
|
||||
"wideRoadCameraState", "managerState", "selfdriveState", "longitudinalPlan",
|
||||
});
|
||||
|
||||
// update timer
|
||||
timer = new QTimer(this);
|
||||
QObject::connect(timer, &QTimer::timeout, this, &UIStateSP::update);
|
||||
timer->start(1000 / UI_FREQ);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
DeviceSP::DeviceSP(QObject *parent) : Device(parent) {
|
||||
QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &DeviceSP::update);
|
||||
}
|
||||
|
||||
UIStateSP *uiStateSP() {
|
||||
static UIStateSP ui_state;
|
||||
return &ui_state;
|
||||
}
|
||||
|
||||
DeviceSP *deviceSP() {
|
||||
static DeviceSP _device;
|
||||
return &_device;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 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/ui.h"
|
||||
|
||||
class UIStateSP : public UIState {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UIStateSP(QObject *parent = 0);
|
||||
void updateStatus() override;
|
||||
|
||||
signals:
|
||||
void uiUpdate(const UIStateSP &s);
|
||||
|
||||
private slots:
|
||||
void update() override;
|
||||
};
|
||||
|
||||
UIStateSP *uiStateSP();
|
||||
inline UIStateSP *uiState() { return uiStateSP(); };
|
||||
|
||||
// device management class
|
||||
class DeviceSP : public Device {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DeviceSP(QObject *parent = 0);
|
||||
};
|
||||
|
||||
DeviceSP *deviceSP();
|
||||
inline DeviceSP *device() { return deviceSP(); }
|
||||
@@ -160,7 +160,7 @@ def setup_offroad_alert(click, pm: PubMaster):
|
||||
|
||||
# Toggle between settings and home to refresh the offroad alert widget
|
||||
setup_settings_device(click, pm)
|
||||
click(240, 216)
|
||||
click(100, 100)
|
||||
|
||||
def setup_update_available(click, pm: PubMaster):
|
||||
Params().put_bool("UpdateAvailable", True)
|
||||
@@ -170,7 +170,7 @@ def setup_update_available(click, pm: PubMaster):
|
||||
Params().put("UpdaterNewReleaseNotes", release_notes + "\n")
|
||||
|
||||
setup_settings_device(click, pm)
|
||||
click(240, 216)
|
||||
click(100, 100)
|
||||
|
||||
def setup_pair_device(click, pm: PubMaster):
|
||||
click(1950, 435)
|
||||
|
||||
@@ -480,6 +480,17 @@
|
||||
<translation>إلغاء</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation>تمكين</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>إلغاء</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PrimeAdWidget</name>
|
||||
<message>
|
||||
@@ -642,6 +653,37 @@ This may take up to a minute.</source>
|
||||
<translation>المطور</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation>الجهاز</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation>الشبكة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>المثبتتات</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>البرنامج</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation>المطور</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
<message>
|
||||
|
||||
@@ -475,6 +475,17 @@
|
||||
<translation>Aktivieren</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>Abbrechen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation>Aktivieren</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PrimeAdWidget</name>
|
||||
<message>
|
||||
@@ -624,6 +635,37 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation>x</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation>Gerät</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation>Netzwerk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>Schalter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>Software</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
<message>
|
||||
|
||||
@@ -476,6 +476,17 @@
|
||||
<translation>Cancelar</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation>Activar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>Cancelar</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PrimeAdWidget</name>
|
||||
<message>
|
||||
@@ -626,6 +637,37 @@ Esto puede tardar un minuto.</translation>
|
||||
<translation>Desarrollador</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation>Dispositivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation>Red</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>Ajustes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>Software</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation>Desarrollador</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
<message>
|
||||
|
||||
@@ -476,6 +476,17 @@
|
||||
<translation>Annuler</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation>Activer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>Annuler</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PrimeAdWidget</name>
|
||||
<message>
|
||||
@@ -626,6 +637,37 @@ Cela peut prendre jusqu'à une minute.</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation>Appareil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation>Réseau</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>Options</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>Logiciel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
<message>
|
||||
|
||||
@@ -474,6 +474,17 @@
|
||||
<translation>を有効化</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>キャンセル</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation>を有効化</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PrimeAdWidget</name>
|
||||
<message>
|
||||
@@ -620,6 +631,37 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation>デバイス</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation>ネットワーク</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>機能設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>ソフトウェア</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
<message>
|
||||
|
||||
@@ -475,6 +475,17 @@
|
||||
<translation>활성화</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>취소</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation>활성화</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PrimeAdWidget</name>
|
||||
<message>
|
||||
@@ -622,6 +633,37 @@ This may take up to a minute.</source>
|
||||
<translation>개발자</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation>장치</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation>네트워크</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>토글</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>소프트웨어</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation>개발자</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
<message>
|
||||
|
||||
@@ -476,6 +476,17 @@
|
||||
<translation>Ativar</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>Cancelar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation>Ativar</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PrimeAdWidget</name>
|
||||
<message>
|
||||
@@ -626,6 +637,37 @@ Isso pode levar até um minuto.</translation>
|
||||
<translation>Desenvdor</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation>Dispositivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation>Rede</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>Ajustes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>Software</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation>Desenvdor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
<message>
|
||||
|
||||
@@ -475,6 +475,17 @@
|
||||
<translation>ยกเลิก</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation>เปิดใช้งาน</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>ยกเลิก</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PrimeAdWidget</name>
|
||||
<message>
|
||||
@@ -622,6 +633,37 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation>อุปกรณ์</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation>เครือข่าย</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>ตัวเลือก</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>ซอฟต์แวร์</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
<message>
|
||||
|
||||
@@ -474,6 +474,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PrimeAdWidget</name>
|
||||
<message>
|
||||
@@ -620,6 +631,37 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation>x</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation>Cihaz</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation>Ağ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>Değiştirme</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>Yazılım</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
<message>
|
||||
|
||||
@@ -475,6 +475,17 @@
|
||||
<translation>启用</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>取消</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation>启用</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PrimeAdWidget</name>
|
||||
<message>
|
||||
@@ -622,6 +633,37 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation>设备</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation>网络</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>设定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>软件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
<message>
|
||||
|
||||
@@ -475,6 +475,17 @@
|
||||
<translation>啟用</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>取消</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation>啟用</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PrimeAdWidget</name>
|
||||
<message>
|
||||
@@ -622,6 +633,37 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation>裝置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation>網路</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>軟體</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
<message>
|
||||
|
||||
+9
-3
@@ -9,16 +9,17 @@
|
||||
#include "common/swaglog.h"
|
||||
#include "common/util.h"
|
||||
#include "common/watchdog.h"
|
||||
#include "qt/util.h"
|
||||
#include "system/hardware/hw.h"
|
||||
|
||||
#define BACKLIGHT_DT 0.05
|
||||
#define BACKLIGHT_TS 10.00
|
||||
|
||||
static void update_sockets(UIState *s) {
|
||||
void update_sockets(UIState *s) {
|
||||
s->sm->update(0);
|
||||
}
|
||||
|
||||
static void update_state(UIState *s) {
|
||||
void update_state(UIState *s) {
|
||||
SubMaster &sm = *(s->sm);
|
||||
UIScene &scene = s->scene;
|
||||
|
||||
@@ -98,6 +99,7 @@ UIState::UIState(QObject *parent) : QObject(parent) {
|
||||
prime_state = new PrimeState(this);
|
||||
language = QString::fromStdString(Params().get("LanguageSetting"));
|
||||
|
||||
RETURN_IF_SUNNYPILOT
|
||||
// update timer
|
||||
timer = new QTimer(this);
|
||||
QObject::connect(timer, &QTimer::timeout, this, &UIState::update);
|
||||
@@ -105,6 +107,7 @@ UIState::UIState(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
void UIState::update() {
|
||||
RETURN_IF_SUNNYPILOT
|
||||
update_sockets(this);
|
||||
update_state(this);
|
||||
updateStatus();
|
||||
@@ -118,8 +121,9 @@ void UIState::update() {
|
||||
Device::Device(QObject *parent) : brightness_filter(BACKLIGHT_OFFROAD, BACKLIGHT_TS, BACKLIGHT_DT), QObject(parent) {
|
||||
setAwake(true);
|
||||
resetInteractiveTimeout();
|
||||
|
||||
#ifndef SUNNYPILOT
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &Device::update);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Device::update(const UIState &s) {
|
||||
@@ -185,6 +189,7 @@ void Device::updateWakefulness(const UIState &s) {
|
||||
setAwake(s.scene.ignition || interactive_timeout > 0);
|
||||
}
|
||||
|
||||
#ifndef SUNNYPILOT
|
||||
UIState *uiState() {
|
||||
static UIState ui_state;
|
||||
return &ui_state;
|
||||
@@ -194,3 +199,4 @@ Device *device() {
|
||||
static Device _device;
|
||||
return &_device;
|
||||
}
|
||||
#endif
|
||||
|
||||
+14
-5
@@ -67,7 +67,7 @@ class UIState : public QObject {
|
||||
|
||||
public:
|
||||
UIState(QObject* parent = 0);
|
||||
void updateStatus();
|
||||
virtual void updateStatus();
|
||||
inline bool engaged() const {
|
||||
return scene.started && (*sm)["selfdriveState"].getSelfdriveState().getEnabled();
|
||||
}
|
||||
@@ -82,15 +82,19 @@ signals:
|
||||
void uiUpdate(const UIState &s);
|
||||
void offroadTransition(bool offroad);
|
||||
|
||||
private slots:
|
||||
void update();
|
||||
protected slots:
|
||||
virtual void update();
|
||||
|
||||
protected:
|
||||
QTimer *timer;
|
||||
|
||||
private:
|
||||
QTimer *timer;
|
||||
bool started_prev = false;
|
||||
};
|
||||
|
||||
#ifndef SUNNYPILOT
|
||||
UIState *uiState();
|
||||
#endif
|
||||
|
||||
// device management class
|
||||
class Device : public QObject {
|
||||
@@ -103,7 +107,7 @@ public:
|
||||
offroad_brightness = std::clamp(brightness, 0, 100);
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
bool awake = false;
|
||||
int interactive_timeout = 0;
|
||||
bool ignition_on = false;
|
||||
@@ -126,5 +130,10 @@ public slots:
|
||||
void update(const UIState &s);
|
||||
};
|
||||
|
||||
#ifndef SUNNYPILOT
|
||||
Device *device();
|
||||
#endif
|
||||
|
||||
void ui_update_params(UIState *s);
|
||||
void update_state(UIState *s);
|
||||
void update_sockets(UIState *s);
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1673f8d46251a05787b60346193852991739345506dc7e9b106dfb370d3611ed
|
||||
size 489
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:01fd38c0d5b05c3ce4ed07bfe4cd47a3ea61f68f24e6cc3058190d90d8200f9b
|
||||
size 4785
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:11336d2f65100bc0dc2a53e09efae41ae85817b27e1a5bf134cc995e631c5b52
|
||||
size 4073
|
||||
Reference in New Issue
Block a user