ui/onroad: split into multiple files (#32059)
parent
70cdcc51a9
commit
c1b059de1e
12 changed files with 484 additions and 466 deletions
@ -1,162 +0,0 @@ |
|||||||
#pragma once |
|
||||||
|
|
||||||
#include <memory> |
|
||||||
|
|
||||||
#include <QPushButton> |
|
||||||
#include <QStackedLayout> |
|
||||||
#include <QWidget> |
|
||||||
|
|
||||||
#include "common/util.h" |
|
||||||
#include "selfdrive/ui/ui.h" |
|
||||||
#include "selfdrive/ui/qt/widgets/cameraview.h" |
|
||||||
|
|
||||||
|
|
||||||
const int btn_size = 192; |
|
||||||
const int img_size = (btn_size / 4) * 3; |
|
||||||
|
|
||||||
|
|
||||||
// ***** onroad widgets *****
|
|
||||||
class OnroadAlerts : public QWidget { |
|
||||||
Q_OBJECT |
|
||||||
|
|
||||||
public: |
|
||||||
OnroadAlerts(QWidget *parent = 0) : QWidget(parent) {} |
|
||||||
void updateState(const UIState &s); |
|
||||||
void clear(); |
|
||||||
|
|
||||||
protected: |
|
||||||
struct Alert { |
|
||||||
QString text1; |
|
||||||
QString text2; |
|
||||||
QString type; |
|
||||||
cereal::ControlsState::AlertSize size; |
|
||||||
cereal::ControlsState::AlertStatus status; |
|
||||||
|
|
||||||
bool equal(const Alert &other) const { |
|
||||||
return text1 == other.text1 && other.text2 == other.text2 && type == other.type; |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
const QMap<cereal::ControlsState::AlertStatus, QColor> alert_colors = { |
|
||||||
{cereal::ControlsState::AlertStatus::NORMAL, QColor(0x15, 0x15, 0x15, 0xf1)}, |
|
||||||
{cereal::ControlsState::AlertStatus::USER_PROMPT, QColor(0xDA, 0x6F, 0x25, 0xf1)}, |
|
||||||
{cereal::ControlsState::AlertStatus::CRITICAL, QColor(0xC9, 0x22, 0x31, 0xf1)}, |
|
||||||
}; |
|
||||||
|
|
||||||
void paintEvent(QPaintEvent*) override; |
|
||||||
OnroadAlerts::Alert getAlert(const SubMaster &sm, uint64_t started_frame); |
|
||||||
|
|
||||||
QColor bg; |
|
||||||
Alert alert = {}; |
|
||||||
}; |
|
||||||
|
|
||||||
class ExperimentalButton : public QPushButton { |
|
||||||
Q_OBJECT |
|
||||||
|
|
||||||
public: |
|
||||||
explicit ExperimentalButton(QWidget *parent = 0); |
|
||||||
void updateState(const UIState &s); |
|
||||||
|
|
||||||
private: |
|
||||||
void paintEvent(QPaintEvent *event) override; |
|
||||||
void changeMode(); |
|
||||||
|
|
||||||
Params params; |
|
||||||
QPixmap engage_img; |
|
||||||
QPixmap experimental_img; |
|
||||||
bool experimental_mode; |
|
||||||
bool engageable; |
|
||||||
}; |
|
||||||
|
|
||||||
|
|
||||||
class MapSettingsButton : public QPushButton { |
|
||||||
Q_OBJECT |
|
||||||
|
|
||||||
public: |
|
||||||
explicit MapSettingsButton(QWidget *parent = 0); |
|
||||||
|
|
||||||
private: |
|
||||||
void paintEvent(QPaintEvent *event) override; |
|
||||||
|
|
||||||
QPixmap settings_img; |
|
||||||
}; |
|
||||||
|
|
||||||
// container window for the NVG UI
|
|
||||||
class AnnotatedCameraWidget : public CameraWidget { |
|
||||||
Q_OBJECT |
|
||||||
|
|
||||||
public: |
|
||||||
explicit AnnotatedCameraWidget(VisionStreamType type, QWidget* parent = 0); |
|
||||||
void updateState(const UIState &s); |
|
||||||
|
|
||||||
MapSettingsButton *map_settings_btn; |
|
||||||
|
|
||||||
private: |
|
||||||
void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255); |
|
||||||
|
|
||||||
QVBoxLayout *main_layout; |
|
||||||
ExperimentalButton *experimental_btn; |
|
||||||
QPixmap dm_img; |
|
||||||
float speed; |
|
||||||
QString speedUnit; |
|
||||||
float setSpeed; |
|
||||||
float speedLimit; |
|
||||||
bool is_cruise_set = false; |
|
||||||
bool is_metric = false; |
|
||||||
bool dmActive = false; |
|
||||||
bool hideBottomIcons = false; |
|
||||||
bool rightHandDM = false; |
|
||||||
float dm_fade_state = 1.0; |
|
||||||
bool has_us_speed_limit = false; |
|
||||||
bool has_eu_speed_limit = false; |
|
||||||
bool v_ego_cluster_seen = false; |
|
||||||
int status = STATUS_DISENGAGED; |
|
||||||
std::unique_ptr<PubMaster> pm; |
|
||||||
|
|
||||||
int skip_frame_count = 0; |
|
||||||
bool wide_cam_requested = false; |
|
||||||
|
|
||||||
protected: |
|
||||||
void paintGL() override; |
|
||||||
void initializeGL() override; |
|
||||||
void showEvent(QShowEvent *event) override; |
|
||||||
void updateFrameMat() override; |
|
||||||
void drawLaneLines(QPainter &painter, const UIState *s); |
|
||||||
void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd); |
|
||||||
void drawHud(QPainter &p); |
|
||||||
void drawDriverState(QPainter &painter, const UIState *s); |
|
||||||
inline QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); } |
|
||||||
inline QColor whiteColor(int alpha = 255) { return QColor(255, 255, 255, alpha); } |
|
||||||
inline QColor blackColor(int alpha = 255) { return QColor(0, 0, 0, alpha); } |
|
||||||
|
|
||||||
double prev_draw_t = 0; |
|
||||||
FirstOrderFilter fps_filter; |
|
||||||
}; |
|
||||||
|
|
||||||
// container for all onroad widgets
|
|
||||||
class OnroadWindow : public QWidget { |
|
||||||
Q_OBJECT |
|
||||||
|
|
||||||
public: |
|
||||||
OnroadWindow(QWidget* parent = 0); |
|
||||||
bool isMapVisible() const { return map && map->isVisible(); } |
|
||||||
void showMapPanel(bool show) { if (map) map->setVisible(show); } |
|
||||||
|
|
||||||
signals: |
|
||||||
void mapPanelRequested(); |
|
||||||
|
|
||||||
private: |
|
||||||
void createMapWidget(); |
|
||||||
void paintEvent(QPaintEvent *event); |
|
||||||
void mousePressEvent(QMouseEvent* e) override; |
|
||||||
OnroadAlerts *alerts; |
|
||||||
AnnotatedCameraWidget *nvg; |
|
||||||
QColor bg = bg_colors[STATUS_DISENGAGED]; |
|
||||||
QWidget *map = nullptr; |
|
||||||
QHBoxLayout* split; |
|
||||||
|
|
||||||
private slots: |
|
||||||
void offroadTransition(bool offroad); |
|
||||||
void primeChanged(bool prime); |
|
||||||
void updateState(const UIState &s); |
|
||||||
}; |
|
@ -0,0 +1,112 @@ |
|||||||
|
#include "selfdrive/ui/qt/onroad/alerts.h" |
||||||
|
|
||||||
|
#include <QPainter> |
||||||
|
#include <map> |
||||||
|
|
||||||
|
#include "selfdrive/ui/qt/util.h" |
||||||
|
|
||||||
|
void OnroadAlerts::updateState(const UIState &s) { |
||||||
|
Alert a = getAlert(*(s.sm), s.scene.started_frame); |
||||||
|
if (!alert.equal(a)) { |
||||||
|
alert = a; |
||||||
|
update(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void OnroadAlerts::clear() { |
||||||
|
alert = {}; |
||||||
|
update(); |
||||||
|
} |
||||||
|
|
||||||
|
OnroadAlerts::Alert OnroadAlerts::getAlert(const SubMaster &sm, uint64_t started_frame) { |
||||||
|
const cereal::ControlsState::Reader &cs = sm["controlsState"].getControlsState(); |
||||||
|
const uint64_t controls_frame = sm.rcv_frame("controlsState"); |
||||||
|
|
||||||
|
Alert a = {}; |
||||||
|
if (controls_frame >= started_frame) { // Don't get old alert.
|
||||||
|
a = {cs.getAlertText1().cStr(), cs.getAlertText2().cStr(), |
||||||
|
cs.getAlertType().cStr(), cs.getAlertSize(), cs.getAlertStatus()}; |
||||||
|
} |
||||||
|
|
||||||
|
if (!sm.updated("controlsState") && (sm.frame - started_frame) > 5 * UI_FREQ) { |
||||||
|
const int CONTROLS_TIMEOUT = 5; |
||||||
|
const int controls_missing = (nanos_since_boot() - sm.rcv_time("controlsState")) / 1e9; |
||||||
|
|
||||||
|
// Handle controls timeout
|
||||||
|
if (controls_frame < started_frame) { |
||||||
|
// car is started, but controlsState hasn't been seen at all
|
||||||
|
a = {tr("openpilot Unavailable"), tr("Waiting for controls to start"), |
||||||
|
"controlsWaiting", cereal::ControlsState::AlertSize::MID, |
||||||
|
cereal::ControlsState::AlertStatus::NORMAL}; |
||||||
|
} else if (controls_missing > CONTROLS_TIMEOUT && !Hardware::PC()) { |
||||||
|
// car is started, but controls is lagging or died
|
||||||
|
if (cs.getEnabled() && (controls_missing - CONTROLS_TIMEOUT) < 10) { |
||||||
|
a = {tr("TAKE CONTROL IMMEDIATELY"), tr("Controls Unresponsive"), |
||||||
|
"controlsUnresponsive", cereal::ControlsState::AlertSize::FULL, |
||||||
|
cereal::ControlsState::AlertStatus::CRITICAL}; |
||||||
|
} else { |
||||||
|
a = {tr("Controls Unresponsive"), tr("Reboot Device"), |
||||||
|
"controlsUnresponsivePermanent", cereal::ControlsState::AlertSize::MID, |
||||||
|
cereal::ControlsState::AlertStatus::NORMAL}; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return a; |
||||||
|
} |
||||||
|
|
||||||
|
void OnroadAlerts::paintEvent(QPaintEvent *event) { |
||||||
|
if (alert.size == cereal::ControlsState::AlertSize::NONE) { |
||||||
|
return; |
||||||
|
} |
||||||
|
static std::map<cereal::ControlsState::AlertSize, const int> alert_heights = { |
||||||
|
{cereal::ControlsState::AlertSize::SMALL, 271}, |
||||||
|
{cereal::ControlsState::AlertSize::MID, 420}, |
||||||
|
{cereal::ControlsState::AlertSize::FULL, height()}, |
||||||
|
}; |
||||||
|
int h = alert_heights[alert.size]; |
||||||
|
|
||||||
|
int margin = 40; |
||||||
|
int radius = 30; |
||||||
|
if (alert.size == cereal::ControlsState::AlertSize::FULL) { |
||||||
|
margin = 0; |
||||||
|
radius = 0; |
||||||
|
} |
||||||
|
QRect r = QRect(0 + margin, height() - h + margin, width() - margin*2, h - margin*2); |
||||||
|
|
||||||
|
QPainter p(this); |
||||||
|
|
||||||
|
// draw background + gradient
|
||||||
|
p.setPen(Qt::NoPen); |
||||||
|
p.setCompositionMode(QPainter::CompositionMode_SourceOver); |
||||||
|
p.setBrush(QBrush(alert_colors[alert.status])); |
||||||
|
p.drawRoundedRect(r, radius, radius); |
||||||
|
|
||||||
|
QLinearGradient g(0, r.y(), 0, r.bottom()); |
||||||
|
g.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.05)); |
||||||
|
g.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0.35)); |
||||||
|
|
||||||
|
p.setCompositionMode(QPainter::CompositionMode_DestinationOver); |
||||||
|
p.setBrush(QBrush(g)); |
||||||
|
p.drawRoundedRect(r, radius, radius); |
||||||
|
p.setCompositionMode(QPainter::CompositionMode_SourceOver); |
||||||
|
|
||||||
|
// text
|
||||||
|
const QPoint c = r.center(); |
||||||
|
p.setPen(QColor(0xff, 0xff, 0xff)); |
||||||
|
p.setRenderHint(QPainter::TextAntialiasing); |
||||||
|
if (alert.size == cereal::ControlsState::AlertSize::SMALL) { |
||||||
|
p.setFont(InterFont(74, QFont::DemiBold)); |
||||||
|
p.drawText(r, Qt::AlignCenter, alert.text1); |
||||||
|
} else if (alert.size == cereal::ControlsState::AlertSize::MID) { |
||||||
|
p.setFont(InterFont(88, QFont::Bold)); |
||||||
|
p.drawText(QRect(0, c.y() - 125, width(), 150), Qt::AlignHCenter | Qt::AlignTop, alert.text1); |
||||||
|
p.setFont(InterFont(66)); |
||||||
|
p.drawText(QRect(0, c.y() + 21, width(), 90), Qt::AlignHCenter, alert.text2); |
||||||
|
} else if (alert.size == cereal::ControlsState::AlertSize::FULL) { |
||||||
|
bool l = alert.text1.length() > 15; |
||||||
|
p.setFont(InterFont(l ? 132 : 177, QFont::Bold)); |
||||||
|
p.drawText(QRect(0, r.y() + (l ? 240 : 270), width(), 600), Qt::AlignHCenter | Qt::TextWordWrap, alert.text1); |
||||||
|
p.setFont(InterFont(88)); |
||||||
|
p.drawText(QRect(0, r.height() - (l ? 361 : 420), width(), 300), Qt::AlignHCenter | Qt::TextWordWrap, alert.text2); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <QWidget> |
||||||
|
|
||||||
|
#include "selfdrive/ui/ui.h" |
||||||
|
|
||||||
|
class OnroadAlerts : public QWidget { |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
public: |
||||||
|
OnroadAlerts(QWidget *parent = 0) : QWidget(parent) {} |
||||||
|
void updateState(const UIState &s); |
||||||
|
void clear(); |
||||||
|
|
||||||
|
protected: |
||||||
|
struct Alert { |
||||||
|
QString text1; |
||||||
|
QString text2; |
||||||
|
QString type; |
||||||
|
cereal::ControlsState::AlertSize size; |
||||||
|
cereal::ControlsState::AlertStatus status; |
||||||
|
|
||||||
|
bool equal(const Alert &other) const { |
||||||
|
return text1 == other.text1 && other.text2 == other.text2 && type == other.type; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const QMap<cereal::ControlsState::AlertStatus, QColor> alert_colors = { |
||||||
|
{cereal::ControlsState::AlertStatus::NORMAL, QColor(0x15, 0x15, 0x15, 0xf1)}, |
||||||
|
{cereal::ControlsState::AlertStatus::USER_PROMPT, QColor(0xDA, 0x6F, 0x25, 0xf1)}, |
||||||
|
{cereal::ControlsState::AlertStatus::CRITICAL, QColor(0xC9, 0x22, 0x31, 0xf1)}, |
||||||
|
}; |
||||||
|
|
||||||
|
void paintEvent(QPaintEvent*) override; |
||||||
|
OnroadAlerts::Alert getAlert(const SubMaster &sm, uint64_t started_frame); |
||||||
|
|
||||||
|
QColor bg; |
||||||
|
Alert alert = {}; |
||||||
|
}; |
@ -1,310 +1,13 @@ |
|||||||
#include "selfdrive/ui/qt/onroad.h" |
|
||||||
|
|
||||||
|
#include "selfdrive/ui/qt/onroad/annotated_camera.h" |
||||||
|
|
||||||
|
#include <QPainter> |
||||||
#include <algorithm> |
#include <algorithm> |
||||||
#include <cmath> |
#include <cmath> |
||||||
#include <map> |
|
||||||
#include <memory> |
|
||||||
#include <sstream> |
|
||||||
|
|
||||||
#include <QDebug> |
|
||||||
#include <QMouseEvent> |
|
||||||
|
|
||||||
#include "common/swaglog.h" |
#include "common/swaglog.h" |
||||||
#include "common/timing.h" |
#include "selfdrive/ui/qt/onroad/buttons.h" |
||||||
#include "selfdrive/ui/qt/util.h" |
#include "selfdrive/ui/qt/util.h" |
||||||
#ifdef ENABLE_MAPS |
|
||||||
#include "selfdrive/ui/qt/maps/map_helpers.h" |
|
||||||
#include "selfdrive/ui/qt/maps/map_panel.h" |
|
||||||
#endif |
|
||||||
|
|
||||||
static void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity) { |
|
||||||
p.setRenderHint(QPainter::Antialiasing); |
|
||||||
p.setOpacity(1.0); // bg dictates opacity of ellipse
|
|
||||||
p.setPen(Qt::NoPen); |
|
||||||
p.setBrush(bg); |
|
||||||
p.drawEllipse(center, btn_size / 2, btn_size / 2); |
|
||||||
p.setOpacity(opacity); |
|
||||||
p.drawPixmap(center - QPoint(img.width() / 2, img.height() / 2), img); |
|
||||||
p.setOpacity(1.0); |
|
||||||
} |
|
||||||
|
|
||||||
OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { |
|
||||||
QVBoxLayout *main_layout = new QVBoxLayout(this); |
|
||||||
main_layout->setMargin(UI_BORDER_SIZE); |
|
||||||
QStackedLayout *stacked_layout = new QStackedLayout; |
|
||||||
stacked_layout->setStackingMode(QStackedLayout::StackAll); |
|
||||||
main_layout->addLayout(stacked_layout); |
|
||||||
|
|
||||||
nvg = new AnnotatedCameraWidget(VISION_STREAM_ROAD, this); |
|
||||||
|
|
||||||
QWidget * split_wrapper = new QWidget; |
|
||||||
split = new QHBoxLayout(split_wrapper); |
|
||||||
split->setContentsMargins(0, 0, 0, 0); |
|
||||||
split->setSpacing(0); |
|
||||||
split->addWidget(nvg); |
|
||||||
|
|
||||||
if (getenv("DUAL_CAMERA_VIEW")) { |
|
||||||
CameraWidget *arCam = new CameraWidget("camerad", VISION_STREAM_ROAD, true, this); |
|
||||||
split->insertWidget(0, arCam); |
|
||||||
} |
|
||||||
|
|
||||||
if (getenv("MAP_RENDER_VIEW")) { |
|
||||||
CameraWidget *map_render = new CameraWidget("navd", VISION_STREAM_MAP, false, this); |
|
||||||
split->insertWidget(0, map_render); |
|
||||||
} |
|
||||||
|
|
||||||
stacked_layout->addWidget(split_wrapper); |
|
||||||
|
|
||||||
alerts = new OnroadAlerts(this); |
|
||||||
alerts->setAttribute(Qt::WA_TransparentForMouseEvents, true); |
|
||||||
stacked_layout->addWidget(alerts); |
|
||||||
|
|
||||||
// setup stacking order
|
|
||||||
alerts->raise(); |
|
||||||
|
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent); |
|
||||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &OnroadWindow::updateState); |
|
||||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &OnroadWindow::offroadTransition); |
|
||||||
QObject::connect(uiState(), &UIState::primeChanged, this, &OnroadWindow::primeChanged); |
|
||||||
} |
|
||||||
|
|
||||||
void OnroadWindow::updateState(const UIState &s) { |
|
||||||
if (!s.scene.started) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
if (s.scene.map_on_left) { |
|
||||||
split->setDirection(QBoxLayout::LeftToRight); |
|
||||||
} else { |
|
||||||
split->setDirection(QBoxLayout::RightToLeft); |
|
||||||
} |
|
||||||
|
|
||||||
alerts->updateState(s); |
|
||||||
nvg->updateState(s); |
|
||||||
|
|
||||||
QColor bgColor = bg_colors[s.status]; |
|
||||||
if (bg != bgColor) { |
|
||||||
// repaint border
|
|
||||||
bg = bgColor; |
|
||||||
update(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void OnroadWindow::mousePressEvent(QMouseEvent* e) { |
|
||||||
#ifdef ENABLE_MAPS |
|
||||||
if (map != nullptr) { |
|
||||||
bool sidebarVisible = geometry().x() > 0; |
|
||||||
bool show_map = !sidebarVisible; |
|
||||||
map->setVisible(show_map && !map->isVisible()); |
|
||||||
} |
|
||||||
#endif |
|
||||||
// propagation event to parent(HomeWindow)
|
|
||||||
QWidget::mousePressEvent(e); |
|
||||||
} |
|
||||||
|
|
||||||
void OnroadWindow::createMapWidget() { |
|
||||||
#ifdef ENABLE_MAPS |
|
||||||
auto m = new MapPanel(get_mapbox_settings()); |
|
||||||
map = m; |
|
||||||
QObject::connect(m, &MapPanel::mapPanelRequested, this, &OnroadWindow::mapPanelRequested); |
|
||||||
QObject::connect(nvg->map_settings_btn, &MapSettingsButton::clicked, m, &MapPanel::toggleMapSettings); |
|
||||||
nvg->map_settings_btn->setEnabled(true); |
|
||||||
|
|
||||||
m->setFixedWidth(topWidget(this)->width() / 2 - UI_BORDER_SIZE); |
|
||||||
split->insertWidget(0, m); |
|
||||||
// hidden by default, made visible when navRoute is published
|
|
||||||
m->setVisible(false); |
|
||||||
#endif |
|
||||||
} |
|
||||||
|
|
||||||
void OnroadWindow::offroadTransition(bool offroad) { |
|
||||||
#ifdef ENABLE_MAPS |
|
||||||
if (!offroad) { |
|
||||||
if (map == nullptr && (uiState()->hasPrime() || !MAPBOX_TOKEN.isEmpty())) { |
|
||||||
createMapWidget(); |
|
||||||
} |
|
||||||
} |
|
||||||
#endif |
|
||||||
alerts->clear(); |
|
||||||
} |
|
||||||
|
|
||||||
void OnroadWindow::primeChanged(bool prime) { |
|
||||||
#ifdef ENABLE_MAPS |
|
||||||
if (map && (!prime && MAPBOX_TOKEN.isEmpty())) { |
|
||||||
nvg->map_settings_btn->setEnabled(false); |
|
||||||
nvg->map_settings_btn->setVisible(false); |
|
||||||
map->deleteLater(); |
|
||||||
map = nullptr; |
|
||||||
} else if (!map && (prime || !MAPBOX_TOKEN.isEmpty())) { |
|
||||||
createMapWidget(); |
|
||||||
} |
|
||||||
#endif |
|
||||||
} |
|
||||||
|
|
||||||
void OnroadWindow::paintEvent(QPaintEvent *event) { |
|
||||||
QPainter p(this); |
|
||||||
p.fillRect(rect(), QColor(bg.red(), bg.green(), bg.blue(), 255)); |
|
||||||
} |
|
||||||
|
|
||||||
// ***** onroad widgets *****
|
|
||||||
|
|
||||||
// OnroadAlerts
|
|
||||||
|
|
||||||
void OnroadAlerts::updateState(const UIState &s) { |
|
||||||
Alert a = getAlert(*(s.sm), s.scene.started_frame); |
|
||||||
if (!alert.equal(a)) { |
|
||||||
alert = a; |
|
||||||
update(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void OnroadAlerts::clear() { |
|
||||||
alert = {}; |
|
||||||
update(); |
|
||||||
} |
|
||||||
|
|
||||||
OnroadAlerts::Alert OnroadAlerts::getAlert(const SubMaster &sm, uint64_t started_frame) { |
|
||||||
const cereal::ControlsState::Reader &cs = sm["controlsState"].getControlsState(); |
|
||||||
const uint64_t controls_frame = sm.rcv_frame("controlsState"); |
|
||||||
|
|
||||||
Alert a = {}; |
|
||||||
if (controls_frame >= started_frame) { // Don't get old alert.
|
|
||||||
a = {cs.getAlertText1().cStr(), cs.getAlertText2().cStr(), |
|
||||||
cs.getAlertType().cStr(), cs.getAlertSize(), cs.getAlertStatus()}; |
|
||||||
} |
|
||||||
|
|
||||||
if (!sm.updated("controlsState") && (sm.frame - started_frame) > 5 * UI_FREQ) { |
|
||||||
const int CONTROLS_TIMEOUT = 5; |
|
||||||
const int controls_missing = (nanos_since_boot() - sm.rcv_time("controlsState")) / 1e9; |
|
||||||
|
|
||||||
// Handle controls timeout
|
|
||||||
if (controls_frame < started_frame) { |
|
||||||
// car is started, but controlsState hasn't been seen at all
|
|
||||||
a = {tr("openpilot Unavailable"), tr("Waiting for controls to start"), |
|
||||||
"controlsWaiting", cereal::ControlsState::AlertSize::MID, |
|
||||||
cereal::ControlsState::AlertStatus::NORMAL}; |
|
||||||
} else if (controls_missing > CONTROLS_TIMEOUT && !Hardware::PC()) { |
|
||||||
// car is started, but controls is lagging or died
|
|
||||||
if (cs.getEnabled() && (controls_missing - CONTROLS_TIMEOUT) < 10) { |
|
||||||
a = {tr("TAKE CONTROL IMMEDIATELY"), tr("Controls Unresponsive"), |
|
||||||
"controlsUnresponsive", cereal::ControlsState::AlertSize::FULL, |
|
||||||
cereal::ControlsState::AlertStatus::CRITICAL}; |
|
||||||
} else { |
|
||||||
a = {tr("Controls Unresponsive"), tr("Reboot Device"), |
|
||||||
"controlsUnresponsivePermanent", cereal::ControlsState::AlertSize::MID, |
|
||||||
cereal::ControlsState::AlertStatus::NORMAL}; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return a; |
|
||||||
} |
|
||||||
|
|
||||||
void OnroadAlerts::paintEvent(QPaintEvent *event) { |
|
||||||
if (alert.size == cereal::ControlsState::AlertSize::NONE) { |
|
||||||
return; |
|
||||||
} |
|
||||||
static std::map<cereal::ControlsState::AlertSize, const int> alert_heights = { |
|
||||||
{cereal::ControlsState::AlertSize::SMALL, 271}, |
|
||||||
{cereal::ControlsState::AlertSize::MID, 420}, |
|
||||||
{cereal::ControlsState::AlertSize::FULL, height()}, |
|
||||||
}; |
|
||||||
int h = alert_heights[alert.size]; |
|
||||||
|
|
||||||
int margin = 40; |
|
||||||
int radius = 30; |
|
||||||
if (alert.size == cereal::ControlsState::AlertSize::FULL) { |
|
||||||
margin = 0; |
|
||||||
radius = 0; |
|
||||||
} |
|
||||||
QRect r = QRect(0 + margin, height() - h + margin, width() - margin*2, h - margin*2); |
|
||||||
|
|
||||||
QPainter p(this); |
|
||||||
|
|
||||||
// draw background + gradient
|
|
||||||
p.setPen(Qt::NoPen); |
|
||||||
p.setCompositionMode(QPainter::CompositionMode_SourceOver); |
|
||||||
p.setBrush(QBrush(alert_colors[alert.status])); |
|
||||||
p.drawRoundedRect(r, radius, radius); |
|
||||||
|
|
||||||
QLinearGradient g(0, r.y(), 0, r.bottom()); |
|
||||||
g.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.05)); |
|
||||||
g.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0.35)); |
|
||||||
|
|
||||||
p.setCompositionMode(QPainter::CompositionMode_DestinationOver); |
|
||||||
p.setBrush(QBrush(g)); |
|
||||||
p.drawRoundedRect(r, radius, radius); |
|
||||||
p.setCompositionMode(QPainter::CompositionMode_SourceOver); |
|
||||||
|
|
||||||
// text
|
|
||||||
const QPoint c = r.center(); |
|
||||||
p.setPen(QColor(0xff, 0xff, 0xff)); |
|
||||||
p.setRenderHint(QPainter::TextAntialiasing); |
|
||||||
if (alert.size == cereal::ControlsState::AlertSize::SMALL) { |
|
||||||
p.setFont(InterFont(74, QFont::DemiBold)); |
|
||||||
p.drawText(r, Qt::AlignCenter, alert.text1); |
|
||||||
} else if (alert.size == cereal::ControlsState::AlertSize::MID) { |
|
||||||
p.setFont(InterFont(88, QFont::Bold)); |
|
||||||
p.drawText(QRect(0, c.y() - 125, width(), 150), Qt::AlignHCenter | Qt::AlignTop, alert.text1); |
|
||||||
p.setFont(InterFont(66)); |
|
||||||
p.drawText(QRect(0, c.y() + 21, width(), 90), Qt::AlignHCenter, alert.text2); |
|
||||||
} else if (alert.size == cereal::ControlsState::AlertSize::FULL) { |
|
||||||
bool l = alert.text1.length() > 15; |
|
||||||
p.setFont(InterFont(l ? 132 : 177, QFont::Bold)); |
|
||||||
p.drawText(QRect(0, r.y() + (l ? 240 : 270), width(), 600), Qt::AlignHCenter | Qt::TextWordWrap, alert.text1); |
|
||||||
p.setFont(InterFont(88)); |
|
||||||
p.drawText(QRect(0, r.height() - (l ? 361 : 420), width(), 300), Qt::AlignHCenter | Qt::TextWordWrap, alert.text2); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// ExperimentalButton
|
|
||||||
ExperimentalButton::ExperimentalButton(QWidget *parent) : experimental_mode(false), engageable(false), QPushButton(parent) { |
|
||||||
setFixedSize(btn_size, btn_size); |
|
||||||
|
|
||||||
engage_img = loadPixmap("../assets/img_chffr_wheel.png", {img_size, img_size}); |
|
||||||
experimental_img = loadPixmap("../assets/img_experimental.svg", {img_size, img_size}); |
|
||||||
QObject::connect(this, &QPushButton::clicked, this, &ExperimentalButton::changeMode); |
|
||||||
} |
|
||||||
|
|
||||||
void ExperimentalButton::changeMode() { |
|
||||||
const auto cp = (*uiState()->sm)["carParams"].getCarParams(); |
|
||||||
bool can_change = hasLongitudinalControl(cp) && params.getBool("ExperimentalModeConfirmed"); |
|
||||||
if (can_change) { |
|
||||||
params.putBool("ExperimentalMode", !experimental_mode); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void ExperimentalButton::updateState(const UIState &s) { |
|
||||||
const auto cs = (*s.sm)["controlsState"].getControlsState(); |
|
||||||
bool eng = cs.getEngageable() || cs.getEnabled(); |
|
||||||
if ((cs.getExperimentalMode() != experimental_mode) || (eng != engageable)) { |
|
||||||
engageable = eng; |
|
||||||
experimental_mode = cs.getExperimentalMode(); |
|
||||||
update(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void ExperimentalButton::paintEvent(QPaintEvent *event) { |
|
||||||
QPainter p(this); |
|
||||||
QPixmap img = experimental_mode ? experimental_img : engage_img; |
|
||||||
drawIcon(p, QPoint(btn_size / 2, btn_size / 2), img, QColor(0, 0, 0, 166), (isDown() || !engageable) ? 0.6 : 1.0); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// MapSettingsButton
|
|
||||||
MapSettingsButton::MapSettingsButton(QWidget *parent) : QPushButton(parent) { |
|
||||||
setFixedSize(btn_size, btn_size); |
|
||||||
settings_img = loadPixmap("../assets/navigation/icon_directions_outlined.svg", {img_size, img_size}); |
|
||||||
|
|
||||||
// hidden by default, made visible if map is created (has prime or mapbox token)
|
|
||||||
setVisible(false); |
|
||||||
setEnabled(false); |
|
||||||
} |
|
||||||
|
|
||||||
void MapSettingsButton::paintEvent(QPaintEvent *event) { |
|
||||||
QPainter p(this); |
|
||||||
drawIcon(p, QPoint(btn_size / 2, btn_size / 2), settings_img, QColor(0, 0, 0, 166), isDown() ? 0.6 : 1.0); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// Window that shows camera view and variety of info drawn on top
|
// Window that shows camera view and variety of info drawn on top
|
||||||
AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent) { |
AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent) { |
@ -0,0 +1,58 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <QVBoxLayout> |
||||||
|
#include <memory> |
||||||
|
|
||||||
|
#include "selfdrive/ui/qt/onroad/buttons.h" |
||||||
|
#include "selfdrive/ui/qt/widgets/cameraview.h" |
||||||
|
|
||||||
|
class AnnotatedCameraWidget : public CameraWidget { |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
public: |
||||||
|
explicit AnnotatedCameraWidget(VisionStreamType type, QWidget* parent = 0); |
||||||
|
void updateState(const UIState &s); |
||||||
|
|
||||||
|
MapSettingsButton *map_settings_btn; |
||||||
|
|
||||||
|
private: |
||||||
|
void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255); |
||||||
|
|
||||||
|
QVBoxLayout *main_layout; |
||||||
|
ExperimentalButton *experimental_btn; |
||||||
|
QPixmap dm_img; |
||||||
|
float speed; |
||||||
|
QString speedUnit; |
||||||
|
float setSpeed; |
||||||
|
float speedLimit; |
||||||
|
bool is_cruise_set = false; |
||||||
|
bool is_metric = false; |
||||||
|
bool dmActive = false; |
||||||
|
bool hideBottomIcons = false; |
||||||
|
bool rightHandDM = false; |
||||||
|
float dm_fade_state = 1.0; |
||||||
|
bool has_us_speed_limit = false; |
||||||
|
bool has_eu_speed_limit = false; |
||||||
|
bool v_ego_cluster_seen = false; |
||||||
|
int status = STATUS_DISENGAGED; |
||||||
|
std::unique_ptr<PubMaster> pm; |
||||||
|
|
||||||
|
int skip_frame_count = 0; |
||||||
|
bool wide_cam_requested = false; |
||||||
|
|
||||||
|
protected: |
||||||
|
void paintGL() override; |
||||||
|
void initializeGL() override; |
||||||
|
void showEvent(QShowEvent *event) override; |
||||||
|
void updateFrameMat() override; |
||||||
|
void drawLaneLines(QPainter &painter, const UIState *s); |
||||||
|
void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd); |
||||||
|
void drawHud(QPainter &p); |
||||||
|
void drawDriverState(QPainter &painter, const UIState *s); |
||||||
|
inline QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); } |
||||||
|
inline QColor whiteColor(int alpha = 255) { return QColor(255, 255, 255, alpha); } |
||||||
|
inline QColor blackColor(int alpha = 255) { return QColor(0, 0, 0, alpha); } |
||||||
|
|
||||||
|
double prev_draw_t = 0; |
||||||
|
FirstOrderFilter fps_filter; |
||||||
|
}; |
@ -0,0 +1,64 @@ |
|||||||
|
#include "selfdrive/ui/qt/onroad/buttons.h" |
||||||
|
|
||||||
|
#include <QPainter> |
||||||
|
|
||||||
|
#include "selfdrive/ui/qt/util.h" |
||||||
|
|
||||||
|
void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity) { |
||||||
|
p.setRenderHint(QPainter::Antialiasing); |
||||||
|
p.setOpacity(1.0); // bg dictates opacity of ellipse
|
||||||
|
p.setPen(Qt::NoPen); |
||||||
|
p.setBrush(bg); |
||||||
|
p.drawEllipse(center, btn_size / 2, btn_size / 2); |
||||||
|
p.setOpacity(opacity); |
||||||
|
p.drawPixmap(center - QPoint(img.width() / 2, img.height() / 2), img); |
||||||
|
p.setOpacity(1.0); |
||||||
|
} |
||||||
|
|
||||||
|
// ExperimentalButton
|
||||||
|
ExperimentalButton::ExperimentalButton(QWidget *parent) : experimental_mode(false), engageable(false), QPushButton(parent) { |
||||||
|
setFixedSize(btn_size, btn_size); |
||||||
|
|
||||||
|
engage_img = loadPixmap("../assets/img_chffr_wheel.png", {img_size, img_size}); |
||||||
|
experimental_img = loadPixmap("../assets/img_experimental.svg", {img_size, img_size}); |
||||||
|
QObject::connect(this, &QPushButton::clicked, this, &ExperimentalButton::changeMode); |
||||||
|
} |
||||||
|
|
||||||
|
void ExperimentalButton::changeMode() { |
||||||
|
const auto cp = (*uiState()->sm)["carParams"].getCarParams(); |
||||||
|
bool can_change = hasLongitudinalControl(cp) && params.getBool("ExperimentalModeConfirmed"); |
||||||
|
if (can_change) { |
||||||
|
params.putBool("ExperimentalMode", !experimental_mode); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void ExperimentalButton::updateState(const UIState &s) { |
||||||
|
const auto cs = (*s.sm)["controlsState"].getControlsState(); |
||||||
|
bool eng = cs.getEngageable() || cs.getEnabled(); |
||||||
|
if ((cs.getExperimentalMode() != experimental_mode) || (eng != engageable)) { |
||||||
|
engageable = eng; |
||||||
|
experimental_mode = cs.getExperimentalMode(); |
||||||
|
update(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void ExperimentalButton::paintEvent(QPaintEvent *event) { |
||||||
|
QPainter p(this); |
||||||
|
QPixmap img = experimental_mode ? experimental_img : engage_img; |
||||||
|
drawIcon(p, QPoint(btn_size / 2, btn_size / 2), img, QColor(0, 0, 0, 166), (isDown() || !engageable) ? 0.6 : 1.0); |
||||||
|
} |
||||||
|
|
||||||
|
// MapSettingsButton
|
||||||
|
MapSettingsButton::MapSettingsButton(QWidget *parent) : QPushButton(parent) { |
||||||
|
setFixedSize(btn_size, btn_size); |
||||||
|
settings_img = loadPixmap("../assets/navigation/icon_directions_outlined.svg", {img_size, img_size}); |
||||||
|
|
||||||
|
// hidden by default, made visible if map is created (has prime or mapbox token)
|
||||||
|
setVisible(false); |
||||||
|
setEnabled(false); |
||||||
|
} |
||||||
|
|
||||||
|
void MapSettingsButton::paintEvent(QPaintEvent *event) { |
||||||
|
QPainter p(this); |
||||||
|
drawIcon(p, QPoint(btn_size / 2, btn_size / 2), settings_img, QColor(0, 0, 0, 166), isDown() ? 0.6 : 1.0); |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <QPushButton> |
||||||
|
|
||||||
|
#include "selfdrive/ui/ui.h" |
||||||
|
|
||||||
|
const int btn_size = 192; |
||||||
|
const int img_size = (btn_size / 4) * 3; |
||||||
|
|
||||||
|
class ExperimentalButton : public QPushButton { |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
public: |
||||||
|
explicit ExperimentalButton(QWidget *parent = 0); |
||||||
|
void updateState(const UIState &s); |
||||||
|
|
||||||
|
private: |
||||||
|
void paintEvent(QPaintEvent *event) override; |
||||||
|
void changeMode(); |
||||||
|
|
||||||
|
Params params; |
||||||
|
QPixmap engage_img; |
||||||
|
QPixmap experimental_img; |
||||||
|
bool experimental_mode; |
||||||
|
bool engageable; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
class MapSettingsButton : public QPushButton { |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
public: |
||||||
|
explicit MapSettingsButton(QWidget *parent = 0); |
||||||
|
|
||||||
|
private: |
||||||
|
void paintEvent(QPaintEvent *event) override; |
||||||
|
|
||||||
|
QPixmap settings_img; |
||||||
|
}; |
||||||
|
|
||||||
|
void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity); |
@ -0,0 +1,128 @@ |
|||||||
|
#include "selfdrive/ui/qt/onroad/onroad_home.h" |
||||||
|
|
||||||
|
#include <QPainter> |
||||||
|
|
||||||
|
#ifdef ENABLE_MAPS |
||||||
|
#include "selfdrive/ui/qt/maps/map_helpers.h" |
||||||
|
#include "selfdrive/ui/qt/maps/map_panel.h" |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "selfdrive/ui/qt/util.h" |
||||||
|
|
||||||
|
OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { |
||||||
|
QVBoxLayout *main_layout = new QVBoxLayout(this); |
||||||
|
main_layout->setMargin(UI_BORDER_SIZE); |
||||||
|
QStackedLayout *stacked_layout = new QStackedLayout; |
||||||
|
stacked_layout->setStackingMode(QStackedLayout::StackAll); |
||||||
|
main_layout->addLayout(stacked_layout); |
||||||
|
|
||||||
|
nvg = new AnnotatedCameraWidget(VISION_STREAM_ROAD, this); |
||||||
|
|
||||||
|
QWidget * split_wrapper = new QWidget; |
||||||
|
split = new QHBoxLayout(split_wrapper); |
||||||
|
split->setContentsMargins(0, 0, 0, 0); |
||||||
|
split->setSpacing(0); |
||||||
|
split->addWidget(nvg); |
||||||
|
|
||||||
|
if (getenv("DUAL_CAMERA_VIEW")) { |
||||||
|
CameraWidget *arCam = new CameraWidget("camerad", VISION_STREAM_ROAD, true, this); |
||||||
|
split->insertWidget(0, arCam); |
||||||
|
} |
||||||
|
|
||||||
|
if (getenv("MAP_RENDER_VIEW")) { |
||||||
|
CameraWidget *map_render = new CameraWidget("navd", VISION_STREAM_MAP, false, this); |
||||||
|
split->insertWidget(0, map_render); |
||||||
|
} |
||||||
|
|
||||||
|
stacked_layout->addWidget(split_wrapper); |
||||||
|
|
||||||
|
alerts = new OnroadAlerts(this); |
||||||
|
alerts->setAttribute(Qt::WA_TransparentForMouseEvents, true); |
||||||
|
stacked_layout->addWidget(alerts); |
||||||
|
|
||||||
|
// setup stacking order
|
||||||
|
alerts->raise(); |
||||||
|
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent); |
||||||
|
QObject::connect(uiState(), &UIState::uiUpdate, this, &OnroadWindow::updateState); |
||||||
|
QObject::connect(uiState(), &UIState::offroadTransition, this, &OnroadWindow::offroadTransition); |
||||||
|
QObject::connect(uiState(), &UIState::primeChanged, this, &OnroadWindow::primeChanged); |
||||||
|
} |
||||||
|
|
||||||
|
void OnroadWindow::updateState(const UIState &s) { |
||||||
|
if (!s.scene.started) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (s.scene.map_on_left) { |
||||||
|
split->setDirection(QBoxLayout::LeftToRight); |
||||||
|
} else { |
||||||
|
split->setDirection(QBoxLayout::RightToLeft); |
||||||
|
} |
||||||
|
|
||||||
|
alerts->updateState(s); |
||||||
|
nvg->updateState(s); |
||||||
|
|
||||||
|
QColor bgColor = bg_colors[s.status]; |
||||||
|
if (bg != bgColor) { |
||||||
|
// repaint border
|
||||||
|
bg = bgColor; |
||||||
|
update(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void OnroadWindow::mousePressEvent(QMouseEvent* e) { |
||||||
|
#ifdef ENABLE_MAPS |
||||||
|
if (map != nullptr) { |
||||||
|
bool sidebarVisible = geometry().x() > 0; |
||||||
|
bool show_map = !sidebarVisible; |
||||||
|
map->setVisible(show_map && !map->isVisible()); |
||||||
|
} |
||||||
|
#endif |
||||||
|
// propagation event to parent(HomeWindow)
|
||||||
|
QWidget::mousePressEvent(e); |
||||||
|
} |
||||||
|
|
||||||
|
void OnroadWindow::createMapWidget() { |
||||||
|
#ifdef ENABLE_MAPS |
||||||
|
auto m = new MapPanel(get_mapbox_settings()); |
||||||
|
map = m; |
||||||
|
QObject::connect(m, &MapPanel::mapPanelRequested, this, &OnroadWindow::mapPanelRequested); |
||||||
|
QObject::connect(nvg->map_settings_btn, &MapSettingsButton::clicked, m, &MapPanel::toggleMapSettings); |
||||||
|
nvg->map_settings_btn->setEnabled(true); |
||||||
|
|
||||||
|
m->setFixedWidth(topWidget(this)->width() / 2 - UI_BORDER_SIZE); |
||||||
|
split->insertWidget(0, m); |
||||||
|
// hidden by default, made visible when navRoute is published
|
||||||
|
m->setVisible(false); |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
void OnroadWindow::offroadTransition(bool offroad) { |
||||||
|
#ifdef ENABLE_MAPS |
||||||
|
if (!offroad) { |
||||||
|
if (map == nullptr && (uiState()->hasPrime() || !MAPBOX_TOKEN.isEmpty())) { |
||||||
|
createMapWidget(); |
||||||
|
} |
||||||
|
} |
||||||
|
#endif |
||||||
|
alerts->clear(); |
||||||
|
} |
||||||
|
|
||||||
|
void OnroadWindow::primeChanged(bool prime) { |
||||||
|
#ifdef ENABLE_MAPS |
||||||
|
if (map && (!prime && MAPBOX_TOKEN.isEmpty())) { |
||||||
|
nvg->map_settings_btn->setEnabled(false); |
||||||
|
nvg->map_settings_btn->setVisible(false); |
||||||
|
map->deleteLater(); |
||||||
|
map = nullptr; |
||||||
|
} else if (!map && (prime || !MAPBOX_TOKEN.isEmpty())) { |
||||||
|
createMapWidget(); |
||||||
|
} |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
void OnroadWindow::paintEvent(QPaintEvent *event) { |
||||||
|
QPainter p(this); |
||||||
|
p.fillRect(rect(), QColor(bg.red(), bg.green(), bg.blue(), 255)); |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include "selfdrive/ui/qt/onroad/alerts.h" |
||||||
|
#include "selfdrive/ui/qt/onroad/annotated_camera.h" |
||||||
|
|
||||||
|
class OnroadWindow : public QWidget { |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
public: |
||||||
|
OnroadWindow(QWidget* parent = 0); |
||||||
|
bool isMapVisible() const { return map && map->isVisible(); } |
||||||
|
void showMapPanel(bool show) { if (map) map->setVisible(show); } |
||||||
|
|
||||||
|
signals: |
||||||
|
void mapPanelRequested(); |
||||||
|
|
||||||
|
private: |
||||||
|
void createMapWidget(); |
||||||
|
void paintEvent(QPaintEvent *event); |
||||||
|
void mousePressEvent(QMouseEvent* e) override; |
||||||
|
OnroadAlerts *alerts; |
||||||
|
AnnotatedCameraWidget *nvg; |
||||||
|
QColor bg = bg_colors[STATUS_DISENGAGED]; |
||||||
|
QWidget *map = nullptr; |
||||||
|
QHBoxLayout* split; |
||||||
|
|
||||||
|
private slots: |
||||||
|
void offroadTransition(bool offroad); |
||||||
|
void primeChanged(bool prime); |
||||||
|
void updateState(const UIState &s); |
||||||
|
}; |
Loading…
Reference in new issue