diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 51418e293f..4f037ba595 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -6,6 +6,8 @@ #include "tools/cabana/mainwin.h" int main(int argc, char *argv[]) { + QCoreApplication::setApplicationName("Cabana"); + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); initApp(argc, argv); QApplication app(argc, argv); @@ -36,7 +38,7 @@ int main(int argc, char *argv[]) { int ret = 0; if (p.loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) { MainWindow w; - w.showMaximized(); + w.show(); ret = app.exec(); } return ret; diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index da39fb1a66..71886a113f 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -1,5 +1,6 @@ #include "tools/cabana/chartswidget.h" +#include #include #include #include @@ -42,7 +43,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { main_layout->addWidget(charts_scroll); max_chart_range = settings.max_chart_x_range; - use_dark_theme = palette().color(QPalette::WindowText).value() > palette().color(QPalette::Background).value(); + use_dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > + QApplication::style()->standardPalette().color(QPalette::Background).value(); updateToolBar(); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 4ae53223a8..43aa330029 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -1,19 +1,16 @@ #include "tools/cabana/mainwin.h" #include -#include #include #include +#include #include #include #include -#include #include #include #include #include -#include -#include #include #include #include @@ -25,58 +22,20 @@ void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const } MainWindow::MainWindow() : QMainWindow() { - setWindowTitle("Cabana"); - QWidget *central_widget = new QWidget(this); - QHBoxLayout *main_layout = new QHBoxLayout(central_widget); - main_layout->setContentsMargins(11, 11, 11, 0); - main_layout->setSpacing(0); - - splitter = new QSplitter(Qt::Horizontal, this); - splitter->setHandleWidth(11); - - QWidget *messages_container = new QWidget(this); - QVBoxLayout *messages_layout = new QVBoxLayout(messages_container); - messages_layout->setContentsMargins(0, 0, 0, 0); - - // left panel - dbc_combo = createDBCSelector(); - messages_layout->addWidget(dbc_combo); - messages_widget = new MessagesWidget(this); - messages_layout->addWidget(messages_widget); - splitter->addWidget(messages_container); - - charts_widget = new ChartsWidget(this); + createDockWindows(); detail_widget = new DetailWidget(charts_widget, this); - splitter->addWidget(detail_widget); - if (!settings.splitter_state.isEmpty()) { - splitter->restoreState(settings.splitter_state); - } - main_layout->addWidget(splitter); - - // right widgets - QWidget *right_container = new QWidget(this); - right_container->setFixedWidth(640); - r_layout = new QVBoxLayout(right_container); - r_layout->setContentsMargins(11, 0, 0, 0); - QHBoxLayout *right_hlayout = new QHBoxLayout(); - fingerprint_label = new QLabel(this); - right_hlayout->addWidget(fingerprint_label, 0, Qt::AlignLeft); - - // TODO: click to select another route. - right_hlayout->addWidget(new QLabel(can->routeName()), 0, Qt::AlignRight); - r_layout->addLayout(right_hlayout); - - video_widget = new VideoWidget(this); - r_layout->addWidget(video_widget, 0, Qt::AlignTop); - r_layout->addWidget(charts_widget, 1); - r_layout->addStretch(0); - main_layout->addWidget(right_container); - - setCentralWidget(central_widget); + detail_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + setCentralWidget(detail_widget); createActions(); createStatusBar(); createShortcuts(); + restoreGeometry(settings.geometry); + if (isMaximized()) { + setGeometry(QApplication::desktop()->availableGeometry(this)); + } + restoreState(settings.window_state); + qRegisterMetaType("uint64_t"); qRegisterMetaType("ReplyMsgType"); installMessageHandler([this](ReplyMsgType type, const std::string msg) { @@ -140,6 +99,39 @@ void MainWindow::createActions() { help_menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); } +void MainWindow::createDockWindows() { + // left panel + QWidget *messages_container = new QWidget(this); + QVBoxLayout *messages_layout = new QVBoxLayout(messages_container); + dbc_combo = createDBCSelector(); + messages_layout->addWidget(dbc_combo); + messages_widget = new MessagesWidget(this); + messages_layout->addWidget(messages_widget); + + QDockWidget *dock = new QDockWidget(tr("MESSAGES"), this); + dock->setObjectName("MessagesPanel"); + dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); + dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); + dock->setWidget(messages_container); + addDockWidget(Qt::LeftDockWidgetArea, dock); + + // right panel + QWidget *right_container = new QWidget(this); + r_layout = new QVBoxLayout(right_container); + charts_widget = new ChartsWidget(this); + video_widget = new VideoWidget(this); + r_layout->addWidget(video_widget, 0, Qt::AlignTop); + r_layout->addWidget(charts_widget, 1); + r_layout->addStretch(0); + + video_dock = new QDockWidget(can->routeName(), this); + video_dock->setObjectName(tr("VideoPanel")); + video_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + video_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); + video_dock->setWidget(right_container); + addDockWidget(Qt::RightDockWidgetArea, video_dock); +} + QComboBox *MainWindow::createDBCSelector() { QComboBox *c = new QComboBox(this); c->setEditable(true); @@ -205,7 +197,7 @@ void MainWindow::loadDBCFromClipboard() { void MainWindow::loadDBCFromFingerprint() { auto fingerprint = can->carFingerprint(); - fingerprint_label->setText(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint); + video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); if (!fingerprint.isEmpty()) { auto dbc_name = fingerprint_to_dbc[fingerprint]; if (dbc_name != QJsonValue::Undefined) { @@ -257,7 +249,6 @@ void MainWindow::dockCharts(bool dock) { floating_window->setLayout(new QVBoxLayout()); floating_window->layout()->addWidget(charts_widget); floating_window->installEventFilter(charts_widget); - floating_window->setMinimumSize(QGuiApplication::primaryScreen()->size() / 2); floating_window->showMaximized(); } } @@ -277,7 +268,8 @@ void MainWindow::closeEvent(QCloseEvent *event) { if (floating_window) floating_window->deleteLater(); - settings.splitter_state = splitter->saveState(); + settings.geometry = saveGeometry(); + settings.window_state = saveState(); settings.save(); QWidget::closeEvent(event); } diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 5d3ba470a1..f8b5f92349 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -1,10 +1,10 @@ #pragma once #include +#include #include #include #include -#include #include #include "tools/cabana/chartswidget.h" @@ -35,6 +35,7 @@ signals: protected: void createActions(); + void createDockWindows(); QComboBox *createDBCSelector(); void createStatusBar(); void createShortcuts(); @@ -45,14 +46,13 @@ protected: void findSimilarBits(); VideoWidget *video_widget; + QDockWidget *video_dock; MessagesWidget *messages_widget; DetailWidget *detail_widget; ChartsWidget *charts_widget; - QSplitter *splitter; QWidget *floating_window = nullptr; QVBoxLayout *r_layout; QProgressBar *progress_bar; - QLabel *fingerprint_label; QJsonDocument fingerprint_to_dbc; QComboBox *dbc_combo; }; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 63e26f3808..5e7f833317 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -19,7 +19,8 @@ void Settings::save() { s.setValue("chart_height", chart_height); s.setValue("max_chart_x_range", max_chart_x_range); s.setValue("last_dir", last_dir); - s.setValue("splitter_state", splitter_state); + s.setValue("window_state", window_state); + s.setValue("geometry", geometry); } void Settings::load() { @@ -29,7 +30,8 @@ void Settings::load() { chart_height = s.value("chart_height", 200).toInt(); max_chart_x_range = s.value("max_chart_x_range", 3 * 60).toInt(); last_dir = s.value("last_dir", QDir::homePath()).toString(); - splitter_state = s.value("splitter_state").toByteArray(); + window_state = s.value("window_state").toByteArray(); + geometry = s.value("geometry").toByteArray(); } // SettingsDlg diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index 1db92fe231..d231a3a53a 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -18,7 +18,7 @@ public: int chart_height = 200; int max_chart_x_range = 3 * 60; // 3 minutes QString last_dir; - QByteArray splitter_state; + QByteArray window_state, geometry; signals: void changed(); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 6cd173b514..7e40ba2adb 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -17,10 +17,17 @@ inline QString formatTime(int seconds) { return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); } -VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); +VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { + setFrameShape(QFrame::StyledPanel); + setFrameShadow(QFrame::Sunken); + QHBoxLayout *containter_layout = new QHBoxLayout(this); + QVBoxLayout *main_layout = new QVBoxLayout(); main_layout->setContentsMargins(0, 0, 0, 0); + containter_layout->addStretch(1); + containter_layout->addLayout(main_layout); + containter_layout->addStretch(1); + cam_widget = new CameraWidget("camerad", can->visionStreamType(), false, this); cam_widget->setFixedSize(parent->width(), parent->width() / 1.596); main_layout->addWidget(cam_widget); @@ -56,8 +63,6 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { } main_layout->addLayout(control_layout); - setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - QObject::connect(can, &CANMessages::updated, this, &VideoWidget::updateState); QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->value() / 1000.0); }); QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(formatTime(value / 1000)); }); diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index ea62081a91..86cdc6f114 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -35,7 +35,7 @@ private: QSize thumbnail_size = {}; }; -class VideoWidget : public QWidget { +class VideoWidget : public QFrame { Q_OBJECT public: