openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

251 lines
8.2 KiB

#include "map_settings.h"
#include <QDebug>
#include "selfdrive/common/util.h"
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/qt_window.h"
#include "selfdrive/ui/qt/request_repeater.h"
#include "selfdrive/ui/qt/widgets/controls.h"
#include "selfdrive/ui/qt/widgets/scrollview.h"
static QString shorten(const QString &str, int max_len) {
return str.size() > max_len ? str.left(max_len).trimmed() + "" : str;
}
MapPanel::MapPanel(QWidget* parent) : QWidget(parent) {
stack = new QStackedWidget;
QWidget * main_widget = new QWidget;
QVBoxLayout *main_layout = new QVBoxLayout(main_widget);
const int icon_size = 200;
// Home
QHBoxLayout *home_layout = new QHBoxLayout;
home_button = new QPushButton;
home_button->setIconSize(QSize(icon_size, icon_size));
home_layout->addWidget(home_button);
home_address = new QLabel;
home_address->setWordWrap(true);
home_layout->addSpacing(30);
home_layout->addWidget(home_address);
home_layout->addStretch();
// Work
QHBoxLayout *work_layout = new QHBoxLayout;
work_button = new QPushButton;
work_button->setIconSize(QSize(icon_size, icon_size));
work_layout->addWidget(work_button);
work_address = new QLabel;
work_address->setWordWrap(true);
work_layout->addSpacing(30);
work_layout->addWidget(work_address);
work_layout->addStretch();
// Home & Work layout
QHBoxLayout *home_work_layout = new QHBoxLayout;
home_work_layout->addLayout(home_layout, 1);
home_work_layout->addSpacing(50);
home_work_layout->addLayout(work_layout, 1);
main_layout->addLayout(home_work_layout);
main_layout->addSpacing(20);
main_layout->addWidget(horizontal_line());
main_layout->addSpacing(20);
// Recents
recent_layout = new QVBoxLayout;
QWidget *recent_widget = new LayoutWidget(recent_layout, this);
ScrollView *recent_scroller = new ScrollView(recent_widget, this);
main_layout->addWidget(recent_scroller, 1);
QWidget * no_prime_widget = new QWidget;
QVBoxLayout *no_prime_layout = new QVBoxLayout(no_prime_widget);
QLabel *signup_header = new QLabel("Try the Navigation Beta");
signup_header->setStyleSheet(R"(font-size: 75px; color: white; font-weight:600;)");
signup_header->setAlignment(Qt::AlignCenter);
no_prime_layout->addWidget(signup_header);
no_prime_layout->addSpacing(50);
QLabel *screenshot = new QLabel;
QPixmap pm = QPixmap("../assets/navigation/screenshot.png");
screenshot->setPixmap(pm.scaledToWidth(vwp_w * 0.5, Qt::SmoothTransformation));
no_prime_layout->addWidget(screenshot, 0, Qt::AlignHCenter);
QLabel *signup = new QLabel("Get turn-by-turn directions displayed and more with a comma \nprime subscription. Sign up now: https://connect.comma.ai");
signup->setStyleSheet(R"(font-size: 45px; color: white; font-weight:300;)");
signup->setAlignment(Qt::AlignCenter);
no_prime_layout->addSpacing(50);
no_prime_layout->addWidget(signup);
no_prime_layout->addStretch();
stack->addWidget(main_widget);
stack->addWidget(no_prime_widget);
stack->setCurrentIndex(1);
QVBoxLayout *wrapper = new QVBoxLayout(this);
wrapper->addWidget(stack);
clear();
if (auto dongle_id = getDongleId()) {
// Fetch favorite and recent locations
{
QString url = "https://api.commadotai.com/v1/navigation/" + *dongle_id + "/locations";
RequestRepeater* repeater = new RequestRepeater(this, url, "ApiCache_NavDestinations", 30, true);
QObject::connect(repeater, &RequestRepeater::receivedResponse, this, &MapPanel::parseResponse);
QObject::connect(repeater, &RequestRepeater::failedResponse, this, &MapPanel::failedResponse);
}
// Destination set while offline
{
QString url = "https://api.commadotai.com/v1/navigation/" + *dongle_id + "/next";
RequestRepeater* repeater = new RequestRepeater(this, url, "", 10, true);
HttpRequest* deleter = new HttpRequest(this);
QObject::connect(repeater, &RequestRepeater::receivedResponse, [=](QString resp) {
auto params = Params();
if (resp != "null") {
if (params.get("NavDestination").empty()) {
qWarning() << "Setting NavDestination from /next" << resp;
params.put("NavDestination", resp.toStdString());
} else {
qWarning() << "Got location from /next, but NavDestination already set";
}
// Send DELETE to clear destination server side
deleter->sendRequest(url, HttpRequest::Method::DELETE);
}
});
}
}
}
void MapPanel::clear() {
home_button->setIcon(QPixmap("../assets/navigation/home_inactive.png"));
home_address->setStyleSheet(R"(font-size: 50px; color: grey;)");
home_address->setText("No home\nlocation set");
home_button->disconnect();
work_button->setIcon(QPixmap("../assets/navigation/work_inactive.png"));
work_address->setStyleSheet(R"(font-size: 50px; color: grey;)");
work_address->setText("No work\nlocation set");
work_button->disconnect();
clearLayout(recent_layout);
}
void MapPanel::parseResponse(const QString &response) {
QJsonDocument doc = QJsonDocument::fromJson(response.trimmed().toUtf8());
if (doc.isNull()) {
qDebug() << "JSON Parse failed on navigation locations";
return;
}
clear();
bool has_recents = false;
for (auto &save_type: {"favorite", "recent"}) {
for (auto location : doc.array()) {
auto obj = location.toObject();
auto type = obj["save_type"].toString();
auto label = obj["label"].toString();
auto name = obj["place_name"].toString();
auto details = obj["place_details"].toString();
if (type != save_type) continue;
if (type == "favorite" && label == "home") {
home_address->setText(name);
home_address->setStyleSheet(R"(font-size: 50px; color: white;)");
home_button->setIcon(QPixmap("../assets/navigation/home.png"));
QObject::connect(home_button, &QPushButton::clicked, [=]() {
navigateTo(obj);
emit closeSettings();
});
} else if (type == "favorite" && label == "work") {
work_address->setText(name);
work_address->setStyleSheet(R"(font-size: 50px; color: white;)");
work_button->setIcon(QPixmap("../assets/navigation/work.png"));
QObject::connect(work_button, &QPushButton::clicked, [=]() {
navigateTo(obj);
emit closeSettings();
});
} else {
ClickableWidget *widget = new ClickableWidget;
QHBoxLayout *layout = new QHBoxLayout(widget);
layout->setContentsMargins(15, 14, 40, 14);
QLabel *star = new QLabel("");
auto sp = star->sizePolicy();
sp.setRetainSizeWhenHidden(true);
star->setSizePolicy(sp);
star->setVisible(type == "favorite");
star->setStyleSheet(R"(font-size: 60px;)");
layout->addWidget(star);
layout->addSpacing(10);
QLabel *recent_label = new QLabel(shorten(name + " " + details, 45));
recent_label->setStyleSheet(R"(font-size: 50px;)");
layout->addWidget(recent_label);
layout->addStretch();
QLabel *arrow = new QLabel("");
arrow->setStyleSheet(R"(font-size: 60px;)");
layout->addWidget(arrow);
widget->setStyleSheet(R"(
.ClickableWidget {
border-radius: 10px;
border-width: 1px;
border-style: solid;
border-color: gray;
}
QWidget {
background-color: #393939;
color: #9c9c9c;
}
)");
QObject::connect(widget, &ClickableWidget::clicked, [=]() {
navigateTo(obj);
emit closeSettings();
});
recent_layout->addWidget(widget);
recent_layout->addSpacing(10);
has_recents = true;
}
}
}
if (!has_recents) {
QLabel *no_recents = new QLabel("no recent destinations");
no_recents->setStyleSheet(R"(font-size: 50px; color: #9c9c9c)");
recent_layout->addWidget(no_recents);
}
recent_layout->addStretch();
stack->setCurrentIndex(0);
repaint();
}
void MapPanel::failedResponse(const QString &response) {
stack->setCurrentIndex(1);
}
void MapPanel::navigateTo(const QJsonObject &place) {
QJsonDocument doc(place);
params.put("NavDestination", doc.toJson().toStdString());
}