##// END OF EJS Templates
Undo zoom box action
trabillard -
r1086:c6451ef8583a
parent child
Show More
@@ -1,123 +1,126
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
6
6
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8 #include <QWidget>
8 #include <QWidget>
9
9
10 #include <memory>
10 #include <memory>
11
11
12 #include <Common/spimpl.h>
12 #include <Common/spimpl.h>
13
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
15
15
16 class QCPRange;
16 class QCPRange;
17 class QCustomPlot;
17 class QCustomPlot;
18 class SqpRange;
18 class SqpRange;
19 class Variable;
19 class Variable;
20 class VisualizationZoneWidget;
20 class VisualizationZoneWidget;
21
21
22 namespace Ui {
22 namespace Ui {
23 class VisualizationGraphWidget;
23 class VisualizationGraphWidget;
24 } // namespace Ui
24 } // namespace Ui
25
25
26 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
26 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
27 Q_OBJECT
27 Q_OBJECT
28
28
29 friend class QCustomPlotSynchronizer;
29 friend class QCustomPlotSynchronizer;
30 friend class VisualizationGraphRenderingDelegate;
30 friend class VisualizationGraphRenderingDelegate;
31
31
32 public:
32 public:
33 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
33 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
34 virtual ~VisualizationGraphWidget();
34 virtual ~VisualizationGraphWidget();
35
35
36 VisualizationZoneWidget *parentZoneWidget() const noexcept;
36 VisualizationZoneWidget *parentZoneWidget() const noexcept;
37
37
38 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
38 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
39 void enableAcquisition(bool enable);
39 void enableAcquisition(bool enable);
40
40
41 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
41 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
42
42
43 /// Removes a variable from the graph
43 /// Removes a variable from the graph
44 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
44 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
45
45
46 /// Returns the list of all variables used in the graph
46 /// Returns the list of all variables used in the graph
47 QList<std::shared_ptr<Variable> > variables() const;
47 QList<std::shared_ptr<Variable> > variables() const;
48
48
49 /// Sets the y-axis range based on the data of a variable
49 /// Sets the y-axis range based on the data of a variable
50 void setYRange(std::shared_ptr<Variable> variable);
50 void setYRange(std::shared_ptr<Variable> variable);
51 SqpRange graphRange() const noexcept;
51 SqpRange graphRange() const noexcept;
52 void setGraphRange(const SqpRange &range);
52 void setGraphRange(const SqpRange &range);
53
53
54 /// Undo the last zoom done with a zoom box
55 void undoZoom();
56
54 // IVisualizationWidget interface
57 // IVisualizationWidget interface
55 void accept(IVisualizationWidgetVisitor *visitor) override;
58 void accept(IVisualizationWidgetVisitor *visitor) override;
56 bool canDrop(const Variable &variable) const override;
59 bool canDrop(const Variable &variable) const override;
57 bool contains(const Variable &variable) const override;
60 bool contains(const Variable &variable) const override;
58 QString name() const override;
61 QString name() const override;
59
62
60 // VisualisationDragWidget
63 // VisualisationDragWidget
61 QMimeData *mimeData() const override;
64 QMimeData *mimeData() const override;
62 bool isDragAllowed() const override;
65 bool isDragAllowed() const override;
63 void highlightForMerge(bool highlighted) override;
66 void highlightForMerge(bool highlighted) override;
64
67
65 // Cursors
68 // Cursors
66 /// Adds or moves the vertical cursor at the specified value on the x-axis
69 /// Adds or moves the vertical cursor at the specified value on the x-axis
67 void addVerticalCursor(double time);
70 void addVerticalCursor(double time);
68 /// Adds or moves the vertical cursor at the specified value on the x-axis
71 /// Adds or moves the vertical cursor at the specified value on the x-axis
69 void addVerticalCursorAtViewportPosition(double position);
72 void addVerticalCursorAtViewportPosition(double position);
70 void removeVerticalCursor();
73 void removeVerticalCursor();
71 /// Adds or moves the vertical cursor at the specified value on the y-axis
74 /// Adds or moves the vertical cursor at the specified value on the y-axis
72 void addHorizontalCursor(double value);
75 void addHorizontalCursor(double value);
73 /// Adds or moves the vertical cursor at the specified value on the y-axis
76 /// Adds or moves the vertical cursor at the specified value on the y-axis
74 void addHorizontalCursorAtViewportPosition(double position);
77 void addHorizontalCursorAtViewportPosition(double position);
75 void removeHorizontalCursor();
78 void removeHorizontalCursor();
76
79
77 signals:
80 signals:
78 void synchronize(const SqpRange &range, const SqpRange &oldRange);
81 void synchronize(const SqpRange &range, const SqpRange &oldRange);
79 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
82 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
80 bool synchronise);
83 bool synchronise);
81
84
82 /// Signal emitted when the variable is about to be removed from the graph
85 /// Signal emitted when the variable is about to be removed from the graph
83 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
86 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
84 /// Signal emitted when the variable has been added to the graph
87 /// Signal emitted when the variable has been added to the graph
85 void variableAdded(std::shared_ptr<Variable> var);
88 void variableAdded(std::shared_ptr<Variable> var);
86
89
87 protected:
90 protected:
88 void closeEvent(QCloseEvent *event) override;
91 void closeEvent(QCloseEvent *event) override;
89 void enterEvent(QEvent *event) override;
92 void enterEvent(QEvent *event) override;
90 void leaveEvent(QEvent *event) override;
93 void leaveEvent(QEvent *event) override;
91
94
92 QCustomPlot &plot() noexcept;
95 QCustomPlot &plot() noexcept;
93
96
94 private:
97 private:
95 Ui::VisualizationGraphWidget *ui;
98 Ui::VisualizationGraphWidget *ui;
96
99
97 class VisualizationGraphWidgetPrivate;
100 class VisualizationGraphWidgetPrivate;
98 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
101 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
99
102
100 private slots:
103 private slots:
101 /// Slot called when right clicking on the graph (displays a menu)
104 /// Slot called when right clicking on the graph (displays a menu)
102 void onGraphMenuRequested(const QPoint &pos) noexcept;
105 void onGraphMenuRequested(const QPoint &pos) noexcept;
103
106
104 /// Rescale the X axe to range parameter
107 /// Rescale the X axe to range parameter
105 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
108 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
106
109
107 /// Slot called when a mouse double click was made
110 /// Slot called when a mouse double click was made
108 void onMouseDoubleClick(QMouseEvent *event) noexcept;
111 void onMouseDoubleClick(QMouseEvent *event) noexcept;
109 /// Slot called when a mouse move was made
112 /// Slot called when a mouse move was made
110 void onMouseMove(QMouseEvent *event) noexcept;
113 void onMouseMove(QMouseEvent *event) noexcept;
111 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
114 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
112 void onMouseWheel(QWheelEvent *event) noexcept;
115 void onMouseWheel(QWheelEvent *event) noexcept;
113 /// Slot called when a mouse press was made, to activate the calibration of a graph
116 /// Slot called when a mouse press was made, to activate the calibration of a graph
114 void onMousePress(QMouseEvent *event) noexcept;
117 void onMousePress(QMouseEvent *event) noexcept;
115 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
118 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
116 void onMouseRelease(QMouseEvent *event) noexcept;
119 void onMouseRelease(QMouseEvent *event) noexcept;
117
120
118 void onDataCacheVariableUpdated();
121 void onDataCacheVariableUpdated();
119
122
120 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
123 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
121 };
124 };
122
125
123 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
126 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,725 +1,747
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationCursorItem.h"
3 #include "Visualization/VisualizationCursorItem.h"
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphHelper.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
7 #include "Visualization/VisualizationSelectionZoneItem.h"
7 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationZoneWidget.h"
8 #include "Visualization/VisualizationZoneWidget.h"
9 #include "ui_VisualizationGraphWidget.h"
9 #include "ui_VisualizationGraphWidget.h"
10
10
11 #include <Common/MimeTypesDef.h>
11 #include <Common/MimeTypesDef.h>
12 #include <Data/ArrayData.h>
12 #include <Data/ArrayData.h>
13 #include <Data/IDataSeries.h>
13 #include <Data/IDataSeries.h>
14 #include <Data/SpectrogramSeries.h>
14 #include <Data/SpectrogramSeries.h>
15 #include <DragAndDrop/DragDropHelper.h>
15 #include <DragAndDrop/DragDropHelper.h>
16 #include <Settings/SqpSettingsDefs.h>
16 #include <Settings/SqpSettingsDefs.h>
17 #include <SqpApplication.h>
17 #include <SqpApplication.h>
18 #include <Time/TimeController.h>
18 #include <Time/TimeController.h>
19 #include <Variable/Variable.h>
19 #include <Variable/Variable.h>
20 #include <Variable/VariableController.h>
20 #include <Variable/VariableController.h>
21
21
22 #include <unordered_map>
22 #include <unordered_map>
23
23
24 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
24 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
25
25
26 namespace {
26 namespace {
27
27
28 /// Key pressed to enable zoom on horizontal axis
28 /// Key pressed to enable zoom on horizontal axis
29 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
29 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
30
30
31 /// Key pressed to enable zoom on vertical axis
31 /// Key pressed to enable zoom on vertical axis
32 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
32 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
33
33
34 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
34 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
35 const auto PAN_SPEED = 5;
35 const auto PAN_SPEED = 5;
36
36
37 /// Key pressed to enable a calibration pan
37 /// Key pressed to enable a calibration pan
38 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
38 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
39
39
40 /// Minimum size for the zoom box, in percentage of the axis range
40 /// Minimum size for the zoom box, in percentage of the axis range
41 const auto ZOOM_BOX_MIN_SIZE = 0.8;
41 const auto ZOOM_BOX_MIN_SIZE = 0.8;
42
42
43 /// Format of the dates appearing in the label of a cursor
43 /// Format of the dates appearing in the label of a cursor
44 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
44 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
45
45
46 } // namespace
46 } // namespace
47
47
48 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
48 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
49
49
50 explicit VisualizationGraphWidgetPrivate(const QString &name)
50 explicit VisualizationGraphWidgetPrivate(const QString &name)
51 : m_Name{name},
51 : m_Name{name},
52 m_DoAcquisition{true},
52 m_DoAcquisition{true},
53 m_IsCalibration{false},
53 m_IsCalibration{false},
54 m_RenderingDelegate{nullptr}
54 m_RenderingDelegate{nullptr}
55 {
55 {
56 }
56 }
57
57
58 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
58 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
59 const SqpRange &range)
59 const SqpRange &range)
60 {
60 {
61 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
61 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
62
62
63 // Prevents that data has changed to update rendering
63 // Prevents that data has changed to update rendering
64 m_RenderingDelegate->onPlotUpdated();
64 m_RenderingDelegate->onPlotUpdated();
65 }
65 }
66
66
67 QString m_Name;
67 QString m_Name;
68 // 1 variable -> n qcpplot
68 // 1 variable -> n qcpplot
69 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
69 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
70 bool m_DoAcquisition;
70 bool m_DoAcquisition;
71 bool m_IsCalibration;
71 bool m_IsCalibration;
72 /// Delegate used to attach rendering features to the plot
72 /// Delegate used to attach rendering features to the plot
73 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
73 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
74
74
75 QCPItemRect *m_DrawingZoomRect = nullptr;
75 QCPItemRect *m_DrawingZoomRect = nullptr;
76 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
76
77
77 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
78 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
78 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
79 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
79
80
80 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
81 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
81 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
82 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
82 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
83 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
83
84
84 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
85 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
85 {
86 {
86 removeDrawingRect(plot);
87 removeDrawingRect(plot);
87
88
88 auto axisPos = posToAxisPos(pos, plot);
89 auto axisPos = posToAxisPos(pos, plot);
89
90
90 m_DrawingZoomRect = new QCPItemRect{&plot};
91 m_DrawingZoomRect = new QCPItemRect{&plot};
91 QPen p;
92 QPen p;
92 p.setWidth(2);
93 p.setWidth(2);
93 m_DrawingZoomRect->setPen(p);
94 m_DrawingZoomRect->setPen(p);
94
95
95 m_DrawingZoomRect->topLeft->setCoords(axisPos);
96 m_DrawingZoomRect->topLeft->setCoords(axisPos);
96 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
97 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
97 }
98 }
98
99
99 void removeDrawingRect(QCustomPlot &plot)
100 void removeDrawingRect(QCustomPlot &plot)
100 {
101 {
101 if (m_DrawingZoomRect) {
102 if (m_DrawingZoomRect) {
102 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
103 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
103 m_DrawingZoomRect = nullptr;
104 m_DrawingZoomRect = nullptr;
104 plot.replot(QCustomPlot::rpQueuedReplot);
105 plot.replot(QCustomPlot::rpQueuedReplot);
105 }
106 }
106 }
107 }
107
108
108 void startDrawingZone(const QPoint &pos, QCustomPlot &plot)
109 void startDrawingZone(const QPoint &pos, QCustomPlot &plot)
109 {
110 {
110 endDrawingZone(plot);
111 endDrawingZone(plot);
111
112
112 auto axisPos = posToAxisPos(pos, plot);
113 auto axisPos = posToAxisPos(pos, plot);
113
114
114 m_DrawingZone = new VisualizationSelectionZoneItem{&plot};
115 m_DrawingZone = new VisualizationSelectionZoneItem{&plot};
115 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
116 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
116 m_DrawingZone->setEditionEnabled(false);
117 m_DrawingZone->setEditionEnabled(false);
117 }
118 }
118
119
119 void endDrawingZone(QCustomPlot &plot)
120 void endDrawingZone(QCustomPlot &plot)
120 {
121 {
121 if (m_DrawingZone) {
122 if (m_DrawingZone) {
122 auto drawingZoneRange = m_DrawingZone->range();
123 auto drawingZoneRange = m_DrawingZone->range();
123 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
124 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
124 m_DrawingZone->setEditionEnabled(true);
125 m_DrawingZone->setEditionEnabled(true);
125 m_SelectionZones.append(m_DrawingZone);
126 m_SelectionZones.append(m_DrawingZone);
126 }
127 }
127 else {
128 else {
128 plot.removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
129 plot.removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
129 }
130 }
130
131
131 plot.replot(QCustomPlot::rpQueuedReplot);
132 plot.replot(QCustomPlot::rpQueuedReplot);
132 m_DrawingZone = nullptr;
133 m_DrawingZone = nullptr;
133 }
134 }
134 }
135 }
135
136
136 void setSelectionZonesEditionEnabled(bool value)
137 void setSelectionZonesEditionEnabled(bool value)
137 {
138 {
138 for (auto s : m_SelectionZones) {
139 for (auto s : m_SelectionZones) {
139 s->setEditionEnabled(value);
140 s->setEditionEnabled(value);
140 }
141 }
141 }
142 }
142
143
143 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
144 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
144 {
145 {
145 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
146 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
146 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
147 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
147 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
148 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
148 }
149 }
149
150
150 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
151 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
151 {
152 {
152 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
153 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
153 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
154 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
154 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
155 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
155 }
156 }
156 };
157 };
157
158
158 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
159 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
159 : VisualizationDragWidget{parent},
160 : VisualizationDragWidget{parent},
160 ui{new Ui::VisualizationGraphWidget},
161 ui{new Ui::VisualizationGraphWidget},
161 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
162 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
162 {
163 {
163 ui->setupUi(this);
164 ui->setupUi(this);
164
165
165 // 'Close' options : widget is deleted when closed
166 // 'Close' options : widget is deleted when closed
166 setAttribute(Qt::WA_DeleteOnClose);
167 setAttribute(Qt::WA_DeleteOnClose);
167
168
168 // Set qcpplot properties :
169 // Set qcpplot properties :
169 // - zoom is enabled
170 // - zoom is enabled
170 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
171 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
171 ui->widget->setInteractions(QCP::iRangeZoom | QCP::iSelectItems);
172 ui->widget->setInteractions(QCP::iRangeZoom | QCP::iSelectItems);
172 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
173 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
173
174
174 // The delegate must be initialized after the ui as it uses the plot
175 // The delegate must be initialized after the ui as it uses the plot
175 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
176 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
176
177
177 // Init the cursors
178 // Init the cursors
178 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
179 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
179 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
180 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
180 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
181 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
181 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
182 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
182
183
183 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
184 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
184 connect(ui->widget, &QCustomPlot::mouseRelease, this,
185 connect(ui->widget, &QCustomPlot::mouseRelease, this,
185 &VisualizationGraphWidget::onMouseRelease);
186 &VisualizationGraphWidget::onMouseRelease);
186 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
187 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
187 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
188 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
188 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
189 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
189 &VisualizationGraphWidget::onMouseDoubleClick);
190 &VisualizationGraphWidget::onMouseDoubleClick);
190 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
191 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
191 &QCPAxis::rangeChanged),
192 &QCPAxis::rangeChanged),
192 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
193 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
193
194
194 // Activates menu when right clicking on the graph
195 // Activates menu when right clicking on the graph
195 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
196 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
196 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
197 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
197 &VisualizationGraphWidget::onGraphMenuRequested);
198 &VisualizationGraphWidget::onGraphMenuRequested);
198
199
199 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
200 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
200 &VariableController::onRequestDataLoading);
201 &VariableController::onRequestDataLoading);
201
202
202 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
203 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
203 &VisualizationGraphWidget::onUpdateVarDisplaying);
204 &VisualizationGraphWidget::onUpdateVarDisplaying);
204
205
205 #ifdef Q_OS_MAC
206 #ifdef Q_OS_MAC
206 plot().setPlottingHint(QCP::phFastPolylines, true);
207 plot().setPlottingHint(QCP::phFastPolylines, true);
207 #endif
208 #endif
208 }
209 }
209
210
210
211
211 VisualizationGraphWidget::~VisualizationGraphWidget()
212 VisualizationGraphWidget::~VisualizationGraphWidget()
212 {
213 {
213 delete ui;
214 delete ui;
214 }
215 }
215
216
216 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
217 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
217 {
218 {
218 auto parent = parentWidget();
219 auto parent = parentWidget();
219 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
220 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
220 parent = parent->parentWidget();
221 parent = parent->parentWidget();
221 }
222 }
222
223
223 return qobject_cast<VisualizationZoneWidget *>(parent);
224 return qobject_cast<VisualizationZoneWidget *>(parent);
224 }
225 }
225
226
226 void VisualizationGraphWidget::enableAcquisition(bool enable)
227 void VisualizationGraphWidget::enableAcquisition(bool enable)
227 {
228 {
228 impl->m_DoAcquisition = enable;
229 impl->m_DoAcquisition = enable;
229 }
230 }
230
231
231 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
232 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
232 {
233 {
233 // Uses delegate to create the qcpplot components according to the variable
234 // Uses delegate to create the qcpplot components according to the variable
234 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
235 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
235
236
236 if (auto dataSeries = variable->dataSeries()) {
237 if (auto dataSeries = variable->dataSeries()) {
237 // Set axes properties according to the units of the data series
238 // Set axes properties according to the units of the data series
238 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
239 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
239
240
240 // Sets rendering properties for the new plottables
241 // Sets rendering properties for the new plottables
241 // Warning: this method must be called after setAxesProperties(), as it can access to some
242 // Warning: this method must be called after setAxesProperties(), as it can access to some
242 // axes properties that have to be initialized
243 // axes properties that have to be initialized
243 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
244 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
244 }
245 }
245
246
246 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
247 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
247
248
248 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
249 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
249
250
250 this->enableAcquisition(false);
251 this->enableAcquisition(false);
251 this->setGraphRange(range);
252 this->setGraphRange(range);
252 this->enableAcquisition(true);
253 this->enableAcquisition(true);
253
254
254 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
255 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
255
256
256 emit variableAdded(variable);
257 emit variableAdded(variable);
257 }
258 }
258
259
259 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
260 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
260 {
261 {
261 // Each component associated to the variable :
262 // Each component associated to the variable :
262 // - is removed from qcpplot (which deletes it)
263 // - is removed from qcpplot (which deletes it)
263 // - is no longer referenced in the map
264 // - is no longer referenced in the map
264 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
265 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
265 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
266 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
266 emit variableAboutToBeRemoved(variable);
267 emit variableAboutToBeRemoved(variable);
267
268
268 auto &plottablesMap = variableIt->second;
269 auto &plottablesMap = variableIt->second;
269
270
270 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
271 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
271 plottableIt != plottableEnd;) {
272 plottableIt != plottableEnd;) {
272 ui->widget->removePlottable(plottableIt->second);
273 ui->widget->removePlottable(plottableIt->second);
273 plottableIt = plottablesMap.erase(plottableIt);
274 plottableIt = plottablesMap.erase(plottableIt);
274 }
275 }
275
276
276 impl->m_VariableToPlotMultiMap.erase(variableIt);
277 impl->m_VariableToPlotMultiMap.erase(variableIt);
277 }
278 }
278
279
279 // Updates graph
280 // Updates graph
280 ui->widget->replot();
281 ui->widget->replot();
281 }
282 }
282
283
283 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
284 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
284 {
285 {
285 auto variables = QList<std::shared_ptr<Variable> >{};
286 auto variables = QList<std::shared_ptr<Variable> >{};
286 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
287 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
287 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
288 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
288 variables << it->first;
289 variables << it->first;
289 }
290 }
290
291
291 return variables;
292 return variables;
292 }
293 }
293
294
294 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
295 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
295 {
296 {
296 if (!variable) {
297 if (!variable) {
297 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
298 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
298 return;
299 return;
299 }
300 }
300
301
301 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
302 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
302 }
303 }
303
304
304 SqpRange VisualizationGraphWidget::graphRange() const noexcept
305 SqpRange VisualizationGraphWidget::graphRange() const noexcept
305 {
306 {
306 auto graphRange = ui->widget->xAxis->range();
307 auto graphRange = ui->widget->xAxis->range();
307 return SqpRange{graphRange.lower, graphRange.upper};
308 return SqpRange{graphRange.lower, graphRange.upper};
308 }
309 }
309
310
310 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
311 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
311 {
312 {
312 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
313 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
313 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
314 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
314 ui->widget->replot();
315 ui->widget->replot();
315 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
316 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
316 }
317 }
317
318
319 void VisualizationGraphWidget::undoZoom()
320 {
321 auto zoom = impl->m_ZoomStack.pop();
322 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
323 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
324
325 axisX->setRange(zoom.first);
326 axisY->setRange(zoom.second);
327
328 plot().replot(QCustomPlot::rpQueuedReplot);
329 }
330
318 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
331 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
319 {
332 {
320 if (visitor) {
333 if (visitor) {
321 visitor->visit(this);
334 visitor->visit(this);
322 }
335 }
323 else {
336 else {
324 qCCritical(LOG_VisualizationGraphWidget())
337 qCCritical(LOG_VisualizationGraphWidget())
325 << tr("Can't visit widget : the visitor is null");
338 << tr("Can't visit widget : the visitor is null");
326 }
339 }
327 }
340 }
328
341
329 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
342 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
330 {
343 {
331 auto isSpectrogram = [](const auto &variable) {
344 auto isSpectrogram = [](const auto &variable) {
332 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
345 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
333 };
346 };
334
347
335 // - A spectrogram series can't be dropped on graph with existing plottables
348 // - A spectrogram series can't be dropped on graph with existing plottables
336 // - No data series can be dropped on graph with existing spectrogram series
349 // - No data series can be dropped on graph with existing spectrogram series
337 return isSpectrogram(variable)
350 return isSpectrogram(variable)
338 ? impl->m_VariableToPlotMultiMap.empty()
351 ? impl->m_VariableToPlotMultiMap.empty()
339 : std::none_of(
352 : std::none_of(
340 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
353 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
341 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
354 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
342 }
355 }
343
356
344 bool VisualizationGraphWidget::contains(const Variable &variable) const
357 bool VisualizationGraphWidget::contains(const Variable &variable) const
345 {
358 {
346 // Finds the variable among the keys of the map
359 // Finds the variable among the keys of the map
347 auto variablePtr = &variable;
360 auto variablePtr = &variable;
348 auto findVariable
361 auto findVariable
349 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
362 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
350
363
351 auto end = impl->m_VariableToPlotMultiMap.cend();
364 auto end = impl->m_VariableToPlotMultiMap.cend();
352 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
365 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
353 return it != end;
366 return it != end;
354 }
367 }
355
368
356 QString VisualizationGraphWidget::name() const
369 QString VisualizationGraphWidget::name() const
357 {
370 {
358 return impl->m_Name;
371 return impl->m_Name;
359 }
372 }
360
373
361 QMimeData *VisualizationGraphWidget::mimeData() const
374 QMimeData *VisualizationGraphWidget::mimeData() const
362 {
375 {
363 auto mimeData = new QMimeData;
376 auto mimeData = new QMimeData;
364 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
377 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
365
378
366 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
379 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
367 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
380 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
368
381
369 return mimeData;
382 return mimeData;
370 }
383 }
371
384
372 bool VisualizationGraphWidget::isDragAllowed() const
385 bool VisualizationGraphWidget::isDragAllowed() const
373 {
386 {
374 return true;
387 return true;
375 }
388 }
376
389
377 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
390 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
378 {
391 {
379 if (highlighted) {
392 if (highlighted) {
380 plot().setBackground(QBrush(QColor("#BBD5EE")));
393 plot().setBackground(QBrush(QColor("#BBD5EE")));
381 }
394 }
382 else {
395 else {
383 plot().setBackground(QBrush(Qt::white));
396 plot().setBackground(QBrush(Qt::white));
384 }
397 }
385
398
386 plot().update();
399 plot().update();
387 }
400 }
388
401
389 void VisualizationGraphWidget::addVerticalCursor(double time)
402 void VisualizationGraphWidget::addVerticalCursor(double time)
390 {
403 {
391 impl->m_VerticalCursor->setPosition(time);
404 impl->m_VerticalCursor->setPosition(time);
392 impl->m_VerticalCursor->setVisible(true);
405 impl->m_VerticalCursor->setVisible(true);
393
406
394 auto text
407 auto text
395 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
408 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
396 impl->m_VerticalCursor->setLabelText(text);
409 impl->m_VerticalCursor->setLabelText(text);
397 }
410 }
398
411
399 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
412 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
400 {
413 {
401 impl->m_VerticalCursor->setAbsolutePosition(position);
414 impl->m_VerticalCursor->setAbsolutePosition(position);
402 impl->m_VerticalCursor->setVisible(true);
415 impl->m_VerticalCursor->setVisible(true);
403
416
404 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
417 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
405 auto text
418 auto text
406 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
419 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
407 impl->m_VerticalCursor->setLabelText(text);
420 impl->m_VerticalCursor->setLabelText(text);
408 }
421 }
409
422
410 void VisualizationGraphWidget::removeVerticalCursor()
423 void VisualizationGraphWidget::removeVerticalCursor()
411 {
424 {
412 impl->m_VerticalCursor->setVisible(false);
425 impl->m_VerticalCursor->setVisible(false);
413 plot().replot(QCustomPlot::rpQueuedReplot);
426 plot().replot(QCustomPlot::rpQueuedReplot);
414 }
427 }
415
428
416 void VisualizationGraphWidget::addHorizontalCursor(double value)
429 void VisualizationGraphWidget::addHorizontalCursor(double value)
417 {
430 {
418 impl->m_HorizontalCursor->setPosition(value);
431 impl->m_HorizontalCursor->setPosition(value);
419 impl->m_HorizontalCursor->setVisible(true);
432 impl->m_HorizontalCursor->setVisible(true);
420 impl->m_HorizontalCursor->setLabelText(QString::number(value));
433 impl->m_HorizontalCursor->setLabelText(QString::number(value));
421 }
434 }
422
435
423 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
436 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
424 {
437 {
425 impl->m_HorizontalCursor->setAbsolutePosition(position);
438 impl->m_HorizontalCursor->setAbsolutePosition(position);
426 impl->m_HorizontalCursor->setVisible(true);
439 impl->m_HorizontalCursor->setVisible(true);
427
440
428 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
441 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
429 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
442 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
430 }
443 }
431
444
432 void VisualizationGraphWidget::removeHorizontalCursor()
445 void VisualizationGraphWidget::removeHorizontalCursor()
433 {
446 {
434 impl->m_HorizontalCursor->setVisible(false);
447 impl->m_HorizontalCursor->setVisible(false);
435 plot().replot(QCustomPlot::rpQueuedReplot);
448 plot().replot(QCustomPlot::rpQueuedReplot);
436 }
449 }
437
450
438 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
451 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
439 {
452 {
440 Q_UNUSED(event);
453 Q_UNUSED(event);
441
454
442 // Prevents that all variables will be removed from graph when it will be closed
455 // Prevents that all variables will be removed from graph when it will be closed
443 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
456 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
444 emit variableAboutToBeRemoved(variableEntry.first);
457 emit variableAboutToBeRemoved(variableEntry.first);
445 }
458 }
446 }
459 }
447
460
448 void VisualizationGraphWidget::enterEvent(QEvent *event)
461 void VisualizationGraphWidget::enterEvent(QEvent *event)
449 {
462 {
450 Q_UNUSED(event);
463 Q_UNUSED(event);
451 impl->m_RenderingDelegate->showGraphOverlay(true);
464 impl->m_RenderingDelegate->showGraphOverlay(true);
452 }
465 }
453
466
454 void VisualizationGraphWidget::leaveEvent(QEvent *event)
467 void VisualizationGraphWidget::leaveEvent(QEvent *event)
455 {
468 {
456 Q_UNUSED(event);
469 Q_UNUSED(event);
457 impl->m_RenderingDelegate->showGraphOverlay(false);
470 impl->m_RenderingDelegate->showGraphOverlay(false);
458
471
459 if (auto parentZone = parentZoneWidget()) {
472 if (auto parentZone = parentZoneWidget()) {
460 parentZone->notifyMouseLeaveGraph(this);
473 parentZone->notifyMouseLeaveGraph(this);
461 }
474 }
462 else {
475 else {
463 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
476 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
464 }
477 }
465
478
466 if (impl->m_HoveredZone) {
479 if (impl->m_HoveredZone) {
467 impl->m_HoveredZone->setHovered(false);
480 impl->m_HoveredZone->setHovered(false);
468 impl->m_HoveredZone = nullptr;
481 impl->m_HoveredZone = nullptr;
469 }
482 }
470 }
483 }
471
484
472 QCustomPlot &VisualizationGraphWidget::plot() noexcept
485 QCustomPlot &VisualizationGraphWidget::plot() noexcept
473 {
486 {
474 return *ui->widget;
487 return *ui->widget;
475 }
488 }
476
489
477 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
490 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
478 {
491 {
479 QMenu graphMenu{};
492 QMenu graphMenu{};
480
493
481 // Iterates on variables (unique keys)
494 // Iterates on variables (unique keys)
482 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
495 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
483 end = impl->m_VariableToPlotMultiMap.cend();
496 end = impl->m_VariableToPlotMultiMap.cend();
484 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
497 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
485 // 'Remove variable' action
498 // 'Remove variable' action
486 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
499 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
487 [ this, var = it->first ]() { removeVariable(var); });
500 [ this, var = it->first ]() { removeVariable(var); });
488 }
501 }
489
502
503 if (!impl->m_ZoomStack.isEmpty()) {
504 if (!graphMenu.isEmpty()) {
505 graphMenu.addSeparator();
506 }
507
508 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
509 }
510
490 if (!graphMenu.isEmpty()) {
511 if (!graphMenu.isEmpty()) {
491 graphMenu.exec(QCursor::pos());
512 graphMenu.exec(QCursor::pos());
492 }
513 }
493 }
514 }
494
515
495 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
516 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
496 {
517 {
497 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
518 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
498 << QThread::currentThread()->objectName() << "DoAcqui"
519 << QThread::currentThread()->objectName() << "DoAcqui"
499 << impl->m_DoAcquisition;
520 << impl->m_DoAcquisition;
500
521
501 auto graphRange = SqpRange{t1.lower, t1.upper};
522 auto graphRange = SqpRange{t1.lower, t1.upper};
502 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
523 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
503
524
504 if (impl->m_DoAcquisition) {
525 if (impl->m_DoAcquisition) {
505 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
526 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
506
527
507 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
528 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
508 end = impl->m_VariableToPlotMultiMap.end();
529 end = impl->m_VariableToPlotMultiMap.end();
509 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
530 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
510 variableUnderGraphVector.push_back(it->first);
531 variableUnderGraphVector.push_back(it->first);
511 }
532 }
512 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
533 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
513 !impl->m_IsCalibration);
534 !impl->m_IsCalibration);
514
535
515 if (!impl->m_IsCalibration) {
536 if (!impl->m_IsCalibration) {
516 qCDebug(LOG_VisualizationGraphWidget())
537 qCDebug(LOG_VisualizationGraphWidget())
517 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
538 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
518 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
539 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
519 emit synchronize(graphRange, oldGraphRange);
540 emit synchronize(graphRange, oldGraphRange);
520 }
541 }
521 }
542 }
522
543
523 auto pos = mapFromGlobal(QCursor::pos());
544 auto pos = mapFromGlobal(QCursor::pos());
524 auto axisPos = impl->posToAxisPos(pos, plot());
545 auto axisPos = impl->posToAxisPos(pos, plot());
525 if (auto parentZone = parentZoneWidget()) {
546 if (auto parentZone = parentZoneWidget()) {
526 if (impl->pointIsInAxisRect(axisPos, plot())) {
547 if (impl->pointIsInAxisRect(axisPos, plot())) {
527 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
548 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
528 }
549 }
529 else {
550 else {
530 parentZone->notifyMouseLeaveGraph(this);
551 parentZone->notifyMouseLeaveGraph(this);
531 }
552 }
532 }
553 }
533 else {
554 else {
534 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
555 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
535 }
556 }
536 }
557 }
537
558
538 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
559 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
539 {
560 {
540 impl->m_RenderingDelegate->onMouseDoubleClick(event);
561 impl->m_RenderingDelegate->onMouseDoubleClick(event);
541 }
562 }
542
563
543 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
564 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
544 {
565 {
545 // Handles plot rendering when mouse is moving
566 // Handles plot rendering when mouse is moving
546 impl->m_RenderingDelegate->onMouseMove(event);
567 impl->m_RenderingDelegate->onMouseMove(event);
547
568
548 auto axisPos = impl->posToAxisPos(event->pos(), plot());
569 auto axisPos = impl->posToAxisPos(event->pos(), plot());
549
570
550 // Zoom box and zone drawing
571 // Zoom box and zone drawing
551 if (impl->m_DrawingZoomRect) {
572 if (impl->m_DrawingZoomRect) {
552 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
573 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
553 }
574 }
554 else if (impl->m_DrawingZone) {
575 else if (impl->m_DrawingZone) {
555 impl->m_DrawingZone->setEnd(axisPos.x());
576 impl->m_DrawingZone->setEnd(axisPos.x());
556 }
577 }
557
578
558 // Cursor
579 // Cursor
559 if (auto parentZone = parentZoneWidget()) {
580 if (auto parentZone = parentZoneWidget()) {
560 if (impl->pointIsInAxisRect(axisPos, plot())) {
581 if (impl->pointIsInAxisRect(axisPos, plot())) {
561 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
582 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
562 }
583 }
563 else {
584 else {
564 parentZone->notifyMouseLeaveGraph(this);
585 parentZone->notifyMouseLeaveGraph(this);
565 }
586 }
566 }
587 }
567 else {
588 else {
568 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
589 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
569 }
590 }
570
591
571 // Search for the selection zone under the mouse
592 // Search for the selection zone under the mouse
572 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
593 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
573 auto minDistanceToZone = -1;
594 auto minDistanceToZone = -1;
574 for (auto zone : impl->m_SelectionZones) {
595 for (auto zone : impl->m_SelectionZones) {
575 auto distanceToZone = zone->selectTest(event->pos(), true);
596 auto distanceToZone = zone->selectTest(event->pos(), true);
576 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone) && distanceToZone >= 0
597 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone) && distanceToZone >= 0
577 && distanceToZone < plot().selectionTolerance()) {
598 && distanceToZone < plot().selectionTolerance()) {
578 selectionZoneItemUnderCursor = zone;
599 selectionZoneItemUnderCursor = zone;
579 }
600 }
580 }
601 }
581
602
582 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
603 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
583 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
604 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
584
605
585 // Sets the appropriate cursor shape
606 // Sets the appropriate cursor shape
586 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
607 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
587 setCursor(cursorShape);
608 setCursor(cursorShape);
588
609
589 // Manages the hovered zone
610 // Manages the hovered zone
590 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
611 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
591 if (impl->m_HoveredZone) {
612 if (impl->m_HoveredZone) {
592 impl->m_HoveredZone->setHovered(false);
613 impl->m_HoveredZone->setHovered(false);
593 }
614 }
594 selectionZoneItemUnderCursor->setHovered(true);
615 selectionZoneItemUnderCursor->setHovered(true);
595 impl->m_HoveredZone = selectionZoneItemUnderCursor;
616 impl->m_HoveredZone = selectionZoneItemUnderCursor;
596 plot().replot(QCustomPlot::rpQueuedReplot);
617 plot().replot(QCustomPlot::rpQueuedReplot);
597 }
618 }
598 }
619 }
599 else {
620 else {
600 // There is no zone under the mouse or the interaction mode is not "selection zones"
621 // There is no zone under the mouse or the interaction mode is not "selection zones"
601 if (impl->m_HoveredZone) {
622 if (impl->m_HoveredZone) {
602 impl->m_HoveredZone->setHovered(false);
623 impl->m_HoveredZone->setHovered(false);
603 impl->m_HoveredZone = nullptr;
624 impl->m_HoveredZone = nullptr;
604 }
625 }
605
626
606 setCursor(Qt::ArrowCursor);
627 setCursor(Qt::ArrowCursor);
607 }
628 }
608
629
609 VisualizationDragWidget::mouseMoveEvent(event);
630 VisualizationDragWidget::mouseMoveEvent(event);
610 }
631 }
611
632
612 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
633 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
613 {
634 {
614 auto value = event->angleDelta().x() + event->angleDelta().y();
635 auto value = event->angleDelta().x() + event->angleDelta().y();
615 if (value != 0) {
636 if (value != 0) {
616
637
617 auto direction = value > 0 ? 1.0 : -1.0;
638 auto direction = value > 0 ? 1.0 : -1.0;
618 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
639 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
619 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
640 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
620 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
641 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
621
642
622 auto zoomOrientations = QFlags<Qt::Orientation>{};
643 auto zoomOrientations = QFlags<Qt::Orientation>{};
623 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
644 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
624 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
645 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
625
646
626 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
647 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
627
648
628 if (!isZoomX && !isZoomY) {
649 if (!isZoomX && !isZoomY) {
629 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
650 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
630 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
651 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
631
652
632 axis->setRange(axis->range() + diff);
653 axis->setRange(axis->range() + diff);
633
654
634 if (plot().noAntialiasingOnDrag()) {
655 if (plot().noAntialiasingOnDrag()) {
635 plot().setNotAntialiasedElements(QCP::aeAll);
656 plot().setNotAntialiasedElements(QCP::aeAll);
636 }
657 }
637
658
638 plot().replot(QCustomPlot::rpQueuedReplot);
659 plot().replot(QCustomPlot::rpQueuedReplot);
639 }
660 }
640 }
661 }
641 }
662 }
642
663
643 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
664 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
644 {
665 {
645 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
666 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
646 // Starts a zoom box
667 // Starts a zoom box
647 impl->startDrawingRect(event->pos(), plot());
668 impl->startDrawingRect(event->pos(), plot());
648 }
669 }
649 else if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
670 else if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
650 && impl->m_DrawingZone == nullptr) {
671 && impl->m_DrawingZone == nullptr) {
651 // Starts a new selection zone
672 // Starts a new selection zone
652 auto itemAtPos = plot().itemAt(event->pos(), true);
673 auto itemAtPos = plot().itemAt(event->pos(), true);
653 if (!itemAtPos) {
674 if (!itemAtPos) {
654 impl->startDrawingZone(event->pos(), plot());
675 impl->startDrawingZone(event->pos(), plot());
655 }
676 }
656 }
677 }
657 else if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::None) {
678 else if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::None) {
658 plot().setInteraction(QCP::iRangeDrag, true);
679 plot().setInteraction(QCP::iRangeDrag, true);
659 }
680 }
660
681
661 // Allows mouse panning only in default mode
682 // Allows mouse panning only in default mode
662 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
683 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
663 == SqpApplication::PlotsInteractionMode::None);
684 == SqpApplication::PlotsInteractionMode::None);
664
685
665 // Allows zone edition only in selection zone mode
686 // Allows zone edition only in selection zone mode
666 impl->setSelectionZonesEditionEnabled(sqpApp->plotsInteractionMode()
687 impl->setSelectionZonesEditionEnabled(sqpApp->plotsInteractionMode()
667 == SqpApplication::PlotsInteractionMode::SelectionZones);
688 == SqpApplication::PlotsInteractionMode::SelectionZones);
668
689
669 VisualizationDragWidget::mousePressEvent(event);
690 VisualizationDragWidget::mousePressEvent(event);
670 }
691 }
671
692
672 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
693 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
673 {
694 {
674 if (impl->m_DrawingZoomRect) {
695 if (impl->m_DrawingZoomRect) {
675
696
676 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
697 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
677 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
698 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
678
699
679 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
700 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
680 impl->m_DrawingZoomRect->bottomRight->coords().x()};
701 impl->m_DrawingZoomRect->bottomRight->coords().x()};
681
702
682 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
703 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
683 impl->m_DrawingZoomRect->bottomRight->coords().y()};
704 impl->m_DrawingZoomRect->bottomRight->coords().y()};
684
705
685 impl->removeDrawingRect(plot());
706 impl->removeDrawingRect(plot());
686
707
687 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
708 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
688 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
709 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
710 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
689 axisX->setRange(newAxisXRange);
711 axisX->setRange(newAxisXRange);
690 axisY->setRange(newAxisYRange);
712 axisY->setRange(newAxisYRange);
691
713
692 plot().replot(QCustomPlot::rpQueuedReplot);
714 plot().replot(QCustomPlot::rpQueuedReplot);
693 }
715 }
694 }
716 }
695
717
696 impl->endDrawingZone(plot());
718 impl->endDrawingZone(plot());
697
719
698 impl->m_IsCalibration = false;
720 impl->m_IsCalibration = false;
699 }
721 }
700
722
701 void VisualizationGraphWidget::onDataCacheVariableUpdated()
723 void VisualizationGraphWidget::onDataCacheVariableUpdated()
702 {
724 {
703 auto graphRange = ui->widget->xAxis->range();
725 auto graphRange = ui->widget->xAxis->range();
704 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
726 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
705
727
706 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
728 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
707 auto variable = variableEntry.first;
729 auto variable = variableEntry.first;
708 qCDebug(LOG_VisualizationGraphWidget())
730 qCDebug(LOG_VisualizationGraphWidget())
709 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
731 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
710 qCDebug(LOG_VisualizationGraphWidget())
732 qCDebug(LOG_VisualizationGraphWidget())
711 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
733 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
712 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
734 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
713 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
735 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
714 }
736 }
715 }
737 }
716 }
738 }
717
739
718 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
740 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
719 const SqpRange &range)
741 const SqpRange &range)
720 {
742 {
721 auto it = impl->m_VariableToPlotMultiMap.find(variable);
743 auto it = impl->m_VariableToPlotMultiMap.find(variable);
722 if (it != impl->m_VariableToPlotMultiMap.end()) {
744 if (it != impl->m_VariableToPlotMultiMap.end()) {
723 impl->updateData(it->second, variable->dataSeries(), range);
745 impl->updateData(it->second, variable->dataSeries(), range);
724 }
746 }
725 }
747 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved

Status change > Approved

You need to be logged in to leave comments. Login now