Visuals - Custom Themes - Color Theme
Switch out the standard openpilot color scheme with themed colors. Want to submit your own color scheme? Post it in the 'feature-request' channel in the FrogPilot Discord!
This commit is contained in:
parent
9d8160756a
commit
c391c8c3b9
|
@ -283,13 +283,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<float>(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<float>(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<float>(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<float>(1.0 - scene.road_edge_stds[i], 0.0, 1.0)));
|
||||
}
|
||||
painter.drawPolygon(scene.road_edge_vertices[i]);
|
||||
}
|
||||
|
||||
|
@ -298,8 +306,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<int>(scene.track_vertices.length() / 2, acceleration.size());
|
||||
const auto &acceleration_const = sm["uiPlan"].getUiPlan().getAccel();
|
||||
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) {
|
||||
// Some points are out of frame
|
||||
|
@ -308,18 +322,31 @@ 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.25 && (customColors != 0)) {
|
||||
const std::map<double, QBrush> &colorMap = std::get<2>(themeConfiguration[customColors]);
|
||||
for (const std::pair<double, QBrush> &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<double, QBrush> &colorMap = std::get<2>(themeConfiguration[customColors]);
|
||||
for (const std::pair<double, QBrush> &entry : colorMap) {
|
||||
bg.setColorAt(entry.first, entry.second.color());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -432,8 +459,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;
|
||||
|
||||
|
@ -459,7 +486,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();
|
||||
|
@ -583,6 +614,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(const UIScene &scene) {
|
||||
|
@ -629,6 +672,8 @@ void AnnotatedCameraWidget::updateFrogPilotWidgets(const UIScene &scene) {
|
|||
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;
|
||||
|
|
|
@ -137,11 +137,14 @@ private:
|
|||
int conditionalSpeed;
|
||||
int conditionalSpeedLead;
|
||||
int conditionalStatus;
|
||||
int customColors;
|
||||
|
||||
QString accelerationUnit;
|
||||
QString leadDistanceUnit;
|
||||
QString leadSpeedUnit;
|
||||
|
||||
std::unordered_map<int, std::tuple<QString, QColor, std::map<double, QBrush>>> 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); }
|
||||
|
||||
|
|
|
@ -38,6 +38,19 @@ Sidebar::Sidebar(QWidget *parent) : QFrame(parent), onroad(false), flag_pressed(
|
|||
QObject::connect(uiState(), &UIState::uiUpdate, this, &Sidebar::updateState);
|
||||
|
||||
pm = std::make_unique<PubMaster, const std::initializer_list<const char *>>({"userFlag"});
|
||||
|
||||
// FrogPilot variables
|
||||
UIState *s = uiState();
|
||||
UIScene &scene = s->scene;
|
||||
|
||||
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 +93,10 @@ void Sidebar::updateState(const UIState &s) {
|
|||
setProperty("netStrength", strength > 0 ? strength + 1 : 0);
|
||||
|
||||
// FrogPilot properties
|
||||
const UIScene &scene = s.scene;
|
||||
|
||||
currentColors = themeConfiguration[scene.custom_colors].second;
|
||||
|
||||
auto frogpilotDeviceState = sm["frogpilotDeviceState"].getFrogpilotDeviceState();
|
||||
|
||||
ItemStatus connectStatus;
|
||||
|
@ -88,7 +105,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 +113,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()) {
|
||||
|
|
|
@ -62,4 +62,8 @@ private:
|
|||
|
||||
// FrogPilot variables
|
||||
Params params;
|
||||
|
||||
std::unordered_map<int, std::pair<QString, std::vector<QColor>>> themeConfiguration;
|
||||
|
||||
std::vector<QColor> currentColors;
|
||||
};
|
||||
|
|
|
@ -315,6 +315,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");
|
||||
|
||||
|
|
|
@ -179,6 +179,7 @@ typedef struct UIScene {
|
|||
int conditional_speed;
|
||||
int conditional_speed_lead;
|
||||
int conditional_status;
|
||||
int custom_colors;
|
||||
int steering_angle_deg;
|
||||
int tethering_config;
|
||||
int wheel_icon;
|
||||
|
|
Loading…
Reference in New Issue