|
|
|
@ -1,132 +1,95 @@ |
|
|
|
|
#include "map_settings.h" |
|
|
|
|
|
|
|
|
|
#include <QDebug> |
|
|
|
|
#include <vector> |
|
|
|
|
|
|
|
|
|
#include "common/util.h" |
|
|
|
|
#include "selfdrive/ui/qt/util.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) { |
|
|
|
|
QStackedLayout *stack = new QStackedLayout(this); |
|
|
|
|
MapSettings::MapSettings(bool closeable, QWidget *parent) |
|
|
|
|
: QFrame(parent), current_destination(nullptr) { |
|
|
|
|
QSize icon_size(100, 100); |
|
|
|
|
close_icon = loadPixmap("../assets/icons/close.svg", icon_size); |
|
|
|
|
|
|
|
|
|
QWidget *main_widget = new QWidget; |
|
|
|
|
QVBoxLayout *main_layout = new QVBoxLayout(main_widget); |
|
|
|
|
main_layout->setSpacing(20); |
|
|
|
|
setContentsMargins(0, 0, 0, 0); |
|
|
|
|
|
|
|
|
|
// Home & Work layout
|
|
|
|
|
QHBoxLayout *home_work_layout = new QHBoxLayout; |
|
|
|
|
{ |
|
|
|
|
// Home
|
|
|
|
|
home_button = new QPushButton; |
|
|
|
|
home_button->setIconSize(QSize(MAP_PANEL_ICON_SIZE, MAP_PANEL_ICON_SIZE)); |
|
|
|
|
home_address = new QLabel; |
|
|
|
|
home_address->setWordWrap(true); |
|
|
|
|
|
|
|
|
|
QHBoxLayout *home_layout = new QHBoxLayout; |
|
|
|
|
home_layout->addWidget(home_button); |
|
|
|
|
home_layout->addSpacing(30); |
|
|
|
|
home_layout->addWidget(home_address); |
|
|
|
|
home_layout->addStretch(); |
|
|
|
|
|
|
|
|
|
// Work
|
|
|
|
|
work_button = new QPushButton; |
|
|
|
|
work_button->setIconSize(QSize(MAP_PANEL_ICON_SIZE, MAP_PANEL_ICON_SIZE)); |
|
|
|
|
work_address = new QLabel; |
|
|
|
|
work_address->setWordWrap(true); |
|
|
|
|
|
|
|
|
|
QHBoxLayout *work_layout = new QHBoxLayout; |
|
|
|
|
work_layout->addWidget(work_button); |
|
|
|
|
work_layout->addSpacing(30); |
|
|
|
|
work_layout->addWidget(work_address); |
|
|
|
|
work_layout->addStretch(); |
|
|
|
|
|
|
|
|
|
home_work_layout->addLayout(home_layout, 1); |
|
|
|
|
home_work_layout->addSpacing(50); |
|
|
|
|
home_work_layout->addLayout(work_layout, 1); |
|
|
|
|
} |
|
|
|
|
auto *frame = new QVBoxLayout(this); |
|
|
|
|
frame->setContentsMargins(40, 40, 40, 0); |
|
|
|
|
frame->setSpacing(0); |
|
|
|
|
|
|
|
|
|
main_layout->addLayout(home_work_layout); |
|
|
|
|
main_layout->addWidget(horizontal_line()); |
|
|
|
|
|
|
|
|
|
// Current route
|
|
|
|
|
auto *heading_frame = new QHBoxLayout; |
|
|
|
|
heading_frame->setContentsMargins(0, 0, 0, 0); |
|
|
|
|
heading_frame->setSpacing(32); |
|
|
|
|
{ |
|
|
|
|
current_widget = new QWidget(this); |
|
|
|
|
QVBoxLayout *current_layout = new QVBoxLayout(current_widget); |
|
|
|
|
|
|
|
|
|
QLabel *title = new QLabel(tr("Current Destination")); |
|
|
|
|
title->setStyleSheet("font-size: 55px"); |
|
|
|
|
current_layout->addWidget(title); |
|
|
|
|
|
|
|
|
|
current_route = new ButtonControl("", tr("CLEAR")); |
|
|
|
|
current_route->setStyleSheet("padding-left: 40px;"); |
|
|
|
|
current_layout->addWidget(current_route); |
|
|
|
|
QObject::connect(current_route, &ButtonControl::clicked, [=]() { |
|
|
|
|
params.remove("NavDestination"); |
|
|
|
|
updateCurrentRoute(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
current_layout->addSpacing(10); |
|
|
|
|
current_layout->addWidget(horizontal_line()); |
|
|
|
|
current_layout->addSpacing(20); |
|
|
|
|
} |
|
|
|
|
main_layout->addWidget(current_widget); |
|
|
|
|
|
|
|
|
|
// Recents
|
|
|
|
|
QLabel *recents_title = new QLabel(tr("Recent Destinations")); |
|
|
|
|
recents_title->setStyleSheet("font-size: 55px"); |
|
|
|
|
main_layout->addWidget(recents_title); |
|
|
|
|
if (closeable) { |
|
|
|
|
auto *close_btn = new QPushButton("←"); |
|
|
|
|
close_btn->setStyleSheet(R"( |
|
|
|
|
QPushButton { |
|
|
|
|
color: #FFFFFF; |
|
|
|
|
font-size: 100px; |
|
|
|
|
padding-bottom: 8px; |
|
|
|
|
border 1px grey solid; |
|
|
|
|
border-radius: 70px; |
|
|
|
|
background-color: #292929; |
|
|
|
|
font-weight: 500; |
|
|
|
|
} |
|
|
|
|
QPushButton:pressed { |
|
|
|
|
background-color: #3B3B3B; |
|
|
|
|
} |
|
|
|
|
)"); |
|
|
|
|
close_btn->setFixedSize(140, 140); |
|
|
|
|
QObject::connect(close_btn, &QPushButton::clicked, [=]() { emit closeSettings(); }); |
|
|
|
|
// TODO: read map_on_left from ui state
|
|
|
|
|
heading_frame->addWidget(close_btn); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
auto *heading = new QVBoxLayout; |
|
|
|
|
heading->setContentsMargins(0, 0, 0, 0); |
|
|
|
|
heading->setSpacing(16); |
|
|
|
|
{ |
|
|
|
|
auto *title = new QLabel(tr("NAVIGATION"), this); |
|
|
|
|
title->setStyleSheet("color: #FFFFFF; font-size: 54px; font-weight: 600;"); |
|
|
|
|
heading->addWidget(title); |
|
|
|
|
|
|
|
|
|
// No prime upsell
|
|
|
|
|
QWidget * no_prime_widget = new QWidget; |
|
|
|
|
{ |
|
|
|
|
QVBoxLayout *no_prime_layout = new QVBoxLayout(no_prime_widget); |
|
|
|
|
QLabel *signup_header = new QLabel(tr("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(1080, Qt::SmoothTransformation)); |
|
|
|
|
no_prime_layout->addWidget(screenshot, 0, Qt::AlignHCenter); |
|
|
|
|
|
|
|
|
|
QLabel *signup = new QLabel(tr("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(20); |
|
|
|
|
no_prime_layout->addWidget(signup); |
|
|
|
|
no_prime_layout->addStretch(); |
|
|
|
|
auto *subtitle = new QLabel(tr("Manage at connect.comma.ai"), this); |
|
|
|
|
subtitle->setStyleSheet("color: #A0A0A0; font-size: 40px; font-weight: 300;"); |
|
|
|
|
heading->addWidget(subtitle); |
|
|
|
|
} |
|
|
|
|
heading_frame->addLayout(heading, 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
stack->addWidget(main_widget); |
|
|
|
|
stack->addWidget(no_prime_widget); |
|
|
|
|
connect(uiState(), &UIState::primeTypeChanged, [=](int prime_type) { |
|
|
|
|
stack->setCurrentIndex(prime_type ? 0 : 1); |
|
|
|
|
frame->addLayout(heading_frame); |
|
|
|
|
frame->addSpacing(32); |
|
|
|
|
|
|
|
|
|
current_widget = new DestinationWidget(this); |
|
|
|
|
QObject::connect(current_widget, &DestinationWidget::actionClicked, [=]() { |
|
|
|
|
if (!current_destination) return; |
|
|
|
|
params.remove("NavDestination"); |
|
|
|
|
updateCurrentRoute(); |
|
|
|
|
}); |
|
|
|
|
frame->addWidget(current_widget); |
|
|
|
|
frame->addSpacing(32); |
|
|
|
|
frame->addWidget(horizontal_line()); |
|
|
|
|
|
|
|
|
|
QWidget *destinations_container = new QWidget(this); |
|
|
|
|
destinations_layout = new QVBoxLayout(destinations_container); |
|
|
|
|
destinations_layout->setContentsMargins(0, 32, 0, 32); |
|
|
|
|
destinations_layout->setSpacing(20); |
|
|
|
|
ScrollView *destinations_scroller = new ScrollView(destinations_container, this); |
|
|
|
|
frame->addWidget(destinations_scroller); |
|
|
|
|
|
|
|
|
|
clear(); |
|
|
|
|
setStyleSheet("MapSettings { background-color: #333333; }"); |
|
|
|
|
|
|
|
|
|
if (auto dongle_id = getDongleId()) { |
|
|
|
|
// Fetch favorite and recent locations
|
|
|
|
|
{ |
|
|
|
|
QString url = CommaApi::BASE_URL + "/v1/navigation/" + *dongle_id + "/locations"; |
|
|
|
|
RequestRepeater* repeater = new RequestRepeater(this, url, "ApiCache_NavDestinations", 30, true); |
|
|
|
|
QObject::connect(repeater, &RequestRepeater::requestDone, this, &MapPanel::parseResponse); |
|
|
|
|
QObject::connect(repeater, &RequestRepeater::requestDone, this, &MapSettings::parseResponse); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Destination set while offline
|
|
|
|
@ -147,153 +110,236 @@ MapPanel::MapPanel(QWidget* parent) : QWidget(parent) { |
|
|
|
|
// Send DELETE to clear destination server side
|
|
|
|
|
deleter->sendRequest(url, HttpRequest::Method::DELETE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Update UI (athena can set destination at any time)
|
|
|
|
|
updateCurrentRoute(); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void MapPanel::showEvent(QShowEvent *event) { |
|
|
|
|
void MapSettings::showEvent(QShowEvent *event) { |
|
|
|
|
updateCurrentRoute(); |
|
|
|
|
refresh(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void MapPanel::clear() { |
|
|
|
|
home_button->setIcon(QPixmap("../assets/navigation/home_inactive.png")); |
|
|
|
|
home_address->setStyleSheet(R"(font-size: 50px; color: grey;)"); |
|
|
|
|
home_address->setText(tr("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(tr("No work\nlocation set")); |
|
|
|
|
work_button->disconnect(); |
|
|
|
|
|
|
|
|
|
clearLayout(recent_layout); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void MapPanel::updateCurrentRoute() { |
|
|
|
|
void MapSettings::updateCurrentRoute() { |
|
|
|
|
auto dest = QString::fromStdString(params.get("NavDestination")); |
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson(dest.trimmed().toUtf8()); |
|
|
|
|
if (dest.size() && !doc.isNull()) { |
|
|
|
|
auto name = doc["place_name"].toString(); |
|
|
|
|
auto details = doc["place_details"].toString(); |
|
|
|
|
current_route->setTitle(shorten(name + " " + details, 42)); |
|
|
|
|
if (dest.size()) { |
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson(dest.trimmed().toUtf8()); |
|
|
|
|
if (doc.isNull()) { |
|
|
|
|
qWarning() << "JSON Parse failed on NavDestination" << dest; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
auto destination = new NavDestination(doc.object()); |
|
|
|
|
if (current_destination && *destination == *current_destination) return; |
|
|
|
|
current_destination = destination; |
|
|
|
|
current_widget->set(current_destination, true); |
|
|
|
|
} else { |
|
|
|
|
current_destination = nullptr; |
|
|
|
|
current_widget->unset("", true); |
|
|
|
|
} |
|
|
|
|
current_widget->setVisible(dest.size() && !doc.isNull()); |
|
|
|
|
if (isVisible()) refresh(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void MapPanel::parseResponse(const QString &response, bool success) { |
|
|
|
|
if (!success) return; |
|
|
|
|
|
|
|
|
|
void MapSettings::parseResponse(const QString &response, bool success) { |
|
|
|
|
if (!success || response == cur_destinations) return; |
|
|
|
|
cur_destinations = response; |
|
|
|
|
if (isVisible()) { |
|
|
|
|
refresh(); |
|
|
|
|
} |
|
|
|
|
refresh(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void MapPanel::refresh() { |
|
|
|
|
if (cur_destinations == prev_destinations) return; |
|
|
|
|
|
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson(cur_destinations.trimmed().toUtf8()); |
|
|
|
|
if (doc.isNull()) { |
|
|
|
|
qDebug() << "JSON Parse failed on navigation locations"; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
void MapSettings::refresh() { |
|
|
|
|
bool has_home = false, has_work = false; |
|
|
|
|
auto destinations = std::vector<NavDestination*>(); |
|
|
|
|
|
|
|
|
|
prev_destinations = cur_destinations; |
|
|
|
|
clear(); |
|
|
|
|
|
|
|
|
|
// add favorites before recents
|
|
|
|
|
bool has_recents = false; |
|
|
|
|
for (auto &save_type: {NAV_TYPE_FAVORITE, NAV_TYPE_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 == NAV_TYPE_FAVORITE && label == NAV_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 == NAV_TYPE_FAVORITE && label == NAV_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 == NAV_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; |
|
|
|
|
} |
|
|
|
|
)"); |
|
|
|
|
auto destinations_str = cur_destinations.trimmed(); |
|
|
|
|
if (!destinations_str.isEmpty()) { |
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson(destinations_str.toUtf8()); |
|
|
|
|
if (doc.isNull()) { |
|
|
|
|
qWarning() << "JSON Parse failed on navigation locations" << cur_destinations; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QObject::connect(widget, &ClickableWidget::clicked, [=]() { |
|
|
|
|
navigateTo(obj); |
|
|
|
|
emit closeSettings(); |
|
|
|
|
}); |
|
|
|
|
for (auto el : doc.array()) { |
|
|
|
|
auto destination = new NavDestination(el.toObject()); |
|
|
|
|
|
|
|
|
|
recent_layout->addWidget(widget); |
|
|
|
|
recent_layout->addSpacing(10); |
|
|
|
|
has_recents = true; |
|
|
|
|
// add home and work later if they are missing
|
|
|
|
|
if (destination->isFavorite()) { |
|
|
|
|
if (destination->label() == NAV_FAVORITE_LABEL_HOME) has_home = true; |
|
|
|
|
else if (destination->label() == NAV_FAVORITE_LABEL_WORK) has_work = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// skip current destination
|
|
|
|
|
if (current_destination && *destination == *current_destination) continue; |
|
|
|
|
destinations.push_back(destination); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!has_recents) { |
|
|
|
|
QLabel *no_recents = new QLabel(tr("no recent destinations")); |
|
|
|
|
no_recents->setStyleSheet(R"(font-size: 50px; color: #9c9c9c)"); |
|
|
|
|
recent_layout->addWidget(no_recents); |
|
|
|
|
// TODO: should we build a new layout and swap it in?
|
|
|
|
|
clearLayout(destinations_layout); |
|
|
|
|
|
|
|
|
|
// Sort: HOME, WORK, and then descending-alphabetical FAVORITES, RECENTS
|
|
|
|
|
std::sort(destinations.begin(), destinations.end(), [](const NavDestination *a, const NavDestination *b) { |
|
|
|
|
if (a->isFavorite() && b->isFavorite()) { |
|
|
|
|
if (a->label() == NAV_FAVORITE_LABEL_HOME) return true; |
|
|
|
|
else if (b->label() == NAV_FAVORITE_LABEL_HOME) return false; |
|
|
|
|
else if (a->label() == NAV_FAVORITE_LABEL_WORK) return true; |
|
|
|
|
else if (b->label() == NAV_FAVORITE_LABEL_WORK) return false; |
|
|
|
|
else if (a->label() != b->label()) return a->label() < b->label(); |
|
|
|
|
} |
|
|
|
|
else if (a->isFavorite()) return true; |
|
|
|
|
else if (b->isFavorite()) return false; |
|
|
|
|
return a->name() < b->name(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
for (auto destination : destinations) { |
|
|
|
|
auto widget = new DestinationWidget(this); |
|
|
|
|
widget->set(destination, false); |
|
|
|
|
|
|
|
|
|
QObject::connect(widget, &QPushButton::clicked, [=]() { |
|
|
|
|
navigateTo(destination->toJson()); |
|
|
|
|
emit closeSettings(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
destinations_layout->addWidget(widget); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
recent_layout->addStretch(); |
|
|
|
|
// add home and work if missing
|
|
|
|
|
if (!has_home) { |
|
|
|
|
auto widget = new DestinationWidget(this); |
|
|
|
|
widget->unset(NAV_FAVORITE_LABEL_HOME); |
|
|
|
|
destinations_layout->insertWidget(0, widget); |
|
|
|
|
} |
|
|
|
|
if (!has_work) { |
|
|
|
|
auto widget = new DestinationWidget(this); |
|
|
|
|
widget->unset(NAV_FAVORITE_LABEL_WORK); |
|
|
|
|
// TODO: refactor to remove this hack
|
|
|
|
|
int index = !has_home || (current_destination && current_destination->isFavorite() && current_destination->label() == NAV_FAVORITE_LABEL_HOME) ? 0 : 1; |
|
|
|
|
destinations_layout->insertWidget(index, widget); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
destinations_layout->addStretch(); |
|
|
|
|
repaint(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void MapPanel::navigateTo(const QJsonObject &place) { |
|
|
|
|
void MapSettings::navigateTo(const QJsonObject &place) { |
|
|
|
|
QJsonDocument doc(place); |
|
|
|
|
params.put("NavDestination", doc.toJson().toStdString()); |
|
|
|
|
updateCurrentRoute(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
DestinationWidget::DestinationWidget(QWidget *parent) : QPushButton(parent) { |
|
|
|
|
setContentsMargins(0, 0, 0, 0); |
|
|
|
|
|
|
|
|
|
auto *frame = new QHBoxLayout(this); |
|
|
|
|
frame->setContentsMargins(32, 24, 32, 24); |
|
|
|
|
frame->setSpacing(32); |
|
|
|
|
|
|
|
|
|
icon = new QLabel(this); |
|
|
|
|
icon->setAlignment(Qt::AlignCenter); |
|
|
|
|
icon->setFixedSize(96, 96); |
|
|
|
|
icon->setObjectName("icon"); |
|
|
|
|
frame->addWidget(icon); |
|
|
|
|
|
|
|
|
|
auto *inner_frame = new QVBoxLayout; |
|
|
|
|
inner_frame->setContentsMargins(0, 0, 0, 0); |
|
|
|
|
inner_frame->setSpacing(0); |
|
|
|
|
{ |
|
|
|
|
title = new ElidedLabel(this); |
|
|
|
|
title->setAttribute(Qt::WA_TransparentForMouseEvents); |
|
|
|
|
inner_frame->addWidget(title); |
|
|
|
|
|
|
|
|
|
subtitle = new ElidedLabel(this); |
|
|
|
|
subtitle->setAttribute(Qt::WA_TransparentForMouseEvents); |
|
|
|
|
subtitle->setObjectName("subtitle"); |
|
|
|
|
inner_frame->addWidget(subtitle); |
|
|
|
|
} |
|
|
|
|
frame->addLayout(inner_frame, 1); |
|
|
|
|
|
|
|
|
|
action = new QPushButton(this); |
|
|
|
|
action->setFixedSize(96, 96); |
|
|
|
|
action->setObjectName("action"); |
|
|
|
|
action->setStyleSheet("font-size: 65px; font-weight: 600;"); |
|
|
|
|
QObject::connect(action, &QPushButton::clicked, [=]() { emit clicked(); }); |
|
|
|
|
QObject::connect(action, &QPushButton::clicked, [=]() { emit actionClicked(); }); |
|
|
|
|
frame->addWidget(action); |
|
|
|
|
|
|
|
|
|
setFixedHeight(164); |
|
|
|
|
setStyleSheet(R"( |
|
|
|
|
DestinationWidget { background-color: #202123; border-radius: 10px; } |
|
|
|
|
QLabel { color: #FFFFFF; font-size: 48px; font-weight: 400; } |
|
|
|
|
#icon { background-color: #3B4356; border-radius: 48px; } |
|
|
|
|
#subtitle { color: #9BA0A5; } |
|
|
|
|
#action { border: none; border-radius: 48px; color: #FFFFFF; padding-bottom: 4px; } |
|
|
|
|
|
|
|
|
|
/* current destination */ |
|
|
|
|
[current="true"] { background-color: #E8E8E8; } |
|
|
|
|
[current="true"] QLabel { color: #000000; } |
|
|
|
|
[current="true"] #icon { background-color: #42906B; } |
|
|
|
|
[current="true"] #subtitle { color: #333333; } |
|
|
|
|
[current="true"] #action { color: #202123; } |
|
|
|
|
|
|
|
|
|
/* no saved destination */ |
|
|
|
|
[set="false"] QLabel { color: #9BA0A5; } |
|
|
|
|
[current="true"][set="false"] QLabel { color: #A0000000; } |
|
|
|
|
|
|
|
|
|
/* pressed */ |
|
|
|
|
[current="false"]:pressed { background-color: #18191B; } |
|
|
|
|
[current="true"] #action:pressed { background-color: #D6D6D6; } |
|
|
|
|
)"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void DestinationWidget::set(NavDestination *destination, bool current) { |
|
|
|
|
setProperty("current", current); |
|
|
|
|
setProperty("set", true); |
|
|
|
|
|
|
|
|
|
auto icon_pixmap = current ? icons().directions : icons().recent; |
|
|
|
|
auto title_text = destination->name(); |
|
|
|
|
auto subtitle_text = destination->details(); |
|
|
|
|
|
|
|
|
|
if (destination->isFavorite()) { |
|
|
|
|
if (destination->label() == NAV_FAVORITE_LABEL_HOME) { |
|
|
|
|
icon_pixmap = icons().home; |
|
|
|
|
title_text = tr("Home"); |
|
|
|
|
subtitle_text = destination->name() + ", " + destination->details(); |
|
|
|
|
} else if (destination->label() == NAV_FAVORITE_LABEL_WORK) { |
|
|
|
|
icon_pixmap = icons().work; |
|
|
|
|
title_text = tr("Work"); |
|
|
|
|
subtitle_text = destination->name() + ", " + destination->details(); |
|
|
|
|
} else { |
|
|
|
|
icon_pixmap = icons().favorite; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
icon->setPixmap(icon_pixmap); |
|
|
|
|
|
|
|
|
|
// TODO: onroad and offroad have different dimensions
|
|
|
|
|
title->setText(shorten(title_text, 26)); |
|
|
|
|
subtitle->setText(shorten(subtitle_text, 26)); |
|
|
|
|
subtitle->setVisible(true); |
|
|
|
|
|
|
|
|
|
// TODO: use pixmap
|
|
|
|
|
action->setAttribute(Qt::WA_TransparentForMouseEvents, !current); |
|
|
|
|
action->setText(current ? "×" : "→"); |
|
|
|
|
action->setVisible(true); |
|
|
|
|
|
|
|
|
|
setStyleSheet(styleSheet()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void DestinationWidget::unset(const QString &label, bool current) { |
|
|
|
|
setProperty("current", current); |
|
|
|
|
setProperty("set", false); |
|
|
|
|
|
|
|
|
|
if (label.isEmpty()) { |
|
|
|
|
icon->setPixmap(icons().directions); |
|
|
|
|
title->setText(tr("No destination set")); |
|
|
|
|
} else { |
|
|
|
|
QString title_text = label == NAV_FAVORITE_LABEL_HOME ? tr("home") : tr("work"); |
|
|
|
|
icon->setPixmap(label == NAV_FAVORITE_LABEL_HOME ? icons().home : icons().work); |
|
|
|
|
title->setText(tr("No %1 location set").arg(title_text)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
subtitle->setVisible(false); |
|
|
|
|
action->setVisible(false); |
|
|
|
|
|
|
|
|
|
setStyleSheet(styleSheet()); |
|
|
|
|
} |
|
|
|
|