mirror of
https://github.com/dragonpilot/dragonpilot.git
synced 2026-06-27 00:42:05 +08:00
Cabana: make all panels dockable into each other (#26838)
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "tools/cabana/chartswidget.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCompleter>
|
||||
#include <QLineEdit>
|
||||
#include <QFutureSynchronizer>
|
||||
@@ -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);
|
||||
|
||||
+46
-54
@@ -1,19 +1,16 @@
|
||||
#include "tools/cabana/mainwin.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QCompleter>
|
||||
#include <QDesktopWidget>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
#include <QMessageBox>
|
||||
#include <QShortcut>
|
||||
#include <QScreen>
|
||||
#include <QToolBar>
|
||||
#include <QUndoView>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidgetAction>
|
||||
@@ -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>("uint64_t");
|
||||
qRegisterMetaType<ReplyMsgType>("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);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDockWidget>
|
||||
#include <QJsonDocument>
|
||||
#include <QMainWindow>
|
||||
#include <QProgressBar>
|
||||
#include <QSplitter>
|
||||
#include <QStatusBar>
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)); });
|
||||
|
||||
@@ -35,7 +35,7 @@ private:
|
||||
QSize thumbnail_size = {};
|
||||
};
|
||||
|
||||
class VideoWidget : public QWidget {
|
||||
class VideoWidget : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user