cabana: use bootstrap icons (#26981)

* use bootstrap icons

* typo

* build into asset_obj

* add to files_common
old-commit-hash: c21d9408a1
beeps
Dean Lee 2 years ago committed by GitHub
parent 215526119d
commit fa47048e44
  1. 2
      SConstruct
  2. 1
      release/files_common
  3. 1
      selfdrive/assets/assets.qrc
  4. 1
      selfdrive/ui/SConscript
  5. 37
      selfdrive/ui/qt/util.cc
  6. 1
      selfdrive/ui/qt/util.h
  7. 4
      tools/cabana/SConscript
  8. 13
      tools/cabana/chartswidget.cc
  9. 5
      tools/cabana/detailwidget.cc
  10. 6
      tools/cabana/signaledit.cc
  11. 15
      tools/cabana/videowidget.cc
  12. 1
      tools/cabana/videowidget.h

@ -282,7 +282,7 @@ Export('envCython')
# Qt build environment # Qt build environment
qt_env = env.Clone() qt_env = env.Clone()
qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "Multimedia", "Quick", "Qml", "QuickWidgets", "Location", "Positioning", "DBus"] qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "Multimedia", "Quick", "Qml", "QuickWidgets", "Location", "Positioning", "DBus", "Xml"]
qt_libs = [] qt_libs = []
if arch == "Darwin": if arch == "Darwin":

