cabana: support undo/redo zoom (#27799)

* support updo/redo zoom

* cleanup eventsMerged

* init axis_x when create chart

* update tool bar after create chart

* align charts after updatelayout
pull/27807/head
Dean Lee 2 years ago committed by GitHub
parent ec39d0515d
commit c5f5a3b5f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 62
      tools/cabana/chartswidget.cc
  2. 26
      tools/cabana/chartswidget.h

@ -57,10 +57,16 @@ ChartsWidget::ChartsWidget(QWidget *parent) : align_timer(this), QFrame(parent)
range_slider->setPageStep(60); // 1 min
range_slider_action = toolbar->addWidget(range_slider);
undo_zoom_action = toolbar->addAction(utils::icon("arrow-counterclockwise"), tr("Previous zoom"));
qobject_cast<QToolButton*>(toolbar->widgetForAction(undo_zoom_action))->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
reset_zoom_action = toolbar->addAction(utils::icon("zoom-out"), tr("Reset Zoom"));
// zoom controls
zoom_undo_stack = new QUndoStack(this);
undo_zoom_action = zoom_undo_stack->createUndoAction(this);
undo_zoom_action->setIcon(utils::icon("arrow-counterclockwise"));
toolbar->addAction(undo_zoom_action);
redo_zoom_action = zoom_undo_stack->createRedoAction(this);
redo_zoom_action->setIcon(utils::icon("arrow-clockwise"));
toolbar->addAction(redo_zoom_action);
reset_zoom_action = toolbar->addAction(utils::icon("zoom-out"), "");
reset_zoom_action->setToolTip(tr("Reset zoom"));
qobject_cast<QToolButton*>(toolbar->widgetForAction(reset_zoom_action))->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
remove_all_btn = toolbar->addAction(utils::icon("x"), tr("Remove all charts"));
@ -99,7 +105,6 @@ ChartsWidget::ChartsWidget(QWidget *parent) : align_timer(this), QFrame(parent)
QObject::connect(range_slider, &QSlider::valueChanged, this, &ChartsWidget::setMaxChartRange);
QObject::connect(new_plot_btn, &QAction::triggered, this, &ChartsWidget::newChart);
QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll);
QObject::connect(undo_zoom_action, &QAction::triggered, this, &ChartsWidget::zoomUndo);
QObject::connect(reset_zoom_action, &QAction::triggered, this, &ChartsWidget::zoomReset);
QObject::connect(&settings, &Settings::changed, this, &ChartsWidget::settingChanged);
QObject::connect(dock_btn, &QAction::triggered, [this]() {
@ -115,14 +120,9 @@ ChartsWidget::ChartsWidget(QWidget *parent) : align_timer(this), QFrame(parent)
}
void ChartsWidget::eventsMerged() {
{
QFutureSynchronizer<void> future_synchronizer;
for (auto c : charts) {
future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::updateSeries, nullptr));
}
}
if (can->isPaused()) {
updateState();
QFutureSynchronizer<void> future_synchronizer;
for (auto c : charts) {
future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::updateSeries, nullptr));
}
}
@ -135,25 +135,12 @@ void ChartsWidget::setZoom(double min, double max) {
}
void ChartsWidget::zoomIn(double min, double max) {
// Save previous zoom on undo stack
if (is_zoomed) {
zoom_stack.push({zoomed_range.first, zoomed_range.second});
}
setZoom(min, max);
zoom_undo_stack->push(new ZoomCommand(this, {min, max}));
}
void ChartsWidget::zoomReset() {
setZoom(display_range.first, display_range.second);
zoom_stack.clear();
}
void ChartsWidget::zoomUndo() {
if (!zoom_stack.isEmpty()) {
auto r = zoom_stack.pop();
setZoom(r.first, r.second);
} else {
zoomReset();
}
zoom_undo_stack->clear();
}
void ChartsWidget::showValueTip(double sec) {
@ -199,12 +186,13 @@ void ChartsWidget::setMaxChartRange(int value) {
void ChartsWidget::updateToolBar() {
title_label->setText(tr("Charts: %1").arg(charts.size()));
columns_action->setText(tr("Column: %1").arg(column_count));
range_lb->setText(QString("Range: %1 ").arg(utils::formatSeconds(max_chart_range)));
range_lb->setText(utils::formatSeconds(max_chart_range));
range_lb_action->setVisible(!is_zoomed);
range_slider_action->setVisible(!is_zoomed);
undo_zoom_action->setVisible(is_zoomed);
redo_zoom_action->setVisible(is_zoomed);
reset_zoom_action->setVisible(is_zoomed);
reset_zoom_action->setText(is_zoomed ? tr("Zoomin: %1-%2").arg(zoomed_range.first, 0, 'f', 1).arg(zoomed_range.second, 0, 'f', 1) : "");
reset_zoom_action->setText(is_zoomed ? tr("%1-%2").arg(zoomed_range.first, 0, 'f', 1).arg(zoomed_range.second, 0, 'f', 1) : "");
remove_all_btn->setEnabled(!charts.isEmpty());
dock_btn->setIcon(utils::icon(docking ? "arrow-up-right-square" : "arrow-down-left-square"));
dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts"));
@ -225,20 +213,21 @@ ChartView *ChartsWidget::findChart(const MessageId &id, const cabana::Signal *si
}
ChartView *ChartsWidget::createChart() {
auto chart = new ChartView(this);
auto chart = new ChartView(is_zoomed ? zoomed_range : display_range, this);
chart->setFixedHeight(settings.chart_height);
chart->setMinimumWidth(CHART_MIN_WIDTH);
chart->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
chart->chart()->setTheme(settings.theme == 2 ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight);
QObject::connect(chart, &ChartView::remove, [=]() { removeChart(chart); });
QObject::connect(chart, &ChartView::zoomIn, this, &ChartsWidget::zoomIn);
QObject::connect(chart, &ChartView::zoomUndo, this, &ChartsWidget::zoomUndo);
QObject::connect(chart, &ChartView::zoomUndo, undo_zoom_action, &QAction::trigger);
QObject::connect(chart, &ChartView::seriesRemoved, this, &ChartsWidget::seriesChanged);
QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged);
QObject::connect(chart, &ChartView::axisYLabelWidthChanged, &align_timer, qOverload<>(&QTimer::start));
QObject::connect(chart, &ChartView::hovered, this, &ChartsWidget::showValueTip);
charts.push_back(chart);
updateLayout();
updateToolBar();
return chart;
}
@ -247,11 +236,9 @@ void ChartsWidget::showChart(const MessageId &id, const cabana::Signal *sig, boo
if (show && !chart) {
chart = merge && charts.size() > 0 ? charts.back() : createChart();
chart->addSeries(id, sig);
updateState();
} else if (!show && chart) {
chart->removeIf([&](auto &s) { return s.msg_id == id && s.sig == sig; });
}
updateToolBar();
}
void ChartsWidget::setColumnCount(int n) {
@ -305,8 +292,8 @@ void ChartsWidget::removeChart(ChartView *chart) {
charts.removeOne(chart);
chart->deleteLater();
updateToolBar();
alignCharts();
updateLayout();
alignCharts();
emit seriesChanged();
}
@ -366,7 +353,7 @@ bool ChartsWidget::event(QEvent *event) {
}
if (back_button) {
zoomUndo();
emit undo_zoom_action->triggered();
return true;
}
return QFrame::event(event);
@ -374,7 +361,7 @@ bool ChartsWidget::event(QEvent *event) {
// ChartView
ChartView::ChartView(QWidget *parent) : tip_label(this), QChartView(nullptr, parent) {
ChartView::ChartView(const std::pair<double, double> &x_range, QWidget *parent) : tip_label(this), QChartView(nullptr, parent) {
series_type = (SeriesType)settings.chart_series_type;
QChart *chart = new QChart();
chart->setBackgroundVisible(false);
@ -386,6 +373,7 @@ ChartView::ChartView(QWidget *parent) : tip_label(this), QChartView(nullptr, par
chart->legend()->setShowToolTips(true);
chart->setMargins({0, 0, 0, 0});
axis_x->setRange(x_range.first, x_range.second);
setChart(chart);
createToolButtons();

@ -5,8 +5,9 @@
#include <QListWidget>
#include <QGraphicsPixmapItem>
#include <QGraphicsProxyWidget>
#include <QStack>
#include <QTimer>
#include <QUndoCommand>
#include <QUndoStack>
#include <QtCharts/QChartView>
#include <QtCharts/QLegendMarker>
#include <QtCharts/QLineSeries>
@ -36,7 +37,7 @@ class ChartView : public QChartView {
Q_OBJECT
public:
ChartView(QWidget *parent = nullptr);
ChartView(const std::pair<double, double> &x_range, QWidget *parent = nullptr);
void addSeries(const MessageId &msg_id, const cabana::Signal *sig);
bool hasSeries(const MessageId &msg_id, const cabana::Signal *sig) const;
void updateSeries(const cabana::Signal *sig = nullptr);
@ -129,6 +130,7 @@ public:
public slots:
void setColumnCount(int n);
void removeAll();
void setZoom(double min, double max);
signals:
void dock(bool floating);
@ -146,8 +148,6 @@ private:
void updateState();
void zoomIn(double min, double max);
void zoomReset();
void zoomUndo();
void setZoom(double min, double max);
void updateToolBar();
void setMaxChartRange(int value);
void updateLayout();
@ -163,8 +163,12 @@ private:
QAction *range_slider_action;
bool docking = true;
QAction *dock_btn;
QAction *undo_zoom_action;
QAction *redo_zoom_action;
QAction *reset_zoom_action;
QUndoStack *zoom_undo_stack;
QAction *remove_all_btn;
QGridLayout *charts_layout;
QList<ChartView *> charts;
@ -174,11 +178,23 @@ private:
bool is_zoomed = false;
std::pair<double, double> display_range;
std::pair<double, double> zoomed_range;
QStack<QPair<double, double>> zoom_stack;
QAction *columns_action;
int column_count = 1;
int current_column_count = 0;
QTimer align_timer;
friend class ZoomCommand;
};
class ZoomCommand : public QUndoCommand {
public:
ZoomCommand(ChartsWidget *charts, std::pair<double, double> range) : charts(charts), range(range), QUndoCommand() {
prev_range = charts->is_zoomed ? charts->zoomed_range : charts->display_range;
setText(QObject::tr("Zoom to %1-%2").arg(range.first, 0, 'f', 1).arg(range.second, 0, 'f', 1));
}
void undo() override { charts->setZoom(prev_range.first, prev_range.second); }
void redo() override { charts->setZoom(range.first, range.second); }
ChartsWidget *charts;
std::pair<double, double> prev_range, range;
};
class SeriesSelector : public QDialog {

Loading…
Cancel
Save