diff --git a/selfdrive/hardware/hw.h b/selfdrive/hardware/hw.h index d7a6c8d1d5..441c38d784 100644 --- a/selfdrive/hardware/hw.h +++ b/selfdrive/hardware/hw.h @@ -13,7 +13,7 @@ class HardwarePC : public HardwareNone { public: static std::string get_os_version() { return "openpilot for PC"; } - static bool PC() { return true; } + static constexpr bool PC() { return true; } static bool TICI() { return util::getenv("TICI", 0) == 1; } }; #define Hardware HardwarePC diff --git a/selfdrive/ui/paint.cc b/selfdrive/ui/paint.cc index 1bbbb8379c..858de5378a 100644 --- a/selfdrive/ui/paint.cc +++ b/selfdrive/ui/paint.cc @@ -151,72 +151,86 @@ static void ui_draw_world(UIState *s) { nvgResetScissor(s->vg); } -static void ui_draw_vision_maxspeed(UIState *s) { +static void ui_draw_vision_maxspeed(UIState *s, const float ratio) { const int SET_SPEED_NA = 255; float maxspeed = (*s->sm)["controlsState"].getControlsState().getVCruise(); const bool is_cruise_set = maxspeed != 0 && maxspeed != SET_SPEED_NA; if (is_cruise_set && !s->scene.is_metric) { maxspeed *= KM_TO_MILE; } - const Rect rect = {bdr_s * 2, int(bdr_s * 1.5), 184, 202}; + const Rect rect = {int(bdr_s * 2 * ratio), int(bdr_s * 1.5 * ratio), + int(184 * ratio), int(202 * ratio)}; 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(), 118, "MAX", 26 * 2.5, COLOR_WHITE_ALPHA(is_cruise_set ? 200 : 100), "sans-regular"); + ui_draw_text(s, rect.centerX(), 118 * ratio, "MAX", + 26 * 2.5 * ratio, 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(), 212, maxspeed_str.c_str(), 48 * 2.5, COLOR_WHITE, "sans-bold"); + ui_draw_text(s, rect.centerX(), 212 * ratio, maxspeed_str.c_str(), + 48 * 2.5 * ratio, COLOR_WHITE, "sans-bold"); } else { - ui_draw_text(s, rect.centerX(), 212, "N/A", 42 * 2.5, COLOR_WHITE_ALPHA(100), "sans-semibold"); + ui_draw_text(s, rect.centerX(), 212 * ratio, "N/A", + 42 * 2.5 * ratio, COLOR_WHITE_ALPHA(100), "sans-semibold"); } } -static void ui_draw_vision_speed(UIState *s) { +static void ui_draw_vision_speed(UIState *s, const float ratio) { const float speed = std::max(0.0, (*s->sm)["carState"].getCarState().getVEgo() * (s->scene.is_metric ? MS_TO_KPH : MS_TO_MPH)); 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->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"); + ui_draw_text(s, s->fb_w/2, 210 * ratio, speed_str.c_str(), + 96 * 2.5 * ratio, COLOR_WHITE, "sans-bold"); + ui_draw_text(s, s->fb_w/2, 290 * ratio, s->scene.is_metric ? "km/h" : "mph", + 36 * 2.5 * ratio, COLOR_WHITE_ALPHA(200), "sans-regular"); } -static void ui_draw_vision_event(UIState *s) { +static void ui_draw_vision_event(UIState *s, const float ratio) { if (s->scene.engageable) { // draw steering wheel - const int radius = 96; - const int center_x = s->fb_w - radius - bdr_s * 2; - const int center_y = radius + (bdr_s * 1.5); + const int radius = 96 * ratio; + const int center_x = s->fb_w - radius - (bdr_s * ratio* 2); + const int center_y = radius + (bdr_s * ratio * 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); } } -static void ui_draw_vision_face(UIState *s) { - const int radius = 96; - const int center_x = radius + (bdr_s * 2); - const int center_y = s->fb_h - footer_h / 2; +static void ui_draw_vision_face(UIState *s, const float ratio) { + const int radius = 96 * ratio; + const int center_x = radius + (bdr_s * ratio * 2); + const int center_y = s->fb_h - (footer_h * ratio / 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) { +static void ui_draw_vision_header(UIState *s, const float ratio) { 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); + ui_draw_vision_maxspeed(s, ratio); + ui_draw_vision_speed(s, ratio); + ui_draw_vision_event(s, ratio); } -static void ui_draw_vision(UIState *s) { +static void ui_draw_vision(UIState *s, const float ratio) { const UIScene *scene = &s->scene; // Draw augmented elements if (scene->world_objects_visible) { ui_draw_world(s); } // Set Speed, Current Speed, Status/Events - ui_draw_vision_header(s); + ui_draw_vision_header(s, ratio); if ((*s->sm)["controlsState"].getControlsState().getAlertSize() == cereal::ControlsState::AlertSize::NONE) { - ui_draw_vision_face(s); + ui_draw_vision_face(s, ratio); + } +} + +inline float resize_ratio(int w, int h) { + if constexpr (Hardware::PC()) { + return std::min(w, h) / 1080.0; // 1080 is min of default 1920 x 1080 + } else { + return 1.0; } } @@ -228,7 +242,7 @@ void ui_draw(UIState *s, int w, int h) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); nvgBeginFrame(s->vg, s->fb_w, s->fb_h, 1.0f); - ui_draw_vision(s); + ui_draw_vision(s, resize_ratio(w, h)); nvgEndFrame(s->vg); glDisable(GL_BLEND); } diff --git a/selfdrive/ui/qt/offroad/driverview.cc b/selfdrive/ui/qt/offroad/driverview.cc index db2a4d6b40..9633c1a705 100644 --- a/selfdrive/ui/qt/offroad/driverview.cc +++ b/selfdrive/ui/qt/offroad/driverview.cc @@ -52,8 +52,10 @@ void DriverViewScene::paintEvent(QPaintEvent* event) { if (!frame_updated) { p.setPen(Qt::white); p.setRenderHint(QPainter::TextAntialiasing); - configFont(p, "Inter", 100, "Bold"); - p.drawText(geometry(), Qt::AlignCenter, "camera starting"); + const QRect r(geometry()); + const QString text("camera starting"); + configFont(p, r, "Inter", 100, "Bold", text); + p.drawText(geometry(), Qt::AlignCenter, text); return; } diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 7c3a610eed..ab42c80818 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -122,18 +122,60 @@ void OnroadAlerts::updateAlert(const Alert &a, const QColor &color) { } } +struct Rects +{ + int x, y, w, h; // bounding box for total text area + int x1, y1, w1, h1; // bounding box for alert text 1 + int x2, y2, w2, h2; // bounding box for alert text 2 + + Rects() + { + memset(this, 0, sizeof(Rects)); + } +}; + +template +void getRects(T t, Rects &r, Alert alert) { + // returns bounding boxes for text area, alert1, alert2 + // w - width, h - height, windows starting position x, y + + const int heightMax = 1080; // adjust to change text box scale + const int width = t->width(); + const int height = t->height(); + + switch (alert.size) { + case cereal::ControlsState::AlertSize::SMALL: + r.h = height * (271.0 / heightMax); + break; + case cereal::ControlsState::AlertSize::MID: + r.h = height * (420.0 / heightMax); + break; + case cereal::ControlsState::AlertSize::FULL: + r.h = height; + break; + case cereal::ControlsState::AlertSize::NONE: + break; + } + + r.w = width; + r.w1 = r.w; + r.w2 = r.w1; + + r.h1 = r.h / 2.0; + r.h2 = r.h1; + + r.y = height - r.h; + r.y1 = r.y; + r.y2 = r.y1 + r.h1; +} + void OnroadAlerts::paintEvent(QPaintEvent *event) { if (alert.size == cereal::ControlsState::AlertSize::NONE) { return; } - static std::map alert_sizes = { - {cereal::ControlsState::AlertSize::SMALL, 271}, - {cereal::ControlsState::AlertSize::MID, 420}, - {cereal::ControlsState::AlertSize::FULL, height()}, - }; - int h = alert_sizes[alert.size]; - QRect r = QRect(0, height() - h, width(), h); - + Rects R; + getRects(this, R, alert); + QRect r = QRect(R.x, R.y, R.w, R.h); QPainter p(this); // draw background + gradient @@ -153,23 +195,28 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) { p.setCompositionMode(QPainter::CompositionMode_SourceOver); // text - const QPoint c = r.center(); p.setPen(QColor(0xff, 0xff, 0xff)); p.setRenderHint(QPainter::TextAntialiasing); + + const QRect a1 = QRect(R.x1, R.y1, R.w1, R.h1); + const QRect a2 = QRect(R.x2, R.y2, R.w2, R.h2); + + const int textBoxFlag = Qt::AlignCenter; + if (alert.size == cereal::ControlsState::AlertSize::SMALL) { - configFont(p, "Open Sans", 74, "SemiBold"); - p.drawText(r, Qt::AlignCenter, alert.text1); + configFont(p, r, "Open Sans", 74, "SemiBold", alert.text1); + p.drawText(r, textBoxFlag, alert.text1); } else if (alert.size == cereal::ControlsState::AlertSize::MID) { - configFont(p, "Open Sans", 88, "Bold"); - p.drawText(QRect(0, c.y() - 125, width(), 150), Qt::AlignHCenter | Qt::AlignTop, alert.text1); - configFont(p, "Open Sans", 66, "Regular"); - p.drawText(QRect(0, c.y() + 21, width(), 90), Qt::AlignHCenter, alert.text2); + configFont(p, a1, "Open Sans", 88, "Bold", alert.text1); + p.drawText(a1, textBoxFlag, alert.text1); + configFont(p, a2, "Open Sans", 66, "Regular", alert.text2); + p.drawText(a2, textBoxFlag, alert.text2); } else if (alert.size == cereal::ControlsState::AlertSize::FULL) { bool l = alert.text1.length() > 15; - configFont(p, "Open Sans", l ? 132 : 177, "Bold"); - p.drawText(QRect(0, r.y() + (l ? 240 : 270), width(), 600), Qt::AlignHCenter | Qt::TextWordWrap, alert.text1); - configFont(p, "Open Sans", 88, "Regular"); - p.drawText(QRect(0, r.height() - (l ? 361 : 420), width(), 300), Qt::AlignHCenter | Qt::TextWordWrap, alert.text2); + configFont(p, a1, "Open Sans", l ? 132 : 177, "Bold", alert.text1); + p.drawText(a1, textBoxFlag, alert.text1); + configFont(p, a2, "Open Sans", 88, "Regular", alert.text2); + p.drawText(a2, textBoxFlag, alert.text2); } } diff --git a/selfdrive/ui/qt/qt_window.cc b/selfdrive/ui/qt/qt_window.cc index aad21e6c06..2c48bdde39 100644 --- a/selfdrive/ui/qt/qt_window.cc +++ b/selfdrive/ui/qt/qt_window.cc @@ -3,9 +3,14 @@ void setMainWindow(QWidget *w) { const bool wide = (QGuiApplication::primaryScreen()->size().width() >= WIDE_WIDTH) ^ (getenv("INVERT_WIDTH") != NULL); - const float scale = util::getenv("SCALE", 1.0f); + if constexpr (Hardware::PC()) { + w->setMinimumSize(QSize(640, 480)); + w->setMaximumSize(QSize(WIDE_WIDTH, 1080)); + w->resize(QSize(1920, 1080)); + } else { + w->setFixedSize(QSize(wide ? WIDE_WIDTH : 1920, 1080)); + } - w->setFixedSize(QSize(wide ? WIDE_WIDTH : 1920, 1080) * scale); w->show(); #ifdef QCOM2 diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc index cd53a5b725..43cb60a5fe 100644 --- a/selfdrive/ui/qt/sidebar.cc +++ b/selfdrive/ui/qt/sidebar.cc @@ -20,8 +20,8 @@ void Sidebar::drawMetric(QPainter &p, const QString &label, QColor c, int y) { p.drawRoundedRect(rect, 20, 20); p.setPen(QColor(0xff, 0xff, 0xff)); - configFont(p, "Open Sans", 35, "Bold"); const QRect r = QRect(rect.x() + 30, rect.y(), rect.width() - 40, rect.height()); + configFont(p, r, "Open Sans", 35, "Bold", label); p.drawText(r, Qt::AlignCenter, label); } @@ -99,9 +99,9 @@ void Sidebar::paintEvent(QPaintEvent *event) { x += 37; } - configFont(p, "Open Sans", 35, "Regular"); p.setPen(QColor(0xff, 0xff, 0xff)); const QRect r = QRect(50, 247, 100, 50); + configFont(p, r, "Open Sans", 35, "Regular", net_type); p.drawText(r, Qt::AlignCenter, net_type); // metrics diff --git a/selfdrive/ui/qt/util.cc b/selfdrive/ui/qt/util.cc index 93bb2b0e79..5187ddc776 100644 --- a/selfdrive/ui/qt/util.cc +++ b/selfdrive/ui/qt/util.cc @@ -33,6 +33,32 @@ void configFont(QPainter &p, const QString &family, int size, const QString &sty p.setFont(f); } +void configFont(QPainter &p, const QRect &r, const QString &family, int size, + const QString &style, const QString &text) { + if constexpr (Hardware::PC()) { + int szTemp = 1; + QFont f(family); + f.setStyleName(style); + while (true) { + f.setPixelSize(szTemp); + QRect rTemp = QFontMetrics(f).boundingRect(r, Qt::AlignCenter, text); + if (rTemp.height() < r.height() && + rTemp.width() < r.width() && + szTemp <= size) { + ++szTemp; + } else { + p.setFont(f); + return; + } + } + } else { + QFont f(family); + f.setPixelSize(size); + f.setStyleName(style); + p.setFont(f); + } +} + void clearLayout(QLayout* layout) { while (QLayoutItem* item = layout->takeAt(0)) { if (QWidget* widget = item->widget()) { diff --git a/selfdrive/ui/qt/util.h b/selfdrive/ui/qt/util.h index ad28b51166..ecdbab4319 100644 --- a/selfdrive/ui/qt/util.h +++ b/selfdrive/ui/qt/util.h @@ -13,6 +13,8 @@ QString getBrand(); QString getBrandVersion(); std::optional getDongleId(); void configFont(QPainter &p, const QString &family, int size, const QString &style); +void configFont(QPainter &p, const QRect &r, const QString &family, int size, + const QString &style, const QString &text); void clearLayout(QLayout* layout); void setQtSurfaceFormat(); QString timeAgo(const QDateTime &date);