diff --git a/selfdrive/ui/qt/offroad/networking.cc b/selfdrive/ui/qt/offroad/networking.cc index c146345eb4..3794c53011 100644 --- a/selfdrive/ui/qt/offroad/networking.cc +++ b/selfdrive/ui/qt/offroad/networking.cc @@ -2,14 +2,11 @@ #include -#include #include -#include -#include #include +#include #include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/qt_window.h" #include "selfdrive/ui/qt/widgets/controls.h" #include "selfdrive/ui/qt/widgets/prime.h" @@ -211,7 +208,7 @@ void AdvancedNetworking::toggleTethering(bool enabled) { // WifiUI functions WifiUI::WifiUI(QWidget *parent, WifiManager* wifi) : QWidget(parent), wifi(wifi) { - main_layout = new QVBoxLayout(this); + QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); main_layout->setSpacing(0); @@ -228,8 +225,9 @@ WifiUI::WifiUI(QWidget *parent, WifiManager* wifi) : QWidget(parent), wifi(wifi) scanningLabel->setStyleSheet("font-size: 65px;"); main_layout->addWidget(scanningLabel, 0, Qt::AlignCenter); - list_layout = new QVBoxLayout; - main_layout->addLayout(list_layout); + wifi_list_widget = new ListWidget(this); + wifi_list_widget->setVisible(false); + main_layout->addWidget(wifi_list_widget); setStyleSheet(R"( QScrollBar::handle:vertical { @@ -279,76 +277,88 @@ WifiUI::WifiUI(QWidget *parent, WifiManager* wifi) : QWidget(parent), wifi(wifi) } void WifiUI::refresh() { - // TODO: don't rebuild this every time - clearLayout(list_layout); - bool is_empty = wifi->seenNetworks.isEmpty(); scanningLabel->setVisible(is_empty); + wifi_list_widget->setVisible(!is_empty); if (is_empty) return; + setUpdatesEnabled(false); + const bool is_tethering_enabled = wifi->isTetheringEnabled(); QList sortedNetworks = wifi->seenNetworks.values(); std::sort(sortedNetworks.begin(), sortedNetworks.end(), compare_by_strength); - // add networks - ListWidget *list = new ListWidget(this); + int n = 0; for (Network &network : sortedNetworks) { - QHBoxLayout *hlayout = new QHBoxLayout; - hlayout->setContentsMargins(44, 0, 73, 0); - hlayout->setSpacing(50); - - // Clickable SSID label - ElidedLabel *ssidLabel = new ElidedLabel(network.ssid); - ssidLabel->setObjectName("ssidLabel"); - ssidLabel->setEnabled(network.security_type != SecurityType::UNSUPPORTED); - ssidLabel->setProperty("disconnected", network.connected == ConnectedType::DISCONNECTED); - if (network.connected == ConnectedType::DISCONNECTED) { - QObject::connect(ssidLabel, &ElidedLabel::clicked, this, [=]() { emit connectToNetwork(network); }); - } - hlayout->addWidget(ssidLabel, network.connected == ConnectedType::CONNECTING ? 0 : 1); - - if (network.connected == ConnectedType::CONNECTING) { - QPushButton *connecting = new QPushButton(tr("CONNECTING...")); - connecting->setObjectName("connecting"); - hlayout->addWidget(connecting, 2, Qt::AlignLeft); - } - - // Forget button - if (wifi->isKnownConnection(network.ssid) && !is_tethering_enabled) { - QPushButton *forgetBtn = new QPushButton(tr("FORGET")); - forgetBtn->setObjectName("forgetBtn"); - QObject::connect(forgetBtn, &QPushButton::clicked, [=]() { - if (ConfirmationDialog::confirm(tr("Forget Wi-Fi Network \"%1\"?").arg(QString::fromUtf8(network.ssid)), tr("Forget"), this)) { - wifi->forgetConnection(network.ssid); - } - }); - hlayout->addWidget(forgetBtn, 0, Qt::AlignRight); - } - - // Status icon + QPixmap status_icon; if (network.connected == ConnectedType::CONNECTED) { - QLabel *connectIcon = new QLabel(); - connectIcon->setPixmap(checkmark); - hlayout->addWidget(connectIcon, 0, Qt::AlignRight); + status_icon = checkmark; } else if (network.security_type == SecurityType::UNSUPPORTED) { - QLabel *unsupportedIcon = new QLabel(); - unsupportedIcon->setPixmap(circled_slash); - hlayout->addWidget(unsupportedIcon, 0, Qt::AlignRight); + status_icon = circled_slash; } else if (network.security_type == SecurityType::WPA) { - QLabel *lockIcon = new QLabel(); - lockIcon->setPixmap(lock); - hlayout->addWidget(lockIcon, 0, Qt::AlignRight); - } else { - hlayout->addSpacing(lock.width() + hlayout->spacing()); + status_icon = lock; } + bool show_forget_btn = wifi->isKnownConnection(network.ssid) && !is_tethering_enabled; + QPixmap strength = strengths[std::clamp((int)round(network.strength / 33.), 0, 3)]; - // Strength indicator - QLabel *strength = new QLabel(); - strength->setPixmap(strengths[std::clamp((int)round(network.strength / 33.), 0, 3)]); - hlayout->addWidget(strength, 0, Qt::AlignRight); + auto item = getItem(n++); + item->setItem(network, status_icon, show_forget_btn, strength); + item->setVisible(true); + } + for (; n < wifi_items.size(); ++n) wifi_items[n]->setVisible(false); - list->addItem(hlayout); + setUpdatesEnabled(true); +} + +WifiItem *WifiUI::getItem(int n) { + auto item = n < wifi_items.size() ? wifi_items[n] : wifi_items.emplace_back(new WifiItem(tr("CONNECTING..."), tr("FORGET"))); + if (!item->parentWidget()) { + QObject::connect(item, &WifiItem::connectToNetwork, this, &WifiUI::connectToNetwork); + QObject::connect(item, &WifiItem::forgotNetwork, [this](const Network &n) { + if (ConfirmationDialog::confirm(tr("Forget Wi-Fi Network \"%1\"?").arg(QString::fromUtf8(n.ssid)), tr("Forget"), this)) + wifi->forgetConnection(n.ssid); + }); + wifi_list_widget->addItem(item); } - list_layout->addWidget(list); - list_layout->addStretch(1); + return item; +} + +// WifiItem + +WifiItem::WifiItem(const QString &connecting_text, const QString &forget_text, QWidget *parent) : QWidget(parent) { + QHBoxLayout *hlayout = new QHBoxLayout(this); + hlayout->setContentsMargins(44, 0, 73, 0); + hlayout->setSpacing(50); + + hlayout->addWidget(ssidLabel = new ElidedLabel()); + ssidLabel->setObjectName("ssidLabel"); + ssidLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + hlayout->addWidget(connecting = new QPushButton(connecting_text), 0, Qt::AlignRight); + connecting->setObjectName("connecting"); + hlayout->addWidget(forgetBtn = new QPushButton(forget_text), 0, Qt::AlignRight); + forgetBtn->setObjectName("forgetBtn"); + hlayout->addWidget(iconLabel = new QLabel(), 0, Qt::AlignRight); + hlayout->addWidget(strengthLabel = new QLabel(), 0, Qt::AlignRight); + + QObject::connect(forgetBtn, &QPushButton::clicked, [this]() { emit forgotNetwork(network); }); + QObject::connect(ssidLabel, &ElidedLabel::clicked, [this]() { + if (network.connected == ConnectedType::DISCONNECTED) emit connectToNetwork(network); + }); +} + +void WifiItem::setItem(const Network &n, const QPixmap &status_icon, bool show_forget_btn, const QPixmap &strength_icon) { + network = n; + + ssidLabel->setText(n.ssid); + ssidLabel->setEnabled(n.security_type != SecurityType::UNSUPPORTED); + ssidLabel->setProperty("disconnected", network.connected == ConnectedType::DISCONNECTED); + ssidLabel->style()->unpolish(ssidLabel); + ssidLabel->style()->polish(ssidLabel); + ssidLabel->update(); + + connecting->setVisible(n.connected == ConnectedType::CONNECTING); + forgetBtn->setVisible(show_forget_btn); + + iconLabel->setPixmap(status_icon); + strengthLabel->setPixmap(strength_icon); } diff --git a/selfdrive/ui/qt/offroad/networking.h b/selfdrive/ui/qt/offroad/networking.h index 79cbcc3493..7078bf9693 100644 --- a/selfdrive/ui/qt/offroad/networking.h +++ b/selfdrive/ui/qt/offroad/networking.h @@ -1,14 +1,29 @@ #pragma once -#include -#include -#include - #include "selfdrive/ui/qt/offroad/wifiManager.h" #include "selfdrive/ui/qt/widgets/input.h" #include "selfdrive/ui/qt/widgets/ssh_keys.h" #include "selfdrive/ui/qt/widgets/toggle.h" +class WifiItem : public QWidget { + Q_OBJECT +public: + explicit WifiItem(const QString &connecting_text, const QString &forget_text, QWidget* parent = nullptr); + void setItem(const Network& n, const QPixmap &icon, bool show_forget_btn, const QPixmap &strength); + +signals: + void connectToNetwork(const Network &n); + void forgotNetwork(const Network &n); + +protected: + ElidedLabel* ssidLabel; + QPushButton* connecting; + QPushButton* forgetBtn; + QLabel* iconLabel; + QLabel* strengthLabel; + Network network; +}; + class WifiUI : public QWidget { Q_OBJECT @@ -16,14 +31,16 @@ public: explicit WifiUI(QWidget *parent = 0, WifiManager* wifi = 0); private: + WifiItem *getItem(int n); + WifiManager *wifi = nullptr; - QVBoxLayout *list_layout = nullptr; QLabel *scanningLabel = nullptr; - QVBoxLayout* main_layout; QPixmap lock; QPixmap checkmark; QPixmap circled_slash; QVector strengths; + ListWidget *wifi_list_widget = nullptr; + std::vector wifi_items; signals: void connectToNetwork(const Network &n); @@ -65,10 +82,8 @@ private: QStackedLayout* main_layout = nullptr; QWidget* wifiScreen = nullptr; AdvancedNetworking* an = nullptr; - WifiUI* wifiWidget; -protected: void showEvent(QShowEvent* event) override; void hideEvent(QHideEvent* event) override; diff --git a/selfdrive/ui/qt/util.cc b/selfdrive/ui/qt/util.cc index a2926548ed..3804aacd78 100644 --- a/selfdrive/ui/qt/util.cc +++ b/selfdrive/ui/qt/util.cc @@ -51,19 +51,6 @@ QMap getSupportedLanguages() { return map; } -void clearLayout(QLayout* layout) { - while (layout->count() > 0) { - QLayoutItem* item = layout->takeAt(0); - if (QWidget* widget = item->widget()) { - widget->deleteLater(); - } - if (QLayout* childLayout = item->layout()) { - clearLayout(childLayout); - } - delete item; - } -} - QString timeAgo(const QDateTime &date) { int diff = date.secsTo(QDateTime::currentDateTimeUtc()); diff --git a/selfdrive/ui/qt/util.h b/selfdrive/ui/qt/util.h index 68c7bd2712..2b1200a861 100644 --- a/selfdrive/ui/qt/util.h +++ b/selfdrive/ui/qt/util.h @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -18,7 +17,6 @@ QString getBrand(); QString getUserAgent(); std::optional getDongleId(); QMap getSupportedLanguages(); -void clearLayout(QLayout* layout); void setQtSurfaceFormat(); void sigTermHandler(int s); QString timeAgo(const QDateTime &date); diff --git a/tools/cabana/streams/pandastream.cc b/tools/cabana/streams/pandastream.cc index 275ed84f43..e19b2450bd 100644 --- a/tools/cabana/streams/pandastream.cc +++ b/tools/cabana/streams/pandastream.cc @@ -7,6 +7,20 @@ #include "selfdrive/ui/qt/util.h" +// TODO: remove clearLayout +static void clearLayout(QLayout* layout) { + while (layout->count() > 0) { + QLayoutItem* item = layout->takeAt(0); + if (QWidget* widget = item->widget()) { + widget->deleteLater(); + } + if (QLayout* childLayout = item->layout()) { + clearLayout(childLayout); + } + delete item; + } +} + PandaStream::PandaStream(QObject *parent, PandaStreamConfig config_) : config(config_), LiveStream(parent) { if (config.serial.isEmpty()) { auto serials = Panda::list();