##// END OF EJS Templates
Multi selection improvements
trabillard -
r1119:8c4e23ece78b
parent child
Show More
@@ -1,938 +1,946
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/VisualizationSelectionZoneManager.h"
8 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationWidget.h"
9 #include "Visualization/VisualizationWidget.h"
10 #include "Visualization/VisualizationZoneWidget.h"
10 #include "Visualization/VisualizationZoneWidget.h"
11 #include "ui_VisualizationGraphWidget.h"
11 #include "ui_VisualizationGraphWidget.h"
12
12
13 #include <Actions/ActionsGuiController.h>
13 #include <Actions/ActionsGuiController.h>
14 #include <Common/MimeTypesDef.h>
14 #include <Common/MimeTypesDef.h>
15 #include <Data/ArrayData.h>
15 #include <Data/ArrayData.h>
16 #include <Data/IDataSeries.h>
16 #include <Data/IDataSeries.h>
17 #include <Data/SpectrogramSeries.h>
17 #include <Data/SpectrogramSeries.h>
18 #include <DragAndDrop/DragDropGuiController.h>
18 #include <DragAndDrop/DragDropGuiController.h>
19 #include <Settings/SqpSettingsDefs.h>
19 #include <Settings/SqpSettingsDefs.h>
20 #include <SqpApplication.h>
20 #include <SqpApplication.h>
21 #include <Time/TimeController.h>
21 #include <Time/TimeController.h>
22 #include <Variable/Variable.h>
22 #include <Variable/Variable.h>
23 #include <Variable/VariableController.h>
23 #include <Variable/VariableController.h>
24
24
25 #include <unordered_map>
25 #include <unordered_map>
26
26
27 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
27 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
28
28
29 namespace {
29 namespace {
30
30
31 /// Key pressed to enable drag&drop in all modes
31 /// Key pressed to enable drag&drop in all modes
32 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
32 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
33
33
34 /// Key pressed to enable zoom on horizontal axis
34 /// Key pressed to enable zoom on horizontal axis
35 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
35 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
36
36
37 /// Key pressed to enable zoom on vertical axis
37 /// Key pressed to enable zoom on vertical axis
38 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
38 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
39
39
40 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
40 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
41 const auto PAN_SPEED = 5;
41 const auto PAN_SPEED = 5;
42
42
43 /// Key pressed to enable a calibration pan
43 /// Key pressed to enable a calibration pan
44 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
44 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
45
45
46 /// Key pressed to enable multi selection of selection zones
46 /// Key pressed to enable multi selection of selection zones
47 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
47 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
48
48
49 /// Minimum size for the zoom box, in percentage of the axis range
49 /// Minimum size for the zoom box, in percentage of the axis range
50 const auto ZOOM_BOX_MIN_SIZE = 0.8;
50 const auto ZOOM_BOX_MIN_SIZE = 0.8;
51
51
52 /// Format of the dates appearing in the label of a cursor
52 /// Format of the dates appearing in the label of a cursor
53 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
53 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
54
54
55 } // namespace
55 } // namespace
56
56
57 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
57 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
58
58
59 explicit VisualizationGraphWidgetPrivate(const QString &name)
59 explicit VisualizationGraphWidgetPrivate(const QString &name)
60 : m_Name{name},
60 : m_Name{name},
61 m_DoAcquisition{true},
61 m_DoAcquisition{true},
62 m_IsCalibration{false},
62 m_IsCalibration{false},
63 m_RenderingDelegate{nullptr}
63 m_RenderingDelegate{nullptr}
64 {
64 {
65 }
65 }
66
66
67 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
67 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
68 const SqpRange &range)
68 const SqpRange &range)
69 {
69 {
70 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
70 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
71
71
72 // Prevents that data has changed to update rendering
72 // Prevents that data has changed to update rendering
73 m_RenderingDelegate->onPlotUpdated();
73 m_RenderingDelegate->onPlotUpdated();
74 }
74 }
75
75
76 QString m_Name;
76 QString m_Name;
77 // 1 variable -> n qcpplot
77 // 1 variable -> n qcpplot
78 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
78 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
79 bool m_DoAcquisition;
79 bool m_DoAcquisition;
80 bool m_IsCalibration;
80 bool m_IsCalibration;
81 /// Delegate used to attach rendering features to the plot
81 /// Delegate used to attach rendering features to the plot
82 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
82 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
83
83
84 QCPItemRect *m_DrawingZoomRect = nullptr;
84 QCPItemRect *m_DrawingZoomRect = nullptr;
85 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
85 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
86
86
87 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
87 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
88 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
88 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
89
89
90 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
90 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
91 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
91 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
92 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
92 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
93
93
94 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
94 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
95
95
96 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
96 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
97 {
97 {
98 removeDrawingRect(plot);
98 removeDrawingRect(plot);
99
99
100 auto axisPos = posToAxisPos(pos, plot);
100 auto axisPos = posToAxisPos(pos, plot);
101
101
102 m_DrawingZoomRect = new QCPItemRect{&plot};
102 m_DrawingZoomRect = new QCPItemRect{&plot};
103 QPen p;
103 QPen p;
104 p.setWidth(2);
104 p.setWidth(2);
105 m_DrawingZoomRect->setPen(p);
105 m_DrawingZoomRect->setPen(p);
106
106
107 m_DrawingZoomRect->topLeft->setCoords(axisPos);
107 m_DrawingZoomRect->topLeft->setCoords(axisPos);
108 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
108 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
109 }
109 }
110
110
111 void removeDrawingRect(QCustomPlot &plot)
111 void removeDrawingRect(QCustomPlot &plot)
112 {
112 {
113 if (m_DrawingZoomRect) {
113 if (m_DrawingZoomRect) {
114 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
114 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
115 m_DrawingZoomRect = nullptr;
115 m_DrawingZoomRect = nullptr;
116 plot.replot(QCustomPlot::rpQueuedReplot);
116 plot.replot(QCustomPlot::rpQueuedReplot);
117 }
117 }
118 }
118 }
119
119
120 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
120 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
121 {
121 {
122 endDrawingZone(graph);
122 endDrawingZone(graph);
123
123
124 auto axisPos = posToAxisPos(pos, graph->plot());
124 auto axisPos = posToAxisPos(pos, graph->plot());
125
125
126 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
126 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
127 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
127 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
128 m_DrawingZone->setEditionEnabled(false);
128 m_DrawingZone->setEditionEnabled(false);
129 }
129 }
130
130
131 void endDrawingZone(VisualizationGraphWidget *graph)
131 void endDrawingZone(VisualizationGraphWidget *graph)
132 {
132 {
133 if (m_DrawingZone) {
133 if (m_DrawingZone) {
134 auto drawingZoneRange = m_DrawingZone->range();
134 auto drawingZoneRange = m_DrawingZone->range();
135 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
135 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
136 m_DrawingZone->setEditionEnabled(true);
136 m_DrawingZone->setEditionEnabled(true);
137 addSelectionZone(m_DrawingZone);
137 addSelectionZone(m_DrawingZone);
138 }
138 }
139 else {
139 else {
140 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
140 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
141 }
141 }
142
142
143 graph->plot().replot(QCustomPlot::rpQueuedReplot);
143 graph->plot().replot(QCustomPlot::rpQueuedReplot);
144 m_DrawingZone = nullptr;
144 m_DrawingZone = nullptr;
145 }
145 }
146 }
146 }
147
147
148 void setSelectionZonesEditionEnabled(bool value)
148 void setSelectionZonesEditionEnabled(bool value)
149 {
149 {
150 for (auto s : m_SelectionZones) {
150 for (auto s : m_SelectionZones) {
151 s->setEditionEnabled(value);
151 s->setEditionEnabled(value);
152 }
152 }
153 }
153 }
154
154
155 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
155 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
156
156
157 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
157 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
158 const QCustomPlot &plot) const
158 const QCustomPlot &plot) const
159 {
159 {
160 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
160 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
161 auto minDistanceToZone = -1;
161 auto minDistanceToZone = -1;
162 for (auto zone : m_SelectionZones) {
162 for (auto zone : m_SelectionZones) {
163 auto distanceToZone = zone->selectTest(pos, false);
163 auto distanceToZone = zone->selectTest(pos, false);
164 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
164 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
165 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
165 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
166 selectionZoneItemUnderCursor = zone;
166 selectionZoneItemUnderCursor = zone;
167 }
167 }
168 }
168 }
169
169
170 return selectionZoneItemUnderCursor;
170 return selectionZoneItemUnderCursor;
171 }
171 }
172
172
173 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
173 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
174 {
174 {
175 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
175 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
176 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
176 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
177 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
177 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
178 }
178 }
179
179
180 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
180 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
181 {
181 {
182 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
182 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
183 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
183 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
184 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
184 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
185 }
185 }
186 };
186 };
187
187
188 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
188 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
189 : VisualizationDragWidget{parent},
189 : VisualizationDragWidget{parent},
190 ui{new Ui::VisualizationGraphWidget},
190 ui{new Ui::VisualizationGraphWidget},
191 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
191 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
192 {
192 {
193 ui->setupUi(this);
193 ui->setupUi(this);
194
194
195 // 'Close' options : widget is deleted when closed
195 // 'Close' options : widget is deleted when closed
196 setAttribute(Qt::WA_DeleteOnClose);
196 setAttribute(Qt::WA_DeleteOnClose);
197
197
198 // Set qcpplot properties :
198 // Set qcpplot properties :
199 // - zoom is enabled
199 // - zoom is enabled
200 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
200 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
201 ui->widget->setInteractions(QCP::iRangeZoom);
201 ui->widget->setInteractions(QCP::iRangeZoom);
202 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
202 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
203
203
204 // The delegate must be initialized after the ui as it uses the plot
204 // The delegate must be initialized after the ui as it uses the plot
205 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
205 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
206
206
207 // Init the cursors
207 // Init the cursors
208 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
208 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
209 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
209 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
210 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
210 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
211 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
211 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
212
212
213 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
213 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
214 connect(ui->widget, &QCustomPlot::mouseRelease, this,
214 connect(ui->widget, &QCustomPlot::mouseRelease, this,
215 &VisualizationGraphWidget::onMouseRelease);
215 &VisualizationGraphWidget::onMouseRelease);
216 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
216 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
217 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
217 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
218 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
218 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
219 &VisualizationGraphWidget::onMouseDoubleClick);
219 &VisualizationGraphWidget::onMouseDoubleClick);
220 connect(
220 connect(
221 ui->widget->xAxis,
221 ui->widget->xAxis,
222 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
222 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
223 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
223 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
224
224
225 // Activates menu when right clicking on the graph
225 // Activates menu when right clicking on the graph
226 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
226 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
227 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
227 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
228 &VisualizationGraphWidget::onGraphMenuRequested);
228 &VisualizationGraphWidget::onGraphMenuRequested);
229
229
230 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
230 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
231 &VariableController::onRequestDataLoading);
231 &VariableController::onRequestDataLoading);
232
232
233 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
233 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
234 &VisualizationGraphWidget::onUpdateVarDisplaying);
234 &VisualizationGraphWidget::onUpdateVarDisplaying);
235
235
236 #ifdef Q_OS_MAC
236 #ifdef Q_OS_MAC
237 plot().setPlottingHint(QCP::phFastPolylines, true);
237 plot().setPlottingHint(QCP::phFastPolylines, true);
238 #endif
238 #endif
239 }
239 }
240
240
241
241
242 VisualizationGraphWidget::~VisualizationGraphWidget()
242 VisualizationGraphWidget::~VisualizationGraphWidget()
243 {
243 {
244 delete ui;
244 delete ui;
245 }
245 }
246
246
247 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
247 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
248 {
248 {
249 auto parent = parentWidget();
249 auto parent = parentWidget();
250 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
250 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
251 parent = parent->parentWidget();
251 parent = parent->parentWidget();
252 }
252 }
253
253
254 return qobject_cast<VisualizationZoneWidget *>(parent);
254 return qobject_cast<VisualizationZoneWidget *>(parent);
255 }
255 }
256
256
257 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
257 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
258 {
258 {
259 auto parent = parentWidget();
259 auto parent = parentWidget();
260 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
260 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
261 parent = parent->parentWidget();
261 parent = parent->parentWidget();
262 }
262 }
263
263
264 return qobject_cast<VisualizationWidget *>(parent);
264 return qobject_cast<VisualizationWidget *>(parent);
265 }
265 }
266
266
267 void VisualizationGraphWidget::enableAcquisition(bool enable)
267 void VisualizationGraphWidget::enableAcquisition(bool enable)
268 {
268 {
269 impl->m_DoAcquisition = enable;
269 impl->m_DoAcquisition = enable;
270 }
270 }
271
271
272 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
272 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
273 {
273 {
274 // Uses delegate to create the qcpplot components according to the variable
274 // Uses delegate to create the qcpplot components according to the variable
275 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
275 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
276
276
277 if (auto dataSeries = variable->dataSeries()) {
277 if (auto dataSeries = variable->dataSeries()) {
278 // Set axes properties according to the units of the data series
278 // Set axes properties according to the units of the data series
279 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
279 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
280
280
281 // Sets rendering properties for the new plottables
281 // Sets rendering properties for the new plottables
282 // Warning: this method must be called after setAxesProperties(), as it can access to some
282 // Warning: this method must be called after setAxesProperties(), as it can access to some
283 // axes properties that have to be initialized
283 // axes properties that have to be initialized
284 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
284 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
285 }
285 }
286
286
287 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
287 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
288
288
289 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
289 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
290
290
291 this->enableAcquisition(false);
291 this->enableAcquisition(false);
292 this->setGraphRange(range);
292 this->setGraphRange(range);
293 this->enableAcquisition(true);
293 this->enableAcquisition(true);
294
294
295 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
295 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
296
296
297 emit variableAdded(variable);
297 emit variableAdded(variable);
298 }
298 }
299
299
300 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
300 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
301 {
301 {
302 // Each component associated to the variable :
302 // Each component associated to the variable :
303 // - is removed from qcpplot (which deletes it)
303 // - is removed from qcpplot (which deletes it)
304 // - is no longer referenced in the map
304 // - is no longer referenced in the map
305 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
305 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
306 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
306 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
307 emit variableAboutToBeRemoved(variable);
307 emit variableAboutToBeRemoved(variable);
308
308
309 auto &plottablesMap = variableIt->second;
309 auto &plottablesMap = variableIt->second;
310
310
311 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
311 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
312 plottableIt != plottableEnd;) {
312 plottableIt != plottableEnd;) {
313 ui->widget->removePlottable(plottableIt->second);
313 ui->widget->removePlottable(plottableIt->second);
314 plottableIt = plottablesMap.erase(plottableIt);
314 plottableIt = plottablesMap.erase(plottableIt);
315 }
315 }
316
316
317 impl->m_VariableToPlotMultiMap.erase(variableIt);
317 impl->m_VariableToPlotMultiMap.erase(variableIt);
318 }
318 }
319
319
320 // Updates graph
320 // Updates graph
321 ui->widget->replot();
321 ui->widget->replot();
322 }
322 }
323
323
324 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
324 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
325 {
325 {
326 auto variables = QList<std::shared_ptr<Variable> >{};
326 auto variables = QList<std::shared_ptr<Variable> >{};
327 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
327 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
328 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
328 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
329 variables << it->first;
329 variables << it->first;
330 }
330 }
331
331
332 return variables;
332 return variables;
333 }
333 }
334
334
335 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
335 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
336 {
336 {
337 if (!variable) {
337 if (!variable) {
338 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
338 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
339 return;
339 return;
340 }
340 }
341
341
342 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
342 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
343 }
343 }
344
344
345 SqpRange VisualizationGraphWidget::graphRange() const noexcept
345 SqpRange VisualizationGraphWidget::graphRange() const noexcept
346 {
346 {
347 auto graphRange = ui->widget->xAxis->range();
347 auto graphRange = ui->widget->xAxis->range();
348 return SqpRange{graphRange.lower, graphRange.upper};
348 return SqpRange{graphRange.lower, graphRange.upper};
349 }
349 }
350
350
351 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
351 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
352 {
352 {
353 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
353 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
354 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
354 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
355 ui->widget->replot();
355 ui->widget->replot();
356 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
356 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
357 }
357 }
358
358
359 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
359 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
360 {
360 {
361 QVector<SqpRange> ranges;
361 QVector<SqpRange> ranges;
362 for (auto zone : impl->m_SelectionZones) {
362 for (auto zone : impl->m_SelectionZones) {
363 ranges << zone->range();
363 ranges << zone->range();
364 }
364 }
365
365
366 return ranges;
366 return ranges;
367 }
367 }
368
368
369 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
369 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
370 {
370 {
371 for (const auto &range : ranges) {
371 for (const auto &range : ranges) {
372 // note: ownership is transfered to QCustomPlot
372 // note: ownership is transfered to QCustomPlot
373 auto zone = new VisualizationSelectionZoneItem(&plot());
373 auto zone = new VisualizationSelectionZoneItem(&plot());
374 zone->setRange(range.m_TStart, range.m_TEnd);
374 zone->setRange(range.m_TStart, range.m_TEnd);
375 impl->addSelectionZone(zone);
375 impl->addSelectionZone(zone);
376 }
376 }
377
377
378 plot().replot(QCustomPlot::rpQueuedReplot);
378 plot().replot(QCustomPlot::rpQueuedReplot);
379 }
379 }
380
380
381 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
381 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
382 {
382 {
383 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
383 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
384
384
385 if (impl->m_HoveredZone == selectionZone) {
385 if (impl->m_HoveredZone == selectionZone) {
386 impl->m_HoveredZone = nullptr;
386 impl->m_HoveredZone = nullptr;
387 setCursor(Qt::ArrowCursor);
387 setCursor(Qt::ArrowCursor);
388 }
388 }
389
389
390 impl->m_SelectionZones.removeAll(selectionZone);
390 impl->m_SelectionZones.removeAll(selectionZone);
391 plot().removeItem(selectionZone);
391 plot().removeItem(selectionZone);
392 plot().replot(QCustomPlot::rpQueuedReplot);
392 plot().replot(QCustomPlot::rpQueuedReplot);
393 }
393 }
394
394
395 void VisualizationGraphWidget::undoZoom()
395 void VisualizationGraphWidget::undoZoom()
396 {
396 {
397 auto zoom = impl->m_ZoomStack.pop();
397 auto zoom = impl->m_ZoomStack.pop();
398 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
398 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
399 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
399 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
400
400
401 axisX->setRange(zoom.first);
401 axisX->setRange(zoom.first);
402 axisY->setRange(zoom.second);
402 axisY->setRange(zoom.second);
403
403
404 plot().replot(QCustomPlot::rpQueuedReplot);
404 plot().replot(QCustomPlot::rpQueuedReplot);
405 }
405 }
406
406
407 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
407 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
408 {
408 {
409 if (visitor) {
409 if (visitor) {
410 visitor->visit(this);
410 visitor->visit(this);
411 }
411 }
412 else {
412 else {
413 qCCritical(LOG_VisualizationGraphWidget())
413 qCCritical(LOG_VisualizationGraphWidget())
414 << tr("Can't visit widget : the visitor is null");
414 << tr("Can't visit widget : the visitor is null");
415 }
415 }
416 }
416 }
417
417
418 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
418 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
419 {
419 {
420 auto isSpectrogram = [](const auto &variable) {
420 auto isSpectrogram = [](const auto &variable) {
421 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
421 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
422 };
422 };
423
423
424 // - A spectrogram series can't be dropped on graph with existing plottables
424 // - A spectrogram series can't be dropped on graph with existing plottables
425 // - No data series can be dropped on graph with existing spectrogram series
425 // - No data series can be dropped on graph with existing spectrogram series
426 return isSpectrogram(variable)
426 return isSpectrogram(variable)
427 ? impl->m_VariableToPlotMultiMap.empty()
427 ? impl->m_VariableToPlotMultiMap.empty()
428 : std::none_of(
428 : std::none_of(
429 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
429 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
430 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
430 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
431 }
431 }
432
432
433 bool VisualizationGraphWidget::contains(const Variable &variable) const
433 bool VisualizationGraphWidget::contains(const Variable &variable) const
434 {
434 {
435 // Finds the variable among the keys of the map
435 // Finds the variable among the keys of the map
436 auto variablePtr = &variable;
436 auto variablePtr = &variable;
437 auto findVariable
437 auto findVariable
438 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
438 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
439
439
440 auto end = impl->m_VariableToPlotMultiMap.cend();
440 auto end = impl->m_VariableToPlotMultiMap.cend();
441 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
441 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
442 return it != end;
442 return it != end;
443 }
443 }
444
444
445 QString VisualizationGraphWidget::name() const
445 QString VisualizationGraphWidget::name() const
446 {
446 {
447 return impl->m_Name;
447 return impl->m_Name;
448 }
448 }
449
449
450 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
450 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
451 {
451 {
452 auto mimeData = new QMimeData;
452 auto mimeData = new QMimeData;
453
453
454 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
454 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
455 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
455 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
456 && selectionZoneItemUnderCursor) {
456 && selectionZoneItemUnderCursor) {
457 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
457 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
458 selectionZoneItemUnderCursor->range()));
458 selectionZoneItemUnderCursor->range()));
459 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
459 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
460 selectionZoneItemUnderCursor->range()));
460 selectionZoneItemUnderCursor->range()));
461 }
461 }
462 else {
462 else {
463 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
463 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
464
464
465 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
465 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
466 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
466 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
467 }
467 }
468
468
469 return mimeData;
469 return mimeData;
470 }
470 }
471
471
472 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
472 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
473 {
473 {
474 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
474 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
475 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
475 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
476 && selectionZoneItemUnderCursor) {
476 && selectionZoneItemUnderCursor) {
477
477
478 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
478 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
479 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
479 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
480
480
481 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
481 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
482 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
482 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
483 .toSize();
483 .toSize();
484
484
485 auto pixmap = QPixmap(zoneSize);
485 auto pixmap = QPixmap(zoneSize);
486 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
486 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
487
487
488 return pixmap;
488 return pixmap;
489 }
489 }
490
490
491 return QPixmap();
491 return QPixmap();
492 }
492 }
493
493
494 bool VisualizationGraphWidget::isDragAllowed() const
494 bool VisualizationGraphWidget::isDragAllowed() const
495 {
495 {
496 return true;
496 return true;
497 }
497 }
498
498
499 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
499 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
500 {
500 {
501 if (highlighted) {
501 if (highlighted) {
502 plot().setBackground(QBrush(QColor("#BBD5EE")));
502 plot().setBackground(QBrush(QColor("#BBD5EE")));
503 }
503 }
504 else {
504 else {
505 plot().setBackground(QBrush(Qt::white));
505 plot().setBackground(QBrush(Qt::white));
506 }
506 }
507
507
508 plot().update();
508 plot().update();
509 }
509 }
510
510
511 void VisualizationGraphWidget::addVerticalCursor(double time)
511 void VisualizationGraphWidget::addVerticalCursor(double time)
512 {
512 {
513 impl->m_VerticalCursor->setPosition(time);
513 impl->m_VerticalCursor->setPosition(time);
514 impl->m_VerticalCursor->setVisible(true);
514 impl->m_VerticalCursor->setVisible(true);
515
515
516 auto text
516 auto text
517 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
517 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
518 impl->m_VerticalCursor->setLabelText(text);
518 impl->m_VerticalCursor->setLabelText(text);
519 }
519 }
520
520
521 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
521 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
522 {
522 {
523 impl->m_VerticalCursor->setAbsolutePosition(position);
523 impl->m_VerticalCursor->setAbsolutePosition(position);
524 impl->m_VerticalCursor->setVisible(true);
524 impl->m_VerticalCursor->setVisible(true);
525
525
526 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
526 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
527 auto text
527 auto text
528 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
528 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
529 impl->m_VerticalCursor->setLabelText(text);
529 impl->m_VerticalCursor->setLabelText(text);
530 }
530 }
531
531
532 void VisualizationGraphWidget::removeVerticalCursor()
532 void VisualizationGraphWidget::removeVerticalCursor()
533 {
533 {
534 impl->m_VerticalCursor->setVisible(false);
534 impl->m_VerticalCursor->setVisible(false);
535 plot().replot(QCustomPlot::rpQueuedReplot);
535 plot().replot(QCustomPlot::rpQueuedReplot);
536 }
536 }
537
537
538 void VisualizationGraphWidget::addHorizontalCursor(double value)
538 void VisualizationGraphWidget::addHorizontalCursor(double value)
539 {
539 {
540 impl->m_HorizontalCursor->setPosition(value);
540 impl->m_HorizontalCursor->setPosition(value);
541 impl->m_HorizontalCursor->setVisible(true);
541 impl->m_HorizontalCursor->setVisible(true);
542 impl->m_HorizontalCursor->setLabelText(QString::number(value));
542 impl->m_HorizontalCursor->setLabelText(QString::number(value));
543 }
543 }
544
544
545 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
545 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
546 {
546 {
547 impl->m_HorizontalCursor->setAbsolutePosition(position);
547 impl->m_HorizontalCursor->setAbsolutePosition(position);
548 impl->m_HorizontalCursor->setVisible(true);
548 impl->m_HorizontalCursor->setVisible(true);
549
549
550 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
550 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
551 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
551 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
552 }
552 }
553
553
554 void VisualizationGraphWidget::removeHorizontalCursor()
554 void VisualizationGraphWidget::removeHorizontalCursor()
555 {
555 {
556 impl->m_HorizontalCursor->setVisible(false);
556 impl->m_HorizontalCursor->setVisible(false);
557 plot().replot(QCustomPlot::rpQueuedReplot);
557 plot().replot(QCustomPlot::rpQueuedReplot);
558 }
558 }
559
559
560 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
560 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
561 {
561 {
562 Q_UNUSED(event);
562 Q_UNUSED(event);
563
563
564 // Prevents that all variables will be removed from graph when it will be closed
564 // Prevents that all variables will be removed from graph when it will be closed
565 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
565 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
566 emit variableAboutToBeRemoved(variableEntry.first);
566 emit variableAboutToBeRemoved(variableEntry.first);
567 }
567 }
568 }
568 }
569
569
570 void VisualizationGraphWidget::enterEvent(QEvent *event)
570 void VisualizationGraphWidget::enterEvent(QEvent *event)
571 {
571 {
572 Q_UNUSED(event);
572 Q_UNUSED(event);
573 impl->m_RenderingDelegate->showGraphOverlay(true);
573 impl->m_RenderingDelegate->showGraphOverlay(true);
574 }
574 }
575
575
576 void VisualizationGraphWidget::leaveEvent(QEvent *event)
576 void VisualizationGraphWidget::leaveEvent(QEvent *event)
577 {
577 {
578 Q_UNUSED(event);
578 Q_UNUSED(event);
579 impl->m_RenderingDelegate->showGraphOverlay(false);
579 impl->m_RenderingDelegate->showGraphOverlay(false);
580
580
581 if (auto parentZone = parentZoneWidget()) {
581 if (auto parentZone = parentZoneWidget()) {
582 parentZone->notifyMouseLeaveGraph(this);
582 parentZone->notifyMouseLeaveGraph(this);
583 }
583 }
584 else {
584 else {
585 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
585 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
586 }
586 }
587
587
588 if (impl->m_HoveredZone) {
588 if (impl->m_HoveredZone) {
589 impl->m_HoveredZone->setHovered(false);
589 impl->m_HoveredZone->setHovered(false);
590 impl->m_HoveredZone = nullptr;
590 impl->m_HoveredZone = nullptr;
591 }
591 }
592 }
592 }
593
593
594 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
594 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
595 {
595 {
596 return *ui->widget;
596 return *ui->widget;
597 }
597 }
598
598
599 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
599 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
600 {
600 {
601 QMenu graphMenu{};
601 QMenu graphMenu{};
602
602
603 // Iterates on variables (unique keys)
603 // Iterates on variables (unique keys)
604 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
604 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
605 end = impl->m_VariableToPlotMultiMap.cend();
605 end = impl->m_VariableToPlotMultiMap.cend();
606 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
606 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
607 // 'Remove variable' action
607 // 'Remove variable' action
608 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
608 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
609 [ this, var = it->first ]() { removeVariable(var); });
609 [ this, var = it->first ]() { removeVariable(var); });
610 }
610 }
611
611
612 if (!impl->m_ZoomStack.isEmpty()) {
612 if (!impl->m_ZoomStack.isEmpty()) {
613 if (!graphMenu.isEmpty()) {
613 if (!graphMenu.isEmpty()) {
614 graphMenu.addSeparator();
614 graphMenu.addSeparator();
615 }
615 }
616
616
617 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
617 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
618 }
618 }
619
619
620 // Selection Zone Actions
620 // Selection Zone Actions
621 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
621 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
622 if (selectionZoneItem) {
622 if (selectionZoneItem) {
623 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
623 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
624 selectedItems.removeAll(selectionZoneItem);
624 selectedItems.removeAll(selectionZoneItem);
625 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
625 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
626
626
627 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
627 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
628 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
628 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
629 graphMenu.addSeparator();
629 graphMenu.addSeparator();
630 }
630 }
631
631
632 QHash<QString, QMenu *> subMenus;
632 QHash<QString, QMenu *> subMenus;
633 QHash<QString, bool> subMenusEnabled;
633 QHash<QString, bool> subMenusEnabled;
634
634
635 for (auto zoneAction : zoneActions) {
635 for (auto zoneAction : zoneActions) {
636
636
637 auto isEnabled = zoneAction->isEnabled(selectedItems);
637 auto isEnabled = zoneAction->isEnabled(selectedItems);
638
638
639 auto menu = &graphMenu;
639 auto menu = &graphMenu;
640 for (auto subMenuName : zoneAction->subMenuList()) {
640 for (auto subMenuName : zoneAction->subMenuList()) {
641 if (!subMenus.contains(subMenuName)) {
641 if (!subMenus.contains(subMenuName)) {
642 menu = menu->addMenu(subMenuName);
642 menu = menu->addMenu(subMenuName);
643 subMenus[subMenuName] = menu;
643 subMenus[subMenuName] = menu;
644 subMenusEnabled[subMenuName] = isEnabled;
644 subMenusEnabled[subMenuName] = isEnabled;
645 }
645 }
646 else {
646 else {
647 menu = subMenus.value(subMenuName);
647 menu = subMenus.value(subMenuName);
648 if (isEnabled) {
648 if (isEnabled) {
649 // The sub menu is enabled if at least one of its actions is enabled
649 // The sub menu is enabled if at least one of its actions is enabled
650 subMenusEnabled[subMenuName] = true;
650 subMenusEnabled[subMenuName] = true;
651 }
651 }
652 }
652 }
653 }
653 }
654
654
655 auto action = menu->addAction(zoneAction->name());
655 auto action = menu->addAction(zoneAction->name());
656 action->setEnabled(isEnabled);
656 action->setEnabled(isEnabled);
657 action->setShortcut(zoneAction->displayedShortcut());
657 action->setShortcut(zoneAction->displayedShortcut());
658 QObject::connect(action, &QAction::triggered,
658 QObject::connect(action, &QAction::triggered,
659 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
659 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
660 }
660 }
661
661
662 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
662 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
663 it.value()->setEnabled(subMenusEnabled[it.key()]);
663 it.value()->setEnabled(subMenusEnabled[it.key()]);
664 }
664 }
665 }
665 }
666
666
667 if (!graphMenu.isEmpty()) {
667 if (!graphMenu.isEmpty()) {
668 graphMenu.exec(QCursor::pos());
668 graphMenu.exec(QCursor::pos());
669 }
669 }
670 }
670 }
671
671
672 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
672 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
673 {
673 {
674 qCDebug(LOG_VisualizationGraphWidget())
674 qCDebug(LOG_VisualizationGraphWidget())
675 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
675 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
676 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
676 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
677
677
678 auto graphRange = SqpRange{t1.lower, t1.upper};
678 auto graphRange = SqpRange{t1.lower, t1.upper};
679 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
679 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
680
680
681 if (impl->m_DoAcquisition) {
681 if (impl->m_DoAcquisition) {
682 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
682 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
683
683
684 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
684 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
685 end = impl->m_VariableToPlotMultiMap.end();
685 end = impl->m_VariableToPlotMultiMap.end();
686 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
686 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
687 variableUnderGraphVector.push_back(it->first);
687 variableUnderGraphVector.push_back(it->first);
688 }
688 }
689 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
689 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
690 !impl->m_IsCalibration);
690 !impl->m_IsCalibration);
691
691
692 if (!impl->m_IsCalibration) {
692 if (!impl->m_IsCalibration) {
693 qCDebug(LOG_VisualizationGraphWidget())
693 qCDebug(LOG_VisualizationGraphWidget())
694 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
694 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
695 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
695 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
696 emit synchronize(graphRange, oldGraphRange);
696 emit synchronize(graphRange, oldGraphRange);
697 }
697 }
698 }
698 }
699
699
700 auto pos = mapFromGlobal(QCursor::pos());
700 auto pos = mapFromGlobal(QCursor::pos());
701 auto axisPos = impl->posToAxisPos(pos, plot());
701 auto axisPos = impl->posToAxisPos(pos, plot());
702 if (auto parentZone = parentZoneWidget()) {
702 if (auto parentZone = parentZoneWidget()) {
703 if (impl->pointIsInAxisRect(axisPos, plot())) {
703 if (impl->pointIsInAxisRect(axisPos, plot())) {
704 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
704 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
705 }
705 }
706 else {
706 else {
707 parentZone->notifyMouseLeaveGraph(this);
707 parentZone->notifyMouseLeaveGraph(this);
708 }
708 }
709 }
709 }
710 else {
710 else {
711 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
711 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
712 }
712 }
713 }
713 }
714
714
715 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
715 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
716 {
716 {
717 impl->m_RenderingDelegate->onMouseDoubleClick(event);
717 impl->m_RenderingDelegate->onMouseDoubleClick(event);
718 }
718 }
719
719
720 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
720 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
721 {
721 {
722 // Handles plot rendering when mouse is moving
722 // Handles plot rendering when mouse is moving
723 impl->m_RenderingDelegate->onMouseMove(event);
723 impl->m_RenderingDelegate->onMouseMove(event);
724
724
725 auto axisPos = impl->posToAxisPos(event->pos(), plot());
725 auto axisPos = impl->posToAxisPos(event->pos(), plot());
726
726
727 // Zoom box and zone drawing
727 // Zoom box and zone drawing
728 if (impl->m_DrawingZoomRect) {
728 if (impl->m_DrawingZoomRect) {
729 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
729 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
730 }
730 }
731 else if (impl->m_DrawingZone) {
731 else if (impl->m_DrawingZone) {
732 impl->m_DrawingZone->setEnd(axisPos.x());
732 impl->m_DrawingZone->setEnd(axisPos.x());
733 }
733 }
734
734
735 // Cursor
735 // Cursor
736 if (auto parentZone = parentZoneWidget()) {
736 if (auto parentZone = parentZoneWidget()) {
737 if (impl->pointIsInAxisRect(axisPos, plot())) {
737 if (impl->pointIsInAxisRect(axisPos, plot())) {
738 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
738 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
739 }
739 }
740 else {
740 else {
741 parentZone->notifyMouseLeaveGraph(this);
741 parentZone->notifyMouseLeaveGraph(this);
742 }
742 }
743 }
743 }
744 else {
744 else {
745 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
745 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
746 }
746 }
747
747
748 // Search for the selection zone under the mouse
748 // Search for the selection zone under the mouse
749 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
749 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
750 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
750 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
751 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
751 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
752
752
753 // Sets the appropriate cursor shape
753 // Sets the appropriate cursor shape
754 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
754 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
755 setCursor(cursorShape);
755 setCursor(cursorShape);
756
756
757 // Manages the hovered zone
757 // Manages the hovered zone
758 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
758 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
759 if (impl->m_HoveredZone) {
759 if (impl->m_HoveredZone) {
760 impl->m_HoveredZone->setHovered(false);
760 impl->m_HoveredZone->setHovered(false);
761 }
761 }
762 selectionZoneItemUnderCursor->setHovered(true);
762 selectionZoneItemUnderCursor->setHovered(true);
763 impl->m_HoveredZone = selectionZoneItemUnderCursor;
763 impl->m_HoveredZone = selectionZoneItemUnderCursor;
764 plot().replot(QCustomPlot::rpQueuedReplot);
764 plot().replot(QCustomPlot::rpQueuedReplot);
765 }
765 }
766 }
766 }
767 else {
767 else {
768 // There is no zone under the mouse or the interaction mode is not "selection zones"
768 // There is no zone under the mouse or the interaction mode is not "selection zones"
769 if (impl->m_HoveredZone) {
769 if (impl->m_HoveredZone) {
770 impl->m_HoveredZone->setHovered(false);
770 impl->m_HoveredZone->setHovered(false);
771 impl->m_HoveredZone = nullptr;
771 impl->m_HoveredZone = nullptr;
772 }
772 }
773
773
774 setCursor(Qt::ArrowCursor);
774 setCursor(Qt::ArrowCursor);
775 }
775 }
776
776
777 impl->m_HasMovedMouse = true;
777 impl->m_HasMovedMouse = true;
778 VisualizationDragWidget::mouseMoveEvent(event);
778 VisualizationDragWidget::mouseMoveEvent(event);
779 }
779 }
780
780
781 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
781 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
782 {
782 {
783 auto value = event->angleDelta().x() + event->angleDelta().y();
783 auto value = event->angleDelta().x() + event->angleDelta().y();
784 if (value != 0) {
784 if (value != 0) {
785
785
786 auto direction = value > 0 ? 1.0 : -1.0;
786 auto direction = value > 0 ? 1.0 : -1.0;
787 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
787 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
788 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
788 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
789 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
789 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
790
790
791 auto zoomOrientations = QFlags<Qt::Orientation>{};
791 auto zoomOrientations = QFlags<Qt::Orientation>{};
792 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
792 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
793 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
793 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
794
794
795 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
795 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
796
796
797 if (!isZoomX && !isZoomY) {
797 if (!isZoomX && !isZoomY) {
798 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
798 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
799 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
799 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
800
800
801 axis->setRange(axis->range() + diff);
801 axis->setRange(axis->range() + diff);
802
802
803 if (plot().noAntialiasingOnDrag()) {
803 if (plot().noAntialiasingOnDrag()) {
804 plot().setNotAntialiasedElements(QCP::aeAll);
804 plot().setNotAntialiasedElements(QCP::aeAll);
805 }
805 }
806
806
807 plot().replot(QCustomPlot::rpQueuedReplot);
807 plot().replot(QCustomPlot::rpQueuedReplot);
808 }
808 }
809 }
809 }
810 }
810 }
811
811
812 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
812 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
813 {
813 {
814 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
814 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
815 auto isSelectionZoneMode
815 auto isSelectionZoneMode
816 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
816 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
817 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
817 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
818
818
819 if (!isDragDropClick && isLeftClick) {
819 if (!isDragDropClick && isLeftClick) {
820 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
820 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
821 // Starts a zoom box
821 // Starts a zoom box
822 impl->startDrawingRect(event->pos(), plot());
822 impl->startDrawingRect(event->pos(), plot());
823 }
823 }
824 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
824 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
825 // Starts a new selection zone
825 // Starts a new selection zone
826 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
826 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
827 if (!zoneAtPos) {
827 if (!zoneAtPos) {
828 impl->startDrawingZone(event->pos(), this);
828 impl->startDrawingZone(event->pos(), this);
829 }
829 }
830 }
830 }
831 }
831 }
832
832
833 // Allows mouse panning only in default mode
833 // Allows mouse panning only in default mode
834 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
834 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
835 == SqpApplication::PlotsInteractionMode::None
835 == SqpApplication::PlotsInteractionMode::None
836 && !isDragDropClick);
836 && !isDragDropClick);
837
837
838 // Allows zone edition only in selection zone mode without drag&drop
838 // Allows zone edition only in selection zone mode without drag&drop
839 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
839 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
840
840
841 // Selection / Deselection
841 // Selection / Deselection
842 if (isSelectionZoneMode) {
842 if (isSelectionZoneMode) {
843 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
843 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
844 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
844 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
845 if (selectionZoneItemUnderCursor && isLeftClick) {
845
846 selectionZoneItemUnderCursor->setAssociatedEditedZones(
846
847 parentVisualizationWidget()->selectionZoneManager().selectedItems());
847 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
848 && !isMultiSelectionClick) {
849 parentVisualizationWidget()->selectionZoneManager().select(
850 {selectionZoneItemUnderCursor});
848 }
851 }
849 else if (!isMultiSelectionClick && isLeftClick) {
852 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
850 parentVisualizationWidget()->selectionZoneManager().clearSelection();
853 parentVisualizationWidget()->selectionZoneManager().clearSelection();
851 }
854 }
852 else {
855 else {
853 // No selection change
856 // No selection change
854 }
857 }
858
859 if (selectionZoneItemUnderCursor && isLeftClick) {
860 selectionZoneItemUnderCursor->setAssociatedEditedZones(
861 parentVisualizationWidget()->selectionZoneManager().selectedItems());
862 }
855 }
863 }
856
864
857
865
858 impl->m_HasMovedMouse = false;
866 impl->m_HasMovedMouse = false;
859 VisualizationDragWidget::mousePressEvent(event);
867 VisualizationDragWidget::mousePressEvent(event);
860 }
868 }
861
869
862 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
870 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
863 {
871 {
864 if (impl->m_DrawingZoomRect) {
872 if (impl->m_DrawingZoomRect) {
865
873
866 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
874 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
867 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
875 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
868
876
869 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
877 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
870 impl->m_DrawingZoomRect->bottomRight->coords().x()};
878 impl->m_DrawingZoomRect->bottomRight->coords().x()};
871
879
872 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
880 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
873 impl->m_DrawingZoomRect->bottomRight->coords().y()};
881 impl->m_DrawingZoomRect->bottomRight->coords().y()};
874
882
875 impl->removeDrawingRect(plot());
883 impl->removeDrawingRect(plot());
876
884
877 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
885 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
878 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
886 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
879 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
887 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
880 axisX->setRange(newAxisXRange);
888 axisX->setRange(newAxisXRange);
881 axisY->setRange(newAxisYRange);
889 axisY->setRange(newAxisYRange);
882
890
883 plot().replot(QCustomPlot::rpQueuedReplot);
891 plot().replot(QCustomPlot::rpQueuedReplot);
884 }
892 }
885 }
893 }
886
894
887 impl->endDrawingZone(this);
895 impl->endDrawingZone(this);
888
896
889 impl->m_IsCalibration = false;
897 impl->m_IsCalibration = false;
890
898
891 // Selection / Deselection
899 // Selection / Deselection
892 auto isSelectionZoneMode
900 auto isSelectionZoneMode
893 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
901 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
894 if (isSelectionZoneMode) {
902 if (isSelectionZoneMode) {
895 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
903 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
896 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
904 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
897 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
905 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
898 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
906 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
899 parentVisualizationWidget()->selectionZoneManager().select(
907 parentVisualizationWidget()->selectionZoneManager().select(
900 {selectionZoneItemUnderCursor});
908 {selectionZoneItemUnderCursor});
901 }
909 }
902 else if (!impl->m_HasMovedMouse) {
910 else if (!impl->m_HasMovedMouse) {
903 parentVisualizationWidget()->selectionZoneManager().setSelected(
911 parentVisualizationWidget()->selectionZoneManager().setSelected(
904 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
912 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
905 || event->button() == Qt::RightButton);
913 || event->button() == Qt::RightButton);
906 }
914 }
907 }
915 }
908 else {
916 else {
909 // No selection change
917 // No selection change
910 }
918 }
911 }
919 }
912 }
920 }
913
921
914 void VisualizationGraphWidget::onDataCacheVariableUpdated()
922 void VisualizationGraphWidget::onDataCacheVariableUpdated()
915 {
923 {
916 auto graphRange = ui->widget->xAxis->range();
924 auto graphRange = ui->widget->xAxis->range();
917 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
925 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
918
926
919 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
927 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
920 auto variable = variableEntry.first;
928 auto variable = variableEntry.first;
921 qCDebug(LOG_VisualizationGraphWidget())
929 qCDebug(LOG_VisualizationGraphWidget())
922 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
930 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
923 qCDebug(LOG_VisualizationGraphWidget())
931 qCDebug(LOG_VisualizationGraphWidget())
924 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
932 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
925 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
933 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
926 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
934 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
927 }
935 }
928 }
936 }
929 }
937 }
930
938
931 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
939 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
932 const SqpRange &range)
940 const SqpRange &range)
933 {
941 {
934 auto it = impl->m_VariableToPlotMultiMap.find(variable);
942 auto it = impl->m_VariableToPlotMultiMap.find(variable);
935 if (it != impl->m_VariableToPlotMultiMap.end()) {
943 if (it != impl->m_VariableToPlotMultiMap.end()) {
936 impl->updateData(it->second, variable->dataSeries(), range);
944 impl->updateData(it->second, variable->dataSeries(), range);
937 }
945 }
938 }
946 }
@@ -1,425 +1,433
1 #include "Visualization/VisualizationSelectionZoneItem.h"
1 #include "Visualization/VisualizationSelectionZoneItem.h"
2 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/VisualizationGraphWidget.h"
3 #include "Visualization/VisualizationSelectionZoneManager.h"
4 #include "Visualization/VisualizationWidget.h"
3
5
4 const QString &DEFAULT_COLOR = QStringLiteral("#E79D41");
6 const QString &DEFAULT_COLOR = QStringLiteral("#E79D41");
5
7
6 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
8 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
7
9
8 QCustomPlot *m_Plot;
10 QCustomPlot *m_Plot;
9 double m_T1 = 0;
11 double m_T1 = 0;
10 double m_T2 = 0;
12 double m_T2 = 0;
11 QColor m_Color;
13 QColor m_Color;
12
14
13 bool m_IsEditionEnabled = true;
15 bool m_IsEditionEnabled = true;
14 double m_MovedOrinalT1 = 0;
16 double m_MovedOrinalT1 = 0;
15 double m_MovedOrinalT2 = 0;
17 double m_MovedOrinalT2 = 0;
16
18
17 QCPItemStraightLine *m_LeftLine;
19 QCPItemStraightLine *m_LeftLine;
18 QCPItemStraightLine *m_RightLine;
20 QCPItemStraightLine *m_RightLine;
19 QCPItemText *m_NameLabelItem = nullptr;
21 QCPItemText *m_NameLabelItem = nullptr;
20
22
21 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
23 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
22 EditionMode m_CurrentEditionMode;
24 EditionMode m_CurrentEditionMode;
23
25
24 QVector<VisualizationSelectionZoneItem *> m_AssociatedEditedZones;
26 QVector<VisualizationSelectionZoneItem *> m_AssociatedEditedZones;
25
27
26 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
28 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
27 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
29 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
28 {
30 {
29 }
31 }
30
32
31 void updatePosition(VisualizationSelectionZoneItem *item)
33 void updatePosition(VisualizationSelectionZoneItem *item)
32 {
34 {
33 item->topLeft->setCoords(m_T1, 0);
35 item->topLeft->setCoords(m_T1, 0);
34 item->bottomRight->setCoords(m_T2, 1);
36 item->bottomRight->setCoords(m_T2, 1);
35 }
37 }
36
38
37 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
39 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
38 {
40 {
39 auto distanceLeft = m_LeftLine->selectTest(pos, false);
41 auto distanceLeft = m_LeftLine->selectTest(pos, false);
40 auto distanceRight = m_RightLine->selectTest(pos, false);
42 auto distanceRight = m_RightLine->selectTest(pos, false);
41 auto distance = zoneItem->selectTest(pos, false);
43 auto distance = zoneItem->selectTest(pos, false);
42
44
43 if (distanceRight <= distance) {
45 if (distanceRight <= distance) {
44 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
46 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
45 }
47 }
46 else if (distanceLeft <= distance) {
48 else if (distanceLeft <= distance) {
47 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
49 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
48 }
50 }
49
51
50 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
52 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
51 }
53 }
52
54
53 double pixelSizeToAxisXSize(double pixels)
55 double pixelSizeToAxisXSize(double pixels)
54 {
56 {
55 auto axis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
57 auto axis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
56 return axis->pixelToCoord(pixels) - axis->pixelToCoord(0);
58 return axis->pixelToCoord(pixels) - axis->pixelToCoord(0);
57 }
59 }
58
60
59 bool alignZones(VisualizationSelectionZoneItem *referenceZone,
61 bool alignZones(VisualizationSelectionZoneItem *referenceZone,
60 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool alignOnLeft,
62 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool alignOnLeft,
61 bool allowResize, bool vertically)
63 bool allowResize, bool vertically)
62 {
64 {
63 auto result = false;
65 auto result = false;
64
66
65 auto referenceTime
67 auto referenceTime
66 = alignOnLeft ? referenceZone->range().m_TStart : referenceZone->range().m_TEnd;
68 = alignOnLeft ? referenceZone->range().m_TStart : referenceZone->range().m_TEnd;
67
69
68 auto referenceBottomAxis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
70 auto referenceBottomAxis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
69 auto referenceVerticalPosition = referenceBottomAxis->coordToPixel(referenceTime);
71 auto referenceVerticalPosition = referenceBottomAxis->coordToPixel(referenceTime);
70
72
71 for (auto otherZone : zonesToAlign) {
73 for (auto otherZone : zonesToAlign) {
72
74
73 auto otherZoneRange = otherZone->range();
75 auto otherZoneRange = otherZone->range();
74 auto newZoneStart = otherZoneRange.m_TStart;
76 auto newZoneStart = otherZoneRange.m_TStart;
75 auto newZoneEnd = otherZoneRange.m_TEnd;
77 auto newZoneEnd = otherZoneRange.m_TEnd;
76
78
77 auto alignedTime = referenceTime;
79 auto alignedTime = referenceTime;
78 if (vertically) {
80 if (vertically) {
79 auto otherZoneAxis = otherZone->parentPlot()->axisRect()->axis(QCPAxis::atBottom);
81 auto otherZoneAxis = otherZone->parentPlot()->axisRect()->axis(QCPAxis::atBottom);
80 alignedTime = otherZoneAxis->pixelToCoord(referenceVerticalPosition);
82 alignedTime = otherZoneAxis->pixelToCoord(referenceVerticalPosition);
81 }
83 }
82
84
83 if (alignOnLeft) {
85 if (alignOnLeft) {
84 newZoneStart = alignedTime;
86 newZoneStart = alignedTime;
85 if (!allowResize) {
87 if (!allowResize) {
86 newZoneEnd = alignedTime + (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
88 newZoneEnd = alignedTime + (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
87 }
89 }
88 }
90 }
89 else { // align on right
91 else { // align on right
90 newZoneEnd = alignedTime;
92 newZoneEnd = alignedTime;
91 if (!allowResize) {
93 if (!allowResize) {
92 newZoneStart = alignedTime - (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
94 newZoneStart = alignedTime - (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
93 }
95 }
94 }
96 }
95
97
96 if (newZoneStart < newZoneEnd) {
98 if (newZoneStart < newZoneEnd) {
97 result = true;
99 result = true;
98 otherZone->setRange(newZoneStart, newZoneEnd);
100 otherZone->setRange(newZoneStart, newZoneEnd);
99 otherZone->parentPlot()->replot();
101 otherZone->parentPlot()->replot();
100 }
102 }
101 }
103 }
102
104
103 return result;
105 return result;
104 }
106 }
105 };
107 };
106
108
107 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
109 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
108 : QCPItemRect(plot),
110 : QCPItemRect(plot),
109 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
111 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
110 {
112 {
111 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
113 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
112 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
114 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
113 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
115 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
114 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
116 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
115 setSelectable(false);
117 setSelectable(false);
116
118
117 impl->m_RightLine = new QCPItemStraightLine(plot);
119 impl->m_RightLine = new QCPItemStraightLine(plot);
118 impl->m_RightLine->point1->setParentAnchor(topRight);
120 impl->m_RightLine->point1->setParentAnchor(topRight);
119 impl->m_RightLine->point2->setParentAnchor(bottomRight);
121 impl->m_RightLine->point2->setParentAnchor(bottomRight);
120 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
122 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
121 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
123 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
122 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
124 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
123 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
125 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
124 impl->m_RightLine->setSelectable(false);
126 impl->m_RightLine->setSelectable(false);
125
127
126 impl->m_LeftLine = new QCPItemStraightLine(plot);
128 impl->m_LeftLine = new QCPItemStraightLine(plot);
127 impl->m_LeftLine->point1->setParentAnchor(topLeft);
129 impl->m_LeftLine->point1->setParentAnchor(topLeft);
128 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
130 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
129 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
131 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
130 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
132 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
131 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
133 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
132 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
134 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
133 impl->m_LeftLine->setSelectable(false);
135 impl->m_LeftLine->setSelectable(false);
134
136
135 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
137 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
136 &QCPItemStraightLine::setSelected);
138 &QCPItemStraightLine::setSelected);
137 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
139 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
138 &QCPItemStraightLine::setSelected);
140 &QCPItemStraightLine::setSelected);
139
141
140 setColor(QColor(DEFAULT_COLOR));
142 setColor(QColor(DEFAULT_COLOR));
141 }
143 }
142
144
143 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
145 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
144 {
146 {
145 impl->m_Plot->removeItem(impl->m_RightLine);
147 impl->m_Plot->removeItem(impl->m_RightLine);
146 impl->m_Plot->removeItem(impl->m_LeftLine);
148 impl->m_Plot->removeItem(impl->m_LeftLine);
147 }
149 }
148
150
149 VisualizationGraphWidget *VisualizationSelectionZoneItem::parentGraphWidget() const noexcept
151 VisualizationGraphWidget *VisualizationSelectionZoneItem::parentGraphWidget() const noexcept
150 {
152 {
151 auto parent = impl->m_Plot->parentWidget();
153 auto parent = impl->m_Plot->parentWidget();
152 while (parent != nullptr && !qobject_cast<VisualizationGraphWidget *>(parent)) {
154 while (parent != nullptr && !qobject_cast<VisualizationGraphWidget *>(parent)) {
153 parent = parent->parentWidget();
155 parent = parent->parentWidget();
154 }
156 }
155
157
156 return qobject_cast<VisualizationGraphWidget *>(parent);
158 return qobject_cast<VisualizationGraphWidget *>(parent);
157 }
159 }
158
160
159 void VisualizationSelectionZoneItem::setName(const QString &name)
161 void VisualizationSelectionZoneItem::setName(const QString &name)
160 {
162 {
161 if (name.isEmpty() && impl->m_NameLabelItem) {
163 if (name.isEmpty() && impl->m_NameLabelItem) {
162 impl->m_Plot->removeItem(impl->m_NameLabelItem);
164 impl->m_Plot->removeItem(impl->m_NameLabelItem);
163 impl->m_NameLabelItem = nullptr;
165 impl->m_NameLabelItem = nullptr;
164 }
166 }
165 else if (!impl->m_NameLabelItem) {
167 else if (!impl->m_NameLabelItem) {
166 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
168 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
167 impl->m_NameLabelItem->setText(name);
169 impl->m_NameLabelItem->setText(name);
168 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
170 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
169 impl->m_NameLabelItem->setColor(impl->m_Color);
171 impl->m_NameLabelItem->setColor(impl->m_Color);
170 impl->m_NameLabelItem->position->setParentAnchor(top);
172 impl->m_NameLabelItem->position->setParentAnchor(top);
171 }
173 }
172 }
174 }
173
175
174 QString VisualizationSelectionZoneItem::name() const
176 QString VisualizationSelectionZoneItem::name() const
175 {
177 {
176 if (!impl->m_NameLabelItem) {
178 if (!impl->m_NameLabelItem) {
177 return QString();
179 return QString();
178 }
180 }
179
181
180 return impl->m_NameLabelItem->text();
182 return impl->m_NameLabelItem->text();
181 }
183 }
182
184
183 SqpRange VisualizationSelectionZoneItem::range() const
185 SqpRange VisualizationSelectionZoneItem::range() const
184 {
186 {
185 SqpRange range;
187 SqpRange range;
186 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
188 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
187 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
189 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
188 return range;
190 return range;
189 }
191 }
190
192
191 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
193 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
192 {
194 {
193 impl->m_T1 = tstart;
195 impl->m_T1 = tstart;
194 impl->m_T2 = tend;
196 impl->m_T2 = tend;
195 impl->updatePosition(this);
197 impl->updatePosition(this);
196 }
198 }
197
199
198 void VisualizationSelectionZoneItem::setStart(double tstart)
200 void VisualizationSelectionZoneItem::setStart(double tstart)
199 {
201 {
200 impl->m_T1 = tstart;
202 impl->m_T1 = tstart;
201 impl->updatePosition(this);
203 impl->updatePosition(this);
202 }
204 }
203
205
204 void VisualizationSelectionZoneItem::setEnd(double tend)
206 void VisualizationSelectionZoneItem::setEnd(double tend)
205 {
207 {
206 impl->m_T2 = tend;
208 impl->m_T2 = tend;
207 impl->updatePosition(this);
209 impl->updatePosition(this);
208 }
210 }
209
211
210 void VisualizationSelectionZoneItem::setColor(const QColor &color)
212 void VisualizationSelectionZoneItem::setColor(const QColor &color)
211 {
213 {
212 impl->m_Color = color;
214 impl->m_Color = color;
213
215
214 auto brushColor = color;
216 auto brushColor = color;
215 brushColor.setAlpha(80);
217 brushColor.setAlpha(80);
216 setBrush(QBrush(brushColor));
218 setBrush(QBrush(brushColor));
217 setPen(QPen(Qt::NoPen));
219 setPen(QPen(Qt::NoPen));
218
220
219 auto selectedBrushColor = brushColor;
221 auto selectedBrushColor = brushColor;
220 selectedBrushColor.setAlpha(150);
222 selectedBrushColor.setAlpha(150);
221 setSelectedBrush(QBrush(selectedBrushColor));
223 setSelectedBrush(QBrush(selectedBrushColor));
222 setSelectedPen(QPen(Qt::NoPen));
224 setSelectedPen(QPen(Qt::NoPen));
223
225
224 auto linePen = QPen(color);
226 auto linePen = QPen(color);
225 linePen.setStyle(Qt::SolidLine);
227 linePen.setStyle(Qt::SolidLine);
226 linePen.setWidth(4);
228 linePen.setWidth(4);
227
229
228 auto selectedLinePen = linePen;
230 auto selectedLinePen = linePen;
229 selectedLinePen.setColor(color.darker(120));
231 selectedLinePen.setColor(color.darker(120));
230 selectedLinePen.setWidth(4);
232 selectedLinePen.setWidth(4);
231
233
232 impl->m_LeftLine->setPen(linePen);
234 impl->m_LeftLine->setPen(linePen);
233 impl->m_RightLine->setPen(linePen);
235 impl->m_RightLine->setPen(linePen);
234
236
235 impl->m_LeftLine->setSelectedPen(selectedLinePen);
237 impl->m_LeftLine->setSelectedPen(selectedLinePen);
236 impl->m_RightLine->setSelectedPen(selectedLinePen);
238 impl->m_RightLine->setSelectedPen(selectedLinePen);
237 }
239 }
238
240
239 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
241 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
240 {
242 {
241 impl->m_IsEditionEnabled = value;
243 impl->m_IsEditionEnabled = value;
242 setSelectable(value);
244 setSelectable(value);
243 if (!value) {
245 if (!value) {
244 setSelected(false);
246 setSelected(false);
245 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
247 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
246 }
248 }
247 }
249 }
248
250
249 bool VisualizationSelectionZoneItem::isEditionEnabled() const
251 bool VisualizationSelectionZoneItem::isEditionEnabled() const
250 {
252 {
251 return impl->m_IsEditionEnabled;
253 return impl->m_IsEditionEnabled;
252 }
254 }
253
255
254 Qt::CursorShape
256 Qt::CursorShape
255 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
257 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
256 {
258 {
257 auto mode = impl->m_CurrentEditionMode
259 auto mode = impl->m_CurrentEditionMode
258 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
260 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
259 ? impl->getEditionMode(position, this)
261 ? impl->getEditionMode(position, this)
260 : impl->m_CurrentEditionMode;
262 : impl->m_CurrentEditionMode;
261 switch (mode) {
263 switch (mode) {
262 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
264 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
263 return Qt::SizeAllCursor;
265 return Qt::SizeAllCursor;
264 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
266 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
265 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
267 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
266 return Qt::SizeHorCursor;
268 return Qt::SizeHorCursor;
267 default:
269 default:
268 return Qt::ArrowCursor;
270 return Qt::ArrowCursor;
269 }
271 }
270 }
272 }
271
273
272 void VisualizationSelectionZoneItem::setHovered(bool value)
274 void VisualizationSelectionZoneItem::setHovered(bool value)
273 {
275 {
274 if (value) {
276 if (value) {
275 auto linePen = impl->m_LeftLine->pen();
277 auto linePen = impl->m_LeftLine->pen();
276 linePen.setStyle(Qt::DotLine);
278 linePen.setStyle(Qt::DotLine);
277 linePen.setWidth(3);
279 linePen.setWidth(3);
278
280
279 auto selectedLinePen = impl->m_LeftLine->selectedPen();
281 auto selectedLinePen = impl->m_LeftLine->selectedPen();
280 ;
282 ;
281 selectedLinePen.setStyle(Qt::DotLine);
283 selectedLinePen.setStyle(Qt::DotLine);
282 selectedLinePen.setWidth(3);
284 selectedLinePen.setWidth(3);
283
285
284 impl->m_LeftLine->setPen(linePen);
286 impl->m_LeftLine->setPen(linePen);
285 impl->m_RightLine->setPen(linePen);
287 impl->m_RightLine->setPen(linePen);
286
288
287 impl->m_LeftLine->setSelectedPen(selectedLinePen);
289 impl->m_LeftLine->setSelectedPen(selectedLinePen);
288 impl->m_RightLine->setSelectedPen(selectedLinePen);
290 impl->m_RightLine->setSelectedPen(selectedLinePen);
289 }
291 }
290 else {
292 else {
291 setColor(impl->m_Color);
293 setColor(impl->m_Color);
292 }
294 }
293 }
295 }
294
296
295 void VisualizationSelectionZoneItem::setAssociatedEditedZones(
297 void VisualizationSelectionZoneItem::setAssociatedEditedZones(
296 const QVector<VisualizationSelectionZoneItem *> &associatedZones)
298 const QVector<VisualizationSelectionZoneItem *> &associatedZones)
297 {
299 {
298 impl->m_AssociatedEditedZones = associatedZones;
300 impl->m_AssociatedEditedZones = associatedZones;
299 impl->m_AssociatedEditedZones.removeAll(this);
301 impl->m_AssociatedEditedZones.removeAll(this);
300 }
302 }
301
303
302 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnLeft(
304 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnLeft(
303 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
305 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
304 {
306 {
305 return impl->alignZones(this, zonesToAlign, true, allowResize, true);
307 return impl->alignZones(this, zonesToAlign, true, allowResize, true);
306 }
308 }
307
309
308 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnRight(
310 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnRight(
309 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
311 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
310 {
312 {
311 return impl->alignZones(this, zonesToAlign, false, allowResize, true);
313 return impl->alignZones(this, zonesToAlign, false, allowResize, true);
312 }
314 }
313
315
314 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnLeft(
316 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnLeft(
315 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
317 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
316 {
318 {
317 return impl->alignZones(this, zonesToAlign, true, allowResize, false);
319 return impl->alignZones(this, zonesToAlign, true, allowResize, false);
318 }
320 }
319
321
320 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnRight(
322 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnRight(
321 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
323 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
322 {
324 {
323 return impl->alignZones(this, zonesToAlign, false, allowResize, false);
325 return impl->alignZones(this, zonesToAlign, false, allowResize, false);
324 }
326 }
325
327
326 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
328 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
327 {
329 {
328 if (isEditionEnabled() && event->button() == Qt::LeftButton) {
330 if (isEditionEnabled() && event->button() == Qt::LeftButton) {
329 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
331 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
330
332
331 impl->m_MovedOrinalT1 = impl->m_T1;
333 impl->m_MovedOrinalT1 = impl->m_T1;
332 impl->m_MovedOrinalT2 = impl->m_T2;
334 impl->m_MovedOrinalT2 = impl->m_T2;
333 for (auto associatedZone : impl->m_AssociatedEditedZones) {
335 for (auto associatedZone : impl->m_AssociatedEditedZones) {
334 associatedZone->impl->m_MovedOrinalT1 = associatedZone->impl->m_T1;
336 associatedZone->impl->m_MovedOrinalT1 = associatedZone->impl->m_T1;
335 associatedZone->impl->m_MovedOrinalT2 = associatedZone->impl->m_T2;
337 associatedZone->impl->m_MovedOrinalT2 = associatedZone->impl->m_T2;
336 }
338 }
337 }
339 }
338 else {
340 else {
339 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
341 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
340 event->ignore();
342 event->ignore();
341 }
343 }
342 }
344 }
343
345
344 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
346 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
345 {
347 {
346 if (isEditionEnabled()) {
348 if (isEditionEnabled()) {
349 if (!selected()) {
350 // Force the item to be selected during the edition
351 parentGraphWidget()->parentVisualizationWidget()->selectionZoneManager().setSelected(
352 this, true);
353 }
354
347 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
355 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
348 auto pixelDiff = event->pos().x() - startPos.x();
356 auto pixelDiff = event->pos().x() - startPos.x();
349 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
357 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
350
358
351 switch (impl->m_CurrentEditionMode) {
359 switch (impl->m_CurrentEditionMode) {
352 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
360 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
353 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
361 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
354 for (auto associatedZone : impl->m_AssociatedEditedZones) {
362 for (auto associatedZone : impl->m_AssociatedEditedZones) {
355 associatedZone->move(pixelDiff);
363 associatedZone->move(pixelDiff);
356 }
364 }
357 break;
365 break;
358 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
366 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
359 setStart(impl->m_MovedOrinalT1 + diff);
367 setStart(impl->m_MovedOrinalT1 + diff);
360 for (auto associatedZone : impl->m_AssociatedEditedZones) {
368 for (auto associatedZone : impl->m_AssociatedEditedZones) {
361 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
369 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
362 ? associatedZone->resizeLeft(pixelDiff)
370 ? associatedZone->resizeLeft(pixelDiff)
363 : associatedZone->resizeRight(pixelDiff);
371 : associatedZone->resizeRight(pixelDiff);
364 }
372 }
365 break;
373 break;
366 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
374 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
367 setEnd(impl->m_MovedOrinalT2 + diff);
375 setEnd(impl->m_MovedOrinalT2 + diff);
368 for (auto associatedZone : impl->m_AssociatedEditedZones) {
376 for (auto associatedZone : impl->m_AssociatedEditedZones) {
369 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
377 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
370 ? associatedZone->resizeRight(pixelDiff)
378 ? associatedZone->resizeRight(pixelDiff)
371 : associatedZone->resizeLeft(pixelDiff);
379 : associatedZone->resizeLeft(pixelDiff);
372 }
380 }
373 break;
381 break;
374 default:
382 default:
375 break;
383 break;
376 }
384 }
377
385
378 for (auto associatedZone : impl->m_AssociatedEditedZones) {
386 for (auto associatedZone : impl->m_AssociatedEditedZones) {
379 associatedZone->parentPlot()->replot();
387 associatedZone->parentPlot()->replot();
380 }
388 }
381 }
389 }
382 else {
390 else {
383 event->ignore();
391 event->ignore();
384 }
392 }
385 }
393 }
386
394
387 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
395 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
388 {
396 {
389 if (isEditionEnabled()) {
397 if (isEditionEnabled()) {
390 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
398 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
391 }
399 }
392 else {
400 else {
393 event->ignore();
401 event->ignore();
394 }
402 }
395
403
396 impl->m_AssociatedEditedZones.clear();
404 impl->m_AssociatedEditedZones.clear();
397 }
405 }
398
406
399 void VisualizationSelectionZoneItem::resizeLeft(double pixelDiff)
407 void VisualizationSelectionZoneItem::resizeLeft(double pixelDiff)
400 {
408 {
401 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
409 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
402 if (impl->m_MovedOrinalT1 <= impl->m_MovedOrinalT2) {
410 if (impl->m_MovedOrinalT1 <= impl->m_MovedOrinalT2) {
403 setStart(impl->m_MovedOrinalT1 + diff);
411 setStart(impl->m_MovedOrinalT1 + diff);
404 }
412 }
405 else {
413 else {
406 setEnd(impl->m_MovedOrinalT2 + diff);
414 setEnd(impl->m_MovedOrinalT2 + diff);
407 }
415 }
408 }
416 }
409
417
410 void VisualizationSelectionZoneItem::resizeRight(double pixelDiff)
418 void VisualizationSelectionZoneItem::resizeRight(double pixelDiff)
411 {
419 {
412 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
420 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
413 if (impl->m_MovedOrinalT1 > impl->m_MovedOrinalT2) {
421 if (impl->m_MovedOrinalT1 > impl->m_MovedOrinalT2) {
414 setStart(impl->m_MovedOrinalT1 + diff);
422 setStart(impl->m_MovedOrinalT1 + diff);
415 }
423 }
416 else {
424 else {
417 setEnd(impl->m_MovedOrinalT2 + diff);
425 setEnd(impl->m_MovedOrinalT2 + diff);
418 }
426 }
419 }
427 }
420
428
421 void VisualizationSelectionZoneItem::move(double pixelDiff)
429 void VisualizationSelectionZoneItem::move(double pixelDiff)
422 {
430 {
423 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
431 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
424 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
432 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
425 }
433 }
General Comments 4
Under Review
author

Auto status change to "Under Review"

Approved

Status change > Approved

Approved

Status change > Approved

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