diff --git a/tools/cabana/chart/chart.cc b/tools/cabana/chart/chart.cc
index 7a056c767..28d4e068e 100644
--- a/tools/cabana/chart/chart.cc
+++ b/tools/cabana/chart/chart.cc
@@ -421,13 +421,6 @@ qreal ChartView::niceNumber(qreal x, bool ceiling) {
return q * z;
}
-void ChartView::leaveEvent(QEvent *event) {
- if (tip_label->isVisible()) {
- charts_widget->showValueTip(-1);
- }
- QChartView::leaveEvent(event);
-}
-
QPixmap getBlankShadowPixmap(const QPixmap &px, int radius) {
QGraphicsDropShadowEffect *e = new QGraphicsDropShadowEffect;
e->setColor(QColor(40, 40, 40, 245));
@@ -546,7 +539,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) {
bool is_zooming = rubber && rubber->isVisible();
clearTrackPoints();
- if (!is_zooming && plot_area.contains(ev->pos())) {
+ if (!is_zooming && plot_area.contains(ev->pos()) && isActiveWindow()) {
const double sec = chart()->mapToValue(ev->pos()).x();
charts_widget->showValueTip(sec);
} else if (tip_label->isVisible()) {
diff --git a/tools/cabana/chart/chart.h b/tools/cabana/chart/chart.h
index d690a14d1..1bfec6355 100644
--- a/tools/cabana/chart/chart.h
+++ b/tools/cabana/chart/chart.h
@@ -76,7 +76,6 @@ private:
void dragLeaveEvent(QDragLeaveEvent *event) override { drawDropIndicator(false); }
void dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override;
- void leaveEvent(QEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
QSize sizeHint() const override;
void updateAxisY();
diff --git a/tools/cabana/chart/chartswidget.cc b/tools/cabana/chart/chartswidget.cc
index 59c188afb..9822eaa30 100644
--- a/tools/cabana/chart/chartswidget.cc
+++ b/tools/cabana/chart/chartswidget.cc
@@ -116,13 +116,12 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) {
QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) {
if (index != -1) updateLayout(true);
});
- QObject::connect(dock_btn, &QToolButton::clicked, [this]() {
- emit dock(!docking);
- docking = !docking;
- updateToolBar();
- });
+ QObject::connect(dock_btn, &QToolButton::clicked, this, &ChartsWidget::toggleChartsDocking);
+ setIsDocked(true);
newTab();
+ qApp->installEventFilter(this);
+
setWhatsThis(tr(R"(
Chart view
@@ -177,8 +176,11 @@ QRect ChartsWidget::chartVisibleRect(ChartView *chart) {
}
void ChartsWidget::showValueTip(double sec) {
+ if (sec < 0 && !value_tip_visible_) return;
+
+ value_tip_visible_ = sec >= 0;
for (auto c : currentCharts()) {
- sec >= 0 ? c->showTip(sec) : c->hideTip();
+ value_tip_visible_ ? c->showTip(sec) : c->hideTip();
}
}
@@ -209,6 +211,12 @@ void ChartsWidget::setMaxChartRange(int value) {
updateState();
}
+void ChartsWidget::setIsDocked(bool docked) {
+ is_docked = docked;
+ dock_btn->setIcon(is_docked ? "arrow-up-right-square" : "arrow-down-left-square");
+ dock_btn->setToolTip(is_docked ? tr("Float the charts window") : tr("Dock the charts window"));
+}
+
void ChartsWidget::updateToolBar() {
title_label->setText(tr("Charts: %1").arg(charts.size()));
columns_action->setText(tr("Column: %1").arg(column_count));
@@ -222,8 +230,6 @@ void ChartsWidget::updateToolBar() {
reset_zoom_action->setVisible(is_zoomed);
reset_zoom_btn->setText(is_zoomed ? tr("%1-%2").arg(can->timeRange()->first, 0, 'f', 2).arg(can->timeRange()->second, 0, 'f', 2) : "");
remove_all_btn->setEnabled(!charts.isEmpty());
- dock_btn->setIcon(docking ? "arrow-up-right-square" : "arrow-down-left-square");
- dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts"));
}
void ChartsWidget::settingChanged() {
@@ -375,11 +381,6 @@ QSize ChartsWidget::minimumSizeHint() const {
return QSize(CHART_MIN_WIDTH, QWidget::minimumSizeHint().height());
}
-void ChartsWidget::resizeEvent(QResizeEvent *event) {
- QWidget::resizeEvent(event);
- updateLayout();
-}
-
void ChartsWidget::newChart() {
SignalSelector dlg(tr("New Chart"), this);
if (dlg.exec() == QDialog::Accepted) {
@@ -432,10 +433,16 @@ void ChartsWidget::alignCharts() {
}
}
-bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) {
- if (obj != this && event->type() == QEvent::Close) {
- emit dock_btn->clicked();
- return true;
+bool ChartsWidget::eventFilter(QObject *o, QEvent *e) {
+ if (value_tip_visible_ && e->type() == QEvent::MouseMove) {
+ auto pos = static_cast(e)->globalPos();
+ bool outside_plot_area =std::none_of(charts.begin(), charts.end(), [&pos](auto c) {
+ return c->chart()->plotArea().contains(c->mapFromGlobal(pos));
+ });
+
+ if (outside_plot_area) {
+ showValueTip(-1);
+ }
}
return false;
}
@@ -443,30 +450,25 @@ bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) {
bool ChartsWidget::event(QEvent *event) {
bool back_button = false;
switch (event->type()) {
- case QEvent::MouseButtonPress: {
- QMouseEvent *ev = static_cast(event);
- back_button = ev->button() == Qt::BackButton;
+ case QEvent::Resize:
+ updateLayout();
break;
- }
- case QEvent::NativeGesture: {
- QNativeGestureEvent *ev = static_cast(event);
- back_button = (ev->value() == 180);
+ case QEvent::MouseButtonPress:
+ back_button = static_cast(event)->button() == Qt::BackButton;
+ break;
+ case QEvent::NativeGesture:
+ back_button = (static_cast(event)->value() == 180);
break;
- }
- case QEvent::WindowActivate:
case QEvent::WindowDeactivate:
- case QEvent::FocusIn:
case QEvent::FocusOut:
- case QEvent::Leave:
showValueTip(-1);
- break;
default:
break;
}
if (back_button) {
zoom_undo_stack->undo();
- return true;
+ return true; // Return true since the event has been handled
}
return QFrame::event(event);
}
diff --git a/tools/cabana/chart/chartswidget.h b/tools/cabana/chart/chartswidget.h
index a9ac05db2..0b948b342 100644
--- a/tools/cabana/chart/chartswidget.h
+++ b/tools/cabana/chart/chartswidget.h
@@ -47,14 +47,14 @@ public slots:
void setColumnCount(int n);
void removeAll();
void timeRangeChanged(const std::optional> &time_range);
+ void setIsDocked(bool dock);
signals:
- void dock(bool floating);
+ void toggleChartsDocking();
void seriesChanged();
private:
QSize minimumSizeHint() const override;
- void resizeEvent(QResizeEvent *event) override;
bool event(QEvent *event) override;
void alignCharts();
void newChart();
@@ -85,7 +85,7 @@ private:
LogSlider *range_slider;
QAction *range_lb_action;
QAction *range_slider_action;
- bool docking = true;
+ bool is_docked = true;
ToolButton *dock_btn;
QAction *undo_zoom_action;
@@ -109,6 +109,7 @@ private:
QTimer *auto_scroll_timer;
QTimer *align_timer;
int current_theme = 0;
+ bool value_tip_visible_ = false;
friend class ZoomCommand;
friend class ChartView;
friend class ChartsContainer;
diff --git a/tools/cabana/chart/tiplabel.cc b/tools/cabana/chart/tiplabel.cc
index f5c9cc9cb..be7160283 100644
--- a/tools/cabana/chart/tiplabel.cc
+++ b/tools/cabana/chart/tiplabel.cc
@@ -9,8 +9,12 @@
#include "tools/cabana/settings.h"
TipLabel::TipLabel(QWidget *parent) : QLabel(parent, Qt::ToolTip | Qt::FramelessWindowHint) {
+ setAttribute(Qt::WA_ShowWithoutActivating);
+ setAttribute(Qt::WA_TransparentForMouseEvents);
+
setForegroundRole(QPalette::ToolTipText);
setBackgroundRole(QPalette::ToolTipBase);
+
QFont font;
font.setPointSizeF(8.34563465);
setFont(font);
@@ -22,9 +26,7 @@ TipLabel::TipLabel(QWidget *parent) : QLabel(parent, Qt::ToolTip | Qt::Frameless
setPalette(palette);
ensurePolished();
setMargin(1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, nullptr, this));
- setAttribute(Qt::WA_ShowWithoutActivating);
setTextFormat(Qt::RichText);
- setVisible(false);
}
void TipLabel::showText(const QPoint &pt, const QString &text, QWidget *w, const QRect &rect) {
diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc
index d099fcec9..bf1db63ee 100644
--- a/tools/cabana/mainwin.cc
+++ b/tools/cabana/mainwin.cc
@@ -198,7 +198,7 @@ void MainWindow::createDockWidgets() {
video_splitter->restoreState(settings.video_splitter_state);
video_splitter->handle(1)->setEnabled(!can->liveStreaming());
video_dock->setWidget(video_splitter);
- QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts);
+ QObject::connect(charts_widget, &ChartsWidget::toggleChartsDocking, this, &MainWindow::toggleChartsDocking);
}
void MainWindow::createStatusBar() {
@@ -577,20 +577,31 @@ void MainWindow::updateStatus() {
status_label->setText(tr("Cached Minutes:%1 FPS:%2").arg(settings.max_cached_minutes).arg(settings.fps));
}
-void MainWindow::dockCharts(bool dock) {
- if (dock && floating_window) {
- floating_window->removeEventFilter(charts_widget);
+bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
+ if (obj == floating_window && event->type() == QEvent::Close) {
+ toggleChartsDocking();
+ return true;
+ }
+ return QMainWindow::eventFilter(obj, event);
+}
+
+void MainWindow::toggleChartsDocking() {
+ if (floating_window) {
+ // Dock the charts widget back to the main window
+ floating_window->removeEventFilter(this);
charts_layout->insertWidget(0, charts_widget, 1);
floating_window->deleteLater();
floating_window = nullptr;
- } else if (!dock && !floating_window) {
- floating_window = new QWidget(this);
- floating_window->setWindowFlags(Qt::Window);
+ charts_widget->setIsDocked(true);
+ } else {
+ // Float the charts widget in a separate window
+ floating_window = new QWidget(this, Qt::Window);
floating_window->setWindowTitle("Charts");
floating_window->setLayout(new QVBoxLayout());
floating_window->layout()->addWidget(charts_widget);
- floating_window->installEventFilter(charts_widget);
+ floating_window->installEventFilter(this);
floating_window->showMaximized();
+ charts_widget->setIsDocked(false);
}
}
diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h
index 0b869f153..77add4d78 100644
--- a/tools/cabana/mainwin.h
+++ b/tools/cabana/mainwin.h
@@ -21,7 +21,7 @@ class MainWindow : public QMainWindow {
public:
MainWindow();
- void dockCharts(bool dock);
+ void toggleChartsDocking();
void showStatusMessage(const QString &msg, int timeout = 0) { statusBar()->showMessage(msg, timeout); }
void loadFile(const QString &fn, SourceSet s = SOURCE_ALL);
ChartsWidget *charts_widget = nullptr;
@@ -46,6 +46,7 @@ signals:
void updateProgressBar(uint64_t cur, uint64_t total, bool success);
protected:
+ bool eventFilter(QObject *obj, QEvent *event) override;
void remindSaveChanges();
void closeFile(SourceSet s = SOURCE_ALL);
void closeFile(DBCFile *dbc_file);