Custom themes
Added toggles for the "Custom Themes" configuration. Colors, icons, sounds, and turn signal animations are all individually toggleable.
@@ -18,6 +18,7 @@ struct FrogPilotDeviceState @0xaedffd8f31e7b55d {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum FrogPilotEvents @0xf35cc4560bbf6ec2 {
|
enum FrogPilotEvents @0xf35cc4560bbf6ec2 {
|
||||||
|
frogSteerSaturated @0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FrogPilotLateralPlan @0xda96579883444c35 {
|
struct FrogPilotLateralPlan @0xda96579883444c35 {
|
||||||
|
|||||||
@@ -236,10 +236,16 @@ std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"CEStopLights", PERSISTENT},
|
{"CEStopLights", PERSISTENT},
|
||||||
{"CEStopLightsLead", PERSISTENT},
|
{"CEStopLightsLead", PERSISTENT},
|
||||||
{"ConditionalExperimental", PERSISTENT},
|
{"ConditionalExperimental", PERSISTENT},
|
||||||
|
{"CustomColors", PERSISTENT},
|
||||||
|
{"CustomIcons", PERSISTENT},
|
||||||
{"CustomPersonalities", PERSISTENT},
|
{"CustomPersonalities", PERSISTENT},
|
||||||
{"CustomUI", PERSISTENT},
|
{"CustomUI", PERSISTENT},
|
||||||
|
{"CustomSignals", PERSISTENT},
|
||||||
|
{"CustomSounds", PERSISTENT},
|
||||||
|
{"CustomTheme", PERSISTENT},
|
||||||
{"FrogPilotTogglesUpdated", PERSISTENT},
|
{"FrogPilotTogglesUpdated", PERSISTENT},
|
||||||
{"GasRegenCmd", PERSISTENT},
|
{"GasRegenCmd", PERSISTENT},
|
||||||
|
{"GoatScream", PERSISTENT},
|
||||||
{"LaneLinesWidth", PERSISTENT},
|
{"LaneLinesWidth", PERSISTENT},
|
||||||
{"LateralTune", PERSISTENT},
|
{"LateralTune", PERSISTENT},
|
||||||
{"LeadInfo", PERSISTENT},
|
{"LeadInfo", PERSISTENT},
|
||||||
|
|||||||
@@ -698,7 +698,7 @@ class Controls:
|
|||||||
good_speed = CS.vEgo > 5
|
good_speed = CS.vEgo > 5
|
||||||
max_torque = abs(self.last_actuators.steer) > 0.99
|
max_torque = abs(self.last_actuators.steer) > 0.99
|
||||||
if undershooting and turning and good_speed and max_torque:
|
if undershooting and turning and good_speed and max_torque:
|
||||||
lac_log.active and self.events.add(EventName.steerSaturated)
|
lac_log.active and self.events.add(FrogPilotEventName.frogSteerSaturated if self.goat_scream else EventName.steerSaturated)
|
||||||
elif lac_log.saturated:
|
elif lac_log.saturated:
|
||||||
dpath_points = lat_plan.dPathPoints
|
dpath_points = lat_plan.dPathPoints
|
||||||
if len(dpath_points):
|
if len(dpath_points):
|
||||||
@@ -953,6 +953,11 @@ class Controls:
|
|||||||
self.average_desired_curvature = self.params.get_bool("AverageCurvature")
|
self.average_desired_curvature = self.params.get_bool("AverageCurvature")
|
||||||
self.conditional_experimental_mode = self.params.get_bool("ConditionalExperimental")
|
self.conditional_experimental_mode = self.params.get_bool("ConditionalExperimental")
|
||||||
|
|
||||||
|
custom_theme = self.params.get_bool("CustomTheme")
|
||||||
|
custom_sounds = self.params.get_int("CustomSounds") if custom_theme else 0
|
||||||
|
frog_sounds = custom_sounds == 1
|
||||||
|
self.goat_scream = self.params.get_bool("GoatScream") and frog_sounds
|
||||||
|
|
||||||
longitudinal_tune = self.params.get_bool("LongitudinalTune")
|
longitudinal_tune = self.params.get_bool("LongitudinalTune")
|
||||||
self.sport_plus = self.params.get_int("AccelerationProfile") == 3 and longitudinal_tune
|
self.sport_plus = self.params.get_int("AccelerationProfile") == 3 and longitudinal_tune
|
||||||
|
|
||||||
|
|||||||
@@ -967,6 +967,13 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
# FrogPilot Events
|
# FrogPilot Events
|
||||||
|
FrogPilotEventName.frogSteerSaturated: {
|
||||||
|
ET.WARNING: Alert(
|
||||||
|
"Turn Exceeds Steering Limit",
|
||||||
|
"JESUS TAKE THE WHEEL!!",
|
||||||
|
AlertStatus.userPrompt, AlertSize.mid,
|
||||||
|
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.warningSoft, 2.),
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 171 KiB |
|
After Width: | Height: | Size: 312 KiB |
|
After Width: | Height: | Size: 575 KiB |
|
After Width: | Height: | Size: 491 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 957 B |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -3,6 +3,12 @@
|
|||||||
|
|
||||||
FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) {
|
FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) {
|
||||||
const std::vector<std::tuple<QString, QString, QString, QString>> visualToggles {
|
const std::vector<std::tuple<QString, QString, QString, QString>> visualToggles {
|
||||||
|
{"CustomTheme", "Custom Themes", "Enable the ability to use custom themes.", "../frogpilot/assets/wheel_images/frog.png"},
|
||||||
|
{"CustomColors", "Color Theme", "Switch out the standard openpilot color scheme with a custom color scheme.\n\nWant to submit your own color scheme? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""},
|
||||||
|
{"CustomIcons", "Icon Pack", "Switch out the standard openpilot icons with a set of custom icons.\n\nWant to submit your own icon pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""},
|
||||||
|
{"CustomSignals", "Turn Signals", "Add custom animations for your turn signals for a personal touch!\n\nWant to submit your own turn signal animation? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""},
|
||||||
|
{"CustomSounds", "Sound Pack", "Switch out the standard openpilot sounds with a set of custom sounds.\n\nWant to submit your own sound pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""},
|
||||||
|
|
||||||
{"CameraView", "Camera View", "Choose your preferred camera view for the onroad UI. This is a visual change only and doesn't impact openpilot.", "../frogpilot/assets/toggle_icons/icon_camera.png"},
|
{"CameraView", "Camera View", "Choose your preferred camera view for the onroad UI. This is a visual change only and doesn't impact openpilot.", "../frogpilot/assets/toggle_icons/icon_camera.png"},
|
||||||
|
|
||||||
{"CustomUI", "Custom Onroad UI", "Customize the Onroad UI with some additional visual functions.", "../assets/offroad/icon_road.png"},
|
{"CustomUI", "Custom Onroad UI", "Customize the Onroad UI with some additional visual functions.", "../assets/offroad/icon_road.png"},
|
||||||
@@ -31,6 +37,32 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilot
|
|||||||
FrogPilotButtonParamControl *preferredCamera = new FrogPilotButtonParamControl(param, title, desc, icon, cameraOptions);
|
FrogPilotButtonParamControl *preferredCamera = new FrogPilotButtonParamControl(param, title, desc, icon, cameraOptions);
|
||||||
toggle = preferredCamera;
|
toggle = preferredCamera;
|
||||||
|
|
||||||
|
} else if (param == "CustomTheme") {
|
||||||
|
FrogPilotParamManageControl *customThemeToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(customThemeToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(customThemeKeys.find(key.c_str()) != customThemeKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = customThemeToggle;
|
||||||
|
} else if (param == "CustomColors" || param == "CustomIcons" || param == "CustomSignals" || param == "CustomSounds") {
|
||||||
|
std::vector<QString> themeOptions{tr("Stock"), tr("Frog"), tr("Tesla"), tr("Stalin")};
|
||||||
|
FrogPilotButtonParamControl *themeSelection = new FrogPilotButtonParamControl(param, title, desc, icon, themeOptions);
|
||||||
|
toggle = themeSelection;
|
||||||
|
|
||||||
|
if (param == "CustomSounds") {
|
||||||
|
QObject::connect(static_cast<FrogPilotButtonParamControl*>(toggle), &FrogPilotButtonParamControl::buttonClicked, [this](int id) {
|
||||||
|
if (id == 1) {
|
||||||
|
if (FrogPilotConfirmationDialog::yesorno("Do you want to enable the bonus 'Goat' sound effect?", this)) {
|
||||||
|
params.putBool("GoatScream", true);
|
||||||
|
} else {
|
||||||
|
params.putBool("GoatScream", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} else if (param == "CustomUI") {
|
} else if (param == "CustomUI") {
|
||||||
FrogPilotParamManageControl *customUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
FrogPilotParamManageControl *customUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
QObject::connect(customUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
QObject::connect(customUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
@@ -99,7 +131,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilot
|
|||||||
}
|
}
|
||||||
|
|
||||||
customOnroadUIKeys = {"AdjacentPath", "BlindSpotPath", "ShowFPS", "LeadInfo"};
|
customOnroadUIKeys = {"AdjacentPath", "BlindSpotPath", "ShowFPS", "LeadInfo"};
|
||||||
customThemeKeys = {};
|
customThemeKeys = {"CustomColors", "CustomIcons", "CustomSignals", "CustomSounds"};
|
||||||
modelUIKeys = {"AccelerationPath", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"};
|
modelUIKeys = {"AccelerationPath", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"};
|
||||||
|
|
||||||
QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotVisualsPanel::hideSubToggles);
|
QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotVisualsPanel::hideSubToggles);
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ void AnnotatedCameraWidget::updateState(const UIState &s) {
|
|||||||
has_eu_speed_limit = (nav_alive && speed_limit_sign == cereal::NavInstruction::SpeedLimitSign::VIENNA);
|
has_eu_speed_limit = (nav_alive && speed_limit_sign == cereal::NavInstruction::SpeedLimitSign::VIENNA);
|
||||||
is_metric = s.scene.is_metric;
|
is_metric = s.scene.is_metric;
|
||||||
speedUnit = s.scene.is_metric ? tr("km/h") : tr("mph");
|
speedUnit = s.scene.is_metric ? tr("km/h") : tr("mph");
|
||||||
hideBottomIcons = (cs.getAlertSize() != cereal::ControlsState::AlertSize::NONE);
|
hideBottomIcons = (cs.getAlertSize() != cereal::ControlsState::AlertSize::NONE || customSignals && (turnSignalLeft || turnSignalRight));
|
||||||
status = s.status;
|
status = s.status;
|
||||||
|
|
||||||
// update engageability/experimental mode button
|
// update engageability/experimental mode button
|
||||||
@@ -571,13 +571,21 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) {
|
|||||||
|
|
||||||
// lanelines
|
// lanelines
|
||||||
for (int i = 0; i < std::size(scene.lane_line_vertices); ++i) {
|
for (int i = 0; i < std::size(scene.lane_line_vertices); ++i) {
|
||||||
|
if (customColors != 0) {
|
||||||
|
painter.setBrush(themeConfiguration[customColors].second.first);
|
||||||
|
} else {
|
||||||
painter.setBrush(QColor::fromRgbF(1.0, 1.0, 1.0, std::clamp<float>(scene.lane_line_probs[i], 0.0, 0.7)));
|
painter.setBrush(QColor::fromRgbF(1.0, 1.0, 1.0, std::clamp<float>(scene.lane_line_probs[i], 0.0, 0.7)));
|
||||||
|
}
|
||||||
painter.drawPolygon(scene.lane_line_vertices[i]);
|
painter.drawPolygon(scene.lane_line_vertices[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// road edges
|
// road edges
|
||||||
for (int i = 0; i < std::size(scene.road_edge_vertices); ++i) {
|
for (int i = 0; i < std::size(scene.road_edge_vertices); ++i) {
|
||||||
|
if (customColors != 0) {
|
||||||
|
painter.setBrush(themeConfiguration[customColors].second.first);
|
||||||
|
} else {
|
||||||
painter.setBrush(QColor::fromRgbF(1.0, 0, 0, std::clamp<float>(1.0 - scene.road_edge_stds[i], 0.0, 1.0)));
|
painter.setBrush(QColor::fromRgbF(1.0, 0, 0, std::clamp<float>(1.0 - scene.road_edge_stds[i], 0.0, 1.0)));
|
||||||
|
}
|
||||||
painter.drawPolygon(scene.road_edge_vertices[i]);
|
painter.drawPolygon(scene.road_edge_vertices[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,8 +594,14 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) {
|
|||||||
if (sm["controlsState"].getControlsState().getExperimentalMode() || accelerationPath) {
|
if (sm["controlsState"].getControlsState().getExperimentalMode() || accelerationPath) {
|
||||||
// The first half of track_vertices are the points for the right side of the 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
|
// and the indices match the positions of accel from uiPlan
|
||||||
const auto &acceleration = sm["uiPlan"].getUiPlan().getAccel();
|
const auto &acceleration_const = sm["uiPlan"].getUiPlan().getAccel();
|
||||||
const int max_len = std::min<int>(scene.track_vertices.length() / 2, acceleration.size());
|
const int max_len = std::min<int>(scene.track_vertices.length() / 2, acceleration_const.size());
|
||||||
|
|
||||||
|
// Copy of the acceleration vector
|
||||||
|
std::vector<float> acceleration;
|
||||||
|
for (int i = 0; i < acceleration_const.size(); i++) {
|
||||||
|
acceleration.push_back(acceleration_const[i]);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < max_len; ++i) {
|
for (int i = 0; i < max_len; ++i) {
|
||||||
// Some points are out of frame
|
// Some points are out of frame
|
||||||
@@ -596,6 +610,13 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) {
|
|||||||
// Flip so 0 is bottom of frame
|
// Flip so 0 is bottom of frame
|
||||||
float lin_grad_point = (height() - scene.track_vertices[i].y()) / height();
|
float lin_grad_point = (height() - scene.track_vertices[i].y()) / height();
|
||||||
|
|
||||||
|
// If acceleration is between -0.2 and 0.2, resort to the theme color
|
||||||
|
if (std::abs(acceleration[i]) < 0.2 && (customColors != 0)) {
|
||||||
|
const auto &colorMap = themeConfiguration[customColors].second.second;
|
||||||
|
for (const auto &[position, brush] : colorMap) {
|
||||||
|
bg.setColorAt(position, brush.color());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// speed up: 120, slow down: 0
|
// speed up: 120, slow down: 0
|
||||||
float path_hue = fmax(fmin(60 + acceleration[i] * 35, 120), 0);
|
float path_hue = fmax(fmin(60 + acceleration[i] * 35, 120), 0);
|
||||||
// FIXME: painter.drawPolygon can be slow if hue is not rounded
|
// FIXME: painter.drawPolygon can be slow if hue is not rounded
|
||||||
@@ -609,7 +630,13 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) {
|
|||||||
// Skip a point, unless next is last
|
// Skip a point, unless next is last
|
||||||
i += (i + 2) < max_len ? 1 : 0;
|
i += (i + 2) < max_len ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (customColors != 0) {
|
||||||
|
const auto &colorMap = themeConfiguration[customColors].second.second;
|
||||||
|
for (const auto &[position, brush] : colorMap) {
|
||||||
|
bg.setColorAt(position, brush.color());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
bg.setColorAt(0.0, QColor::fromHslF(148 / 360., 0.94, 0.51, 0.4));
|
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));
|
bg.setColorAt(0.5, QColor::fromHslF(112 / 360., 1.0, 0.68, 0.35));
|
||||||
@@ -642,6 +669,12 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) {
|
|||||||
pe.setColorAt(0.0, QColor::fromHslF(205 / 360., 0.85, 0.56, 1.0));
|
pe.setColorAt(0.0, QColor::fromHslF(205 / 360., 0.85, 0.56, 1.0));
|
||||||
pe.setColorAt(0.5, QColor::fromHslF(205 / 360., 0.85, 0.56, 0.5));
|
pe.setColorAt(0.5, QColor::fromHslF(205 / 360., 0.85, 0.56, 0.5));
|
||||||
pe.setColorAt(1.0, QColor::fromHslF(205 / 360., 0.85, 0.56, 0.1));
|
pe.setColorAt(1.0, QColor::fromHslF(205 / 360., 0.85, 0.56, 0.1));
|
||||||
|
} else if (customColors != 0) {
|
||||||
|
const auto &colorMap = themeConfiguration[customColors].second.second;
|
||||||
|
for (const auto &[position, brush] : colorMap) {
|
||||||
|
QColor darkerColor = brush.color().darker(120);
|
||||||
|
pe.setColorAt(position, darkerColor);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pe.setColorAt(0.0, QColor::fromHslF(148 / 360., 0.94, 0.51, 1.0));
|
pe.setColorAt(0.0, QColor::fromHslF(148 / 360., 0.94, 0.51, 1.0));
|
||||||
pe.setColorAt(0.5, QColor::fromHslF(112 / 360., 1.00, 0.68, 0.5));
|
pe.setColorAt(0.5, QColor::fromHslF(112 / 360., 1.00, 0.68, 0.5));
|
||||||
@@ -756,8 +789,8 @@ void AnnotatedCameraWidget::drawDriverState(QPainter &painter, const UIState *s)
|
|||||||
void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd) {
|
void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd) {
|
||||||
painter.save();
|
painter.save();
|
||||||
|
|
||||||
const float speedBuff = 10.;
|
const float speedBuff = customColors ? 25. : 10.; // Make the center of the chevron appear sooner if a custom theme is active
|
||||||
const float leadBuff = 40.;
|
const float leadBuff = customColors ? 100. : 40.; // Make the center of the chevron appear sooner if a custom theme is active
|
||||||
const float d_rel = lead_data.getDRel();
|
const float d_rel = lead_data.getDRel();
|
||||||
const float v_rel = lead_data.getVRel();
|
const float v_rel = lead_data.getVRel();
|
||||||
|
|
||||||
@@ -783,7 +816,11 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState
|
|||||||
|
|
||||||
// chevron
|
// chevron
|
||||||
QPointF chevron[] = {{x + (sz * 1.25), y + sz}, {x, y}, {x - (sz * 1.25), y + sz}};
|
QPointF chevron[] = {{x + (sz * 1.25), y + sz}, {x, y}, {x - (sz * 1.25), y + sz}};
|
||||||
|
if (customColors != 0) {
|
||||||
|
painter.setBrush(themeConfiguration[customColors].second.first);
|
||||||
|
} else {
|
||||||
painter.setBrush(redColor(fillAlpha));
|
painter.setBrush(redColor(fillAlpha));
|
||||||
|
}
|
||||||
painter.drawPolygon(chevron, std::size(chevron));
|
painter.drawPolygon(chevron, std::size(chevron));
|
||||||
|
|
||||||
// Add lead info
|
// Add lead info
|
||||||
@@ -949,6 +986,25 @@ void AnnotatedCameraWidget::initializeFrogPilotWidgets() {
|
|||||||
bottom_layout->addWidget(map_settings_btn_bottom);
|
bottom_layout->addWidget(map_settings_btn_bottom);
|
||||||
|
|
||||||
main_layout->addLayout(bottom_layout);
|
main_layout->addLayout(bottom_layout);
|
||||||
|
|
||||||
|
// Custom themes configuration
|
||||||
|
themeConfiguration = {
|
||||||
|
{1, {QString("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, {QString("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, {QString("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))}}}}}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize the timer for the turn signal animation
|
||||||
|
animationTimer = new QTimer(this);
|
||||||
|
connect(animationTimer, &QTimer::timeout, this, [this] {
|
||||||
|
animationFrameIndex = (animationFrameIndex + 1) % totalFrames;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnnotatedCameraWidget::updateFrogPilotWidgets(QPainter &p) {
|
void AnnotatedCameraWidget::updateFrogPilotWidgets(QPainter &p) {
|
||||||
@@ -962,6 +1018,7 @@ void AnnotatedCameraWidget::updateFrogPilotWidgets(QPainter &p) {
|
|||||||
conditionalSpeed = scene.conditional_speed;
|
conditionalSpeed = scene.conditional_speed;
|
||||||
conditionalSpeedLead = scene.conditional_speed_lead;
|
conditionalSpeedLead = scene.conditional_speed_lead;
|
||||||
conditionalStatus = scene.conditional_status;
|
conditionalStatus = scene.conditional_status;
|
||||||
|
customColors = scene.custom_colors;
|
||||||
desiredFollow = scene.desired_follow;
|
desiredFollow = scene.desired_follow;
|
||||||
experimentalMode = scene.experimental_mode;
|
experimentalMode = scene.experimental_mode;
|
||||||
laneWidthLeft = scene.lane_width_left;
|
laneWidthLeft = scene.lane_width_left;
|
||||||
@@ -970,6 +1027,8 @@ void AnnotatedCameraWidget::updateFrogPilotWidgets(QPainter &p) {
|
|||||||
obstacleDistance = scene.obstacle_distance;
|
obstacleDistance = scene.obstacle_distance;
|
||||||
obstacleDistanceStock = scene.obstacle_distance_stock;
|
obstacleDistanceStock = scene.obstacle_distance_stock;
|
||||||
stoppedEquivalence = scene.stopped_equivalence;
|
stoppedEquivalence = scene.stopped_equivalence;
|
||||||
|
turnSignalLeft = scene.turn_signal_left;
|
||||||
|
turnSignalRight = scene.turn_signal_right;
|
||||||
useSI = scene.use_si;
|
useSI = scene.use_si;
|
||||||
|
|
||||||
if (leadInfo) {
|
if (leadInfo) {
|
||||||
@@ -980,11 +1039,46 @@ void AnnotatedCameraWidget::updateFrogPilotWidgets(QPainter &p) {
|
|||||||
drawStatusBar(p);
|
drawStatusBar(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (customSignals && (turnSignalLeft || turnSignalRight)) {
|
||||||
|
if (!animationTimer->isActive()) {
|
||||||
|
animationTimer->start(totalFrames * 11); // 440 milliseconds per loop; syncs up perfectly with my 2019 Lexus ES 350 turn signal clicks
|
||||||
|
}
|
||||||
|
drawTurnSignals(p);
|
||||||
|
} else if (animationTimer->isActive()) {
|
||||||
|
animationTimer->stop();
|
||||||
|
}
|
||||||
|
|
||||||
map_settings_btn_bottom->setEnabled(map_settings_btn->isEnabled());
|
map_settings_btn_bottom->setEnabled(map_settings_btn->isEnabled());
|
||||||
if (map_settings_btn_bottom->isEnabled()) {
|
if (map_settings_btn_bottom->isEnabled()) {
|
||||||
map_settings_btn_bottom->setVisible(!hideBottomIcons);
|
map_settings_btn_bottom->setVisible(!hideBottomIcons);
|
||||||
bottom_layout->setAlignment(map_settings_btn_bottom, rightHandDM ? Qt::AlignLeft : Qt::AlignRight);
|
bottom_layout->setAlignment(map_settings_btn_bottom, rightHandDM ? Qt::AlignLeft : Qt::AlignRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the turn signal animation images upon toggle change
|
||||||
|
if (customSignals != scene.custom_signals) {
|
||||||
|
customSignals = scene.custom_signals;
|
||||||
|
|
||||||
|
const QString theme_path = QString("../frogpilot/assets/custom_themes/%1/images").arg(themeConfiguration.find(customSignals) != themeConfiguration.end() ?
|
||||||
|
themeConfiguration[customSignals].first : "stock_theme");
|
||||||
|
const QStringList imagePaths = {
|
||||||
|
theme_path + "/turn_signal_1.png",
|
||||||
|
theme_path + "/turn_signal_2.png",
|
||||||
|
theme_path + "/turn_signal_3.png",
|
||||||
|
theme_path + "/turn_signal_4.png"
|
||||||
|
};
|
||||||
|
|
||||||
|
signalImgVector.clear();
|
||||||
|
signalImgVector.reserve(4 * imagePaths.size() + 2); // Reserve space for both regular and flipped images
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
for (const QString &imagePath : imagePaths) {
|
||||||
|
QPixmap pixmap(imagePath);
|
||||||
|
signalImgVector.push_back(pixmap); // Regular image
|
||||||
|
signalImgVector.push_back(pixmap.transformed(QTransform().scale(-1, 1))); // Flipped image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signalImgVector.push_back(QPixmap(theme_path + "/turn_signal_1_red.png")); // Regular blindspot image
|
||||||
|
signalImgVector.push_back(QPixmap(theme_path + "/turn_signal_1_red.png").transformed(QTransform().scale(-1, 1))); // Flipped blindspot image
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnnotatedCameraWidget::drawLeadInfo(QPainter &p) {
|
void AnnotatedCameraWidget::drawLeadInfo(QPainter &p) {
|
||||||
@@ -1162,3 +1256,35 @@ void AnnotatedCameraWidget::drawStatusBar(QPainter &p) {
|
|||||||
|
|
||||||
p.restore();
|
p.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnnotatedCameraWidget::drawTurnSignals(QPainter &p) {
|
||||||
|
// Declare the turn signal size
|
||||||
|
constexpr int signalHeight = 480;
|
||||||
|
constexpr int signalWidth = 360;
|
||||||
|
|
||||||
|
// Calculate the vertical position for the turn signals
|
||||||
|
int baseYPosition = (height() - signalHeight) / 2 + (alwaysOnLateral || conditionalExperimental || roadNameUI ? 225 : 300);
|
||||||
|
// Calculate the x-coordinates for the turn signals
|
||||||
|
int leftSignalXPosition = 75 + width() - signalWidth - 300 * (blindSpotLeft ? 0 : animationFrameIndex);
|
||||||
|
int rightSignalXPosition = -75 + 300 * (blindSpotRight ? 0 : animationFrameIndex);
|
||||||
|
|
||||||
|
// Enable Antialiasing
|
||||||
|
p.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
// Draw the turn signals
|
||||||
|
if (animationFrameIndex < signalImgVector.size()) {
|
||||||
|
auto drawSignal = [&](bool signalActivated, int xPosition, bool flip, bool blindspot) {
|
||||||
|
if (signalActivated) {
|
||||||
|
// Get the appropriate image from the signalImgVector
|
||||||
|
int uniqueImages = signalImgVector.size() / 4; // Each image has a regular, flipped, and two blindspot versions
|
||||||
|
int index = (blindspot ? 2 * uniqueImages : 2 * animationFrameIndex % totalFrames) + (flip ? 1 : 0);
|
||||||
|
QPixmap &signal = signalImgVector[index];
|
||||||
|
p.drawPixmap(xPosition, baseYPosition, signalWidth, signalHeight, signal);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Display the animation based on which signal is activated
|
||||||
|
drawSignal(turnSignalLeft, leftSignalXPosition, false, blindSpotLeft);
|
||||||
|
drawSignal(turnSignalRight, rightSignalXPosition, true, blindSpotRight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ private:
|
|||||||
// FrogPilot widgets
|
// FrogPilot widgets
|
||||||
void drawLeadInfo(QPainter &p);
|
void drawLeadInfo(QPainter &p);
|
||||||
void drawStatusBar(QPainter &p);
|
void drawStatusBar(QPainter &p);
|
||||||
|
void drawTurnSignals(QPainter &p);
|
||||||
void initializeFrogPilotWidgets();
|
void initializeFrogPilotWidgets();
|
||||||
void updateFrogPilotWidgets(QPainter &p);
|
void updateFrogPilotWidgets(QPainter &p);
|
||||||
|
|
||||||
@@ -133,6 +134,8 @@ private:
|
|||||||
bool conditionalExperimental;
|
bool conditionalExperimental;
|
||||||
bool experimentalMode;
|
bool experimentalMode;
|
||||||
bool leadInfo;
|
bool leadInfo;
|
||||||
|
bool turnSignalLeft;
|
||||||
|
bool turnSignalRight;
|
||||||
bool useSI;
|
bool useSI;
|
||||||
double maxAcceleration;
|
double maxAcceleration;
|
||||||
float laneWidthLeft;
|
float laneWidthLeft;
|
||||||
@@ -141,10 +144,18 @@ private:
|
|||||||
int conditionalSpeed;
|
int conditionalSpeed;
|
||||||
int conditionalSpeedLead;
|
int conditionalSpeedLead;
|
||||||
int conditionalStatus;
|
int conditionalStatus;
|
||||||
|
int customColors;
|
||||||
|
int customSignals;
|
||||||
int desiredFollow;
|
int desiredFollow;
|
||||||
int obstacleDistance;
|
int obstacleDistance;
|
||||||
int obstacleDistanceStock;
|
int obstacleDistanceStock;
|
||||||
int stoppedEquivalence;
|
int stoppedEquivalence;
|
||||||
|
int totalFrames = 8;
|
||||||
|
QTimer *animationTimer;
|
||||||
|
size_t animationFrameIndex;
|
||||||
|
|
||||||
|
std::unordered_map<int, std::pair<QString, std::pair<QColor, std::map<double, QBrush>>>> themeConfiguration;
|
||||||
|
std::vector<QPixmap> signalImgVector;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintGL() override;
|
void paintGL() override;
|
||||||
|
|||||||
@@ -48,6 +48,23 @@ Sidebar::Sidebar(QWidget *parent) : QFrame(parent), onroad(false), flag_pressed(
|
|||||||
isStorageLeft = params.getBool("ShowStorageLeft");
|
isStorageLeft = params.getBool("ShowStorageLeft");
|
||||||
isStorageUsed = params.getBool("ShowStorageUsed");
|
isStorageUsed = params.getBool("ShowStorageUsed");
|
||||||
|
|
||||||
|
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)}}}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto &[key, themeData] : themeConfiguration) {
|
||||||
|
QString &themeName = themeData.first;
|
||||||
|
QString base = themeName == "stock" ? "../assets/images" : QString("../frogpilot/assets/custom_themes/%1/images").arg(themeName);
|
||||||
|
std::vector<QString> paths = {base + "/button_home.png", base + "/button_flag.png", base + "/button_settings.png"};
|
||||||
|
|
||||||
|
home_imgs[key] = loadPixmap(paths[0], home_btn.size());
|
||||||
|
flag_imgs[key] = loadPixmap(paths[1], home_btn.size());
|
||||||
|
settings_imgs[key] = loadPixmap(paths[2], settings_btn.size(), Qt::IgnoreAspectRatio);
|
||||||
|
}
|
||||||
|
|
||||||
updateFrogPilotParams();
|
updateFrogPilotParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +134,8 @@ void Sidebar::updateState(const UIState &s) {
|
|||||||
// FrogPilot properties
|
// FrogPilot properties
|
||||||
auto frogpilotDeviceState = sm["frogpilotDeviceState"].getFrogpilotDeviceState();
|
auto frogpilotDeviceState = sm["frogpilotDeviceState"].getFrogpilotDeviceState();
|
||||||
|
|
||||||
|
QColor theme_color = currentColors[0];
|
||||||
|
|
||||||
// FrogPilot metrics
|
// FrogPilot metrics
|
||||||
if (isCPU || isGPU) {
|
if (isCPU || isGPU) {
|
||||||
auto cpu_loads = deviceState.getCpuUsagePercent();
|
auto cpu_loads = deviceState.getCpuUsagePercent();
|
||||||
@@ -129,7 +148,7 @@ void Sidebar::updateState(const UIState &s) {
|
|||||||
QString metric = isGPU ? gpu : cpu;
|
QString metric = isGPU ? gpu : cpu;
|
||||||
int usage = isGPU ? gpu_usage : cpu_usage;
|
int usage = isGPU ? gpu_usage : cpu_usage;
|
||||||
|
|
||||||
ItemStatus cpuStatus = {{tr(isGPU ? "GPU" : "CPU"), metric}, good_color};
|
ItemStatus cpuStatus = {{tr(isGPU ? "GPU" : "CPU"), metric}, theme_color};
|
||||||
if (usage >= 85) {
|
if (usage >= 85) {
|
||||||
cpuStatus = {{tr(isGPU ? "GPU" : "CPU"), metric}, danger_color};
|
cpuStatus = {{tr(isGPU ? "GPU" : "CPU"), metric}, danger_color};
|
||||||
} else if (usage >= 70) {
|
} else if (usage >= 70) {
|
||||||
@@ -147,7 +166,7 @@ void Sidebar::updateState(const UIState &s) {
|
|||||||
QString storage = QString::number(isStorageLeft ? storage_left : storage_used) + " GB";
|
QString storage = QString::number(isStorageLeft ? storage_left : storage_used) + " GB";
|
||||||
|
|
||||||
if (isMemoryUsage) {
|
if (isMemoryUsage) {
|
||||||
ItemStatus memoryStatus = {{tr("MEMORY"), memory}, good_color};
|
ItemStatus memoryStatus = {{tr("MEMORY"), memory}, theme_color};
|
||||||
if (memory_usage >= 85) {
|
if (memory_usage >= 85) {
|
||||||
memoryStatus = {{tr("MEMORY"), memory}, danger_color};
|
memoryStatus = {{tr("MEMORY"), memory}, danger_color};
|
||||||
} else if (memory_usage >= 70) {
|
} else if (memory_usage >= 70) {
|
||||||
@@ -155,7 +174,7 @@ void Sidebar::updateState(const UIState &s) {
|
|||||||
}
|
}
|
||||||
setProperty("memoryStatus", QVariant::fromValue(memoryStatus));
|
setProperty("memoryStatus", QVariant::fromValue(memoryStatus));
|
||||||
} else {
|
} else {
|
||||||
ItemStatus storageStatus = {{tr(isStorageLeft ? "LEFT" : "USED"), storage}, good_color};
|
ItemStatus storageStatus = {{tr(isStorageLeft ? "LEFT" : "USED"), storage}, theme_color};
|
||||||
if (10 <= storage_left && storage_left < 25) {
|
if (10 <= storage_left && storage_left < 25) {
|
||||||
storageStatus = {{tr(isStorageLeft ? "LEFT" : "USED"), storage}, warning_color};
|
storageStatus = {{tr(isStorageLeft ? "LEFT" : "USED"), storage}, warning_color};
|
||||||
} else if (storage_left < 10) {
|
} else if (storage_left < 10) {
|
||||||
@@ -171,7 +190,7 @@ void Sidebar::updateState(const UIState &s) {
|
|||||||
connectStatus = ItemStatus{{tr("CONNECT"), tr("OFFLINE")}, warning_color};
|
connectStatus = ItemStatus{{tr("CONNECT"), tr("OFFLINE")}, warning_color};
|
||||||
} else {
|
} else {
|
||||||
connectStatus = nanos_since_boot() - last_ping < 80e9
|
connectStatus = nanos_since_boot() - last_ping < 80e9
|
||||||
? ItemStatus{{tr("CONNECT"), tr("ONLINE")}, good_color}
|
? ItemStatus{{tr("CONNECT"), tr("ONLINE")}, theme_color}
|
||||||
: ItemStatus{{tr("CONNECT"), tr("ERROR")}, danger_color};
|
: ItemStatus{{tr("CONNECT"), tr("ERROR")}, danger_color};
|
||||||
}
|
}
|
||||||
setProperty("connectStatus", QVariant::fromValue(connectStatus));
|
setProperty("connectStatus", QVariant::fromValue(connectStatus));
|
||||||
@@ -179,13 +198,13 @@ void Sidebar::updateState(const UIState &s) {
|
|||||||
ItemStatus tempStatus = {{tr("TEMP"), tr("HIGH")}, danger_color};
|
ItemStatus tempStatus = {{tr("TEMP"), tr("HIGH")}, danger_color};
|
||||||
auto ts = deviceState.getThermalStatus();
|
auto ts = deviceState.getThermalStatus();
|
||||||
if (ts == cereal::DeviceState::ThermalStatus::GREEN) {
|
if (ts == cereal::DeviceState::ThermalStatus::GREEN) {
|
||||||
tempStatus = {{tr("TEMP"), tr("GOOD")}, good_color};
|
tempStatus = {{tr("TEMP"), tr("GOOD")}, theme_color};
|
||||||
} else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) {
|
} else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) {
|
||||||
tempStatus = {{tr("TEMP"), tr("OK")}, warning_color};
|
tempStatus = {{tr("TEMP"), tr("OK")}, warning_color};
|
||||||
}
|
}
|
||||||
setProperty("tempStatus", QVariant::fromValue(tempStatus));
|
setProperty("tempStatus", QVariant::fromValue(tempStatus));
|
||||||
|
|
||||||
ItemStatus pandaStatus = {{tr("VEHICLE"), tr("ONLINE")}, good_color};
|
ItemStatus pandaStatus = {{tr("VEHICLE"), tr("ONLINE")}, theme_color};
|
||||||
if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) {
|
if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) {
|
||||||
pandaStatus = {{tr("NO"), tr("PANDA")}, danger_color};
|
pandaStatus = {{tr("NO"), tr("PANDA")}, danger_color};
|
||||||
} else if (s.scene.started && !sm["liveLocationKalman"].getLiveLocationKalman().getGpsOK()) {
|
} else if (s.scene.started && !sm["liveLocationKalman"].getLiveLocationKalman().getGpsOK()) {
|
||||||
@@ -196,6 +215,15 @@ void Sidebar::updateState(const UIState &s) {
|
|||||||
|
|
||||||
void Sidebar::updateFrogPilotParams() {
|
void Sidebar::updateFrogPilotParams() {
|
||||||
// Update FrogPilot parameters upon toggle change
|
// Update FrogPilot parameters upon toggle change
|
||||||
|
isCustomTheme = params.getBool("CustomTheme");
|
||||||
|
customColors = isCustomTheme ? params.getInt("CustomColors") : 0;
|
||||||
|
customIcons = isCustomTheme ? params.getInt("CustomIcons") : 0;
|
||||||
|
|
||||||
|
home_img = home_imgs[customIcons];
|
||||||
|
flag_img = flag_imgs[customIcons];
|
||||||
|
settings_img = settings_imgs[customIcons];
|
||||||
|
|
||||||
|
currentColors = themeConfiguration[customColors].second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sidebar::paintEvent(QPaintEvent *event) {
|
void Sidebar::paintEvent(QPaintEvent *event) {
|
||||||
|
|||||||
@@ -73,9 +73,18 @@ private:
|
|||||||
|
|
||||||
ItemStatus cpu_status, memory_status, storage_status;
|
ItemStatus cpu_status, memory_status, storage_status;
|
||||||
|
|
||||||
|
std::unordered_map<int, std::pair<QString, std::vector<QColor>>> themeConfiguration;
|
||||||
|
std::unordered_map<int, QPixmap> flag_imgs;
|
||||||
|
std::unordered_map<int, QPixmap> home_imgs;
|
||||||
|
std::unordered_map<int, QPixmap> settings_imgs;
|
||||||
|
std::vector<QColor> currentColors;
|
||||||
|
|
||||||
bool isCPU;
|
bool isCPU;
|
||||||
|
bool isCustomTheme;
|
||||||
bool isGPU;
|
bool isGPU;
|
||||||
bool isMemoryUsage;
|
bool isMemoryUsage;
|
||||||
bool isStorageLeft;
|
bool isStorageLeft;
|
||||||
bool isStorageUsed;
|
bool isStorageUsed;
|
||||||
|
int customColors;
|
||||||
|
int customIcons;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class Soundd:
|
|||||||
for sound in sound_list:
|
for sound in sound_list:
|
||||||
filename, play_count, volume = sound_list[sound]
|
filename, play_count, volume = sound_list[sound]
|
||||||
|
|
||||||
wavefile = wave.open(BASEDIR + "/selfdrive/assets/sounds/" + filename, 'r')
|
wavefile = wave.open(self.sound_directory + filename, 'r')
|
||||||
|
|
||||||
assert wavefile.getnchannels() == 1
|
assert wavefile.getnchannels() == 1
|
||||||
assert wavefile.getsampwidth() == 2
|
assert wavefile.getsampwidth() == 2
|
||||||
@@ -169,6 +169,21 @@ class Soundd:
|
|||||||
|
|
||||||
def update_frogpilot_params(self):
|
def update_frogpilot_params(self):
|
||||||
|
|
||||||
|
custom_theme = self.params.get_bool("CustomTheme")
|
||||||
|
custom_sounds = self.params.get_int("CustomSounds") if custom_theme else 0
|
||||||
|
|
||||||
|
theme_configuration = {
|
||||||
|
0: "stock",
|
||||||
|
1: "frog_theme",
|
||||||
|
2: "tesla_theme",
|
||||||
|
3: "stalin_theme"
|
||||||
|
}
|
||||||
|
|
||||||
|
theme_name = theme_configuration.get(custom_sounds, "stock")
|
||||||
|
self.sound_directory = (f"{BASEDIR}/selfdrive/frogpilot/assets/custom_themes/{theme_name}/sounds/" if custom_sounds else f"{BASEDIR}/selfdrive/assets/sounds/")
|
||||||
|
|
||||||
|
self.load_sounds()
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
s = Soundd()
|
s = Soundd()
|
||||||
s.soundd_thread()
|
s.soundd_thread()
|
||||||
|
|||||||
@@ -214,10 +214,14 @@ static void update_state(UIState *s) {
|
|||||||
}
|
}
|
||||||
if (sm.updated("carState")) {
|
if (sm.updated("carState")) {
|
||||||
auto carState = sm["carState"].getCarState();
|
auto carState = sm["carState"].getCarState();
|
||||||
if (scene.blind_spot_path) {
|
if (scene.blind_spot_path || scene.custom_signals) {
|
||||||
scene.blind_spot_left = carState.getLeftBlindspot();
|
scene.blind_spot_left = carState.getLeftBlindspot();
|
||||||
scene.blind_spot_right = carState.getRightBlindspot();
|
scene.blind_spot_right = carState.getRightBlindspot();
|
||||||
}
|
}
|
||||||
|
if (scene.custom_signals) {
|
||||||
|
scene.turn_signal_left = carState.getLeftBlinker();
|
||||||
|
scene.turn_signal_right = carState.getRightBlinker();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (sm.updated("controlsState")) {
|
if (sm.updated("controlsState")) {
|
||||||
auto controlsState = sm["controlsState"].getControlsState();
|
auto controlsState = sm["controlsState"].getControlsState();
|
||||||
@@ -285,6 +289,10 @@ void ui_update_params(UIState *s) {
|
|||||||
scene.show_fps = scene.custom_onroad_ui && params.getBool("ShowFPS");
|
scene.show_fps = scene.custom_onroad_ui && params.getBool("ShowFPS");
|
||||||
scene.use_si = scene.custom_onroad_ui && params.getBool("UseSI");
|
scene.use_si = scene.custom_onroad_ui && params.getBool("UseSI");
|
||||||
|
|
||||||
|
scene.custom_theme = params.getBool("CustomTheme");
|
||||||
|
scene.custom_colors = scene.custom_theme ? params.getInt("CustomColors") : 0;
|
||||||
|
scene.custom_signals = scene.custom_theme ? params.getInt("CustomSignals") : 0;
|
||||||
|
|
||||||
scene.model_ui = params.getBool("ModelUI");
|
scene.model_ui = params.getBool("ModelUI");
|
||||||
scene.acceleration_path = scene.model_ui && params.getBool("AccelerationPath");
|
scene.acceleration_path = scene.model_ui && params.getBool("AccelerationPath");
|
||||||
scene.lane_line_width = params.getInt("LaneLinesWidth") * (scene.is_metric ? 1 : INCH_TO_CM) / 200;
|
scene.lane_line_width = params.getInt("LaneLinesWidth") * (scene.is_metric ? 1 : INCH_TO_CM) / 200;
|
||||||
|
|||||||
@@ -178,11 +178,14 @@ typedef struct UIScene {
|
|||||||
bool blind_spot_right;
|
bool blind_spot_right;
|
||||||
bool conditional_experimental;
|
bool conditional_experimental;
|
||||||
bool custom_onroad_ui;
|
bool custom_onroad_ui;
|
||||||
|
bool custom_theme;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
bool experimental_mode;
|
bool experimental_mode;
|
||||||
bool lead_info;
|
bool lead_info;
|
||||||
bool model_ui;
|
bool model_ui;
|
||||||
bool show_fps;
|
bool show_fps;
|
||||||
|
bool turn_signal_left;
|
||||||
|
bool turn_signal_right;
|
||||||
bool unlimited_road_ui_length;
|
bool unlimited_road_ui_length;
|
||||||
bool use_si;
|
bool use_si;
|
||||||
float lane_line_width;
|
float lane_line_width;
|
||||||
@@ -195,6 +198,8 @@ typedef struct UIScene {
|
|||||||
int conditional_speed;
|
int conditional_speed;
|
||||||
int conditional_speed_lead;
|
int conditional_speed_lead;
|
||||||
int conditional_status;
|
int conditional_status;
|
||||||
|
int custom_colors;
|
||||||
|
int custom_signals;
|
||||||
int desired_follow;
|
int desired_follow;
|
||||||
int obstacle_distance;
|
int obstacle_distance;
|
||||||
int obstacle_distance_stock;
|
int obstacle_distance_stock;
|
||||||
|
|||||||