@ -436,6 +436,7 @@ third_party/acados/larch64/**
third_party/acados/include/** third_party/acados/include/**
third_party/acados/acados_template/** third_party/acados/acados_template/**
third_party/bootstrap/**
third_party/qt5/larch64/bin/** third_party/qt5/larch64/bin/**
scripts/update_now.sh scripts/update_now.sh

@ -1,5 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0"> <!DOCTYPE RCC><RCC version="1.0">
<qresource> <qresource>
<file alias="bootstrap-icons.svg">../../third_party/bootstrap/bootstrap-icons.svg</file>
<file>img_continue_triangle.svg</file> <file>img_continue_triangle.svg</file>
<file>img_circled_check.svg</file> <file>img_circled_check.svg</file>
<file>img_circled_slash.svg</file> <file>img_circled_slash.svg</file>

@ -41,6 +41,7 @@ assets_src = "#selfdrive/assets/assets.qrc"
qt_env.Command(assets, assets_src, f"rcc $SOURCES -o $TARGET") qt_env.Command(assets, assets_src, f"rcc $SOURCES -o $TARGET")
qt_env.Depends(assets, Glob('#selfdrive/assets/*', exclude=[assets, assets_src, "#selfdrive/assets/assets.o"])) qt_env.Depends(assets, Glob('#selfdrive/assets/*', exclude=[assets, assets_src, "#selfdrive/assets/assets.o"]))
asset_obj = qt_env.Object("assets", assets) asset_obj = qt_env.Object("assets", assets)
Export('asset_obj')
# build soundd # build soundd
qt_env.Program("soundd/_soundd", ["soundd/main.cc", "soundd/sound.cc"], LIBS=qt_libs) qt_env.Program("soundd/_soundd", ["soundd/main.cc", "soundd/sound.cc"], LIBS=qt_libs)

@ -2,11 +2,14 @@
#include <QApplication> #include <QApplication>
#include <QFile> #include <QFile>
#include <QHash>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QLayoutItem> #include <QLayoutItem>
#include <QStyleOption> #include <QStyleOption>
#include <QPainterPath> #include <QPainterPath>
#include <QTextStream>
#include <QtXml/QDomDocument>
#include "common/params.h" #include "common/params.h"
#include "common/swaglog.h" #include "common/swaglog.h"
@ -218,3 +221,37 @@ QColor interpColor(float xv, std::vector<float> xp, std::vector<QColor> fp) {
); );
} }
} }
static QHash<QString, QByteArray> load_bootstrap_icons() {
QHash<QString, QByteArray> icons;
QFile f(":/bootstrap-icons.svg");
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
QDomDocument xml;
xml.setContent(&f);
QDomNode n = xml.documentElement().firstChild();
while (!n.isNull()) {
QDomElement e = n.toElement();
if (!e.isNull() && e.hasAttribute("id")) {
QString svg_str;
QTextStream stream(&svg_str);
n.save(stream, 0);
svg_str.replace("<symbol", "<svg");
svg_str.replace("</symbol>", "</svg>");
icons[e.attribute("id")] = svg_str.toUtf8();
}
n = n.nextSibling();
}
}
return icons;
}
QPixmap bootstrapPixmap(const QString &id) {
static QHash<QString, QByteArray> icons = load_bootstrap_icons();
QPixmap pixmap;
if (auto it = icons.find(id); it != icons.end()) {
pixmap.loadFromData(it.value(), "svg");
}
return pixmap;
}

@ -22,6 +22,7 @@ void swagLogMessageHandler(QtMsgType type, const QMessageLogContext &context, co
void initApp(int argc, char *argv[]); void initApp(int argc, char *argv[]);
QWidget* topWidget (QWidget* widget); QWidget* topWidget (QWidget* widget);
QPixmap loadPixmap(const QString &fileName, const QSize &size = {}, Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio); QPixmap loadPixmap(const QString &fileName, const QSize &size = {}, Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio);
QPixmap bootstrapPixmap(const QString &id);
QRect getTextRect(QPainter &p, int flags, const QString &text); QRect getTextRect(QPainter &p, int flags, const QString &text);
void drawRoundedRect(QPainter &painter, const QRectF &rect, qreal xRadiusTop, qreal yRadiusTop, qreal xRadiusBottom, qreal yRadiusBottom); void drawRoundedRect(QPainter &painter, const QRectF &rect, qreal xRadiusTop, qreal yRadiusTop, qreal xRadiusBottom, qreal yRadiusBottom);

@ -1,6 +1,6 @@
import os import os
Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'replay_lib', Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'replay_lib',
'cereal', 'transformations', 'widgets', 'opendbc') 'cereal', 'transformations', 'widgets', 'opendbc', 'asset_obj')
base_frameworks = qt_env['FRAMEWORKS'] base_frameworks = qt_env['FRAMEWORKS']
base_libs = [common, messaging, cereal, visionipc, transformations, 'zmq', base_libs = [common, messaging, cereal, visionipc, transformations, 'zmq',
@ -22,7 +22,7 @@ prev_moc_path = cabana_env['QT_MOCHPREFIX']
cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_'
cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc',
'canmessages.cc', 'commands.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) 'canmessages.cc', 'commands.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks)
cabana_env.Program('_cabana', ['cabana.cc', cabana_lib], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, asset_obj], LIBS=cabana_libs, FRAMEWORKS=base_frameworks)
if GetOption('test'): if GetOption('test'):
cabana_env.Program('tests/_test_cabana', ['tests/test_runner.cc', 'tests/test_cabana.cc', cabana_lib], LIBS=[cabana_libs]) cabana_env.Program('tests/_test_cabana', ['tests/test_runner.cc', 'tests/test_cabana.cc', cabana_lib], LIBS=[cabana_libs])

@ -12,6 +12,8 @@
#include <QToolTip> #include <QToolTip>
#include <QtConcurrent> #include <QtConcurrent>
#include "selfdrive/ui/qt/util.h"
// ChartsWidget // ChartsWidget
ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) {
@ -19,14 +21,15 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) {
// toolbar // toolbar
QToolBar *toolbar = new QToolBar(tr("Charts"), this); QToolBar *toolbar = new QToolBar(tr("Charts"), this);
toolbar->setIconSize({16, 16});
title_label = new QLabel(); title_label = new QLabel();
title_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); title_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
toolbar->addWidget(title_label); toolbar->addWidget(title_label);
show_all_values_btn = toolbar->addAction(""); show_all_values_btn = toolbar->addAction("");
toolbar->addWidget(range_label = new QLabel()); toolbar->addWidget(range_label = new QLabel());
reset_zoom_btn = toolbar->addAction(""); reset_zoom_btn = toolbar->addAction(bootstrapPixmap("arrow-counterclockwise"), "");
reset_zoom_btn->setToolTip(tr("Reset zoom (drag on chart to zoom X-Axis)")); reset_zoom_btn->setToolTip(tr("Reset zoom (drag on chart to zoom X-Axis)"));
remove_all_btn = toolbar->addAction(""); remove_all_btn = toolbar->addAction(bootstrapPixmap("x"), "");
remove_all_btn->setToolTip(tr("Remove all charts")); remove_all_btn->setToolTip(tr("Remove all charts"));
dock_btn = toolbar->addAction(""); dock_btn = toolbar->addAction("");
main_layout->addWidget(toolbar); main_layout->addWidget(toolbar);
@ -137,7 +140,7 @@ void ChartsWidget::updateToolBar() {
reset_zoom_btn->setEnabled(is_zoomed); reset_zoom_btn->setEnabled(is_zoomed);
range_label->setText(is_zoomed ? tr("%1 - %2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : ""); range_label->setText(is_zoomed ? tr("%1 - %2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : "");
title_label->setText(charts.size() > 0 ? tr("Charts (%1)").arg(charts.size()) : tr("Charts")); title_label->setText(charts.size() > 0 ? tr("Charts (%1)").arg(charts.size()) : tr("Charts"));
dock_btn->setText(docking ? "" : ""); dock_btn->setIcon(bootstrapPixmap(docking ? "arrow-up-right" : "arrow-down-left"));
dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts"));
} }
@ -223,7 +226,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) {
chart->layout()->setContentsMargins(0, 0, 0, 0); chart->layout()->setContentsMargins(0, 0, 0, 0);
QToolButton *remove_btn = new QToolButton(); QToolButton *remove_btn = new QToolButton();
remove_btn->setText("X"); remove_btn->setIcon(bootstrapPixmap("x"));
remove_btn->setAutoRaise(true); remove_btn->setAutoRaise(true);
remove_btn->setToolTip(tr("Remove Chart")); remove_btn->setToolTip(tr("Remove Chart"));
close_btn_proxy = new QGraphicsProxyWidget(chart); close_btn_proxy = new QGraphicsProxyWidget(chart);
@ -231,7 +234,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) {
close_btn_proxy->setZValue(chart->zValue() + 11); close_btn_proxy->setZValue(chart->zValue() + 11);
QToolButton *manage_btn = new QToolButton(); QToolButton *manage_btn = new QToolButton();
manage_btn->setText("🔧"); manage_btn->setIcon(bootstrapPixmap("gear"));
manage_btn->setAutoRaise(true); manage_btn->setAutoRaise(true);
manage_btn->setToolTip(tr("Manage series")); manage_btn->setToolTip(tr("Manage series"));
manage_btn_proxy = new QGraphicsProxyWidget(chart); manage_btn_proxy = new QGraphicsProxyWidget(chart);

@ -36,6 +36,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
// message title // message title
toolbar = new QToolBar(this); toolbar = new QToolBar(this);
toolbar->setIconSize({16, 16});
toolbar->addWidget(new QLabel("time:")); toolbar->addWidget(new QLabel("time:"));
time_label = new QLabel(this); time_label = new QLabel(this);
time_label->setStyleSheet("font-weight:bold"); time_label->setStyleSheet("font-weight:bold");
@ -45,8 +46,8 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
name_label->setAlignment(Qt::AlignCenter); name_label->setAlignment(Qt::AlignCenter);
name_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); name_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
toolbar->addWidget(name_label); toolbar->addWidget(name_label);
toolbar->addAction("🖍", this, &DetailWidget::editMsg)->setToolTip(tr("Edit Message")); toolbar->addAction(bootstrapPixmap("pencil"), "", this, &DetailWidget::editMsg)->setToolTip(tr("Edit Message"));
remove_msg_act = toolbar->addAction("X", this, &DetailWidget::removeMsg); remove_msg_act = toolbar->addAction(bootstrapPixmap("x-lg"), "", this, &DetailWidget::removeMsg);
remove_msg_act->setToolTip(tr("Remove Message")); remove_msg_act->setToolTip(tr("Remove Message"));
toolbar->setVisible(false); toolbar->setVisible(false);
frame_layout->addWidget(toolbar); frame_layout->addWidget(toolbar);

@ -6,6 +6,8 @@
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QVBoxLayout> #include <QVBoxLayout>
#include "selfdrive/ui/qt/util.h"
// SignalForm // SignalForm
SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { SignalForm::SignalForm(QWidget *parent) : QWidget(parent) {
@ -104,13 +106,13 @@ SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(pa
title_layout->addWidget(title); title_layout->addWidget(title);
plot_btn = new QToolButton(this); plot_btn = new QToolButton(this);
plot_btn->setText("📈"); plot_btn->setIcon(bootstrapPixmap("graph-up"));
plot_btn->setCheckable(true); plot_btn->setCheckable(true);
plot_btn->setAutoRaise(true); plot_btn->setAutoRaise(true);
title_layout->addWidget(plot_btn); title_layout->addWidget(plot_btn);
auto remove_btn = new QToolButton(this); auto remove_btn = new QToolButton(this);
remove_btn->setAutoRaise(true); remove_btn->setAutoRaise(true);
remove_btn->setText("x"); remove_btn->setIcon(bootstrapPixmap("x"));
remove_btn->setToolTip(tr("Remove signal")); remove_btn->setToolTip(tr("Remove signal"));
title_layout->addWidget(remove_btn); title_layout->addWidget(remove_btn);
main_layout->addWidget(title_bar); main_layout->addWidget(title_bar);

@ -13,6 +13,8 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QtConcurrent> #include <QtConcurrent>
#include "selfdrive/ui/qt/util.h"
inline QString formatTime(int seconds) { inline QString formatTime(int seconds) {
return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss");
} }
@ -43,8 +45,7 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) {
// btn controls // btn controls
QHBoxLayout *control_layout = new QHBoxLayout(); QHBoxLayout *control_layout = new QHBoxLayout();
play_btn = new QPushButton(""); play_btn = new QPushButton();
play_btn->setStyleSheet("font-weight:bold; height:16px");
control_layout->addWidget(play_btn); control_layout->addWidget(play_btn);
QButtonGroup *group = new QButtonGroup(this); QButtonGroup *group = new QButtonGroup(this);
@ -68,12 +69,13 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) {
QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); });
QObject::connect(play_btn, &QPushButton::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(play_btn, &QPushButton::clicked, []() { can->pause(!can->isPaused()); });
QObject::connect(can, &CANMessages::updated, this, &VideoWidget::updateState); QObject::connect(can, &CANMessages::updated, this, &VideoWidget::updateState);
QObject::connect(can, &CANMessages::paused, [this]() { play_btn->setText(""); }); QObject::connect(can, &CANMessages::paused, this, &VideoWidget::updatePlayBtnState);
QObject::connect(can, &CANMessages::resume, [this]() { play_btn->setText(""); }); QObject::connect(can, &CANMessages::resume, this, &VideoWidget::updatePlayBtnState);
QObject::connect(can, &CANMessages::streamStarted, [this]() { QObject::connect(can, &CANMessages::streamStarted, [this]() {
end_time_label->setText(formatTime(can->totalSeconds())); end_time_label->setText(formatTime(can->totalSeconds()));
slider->setRange(0, can->totalSeconds() * 1000); slider->setRange(0, can->totalSeconds() * 1000);
}); });
updatePlayBtnState();
} }
void VideoWidget::rangeChanged(double min, double max, bool is_zoomed) { void VideoWidget::rangeChanged(double min, double max, bool is_zoomed) {
@ -90,6 +92,11 @@ void VideoWidget::updateState() {
slider->setValue(can->currentSec() * 1000); slider->setValue(can->currentSec() * 1000);
} }
void VideoWidget::updatePlayBtnState() {
play_btn->setIcon(bootstrapPixmap(can->isPaused() ? "play" : "pause"));
play_btn->setToolTip(can->isPaused() ? tr("Play") : tr("Pause"));
}
// Slider // Slider
Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) { Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) {
QTimer *timer = new QTimer(this); QTimer *timer = new QTimer(this);

@ -44,6 +44,7 @@ public:
protected: protected:
void updateState(); void updateState();
void updatePlayBtnState();
CameraWidget *cam_widget; CameraWidget *cam_widget;
QLabel *end_time_label; QLabel *end_time_label;

Loading…
Cancel
Save