From f0389f7e2d45f7f42e35bdea6a3daff0cd3aa919 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 24 Jul 2021 12:45:47 +0800 Subject: [PATCH] Qt: draw border in OnroadWindow (#21594) * draw border in OnroadAlerts * non transparent * no scissor * set video_rect to the full size * fix header gradient * Revert "fix header gradient" This reverts commit f5565c19d5cabda22fe6b60af23dc26727ecd5bc. * Revert "set video_rect to the full size" This reverts commit c012db105a8cabd140971208431d83ae3592b70e. * fix scissor * fix header gradient * set scissor box to video_rect when draw lines * move up eta * init alert_size to NONE * remove glScissor * cleanup * rename draw_video_frame to draw_vision_frame * remove space * add comment * move border to OnroadWindow * cleanup signals * fw declare MapWindow * fix build err * remove viz_rect * fix build err * continue * cleanup * text rect:no border * use signals * remove space cleanup * merge master * fix map eta * get bgColor from alerts * update alerts in OnroadWindow * add function clearAlert * repaint border * init bg color to STATUS_DISENGAGED * no black frame * cleanup Co-authored-by: Willem Melching Co-authored-by: Adeeb Shihadeh --- selfdrive/ui/paint.cc | 78 +++++++++--------------------- selfdrive/ui/qt/home.cc | 2 +- selfdrive/ui/qt/maps/map.cc | 4 +- selfdrive/ui/qt/onroad.cc | 96 +++++++++++++++++++------------------ selfdrive/ui/qt/onroad.h | 20 ++++---- selfdrive/ui/ui.h | 1 - 6 files changed, 84 insertions(+), 117 deletions(-) diff --git a/selfdrive/ui/paint.cc b/selfdrive/ui/paint.cc index 96d635ac9f..ac944fd872 100644 --- a/selfdrive/ui/paint.cc +++ b/selfdrive/ui/paint.cc @@ -85,8 +85,8 @@ static void draw_lead(UIState *s, const cereal::RadarState::LeadData::Reader &le } float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), 15.0f, 30.0f) * 2.35; - x = std::clamp(x, 0.f, s->viz_rect.right() - sz / 2); - y = std::fmin(s->viz_rect.bottom() - sz * .6, y); + x = std::clamp(x, 0.f, s->fb_w - sz / 2); + y = std::fmin(s->fb_h - sz * .6, y); draw_chevron(s, x, y, sz, nvgRGBA(201, 34, 49, fillAlpha), COLOR_YELLOW); } @@ -108,7 +108,7 @@ static void ui_draw_line(UIState *s, const line_vertices_data &vd, NVGcolor *col nvgFill(s->vg); } -static void draw_frame(UIState *s) { +static void draw_vision_frame(UIState *s) { glBindVertexArray(s->frame_vao); mat4 *out_mat = &s->rear_frame_mat; glActiveTexture(GL_TEXTURE0); @@ -160,8 +160,7 @@ static void ui_draw_vision_lane_lines(UIState *s) { // Draw all world space objects. static void ui_draw_world(UIState *s) { - // Don't draw on top of sidebar - nvgScissor(s->vg, s->viz_rect.x, s->viz_rect.y, s->viz_rect.w, s->viz_rect.h); + nvgScissor(s->vg, 0, 0, s->fb_w, s->fb_h); // Draw lane edges and vision/mpc tracks ui_draw_vision_lane_lines(s); @@ -187,17 +186,17 @@ static void ui_draw_vision_maxspeed(UIState *s) { const bool is_cruise_set = maxspeed != 0 && maxspeed != SET_SPEED_NA; if (is_cruise_set && !s->scene.is_metric) { maxspeed *= 0.6225; } - const Rect rect = {s->viz_rect.x + (bdr_s * 2), int(s->viz_rect.y + (bdr_s * 1.5)), 184, 202}; + const Rect rect = {bdr_s * 2, int(bdr_s * 1.5), 184, 202}; ui_fill_rect(s->vg, rect, COLOR_BLACK_ALPHA(100), 30.); ui_draw_rect(s->vg, rect, COLOR_WHITE_ALPHA(100), 10, 20.); nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); - ui_draw_text(s, rect.centerX(), 148, "MAX", 26 * 2.5, COLOR_WHITE_ALPHA(is_cruise_set ? 200 : 100), "sans-regular"); + ui_draw_text(s, rect.centerX(), 118, "MAX", 26 * 2.5, COLOR_WHITE_ALPHA(is_cruise_set ? 200 : 100), "sans-regular"); if (is_cruise_set) { const std::string maxspeed_str = std::to_string((int)std::nearbyint(maxspeed)); - ui_draw_text(s, rect.centerX(), 242, maxspeed_str.c_str(), 48 * 2.5, COLOR_WHITE, "sans-bold"); + ui_draw_text(s, rect.centerX(), 212, maxspeed_str.c_str(), 48 * 2.5, COLOR_WHITE, "sans-bold"); } else { - ui_draw_text(s, rect.centerX(), 242, "N/A", 42 * 2.5, COLOR_WHITE_ALPHA(100), "sans-semibold"); + ui_draw_text(s, rect.centerX(), 212, "N/A", 42 * 2.5, COLOR_WHITE_ALPHA(100), "sans-semibold"); } } @@ -205,16 +204,16 @@ static void ui_draw_vision_speed(UIState *s) { const float speed = std::max(0.0, (*s->sm)["carState"].getCarState().getVEgo() * (s->scene.is_metric ? 3.6 : 2.2369363)); const std::string speed_str = std::to_string((int)std::nearbyint(speed)); nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); - ui_draw_text(s, s->viz_rect.centerX(), 240, speed_str.c_str(), 96 * 2.5, COLOR_WHITE, "sans-bold"); - ui_draw_text(s, s->viz_rect.centerX(), 320, s->scene.is_metric ? "km/h" : "mph", 36 * 2.5, COLOR_WHITE_ALPHA(200), "sans-regular"); + ui_draw_text(s, s->fb_w/2, 210, speed_str.c_str(), 96 * 2.5, COLOR_WHITE, "sans-bold"); + ui_draw_text(s, s->fb_w/2, 290, s->scene.is_metric ? "km/h" : "mph", 36 * 2.5, COLOR_WHITE_ALPHA(200), "sans-regular"); } static void ui_draw_vision_event(UIState *s) { if (s->scene.engageable) { // draw steering wheel const int radius = 96; - const int center_x = s->viz_rect.right() - radius - bdr_s * 2; - const int center_y = s->viz_rect.y + radius + (bdr_s * 1.5); + const int center_x = s->fb_w - radius - bdr_s * 2; + const int center_y = radius + (bdr_s * 1.5); const QColor &color = bg_colors[s->status]; NVGcolor nvg_color = nvgRGBA(color.red(), color.green(), color.blue(), color.alpha()); ui_draw_circle_image(s, center_x, center_y, radius, "wheel", nvg_color, 1.0f); @@ -223,35 +222,20 @@ static void ui_draw_vision_event(UIState *s) { static void ui_draw_vision_face(UIState *s) { const int radius = 96; - const int center_x = s->viz_rect.x + radius + (bdr_s * 2); - const int center_y = s->viz_rect.bottom() - footer_h / 2; + const int center_x = radius + (bdr_s * 2); + const int center_y = s->fb_h - footer_h / 2; ui_draw_circle_image(s, center_x, center_y, radius, "driver_face", s->scene.dm_active); } static void ui_draw_vision_header(UIState *s) { - NVGpaint gradient = nvgLinearGradient(s->vg, s->viz_rect.x, - s->viz_rect.y+(header_h-(header_h/2.5)), - s->viz_rect.x, s->viz_rect.y+header_h, - nvgRGBAf(0,0,0,0.45), nvgRGBAf(0,0,0,0)); - - ui_fill_rect(s->vg, {s->viz_rect.x, s->viz_rect.y, s->viz_rect.w, header_h}, gradient); - + NVGpaint gradient = nvgLinearGradient(s->vg, 0, header_h - (header_h / 2.5), 0, header_h, + nvgRGBAf(0, 0, 0, 0.45), nvgRGBAf(0, 0, 0, 0)); + ui_fill_rect(s->vg, {0, 0, s->fb_w , header_h}, gradient); ui_draw_vision_maxspeed(s); ui_draw_vision_speed(s); ui_draw_vision_event(s); } -static void ui_draw_vision_frame(UIState *s) { - // Draw video frames - glEnable(GL_SCISSOR_TEST); - glViewport(s->video_rect.x, s->video_rect.y, s->video_rect.w, s->video_rect.h); - glScissor(s->viz_rect.x, s->viz_rect.y, s->viz_rect.w, s->viz_rect.h); - draw_frame(s); - glDisable(GL_SCISSOR_TEST); - - glViewport(0, 0, s->fb_w, s->fb_h); -} - static void ui_draw_vision(UIState *s) { const UIScene *scene = &s->scene; // Draw augmented elements @@ -265,33 +249,20 @@ static void ui_draw_vision(UIState *s) { } } -static void ui_draw_background(UIState *s) { - const QColor &color = bg_colors[s->status]; - glClearColor(color.redF(), color.greenF(), color.blueF(), 1.0); - glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); -} - void ui_draw(UIState *s, int w, int h) { - s->viz_rect = Rect{bdr_s, bdr_s, w - 2 * bdr_s, h - 2 * bdr_s}; - const bool draw_vision = s->scene.started && s->vipc_client->connected; - // GL drawing functions - ui_draw_background(s); + glViewport(0, 0, s->fb_w, s->fb_h); if (draw_vision) { - ui_draw_vision_frame(s); + draw_vision_frame(s); } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glViewport(0, 0, s->fb_w, s->fb_h); - // NVG drawing functions - should be no GL inside NVG frame nvgBeginFrame(s->vg, s->fb_w, s->fb_h, 1.0f); - if (draw_vision) { ui_draw_vision(s); } - nvgEndFrame(s->vg); glDisable(GL_BLEND); } @@ -446,13 +417,12 @@ void ui_resize(UIState *s, int width, int height) { zoom *= 0.5; } - s->video_rect = Rect{bdr_s, bdr_s, s->fb_w - 2 * bdr_s, s->fb_h - 2 * bdr_s}; - float zx = zoom * 2 * intrinsic_matrix.v[2] / s->video_rect.w; - float zy = zoom * 2 * intrinsic_matrix.v[5] / s->video_rect.h; + float zx = zoom * 2 * intrinsic_matrix.v[2] / width; + float zy = zoom * 2 * intrinsic_matrix.v[5] / height; const mat4 frame_transform = {{ zx, 0.0, 0.0, 0.0, - 0.0, zy, 0.0, -y_offset / s->video_rect.h * 2, + 0.0, zy, 0.0, -y_offset / height * 2, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, }}; @@ -461,11 +431,9 @@ void ui_resize(UIState *s, int width, int height) { // Apply transformation such that video pixel coordinates match video // 1) Put (0, 0) in the middle of the video - nvgTranslate(s->vg, s->video_rect.x + s->video_rect.w / 2, s->video_rect.y + s->video_rect.h / 2 + y_offset); - + nvgTranslate(s->vg, width / 2, height / 2 + y_offset); // 2) Apply same scaling as video nvgScale(s->vg, zoom, zoom); - // 3) Put (0, 0) in top left corner of video nvgTranslate(s->vg, -intrinsic_matrix.v[2], -intrinsic_matrix.v[5]); diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 9cc65675ba..d3ec8d2aae 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -31,7 +31,7 @@ HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) { onroad = new OnroadWindow(this); slayout->addWidget(onroad); - QObject::connect(this, &HomeWindow::update, onroad, &OnroadWindow::update); + QObject::connect(this, &HomeWindow::update, onroad, &OnroadWindow::updateStateSignal); QObject::connect(this, &HomeWindow::offroadTransitionSignal, onroad, &OnroadWindow::offroadTransitionSignal); driver_view = new DriverViewWindow(this); diff --git a/selfdrive/ui/qt/maps/map.cc b/selfdrive/ui/qt/maps/map.cc index c61cb35345..7a596a91ef 100644 --- a/selfdrive/ui/qt/maps/map.cc +++ b/selfdrive/ui/qt/maps/map.cc @@ -46,7 +46,7 @@ MapWindow::MapWindow(const QMapboxGLSettings &settings) : const int h = 120; map_eta->setFixedHeight(h); - map_eta->move(25, 1080 - h); + map_eta->move(25, 1080 - h - bdr_s*2); map_eta->setVisible(false); // Routing @@ -807,5 +807,5 @@ void MapETA::updateETA(float s, float s_typical, float d) { setMask(mask); // Center - move(static_cast(parent())->width() / 2 - width() / 2, 1080 - height()); + move(static_cast(parent())->width() / 2 - width() / 2, 1080 - height() - bdr_s*2); } diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index e767d29152..ed0ebb1af0 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -7,18 +7,20 @@ #include "selfdrive/common/timing.h" #include "selfdrive/ui/paint.h" #include "selfdrive/ui/qt/util.h" - #ifdef ENABLE_MAPS #include "selfdrive/ui/qt/maps/map.h" #endif OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { - main_layout = new QStackedLayout(this); - main_layout->setStackingMode(QStackedLayout::StackAll); + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setMargin(bdr_s); + QStackedLayout *stacked_layout = new QStackedLayout; + stacked_layout->setStackingMode(QStackedLayout::StackAll); + main_layout->addLayout(stacked_layout); // old UI on bottom nvg = new NvgWindow(this); - QObject::connect(this, &OnroadWindow::update, nvg, &NvgWindow::update); + QObject::connect(this, &OnroadWindow::updateStateSignal, nvg, &NvgWindow::updateState); QWidget * split_wrapper = new QWidget; split = new QHBoxLayout(split_wrapper); @@ -26,21 +28,46 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { split->setSpacing(0); split->addWidget(nvg); - main_layout->addWidget(split_wrapper); + stacked_layout->addWidget(split_wrapper); alerts = new OnroadAlerts(this); alerts->setAttribute(Qt::WA_TransparentForMouseEvents, true); - QObject::connect(this, &OnroadWindow::update, alerts, &OnroadAlerts::updateState); - QObject::connect(this, &OnroadWindow::offroadTransitionSignal, alerts, &OnroadAlerts::offroadTransition); - QObject::connect(this, &OnroadWindow::offroadTransitionSignal, this, &OnroadWindow::offroadTransition); - main_layout->addWidget(alerts); + stacked_layout->addWidget(alerts); // setup stacking order alerts->raise(); setAttribute(Qt::WA_OpaquePaintEvent); + QObject::connect(this, &OnroadWindow::updateStateSignal, this, &OnroadWindow::updateState); + QObject::connect(this, &OnroadWindow::offroadTransitionSignal, this, &OnroadWindow::offroadTransition); } +void OnroadWindow::updateState(const UIState &s) { + SubMaster &sm = *(s.sm); + QColor bgColor = bg_colors[s.status]; + if (sm.updated("controlsState")) { + const cereal::ControlsState::Reader &cs = sm["controlsState"].getControlsState(); + alerts->updateAlert({QString::fromStdString(cs.getAlertText1()), + QString::fromStdString(cs.getAlertText2()), + QString::fromStdString(cs.getAlertType()), + cs.getAlertSize(), cs.getAlertSound()}, bgColor); + } else if ((sm.frame - s.scene.started_frame) > 5 * UI_FREQ) { + // Handle controls timeout + if (sm.rcv_frame("controlsState") < s.scene.started_frame) { + // car is started, but controlsState hasn't been seen at all + alerts->updateAlert(CONTROLS_WAITING_ALERT, bgColor); + } else if ((nanos_since_boot() - sm.rcv_time("controlsState")) / 1e9 > CONTROLS_TIMEOUT) { + // car is started, but controls is lagging or died + bgColor = bg_colors[STATUS_ALERT]; + alerts->updateAlert(CONTROLS_UNRESPONSIVE_ALERT, bgColor); + } + } + if (bg != bgColor) { + // repaint border + bg = bgColor; + update(); + } +} void OnroadWindow::offroadTransition(bool offroad) { #ifdef ENABLE_MAPS @@ -57,50 +84,25 @@ void OnroadWindow::offroadTransition(bool offroad) { MapWindow * m = new MapWindow(settings); QObject::connect(this, &OnroadWindow::offroadTransitionSignal, m, &MapWindow::offroadTransition); split->addWidget(m); - map = m; } - } #endif -} -// ***** onroad widgets ***** - -void OnroadAlerts::updateState(const UIState &s) { - SubMaster &sm = *(s.sm); - if (sm["deviceState"].getDeviceState().getStarted()) { - if (sm.updated("controlsState")) { - const cereal::ControlsState::Reader &cs = sm["controlsState"].getControlsState(); - updateAlert({QString::fromStdString(cs.getAlertText1()), - QString::fromStdString(cs.getAlertText2()), - QString::fromStdString(cs.getAlertType()), - cs.getAlertSize(), cs.getAlertSound()}); - } else if ((sm.frame - s.scene.started_frame) > 10 * UI_FREQ) { - // Handle controls timeout - if (sm.rcv_frame("controlsState") < s.scene.started_frame) { - // car is started, but controlsState hasn't been seen at all - updateAlert(CONTROLS_WAITING_ALERT); - } else if ((nanos_since_boot() - sm.rcv_time("controlsState")) / 1e9 > CONTROLS_TIMEOUT) { - // car is started, but controls is lagging or died - updateAlert(CONTROLS_UNRESPONSIVE_ALERT); - - // TODO: clean this up once Qt handles the border - QUIState::ui_state.status = STATUS_ALERT; - } - } - } - - bg = bg_colors[s.status]; + alerts->updateAlert({}, bg); } -void OnroadAlerts::offroadTransition(bool offroad) { - updateAlert({}); +void OnroadWindow::paintEvent(QPaintEvent *event) { + QPainter p(this); + p.fillRect(rect(), QColor(bg.red(), bg.green(), bg.blue(), 255)); } -void OnroadAlerts::updateAlert(Alert a) { - if (!alert.equal(a)) { +// ***** onroad widgets ***** + +void OnroadAlerts::updateAlert(const Alert &a, const QColor &color) { + if (!alert.equal(a) || color != bg) { alert = a; + bg = color; update(); } } @@ -135,9 +137,6 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) { p.fillRect(r, g); p.setCompositionMode(QPainter::CompositionMode_SourceOver); - // remove bottom border - r = QRect(0, height() - h, width(), h - 30); - // text const QPoint c = r.center(); p.setPen(QColor(0xff, 0xff, 0xff)); @@ -180,11 +179,14 @@ void NvgWindow::initializeGL() { prev_draw_t = millis_since_boot(); } -void NvgWindow::update(const UIState &s) { +void NvgWindow::updateState(const UIState &s) { // Connecting to visionIPC requires opengl to be current if (s.vipc_client->connected) { makeCurrent(); } + if (isVisible() != s.vipc_client->connected) { + setVisible(s.vipc_client->connected); + } repaint(); } diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index 2120cdc785..d309f2b7f9 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -17,20 +17,15 @@ class OnroadAlerts : public QWidget { Q_OBJECT public: - OnroadAlerts(QWidget *parent = 0) {}; + OnroadAlerts(QWidget *parent = 0) : QWidget(parent) {}; + void updateAlert(const Alert &a, const QColor &color); protected: void paintEvent(QPaintEvent*) override; private: QColor bg; - Alert alert; - - void updateAlert(Alert a); - -public slots: - void updateState(const UIState &s); - void offroadTransition(bool offroad); + Alert alert = {}; }; // container window for the NVG UI @@ -51,7 +46,7 @@ private: double prev_draw_t = 0; public slots: - void update(const UIState &s); + void updateState(const UIState &s); }; // container for all onroad widgets @@ -63,15 +58,18 @@ public: QWidget *map = nullptr; private: + void paintEvent(QPaintEvent *event); + OnroadAlerts *alerts; NvgWindow *nvg; - QStackedLayout *main_layout; + QColor bg = bg_colors[STATUS_DISENGAGED]; QHBoxLayout* split; signals: - void update(const UIState &s); + void updateStateSignal(const UIState &s); void offroadTransitionSignal(bool offroad); private slots: void offroadTransition(bool offroad); + void updateState(const UIState &s); }; diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 8b43449ed5..f3229eee99 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -151,7 +151,6 @@ typedef struct UIState { bool awake; - Rect video_rect, viz_rect; float car_space_transform[6]; bool wide_camera; } UIState;