|  |  | @ -11,9 +11,11 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  | #include <QRubberBand> |  |  |  | #include <QRubberBand> | 
			
		
	
		
		
			
				
					
					|  |  |  | #include <QPushButton> |  |  |  | #include <QPushButton> | 
			
		
	
		
		
			
				
					
					|  |  |  | #include <QToolBar> |  |  |  | #include <QToolBar> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #include <QToolButton> | 
			
		
	
		
		
			
				
					
					|  |  |  | #include <QToolTip> |  |  |  | #include <QToolTip> | 
			
		
	
		
		
			
				
					
					|  |  |  | #include <QtConcurrent> |  |  |  | #include <QtConcurrent> | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const int MAX_COLUMN_COUNT = 4; | 
			
		
	
		
		
			
				
					
					|  |  |  | // ChartsWidget
 |  |  |  | // ChartsWidget
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { |  |  |  | ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -23,14 +25,17 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   QToolBar *toolbar = new QToolBar(tr("Charts"), this); |  |  |  |   QToolBar *toolbar = new QToolBar(tr("Charts"), this); | 
			
		
	
		
		
			
				
					
					|  |  |  |   toolbar->setIconSize({16, 16}); |  |  |  |   toolbar->setIconSize({16, 16}); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   QAction *new_plot_btn = toolbar->addAction(utils::icon("file-plus"), ""); |  |  |  |   QAction *new_plot_btn = toolbar->addAction(utils::icon("file-plus"), tr("New Plot")); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   new_plot_btn->setToolTip(tr("New Plot")); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   toolbar->addWidget(title_label = new QLabel()); |  |  |  |   toolbar->addWidget(title_label = new QLabel()); | 
			
		
	
		
		
			
				
					
					|  |  |  |   title_label->setContentsMargins(0, 0, 12, 0); |  |  |  |   title_label->setContentsMargins(0, 0, 12, 0); | 
			
		
	
		
		
			
				
					
					|  |  |  |   columns_cb = new QComboBox(this); |  |  |  | 
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   columns_cb->addItems({"1", "2", "3", "4"}); |  |  |  |   QMenu *menu = new QMenu(this); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   columns_lb_action = toolbar->addWidget(new QLabel(tr("Columns:"))); |  |  |  |   for (int i = 0; i < MAX_COLUMN_COUNT; ++i) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   columns_cb_action = toolbar->addWidget(columns_cb); |  |  |  |     menu->addAction(tr("%1").arg(i + 1), [=]() { setColumnCount(i + 1); }); | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   columns_action = toolbar->addAction(""); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   columns_action->setMenu(menu); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   qobject_cast<QToolButton*>(toolbar->widgetForAction(columns_action))->setPopupMode(QToolButton::InstantPopup); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   QLabel *stretch_label = new QLabel(this); |  |  |  |   QLabel *stretch_label = new QLabel(this); | 
			
		
	
		
		
			
				
					
					|  |  |  |   stretch_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); |  |  |  |   stretch_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); | 
			
		
	
	
		
		
			
				
					|  |  | @ -44,13 +49,10 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   range_slider->setPageStep(60);  // 1 min
 |  |  |  |   range_slider->setPageStep(60);  // 1 min
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   range_slider_action = toolbar->addWidget(range_slider); |  |  |  |   range_slider_action = toolbar->addWidget(range_slider); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   reset_zoom_action = toolbar->addWidget(reset_zoom_btn = new QToolButton()); |  |  |  |   reset_zoom_action = toolbar->addAction(utils::icon("zoom-out"), tr("Reset Zoom")); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   reset_zoom_btn->setIcon(utils::icon("zoom-out")); |  |  |  |   qobject_cast<QToolButton*>(toolbar->widgetForAction(reset_zoom_action))->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   reset_zoom_btn->setToolTip(tr("Reset zoom")); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   reset_zoom_btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   remove_all_btn = toolbar->addAction(utils::icon("x"), ""); |  |  |  |   remove_all_btn = toolbar->addAction(utils::icon("x"), 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); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -73,10 +75,9 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   // init settings
 |  |  |  |   // init settings
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   use_dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > |  |  |  |   use_dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > | 
			
		
	
		
		
			
				
					
					|  |  |  |                    QApplication::style()->standardPalette().color(QPalette::Background).value(); |  |  |  |                    QApplication::style()->standardPalette().color(QPalette::Background).value(); | 
			
		
	
		
		
			
				
					
					|  |  |  |   column_count = std::clamp(settings.chart_column_count, 1, columns_cb->count()); |  |  |  |   column_count = std::clamp(settings.chart_column_count, 1, MAX_COLUMN_COUNT); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   max_chart_range = std::clamp(settings.chart_range, 1, settings.max_cached_minutes * 60); |  |  |  |   max_chart_range = std::clamp(settings.chart_range, 1, settings.max_cached_minutes * 60); | 
			
		
	
		
		
			
				
					
					|  |  |  |   display_range = {0, max_chart_range}; |  |  |  |   display_range = {0, max_chart_range}; | 
			
		
	
		
		
			
				
					
					|  |  |  |   columns_cb->setCurrentIndex(column_count - 1); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   range_slider->setValue(max_chart_range); |  |  |  |   range_slider->setValue(max_chart_range); | 
			
		
	
		
		
			
				
					
					|  |  |  |   updateToolBar(); |  |  |  |   updateToolBar(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -86,8 +87,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   QObject::connect(range_slider, &QSlider::valueChanged, this, &ChartsWidget::setMaxChartRange); |  |  |  |   QObject::connect(range_slider, &QSlider::valueChanged, this, &ChartsWidget::setMaxChartRange); | 
			
		
	
		
		
			
				
					
					|  |  |  |   QObject::connect(new_plot_btn, &QAction::triggered, this, &ChartsWidget::newChart); |  |  |  |   QObject::connect(new_plot_btn, &QAction::triggered, this, &ChartsWidget::newChart); | 
			
		
	
		
		
			
				
					
					|  |  |  |   QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll); |  |  |  |   QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll); | 
			
		
	
		
		
			
				
					
					|  |  |  |   QObject::connect(reset_zoom_btn, &QToolButton::clicked, this, &ChartsWidget::zoomReset); |  |  |  |   QObject::connect(reset_zoom_action, &QAction::triggered, this, &ChartsWidget::zoomReset); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   QObject::connect(columns_cb, SIGNAL(activated(int)), SLOT(setColumnCount(int))); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   QObject::connect(&settings, &Settings::changed, this, &ChartsWidget::settingChanged); |  |  |  |   QObject::connect(&settings, &Settings::changed, this, &ChartsWidget::settingChanged); | 
			
		
	
		
		
			
				
					
					|  |  |  |   QObject::connect(dock_btn, &QAction::triggered, [this]() { |  |  |  |   QObject::connect(dock_btn, &QAction::triggered, [this]() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     emit dock(!docking); |  |  |  |     emit dock(!docking); | 
			
		
	
	
		
		
			
				
					|  |  | @ -162,11 +162,12 @@ void ChartsWidget::setMaxChartRange(int value) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | void ChartsWidget::updateToolBar() { |  |  |  | void ChartsWidget::updateToolBar() { | 
			
		
	
		
		
			
				
					
					|  |  |  |   title_label->setText(tr("Charts: %1").arg(charts.size())); |  |  |  |   title_label->setText(tr("Charts: %1").arg(charts.size())); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   columns_action->setText(tr("Column: %1").arg(column_count)); | 
			
		
	
		
		
			
				
					
					|  |  |  |   range_lb->setText(QString("Range: %1:%2 ").arg(max_chart_range / 60, 2, 10, QLatin1Char('0')).arg(max_chart_range % 60, 2, 10, QLatin1Char('0'))); |  |  |  |   range_lb->setText(QString("Range: %1:%2 ").arg(max_chart_range / 60, 2, 10, QLatin1Char('0')).arg(max_chart_range % 60, 2, 10, QLatin1Char('0'))); | 
			
		
	
		
		
			
				
					
					|  |  |  |   range_lb_action->setVisible(!is_zoomed); |  |  |  |   range_lb_action->setVisible(!is_zoomed); | 
			
		
	
		
		
			
				
					
					|  |  |  |   range_slider_action->setVisible(!is_zoomed); |  |  |  |   range_slider_action->setVisible(!is_zoomed); | 
			
		
	
		
		
			
				
					
					|  |  |  |   reset_zoom_action->setVisible(is_zoomed); |  |  |  |   reset_zoom_action->setVisible(is_zoomed); | 
			
		
	
		
		
			
				
					
					|  |  |  |   reset_zoom_btn->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("Zoomin: %1-%2").arg(zoomed_range.first, 0, 'f', 1).arg(zoomed_range.second, 0, 'f', 1) : ""); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   remove_all_btn->setEnabled(!charts.isEmpty()); |  |  |  |   remove_all_btn->setEnabled(!charts.isEmpty()); | 
			
		
	
		
		
			
				
					
					|  |  |  |   dock_btn->setIcon(utils::icon(docking ? "arrow-up-right-square" : "arrow-down-left-square")); |  |  |  |   dock_btn->setIcon(utils::icon(docking ? "arrow-up-right-square" : "arrow-down-left-square")); | 
			
		
	
		
		
			
				
					
					|  |  |  |   dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); |  |  |  |   dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); | 
			
		
	
	
		
		
			
				
					|  |  | @ -211,29 +212,29 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo | 
			
		
	
		
		
			
				
					
					|  |  |  |     chart->addSeries(id, sig); |  |  |  |     chart->addSeries(id, sig); | 
			
		
	
		
		
			
				
					
					|  |  |  |     updateState(); |  |  |  |     updateState(); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } else if (!show && chart) { |  |  |  |   } else if (!show && chart) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     chart->removeSeries(id, sig); |  |  |  |     chart->removeIf([&](auto &s) { return s.msg_id == id && s.sig == sig; }); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |   updateToolBar(); |  |  |  |   updateToolBar(); | 
			
		
	
		
		
			
				
					
					|  |  |  |   setUpdatesEnabled(true); |  |  |  |   setUpdatesEnabled(true); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | void ChartsWidget::setColumnCount(int n) { |  |  |  | void ChartsWidget::setColumnCount(int n) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   n = std::clamp(n + 1, 1, columns_cb->count()); |  |  |  |   n = std::clamp(n, 1, MAX_COLUMN_COUNT); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   if (column_count != n) { |  |  |  |   if (column_count != n) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     column_count = settings.chart_column_count = n; |  |  |  |     column_count = settings.chart_column_count = n; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     updateToolBar(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     updateLayout(); |  |  |  |     updateLayout(); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | void ChartsWidget::updateLayout() { |  |  |  | void ChartsWidget::updateLayout() { | 
			
		
	
		
		
			
				
					
					|  |  |  |   int n = columns_cb->count(); |  |  |  |   int n = MAX_COLUMN_COUNT; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   for (; n > 1; --n) { |  |  |  |   for (; n > 1; --n) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     if ((n * CHART_MIN_WIDTH + (n - 1) * charts_layout->spacing()) < charts_layout->geometry().width()) break; |  |  |  |     if ((n * CHART_MIN_WIDTH + (n - 1) * charts_layout->spacing()) < charts_layout->geometry().width()) break; | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   bool show_column_cb = n > 1; |  |  |  |   bool show_column_cb = n > 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |   columns_lb_action->setVisible(show_column_cb); |  |  |  |   columns_action->setVisible(show_column_cb); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   columns_cb_action->setVisible(show_column_cb); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   n = std::min(column_count, n); |  |  |  |   n = std::min(column_count, n); | 
			
		
	
		
		
			
				
					
					|  |  |  |   if (charts.size() != charts_layout->count() || n != current_column_count) { |  |  |  |   if (charts.size() != charts_layout->count() || n != current_column_count) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -305,7 +306,6 @@ bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { |  |  |  | ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   series_type = settings.chart_series_type == 0 ? QAbstractSeries::SeriesTypeLine : QAbstractSeries::SeriesTypeScatter; |  |  |  |   series_type = settings.chart_series_type == 0 ? QAbstractSeries::SeriesTypeLine : QAbstractSeries::SeriesTypeScatter; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   QChart *chart = new QChart(); |  |  |  |   QChart *chart = new QChart(); | 
			
		
	
		
		
			
				
					
					|  |  |  |   chart->setBackgroundVisible(false); |  |  |  |   chart->setBackgroundVisible(false); | 
			
		
	
		
		
			
				
					
					|  |  |  |   axis_x = new QValueAxis(this); |  |  |  |   axis_x = new QValueAxis(this); | 
			
		
	
	
		
		
			
				
					|  |  | @ -367,9 +367,6 @@ void ChartView::addSeries(const QString &msg_id, const Signal *sig) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   if (hasSeries(msg_id, sig)) return; |  |  |  |   if (hasSeries(msg_id, sig)) return; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   QXYSeries *series = createSeries(series_type, getColor(sig)); |  |  |  |   QXYSeries *series = createSeries(series_type, getColor(sig)); | 
			
		
	
		
		
			
				
					
					|  |  |  |   chart()->addSeries(series); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   series->attachAxis(axis_x); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   series->attachAxis(axis_y); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   auto [source, address] = DBCManager::parseId(msg_id); |  |  |  |   auto [source, address] = DBCManager::parseId(msg_id); | 
			
		
	
		
		
			
				
					
					|  |  |  |   sigs.push_back({.msg_id = msg_id, .address = address, .source = source, .sig = sig, .series = series}); |  |  |  |   sigs.push_back({.msg_id = msg_id, .address = address, .source = source, .sig = sig, .series = series}); | 
			
		
	
		
		
			
				
					
					|  |  |  |   updateTitle(); |  |  |  |   updateTitle(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -378,30 +375,29 @@ void ChartView::addSeries(const QString &msg_id, const Signal *sig) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   emit seriesAdded(msg_id, sig); |  |  |  |   emit seriesAdded(msg_id, sig); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | void ChartView::removeSeries(const QString &msg_id, const Signal *sig) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; }); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   if (it != sigs.end()) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     it = removeItem(it); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | bool ChartView::hasSeries(const QString &msg_id, const Signal *sig) const { |  |  |  | bool ChartView::hasSeries(const QString &msg_id, const Signal *sig) const { | 
			
		
	
		
		
			
				
					
					|  |  |  |   return std::any_of(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; }); |  |  |  |   return std::any_of(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; }); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | QList<ChartView::SigItem>::iterator ChartView::removeItem(const QList<ChartView::SigItem>::iterator &it) { |  |  |  | void ChartView::removeIf(std::function<bool(const SigItem &s)> predicate) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   int prev_size = sigs.size(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   for (auto it = sigs.begin(); it != sigs.end(); /**/) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (predicate(*it)) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       chart()->removeSeries(it->series); |  |  |  |       chart()->removeSeries(it->series); | 
			
		
	
		
		
			
				
					
					|  |  |  |       it->series->deleteLater(); |  |  |  |       it->series->deleteLater(); | 
			
		
	
		
		
			
				
					
					|  |  |  |   QString msg_id = it->msg_id; |  |  |  |       auto msg_id = it->msg_id; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   const Signal *sig = it->sig; |  |  |  |       auto sig = it->sig; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   auto ret = sigs.erase(it); |  |  |  |       it = sigs.erase(it); | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       emit seriesRemoved(msg_id, sig); |  |  |  |       emit seriesRemoved(msg_id, sig); | 
			
		
	
		
		
			
				
					
					|  |  |  |   if (!sigs.isEmpty()) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     updateAxisY(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else { |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       ++it; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if (sigs.empty()) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     emit remove(); |  |  |  |     emit remove(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } else if (sigs.size() != prev_size) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     updateAxisY(); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |   return ret; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | void ChartView::signalUpdated(const Signal *sig) { |  |  |  | void ChartView::signalUpdated(const Signal *sig) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -412,23 +408,11 @@ void ChartView::signalUpdated(const Signal *sig) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | void ChartView::signalRemoved(const Signal *sig) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   for (auto it = sigs.begin(); it != sigs.end(); /**/) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     it = (it->sig == sig) ? removeItem(it) : ++it; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | void ChartView::msgUpdated(uint32_t address) { |  |  |  | void ChartView::msgUpdated(uint32_t address) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.address == address; })) |  |  |  |   if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.address == address; })) | 
			
		
	
		
		
			
				
					
					|  |  |  |     updateTitle(); |  |  |  |     updateTitle(); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | void ChartView::msgRemoved(uint32_t address) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   for (auto it = sigs.begin(); it != sigs.end(); /**/) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     it = (it->address == address) ? removeItem(it) : ++it; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | void ChartView::manageSeries() { |  |  |  | void ChartView::manageSeries() { | 
			
		
	
		
		
			
				
					
					|  |  |  |   SeriesSelector dlg(tr("Mange Chart"), this); |  |  |  |   SeriesSelector dlg(tr("Mange Chart"), this); | 
			
		
	
		
		
			
				
					
					|  |  |  |   for (auto &s : sigs) { |  |  |  |   for (auto &s : sigs) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -436,19 +420,12 @@ void ChartView::manageSeries() { | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |   if (dlg.exec() == QDialog::Accepted) { |  |  |  |   if (dlg.exec() == QDialog::Accepted) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     auto items = dlg.seletedItems(); |  |  |  |     auto items = dlg.seletedItems(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (items.isEmpty()) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       emit remove(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     for (auto s : items) { |  |  |  |     for (auto s : items) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       addSeries(s->msg_id, s->sig); |  |  |  |       addSeries(s->msg_id, s->sig); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |       for (auto it = sigs.begin(); it != sigs.end(); /**/) { |  |  |  |     removeIf([&](auto &s) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         bool exists = std::any_of(items.cbegin(), items.cend(), [&](auto &s) { |  |  |  |       return std::none_of(items.cbegin(), items.cend(), [&](auto &it) { return s.msg_id == it->msg_id && s.sig == it->sig; }); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |           return s->msg_id == it->msg_id && s->sig == it->sig; |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     }); |  |  |  |     }); | 
			
		
	
		
		
			
				
					
					|  |  |  |         it = exists ? ++it : removeItem(it); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -503,7 +480,7 @@ void ChartView::updateSeriesPoints() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     int pixels_per_point = width() / num_points; |  |  |  |     int pixels_per_point = width() / num_points; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (series_type == QAbstractSeries::SeriesTypeScatter) { |  |  |  |     if (series_type == QAbstractSeries::SeriesTypeScatter) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 1, 8)); |  |  |  |       ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 2, 8)); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } else { |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |       s.series->setPointsVisible(pixels_per_point > 20); |  |  |  |       s.series->setPointsVisible(pixels_per_point > 20); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
	
		
		
			
				
					|  |  | @ -698,7 +675,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     text_list.push_front(QString::number(chart()->mapToValue(pt).x(), 'f', 3)); |  |  |  |     text_list.push_front(QString::number(chart()->mapToValue(pt).x(), 'f', 3)); | 
			
		
	
		
		
			
				
					
					|  |  |  |     QPointF tooltip_pt(pt.x() + 12, plot_area.top() - 20); |  |  |  |     QPointF tooltip_pt(pt.x() + 12, plot_area.top() - 20); | 
			
		
	
		
		
			
				
					
					|  |  |  |     QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), pt.isNull() ? "" : text_list.join("<br />"), this, plot_area.toRect()); |  |  |  |     QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), pt.isNull() ? "" : text_list.join("<br />"), this, plot_area.toRect()); | 
			
		
	
		
		
			
				
					
					|  |  |  |     scene()->update(); |  |  |  |     scene()->invalidate({}, QGraphicsScene::ForegroundLayer); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   } else { |  |  |  |   } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |     QToolTip::hideText(); |  |  |  |     QToolTip::hideText(); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
	
		
		
			
				
					|  |  | @ -795,6 +772,9 @@ QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type, QColor colo | 
			
		
	
		
		
			
				
					
					|  |  |  |   pen.setWidth(2.0 * qApp->devicePixelRatio()); |  |  |  |   pen.setWidth(2.0 * qApp->devicePixelRatio()); | 
			
		
	
		
		
			
				
					
					|  |  |  |   series->setPen(pen); |  |  |  |   series->setPen(pen); | 
			
		
	
		
		
			
				
					
					|  |  |  | #endif |  |  |  | #endif | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   chart()->addSeries(series); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   series->attachAxis(axis_x); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   series->attachAxis(axis_y); | 
			
		
	
		
		
			
				
					
					|  |  |  |   return series; |  |  |  |   return series; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -809,9 +789,6 @@ void ChartView::setSeriesType(QAbstractSeries::SeriesType type) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |     for (auto &s : sigs) { |  |  |  |     for (auto &s : sigs) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       auto series = createSeries(series_type, getColor(s.sig)); |  |  |  |       auto series = createSeries(series_type, getColor(s.sig)); | 
			
		
	
		
		
			
				
					
					|  |  |  |       chart()->addSeries(series); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       series->attachAxis(axis_x); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       series->attachAxis(axis_y); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       series->replace(s.vals); |  |  |  |       series->replace(s.vals); | 
			
		
	
		
		
			
				
					
					|  |  |  |       s.series = series; |  |  |  |       s.series = series; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
	
		
		
			
				
					|  |  | 
 |