diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index a39b7e0..56da958 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -645,13 +645,21 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { // lanelines for (int i = 0; i < std::size(scene.lane_line_vertices); ++i) { - painter.setBrush(QColor::fromRgbF(1.0, 1.0, 1.0, std::clamp(scene.lane_line_probs[i], 0.0, 0.7))); + if (customColors != 0) { + painter.setBrush(std::get<2>(themeConfiguration[customColors]).begin()->second); + } else { + painter.setBrush(QColor::fromRgbF(1.0, 1.0, 1.0, std::clamp(scene.lane_line_probs[i], 0.0, 0.7))); + } painter.drawPolygon(scene.lane_line_vertices[i]); } // road edges for (int i = 0; i < std::size(scene.road_edge_vertices); ++i) { - painter.setBrush(QColor::fromRgbF(1.0, 0, 0, std::clamp(1.0 - scene.road_edge_stds[i], 0.0, 1.0))); + if (customColors != 0) { + painter.setBrush(std::get<2>(themeConfiguration[customColors]).begin()->second); + } else { + painter.setBrush(QColor::fromRgbF(1.0, 0, 0, std::clamp(1.0 - scene.road_edge_stds[i], 0.0, 1.0))); + } painter.drawPolygon(scene.road_edge_vertices[i]); } @@ -660,8 +668,14 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { if (experimentalMode || scene.acceleration_path) { // The first half of track_vertices are the points for the right side of the path // and the indices match the positions of accel from uiPlan - const auto &acceleration = sm["uiPlan"].getUiPlan().getAccel(); - const int max_len = std::min(scene.track_vertices.length() / 2, acceleration.size()); + const auto &acceleration_const = sm["uiPlan"].getUiPlan().getAccel(); + const int max_len = std::min(scene.track_vertices.length() / 2, acceleration_const.size()); + + // Copy of the acceleration vector + std::vector acceleration; + for (int i = 0; i < acceleration_const.size(); i++) { + acceleration.push_back(acceleration_const[i]); + } for (int i = 0; i < max_len; ++i) { // Some points are out of frame @@ -670,20 +684,32 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { // Flip so 0 is bottom of frame float lin_grad_point = (height() - scene.track_vertices[i].y()) / height(); - // speed up: 120, slow down: 0 - float path_hue = fmax(fmin(60 + acceleration[i] * 35, 120), 0); - // FIXME: painter.drawPolygon can be slow if hue is not rounded - path_hue = int(path_hue * 100 + 0.5) / 100; + // If acceleration is between -0.25 and 0.25, resort to the theme color + if (std::abs(acceleration[i]) < 0.2 && (customColors != 0)) { + const std::map &colorMap = std::get<2>(themeConfiguration[customColors]); + for (const std::pair &entry : colorMap) { + bg.setColorAt(entry.first, entry.second.color()); + } + } else { + // speed up: 120, slow down: 0 + float path_hue = fmax(fmin(60 + acceleration[i] * 35, 120), 0); + // FIXME: painter.drawPolygon can be slow if hue is not rounded + path_hue = int(path_hue * 100 + 0.5) / 100; - float saturation = fmin(fabs(acceleration[i] * 1.5), 1); - float lightness = util::map_val(saturation, 0.0f, 1.0f, 0.95f, 0.62f); // lighter when grey - float alpha = util::map_val(lin_grad_point, 0.75f / 2.f, 0.75f, 0.4f, 0.0f); // matches previous alpha fade - bg.setColorAt(lin_grad_point, QColor::fromHslF(path_hue / 360., saturation, lightness, alpha)); + float saturation = fmin(fabs(acceleration[i] * 1.5), 1); + float lightness = util::map_val(saturation, 0.0f, 1.0f, 0.95f, 0.62f); // lighter when grey + float alpha = util::map_val(lin_grad_point, 0.75f / 2.f, 0.75f, 0.4f, 0.0f); // matches previous alpha fade + bg.setColorAt(lin_grad_point, QColor::fromHslF(path_hue / 360., saturation, lightness, alpha)); - // Skip a point, unless next is last - i += (i + 2) < max_len ? 1 : 0; + // Skip a point, unless next is last + i += (i + 2) < max_len ? 1 : 0; + } + } + } else if (customColors != 0) { + const std::map &colorMap = std::get<2>(themeConfiguration[customColors]); + for (const std::pair &entry : colorMap) { + bg.setColorAt(entry.first, entry.second.color()); } - } else { bg.setColorAt(0.0, QColor::fromHslF(148 / 360., 0.94, 0.51, 0.4)); bg.setColorAt(0.5, QColor::fromHslF(112 / 360., 1.0, 0.68, 0.35)); @@ -791,8 +817,8 @@ void AnnotatedCameraWidget::drawDriverState(QPainter &painter, const UIState *s) void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::ModelDataV2::LeadDataV3::Reader &lead_data, const QPointF &vd, const float v_ego) { painter.save(); - const float speedBuff = 10.; - const float leadBuff = 40.; + const float speedBuff = customColors != 0 ? 25. : 10.; // Make the center of the chevron appear sooner if a custom theme is active + const float leadBuff = customColors != 0 ? 100. : 40.; // Make the center of the chevron appear sooner if a custom theme is active const float d_rel = lead_data.getX()[0]; const float v_rel = lead_data.getV()[0] - v_ego; @@ -818,7 +844,11 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::ModelDataV // chevron QPointF chevron[] = {{x + (sz * 1.25), y + sz}, {x, y}, {x - (sz * 1.25), y + sz}}; - painter.setBrush(redColor(fillAlpha)); + if (customColors != 0) { + painter.setBrush(std::get<2>(themeConfiguration[customColors]).begin()->second); + } else { + painter.setBrush(redColor(fillAlpha)); + } painter.drawPolygon(chevron, std::size(chevron)); painter.restore(); @@ -942,6 +972,18 @@ void AnnotatedCameraWidget::initializeFrogPilotWidgets() { bottom_layout->addWidget(map_settings_btn_bottom); main_layout->addLayout(bottom_layout); + + themeConfiguration = { + {1, {"frog_theme", QColor(23, 134, 68, 242), {{0.0, QBrush(QColor::fromHslF(144 / 360., 0.71, 0.31, 0.9))}, + {0.5, QBrush(QColor::fromHslF(144 / 360., 0.71, 0.31, 0.5))}, + {1.0, QBrush(QColor::fromHslF(144 / 360., 0.71, 0.31, 0.1))}}}}, + {2, {"tesla_theme", QColor(0, 72, 255, 255), {{0.0, QBrush(QColor::fromHslF(223 / 360., 1.0, 0.5, 0.9))}, + {0.5, QBrush(QColor::fromHslF(223 / 360., 1.0, 0.5, 0.5))}, + {1.0, QBrush(QColor::fromHslF(223 / 360., 1.0, 0.5, 0.1))}}}}, + {3, {"stalin_theme", QColor(255, 0, 0, 255), {{0.0, QBrush(QColor::fromHslF(0 / 360., 1.0, 0.5, 0.9))}, + {0.5, QBrush(QColor::fromHslF(0 / 360., 1.0, 0.5, 0.5))}, + {1.0, QBrush(QColor::fromHslF(0 / 360., 1.0, 0.5, 0.1))}}}}, + }; } void AnnotatedCameraWidget::updateFrogPilotWidgets() { @@ -980,6 +1022,8 @@ void AnnotatedCameraWidget::updateFrogPilotWidgets() { cruiseAdjustment = disableSmoothing || !is_cruise_set ? fmax(setSpeed - scene.adjusted_cruise, 0) : fmax(0.25 * (setSpeed - scene.adjusted_cruise) + 0.75 * cruiseAdjustment - 1, 0); vtscControllingCurve = scene.vtsc_controlling_curve; + customColors = scene.custom_colors; + experimentalMode = scene.experimental_mode; laneDetectionWidth = scene.lane_detection_width; diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index e7553fe..f427fb0 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -229,11 +229,14 @@ private: int alertSize; int conditionalStatus; + int customColors; QString accelerationUnit; QString leadDistanceUnit; QString leadSpeedUnit; + std::unordered_map>> themeConfiguration; + inline QColor blueColor(int alpha = 255) { return QColor(0, 150, 255, alpha); } inline QColor greenColor(int alpha = 242) { return QColor(23, 134, 68, alpha); } diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc index 197bbe8..c6e8517 100644 --- a/selfdrive/ui/qt/sidebar.cc +++ b/selfdrive/ui/qt/sidebar.cc @@ -38,6 +38,16 @@ Sidebar::Sidebar(QWidget *parent) : QFrame(parent), onroad(false), flag_pressed( QObject::connect(uiState(), &UIState::uiUpdate, this, &Sidebar::updateState); pm = std::make_unique>({"userFlag"}); + + // FrogPilot variables + themeConfiguration = { + {0, {"stock", {QColor(255, 255, 255)}}}, + {1, {"frog_theme", {QColor(23, 134, 68)}}}, + {2, {"tesla_theme", {QColor(0, 72, 255)}}}, + {3, {"stalin_theme", {QColor(255, 0, 0)}}} + }; + + currentColors = themeConfiguration[scene.custom_colors].second; } void Sidebar::mousePressEvent(QMouseEvent *event) { @@ -80,6 +90,8 @@ void Sidebar::updateState(const UIState &s) { setProperty("netStrength", strength > 0 ? strength + 1 : 0); // FrogPilot properties + currentColors = themeConfiguration[scene.custom_colors].second; + auto frogpilotDeviceState = sm["frogpilotDeviceState"].getFrogpilotDeviceState(); ItemStatus connectStatus; @@ -88,7 +100,7 @@ void Sidebar::updateState(const UIState &s) { connectStatus = ItemStatus{{tr("CONNECT"), tr("OFFLINE")}, warning_color}; } else { connectStatus = nanos_since_boot() - last_ping < 80e9 - ? ItemStatus{{tr("CONNECT"), tr("ONLINE")}, good_color} + ? ItemStatus{{tr("CONNECT"), tr("ONLINE")}, currentColors[0]} : ItemStatus{{tr("CONNECT"), tr("ERROR")}, danger_color}; } setProperty("connectStatus", QVariant::fromValue(connectStatus)); @@ -96,13 +108,13 @@ void Sidebar::updateState(const UIState &s) { ItemStatus tempStatus = {{tr("TEMP"), tr("HIGH")}, danger_color}; auto ts = deviceState.getThermalStatus(); if (ts == cereal::DeviceState::ThermalStatus::GREEN) { - tempStatus = {{tr("TEMP"), tr("GOOD")}, good_color}; + tempStatus = {{tr("TEMP"), tr("GOOD")}, currentColors[0]}; } else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) { tempStatus = {{tr("TEMP"), tr("OK")}, warning_color}; } setProperty("tempStatus", QVariant::fromValue(tempStatus)); - ItemStatus pandaStatus = {{tr("VEHICLE"), tr("ONLINE")}, good_color}; + ItemStatus pandaStatus = {{tr("VEHICLE"), tr("ONLINE")}, currentColors[0]}; if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) { pandaStatus = {{tr("NO"), tr("PANDA")}, danger_color}; } else if (s.scene.started && !sm["liveLocationKalman"].getLiveLocationKalman().getGpsOK()) { diff --git a/selfdrive/ui/qt/sidebar.h b/selfdrive/ui/qt/sidebar.h index f251040..4966ebd 100644 --- a/selfdrive/ui/qt/sidebar.h +++ b/selfdrive/ui/qt/sidebar.h @@ -63,4 +63,8 @@ private: // FrogPilot variables Params params; UIScene &scene; + + std::unordered_map>> themeConfiguration; + + std::vector currentColors; }; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 52cd70a..69e0f9f 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -314,6 +314,9 @@ void ui_update_frogpilot_params(UIState *s) { scene.rotating_wheel = custom_onroad_ui && params.getBool("RotatingWheel"); scene.wheel_icon = custom_onroad_ui ? params.getInt("WheelIcon") : 0; + bool custom_theme = params.getBool("CustomTheme"); + scene.custom_colors = custom_theme ? params.getInt("CustomColors") : 0; + scene.disable_smoothing_mtsc = params.getBool("MTSCEnabled") && params.getBool("DisableMTSCSmoothing"); scene.disable_smoothing_vtsc = params.getBool("VisionTurnControl") && params.getBool("DisableVTSCSmoothing"); diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 6153e76..6f80f46 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -243,6 +243,7 @@ typedef struct UIScene { int conditional_speed; int conditional_speed_lead; int conditional_status; + int custom_colors; int steering_angle_deg; int wheel_icon;