##// END OF EJS Templates
Display of selection zones on a graph
trabillard -
r1044:dd81862d7e96
parent child
Show More
@@ -0,0 +1,39
1 #ifndef SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
2 #define SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
3
4 #include <Common/spimpl.h>
5 #include <Data/SqpRange.h>
6 #include <Visualization/qcustomplot.h>
7
8 class VisualizationSelectionZoneItem : public QCPItemRect {
9 public:
10 VisualizationSelectionZoneItem(QCustomPlot *plot);
11 virtual ~VisualizationSelectionZoneItem();
12
13 void setName(const QString &name);
14 QString name() const;
15
16 SqpRange range() const;
17 void setRange(double tstart, double tend);
18 void setStart(double tstart);
19 void setEnd(double tend);
20
21 void setColor(const QColor &color);
22
23 void setEditionEnabled(bool value);
24 bool isEditionEnabled() const;
25
26 Qt::CursorShape curshorShapeForPosition(const QPoint &position) const;
27 void setHovered(bool value);
28
29 protected:
30 void mousePressEvent(QMouseEvent *event, const QVariant &details) override;
31 void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) override;
32 void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) override;
33
34 private:
35 class VisualizationSelectionZoneItemPrivate;
36 spimpl::unique_impl_ptr<VisualizationSelectionZoneItemPrivate> impl;
37 };
38
39 #endif // SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
@@ -0,0 +1,271
1 #include "Visualization/VisualizationSelectionZoneItem.h"
2
3 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
4
5 QCustomPlot *m_Plot;
6 double m_T1 = 0;
7 double m_T2 = 0;
8 QColor m_Color;
9
10 bool m_IsEditionEnabled = true;
11 double m_MovedOrinalT1 = 0;
12 double m_MovedOrinalT2 = 0;
13
14 QCPItemStraightLine *m_LeftLine;
15 QCPItemStraightLine *m_RightLine;
16 QCPItemText *m_NameLabelItem = nullptr;
17
18 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
19 EditionMode m_CurrentEditionMode;
20
21 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
22 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
23 {
24 }
25
26 void updatePosition(VisualizationSelectionZoneItem *item)
27 {
28 item->topLeft->setCoords(m_T1, 0);
29 item->bottomRight->setCoords(m_T2, 1);
30 }
31
32 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
33 {
34 auto distanceLeft = m_LeftLine->selectTest(pos, false);
35 auto distanceRight = m_RightLine->selectTest(pos, false);
36 auto distance = zoneItem->selectTest(pos, true);
37
38 if (distanceRight <= distance) {
39 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
40 }
41 else if (distanceLeft <= distance) {
42 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
43 }
44
45 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
46 }
47 };
48
49 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
50 : QCPItemRect(plot),
51 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
52 {
53 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
54 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
55 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
56 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
57
58 impl->m_RightLine = new QCPItemStraightLine(plot);
59 impl->m_RightLine->point1->setParentAnchor(topRight);
60 impl->m_RightLine->point2->setParentAnchor(bottomRight);
61 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
62 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
63 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
64 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
65
66 impl->m_LeftLine = new QCPItemStraightLine(plot);
67 impl->m_LeftLine->point1->setParentAnchor(topLeft);
68 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
69 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
70 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
71 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
72 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
73
74 impl->m_RightLine->setSelectable(false);
75 impl->m_LeftLine->setSelectable(false);
76
77 // connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
78 // &QCPItemStraightLine::setSelected);
79 // connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
80 // &QCPItemStraightLine::setSelected);
81
82 setColor(QColor("#E79D41"));
83 }
84
85 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
86 {
87 impl->m_Plot->removeItem(impl->m_RightLine);
88 impl->m_Plot->removeItem(impl->m_LeftLine);
89 }
90
91 void VisualizationSelectionZoneItem::setName(const QString &name)
92 {
93 if (name.isEmpty() && impl->m_NameLabelItem) {
94 impl->m_Plot->removeItem(impl->m_NameLabelItem);
95 impl->m_NameLabelItem = nullptr;
96 }
97 else if (!impl->m_NameLabelItem) {
98 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
99 impl->m_NameLabelItem->setText(name);
100 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
101 impl->m_NameLabelItem->setColor(impl->m_Color);
102 impl->m_NameLabelItem->position->setParentAnchor(top);
103 }
104 }
105
106 QString VisualizationSelectionZoneItem::name() const
107 {
108 if (!impl->m_NameLabelItem) {
109 return QString();
110 }
111
112 return impl->m_NameLabelItem->text();
113 }
114
115 SqpRange VisualizationSelectionZoneItem::range() const
116 {
117 SqpRange range;
118 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
119 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
120 return range;
121 }
122
123 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
124 {
125 impl->m_T1 = tstart;
126 impl->m_T2 = tend;
127 impl->updatePosition(this);
128 }
129
130 void VisualizationSelectionZoneItem::setStart(double tstart)
131 {
132 impl->m_T1 = tstart;
133 impl->updatePosition(this);
134 }
135
136 void VisualizationSelectionZoneItem::setEnd(double tend)
137 {
138 impl->m_T2 = tend;
139 impl->updatePosition(this);
140 }
141
142 void VisualizationSelectionZoneItem::setColor(const QColor &color)
143 {
144 impl->m_Color = color;
145
146 auto brushColor = color;
147 brushColor.setAlpha(40);
148 setBrush(QBrush(brushColor));
149 setPen(QPen(Qt::NoPen));
150
151 auto selectedBrushColor = brushColor;
152 selectedBrushColor.setAlpha(65);
153 setSelectedBrush(QBrush(selectedBrushColor));
154 setSelectedPen(QPen(Qt::NoPen));
155
156 auto linePen = QPen(color);
157 linePen.setStyle(Qt::SolidLine);
158 linePen.setWidth(2);
159
160 auto selectedLinePen = linePen;
161 selectedLinePen.setColor(color.darker(30));
162
163 impl->m_LeftLine->setPen(linePen);
164 impl->m_RightLine->setPen(linePen);
165
166 impl->m_LeftLine->setSelectedPen(selectedLinePen);
167 impl->m_RightLine->setSelectedPen(selectedLinePen);
168 }
169
170 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
171 {
172 impl->m_IsEditionEnabled = value;
173 setSelectable(value);
174 if (!value) {
175 setSelected(false);
176 }
177 }
178
179 bool VisualizationSelectionZoneItem::isEditionEnabled() const
180 {
181 return impl->m_IsEditionEnabled;
182 }
183
184 Qt::CursorShape
185 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
186 {
187 auto mode = impl->m_CurrentEditionMode
188 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
189 ? impl->getEditionMode(position, this)
190 : impl->m_CurrentEditionMode;
191 switch (mode) {
192 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
193 return Qt::SizeAllCursor;
194 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
195 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
196 return Qt::SizeHorCursor;
197 default:
198 return Qt::ArrowCursor;
199 }
200 }
201
202 void VisualizationSelectionZoneItem::setHovered(bool value)
203 {
204 if (value) {
205 auto linePen = impl->m_LeftLine->pen();
206 linePen.setStyle(Qt::DotLine);
207 linePen.setWidth(3);
208
209 auto selectedLinePen = impl->m_LeftLine->selectedPen();
210 ;
211 selectedLinePen.setStyle(Qt::DotLine);
212 selectedLinePen.setWidth(3);
213
214 impl->m_LeftLine->setPen(linePen);
215 impl->m_RightLine->setPen(linePen);
216
217 impl->m_LeftLine->setSelectedPen(selectedLinePen);
218 impl->m_RightLine->setSelectedPen(selectedLinePen);
219 }
220 else {
221 setColor(impl->m_Color);
222 }
223 }
224
225 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
226 {
227 if (isEditionEnabled()) {
228 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
229
230 impl->m_MovedOrinalT1 = impl->m_T1;
231 impl->m_MovedOrinalT2 = impl->m_T2;
232 }
233 else {
234 event->ignore();
235 }
236 }
237
238 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
239 {
240 if (isEditionEnabled()) {
241 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
242 auto diff = axis->pixelToCoord(event->pos().x()) - axis->pixelToCoord(startPos.x());
243
244 switch (impl->m_CurrentEditionMode) {
245 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
246 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
247 break;
248 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
249 setStart(impl->m_MovedOrinalT1 + diff);
250 break;
251 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
252 setEnd(impl->m_MovedOrinalT2 + diff);
253 break;
254 // default:
255 // unknown edition mode
256 }
257 }
258 else {
259 event->ignore();
260 }
261 }
262
263 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
264 {
265 if (isEditionEnabled()) {
266 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
267 }
268 else {
269 event->ignore();
270 }
271 }
@@ -1,101 +1,102
1
1
2 gui_moc_headers = [
2 gui_moc_headers = [
3 'include/DataSource/DataSourceWidget.h',
3 'include/DataSource/DataSourceWidget.h',
4 'include/Settings/SqpSettingsDialog.h',
4 'include/Settings/SqpSettingsDialog.h',
5 'include/Settings/SqpSettingsGeneralWidget.h',
5 'include/Settings/SqpSettingsGeneralWidget.h',
6 'include/SidePane/SqpSidePane.h',
6 'include/SidePane/SqpSidePane.h',
7 'include/SqpApplication.h',
7 'include/SqpApplication.h',
8 'include/DragAndDrop/DragDropScroller.h',
8 'include/DragAndDrop/DragDropScroller.h',
9 'include/DragAndDrop/DragDropTabSwitcher.h',
9 'include/DragAndDrop/DragDropTabSwitcher.h',
10 'include/TimeWidget/TimeWidget.h',
10 'include/TimeWidget/TimeWidget.h',
11 'include/Variable/VariableInspectorWidget.h',
11 'include/Variable/VariableInspectorWidget.h',
12 'include/Variable/RenameVariableDialog.h',
12 'include/Variable/RenameVariableDialog.h',
13 'include/Visualization/qcustomplot.h',
13 'include/Visualization/qcustomplot.h',
14 'include/Visualization/VisualizationGraphWidget.h',
14 'include/Visualization/VisualizationGraphWidget.h',
15 'include/Visualization/VisualizationTabWidget.h',
15 'include/Visualization/VisualizationTabWidget.h',
16 'include/Visualization/VisualizationWidget.h',
16 'include/Visualization/VisualizationWidget.h',
17 'include/Visualization/VisualizationZoneWidget.h',
17 'include/Visualization/VisualizationZoneWidget.h',
18 'include/Visualization/VisualizationDragDropContainer.h',
18 'include/Visualization/VisualizationDragDropContainer.h',
19 'include/Visualization/VisualizationDragWidget.h',
19 'include/Visualization/VisualizationDragWidget.h',
20 'include/Visualization/ColorScaleEditor.h'
20 'include/Visualization/ColorScaleEditor.h'
21 ]
21 ]
22
22
23 gui_ui_files = [
23 gui_ui_files = [
24 'ui/DataSource/DataSourceWidget.ui',
24 'ui/DataSource/DataSourceWidget.ui',
25 'ui/Settings/SqpSettingsDialog.ui',
25 'ui/Settings/SqpSettingsDialog.ui',
26 'ui/Settings/SqpSettingsGeneralWidget.ui',
26 'ui/Settings/SqpSettingsGeneralWidget.ui',
27 'ui/SidePane/SqpSidePane.ui',
27 'ui/SidePane/SqpSidePane.ui',
28 'ui/TimeWidget/TimeWidget.ui',
28 'ui/TimeWidget/TimeWidget.ui',
29 'ui/Variable/VariableInspectorWidget.ui',
29 'ui/Variable/VariableInspectorWidget.ui',
30 'ui/Variable/RenameVariableDialog.ui',
30 'ui/Variable/RenameVariableDialog.ui',
31 'ui/Variable/VariableMenuHeaderWidget.ui',
31 'ui/Variable/VariableMenuHeaderWidget.ui',
32 'ui/Visualization/VisualizationGraphWidget.ui',
32 'ui/Visualization/VisualizationGraphWidget.ui',
33 'ui/Visualization/VisualizationTabWidget.ui',
33 'ui/Visualization/VisualizationTabWidget.ui',
34 'ui/Visualization/VisualizationWidget.ui',
34 'ui/Visualization/VisualizationWidget.ui',
35 'ui/Visualization/VisualizationZoneWidget.ui',
35 'ui/Visualization/VisualizationZoneWidget.ui',
36 'ui/Visualization/ColorScaleEditor.ui'
36 'ui/Visualization/ColorScaleEditor.ui'
37 ]
37 ]
38
38
39 gui_qresources = ['resources/sqpguiresources.qrc']
39 gui_qresources = ['resources/sqpguiresources.qrc']
40
40
41 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
41 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
42 ui_files : gui_ui_files,
42 ui_files : gui_ui_files,
43 qresources : gui_qresources)
43 qresources : gui_qresources)
44
44
45 gui_sources = [
45 gui_sources = [
46 'src/SqpApplication.cpp',
46 'src/SqpApplication.cpp',
47 'src/DragAndDrop/DragDropHelper.cpp',
47 'src/DragAndDrop/DragDropHelper.cpp',
48 'src/DragAndDrop/DragDropScroller.cpp',
48 'src/DragAndDrop/DragDropScroller.cpp',
49 'src/DragAndDrop/DragDropTabSwitcher.cpp',
49 'src/DragAndDrop/DragDropTabSwitcher.cpp',
50 'src/Common/ColorUtils.cpp',
50 'src/Common/ColorUtils.cpp',
51 'src/Common/VisualizationDef.cpp',
51 'src/Common/VisualizationDef.cpp',
52 'src/DataSource/DataSourceTreeWidgetItem.cpp',
52 'src/DataSource/DataSourceTreeWidgetItem.cpp',
53 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
53 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
54 'src/DataSource/DataSourceWidget.cpp',
54 'src/DataSource/DataSourceWidget.cpp',
55 'src/DataSource/DataSourceTreeWidget.cpp',
55 'src/DataSource/DataSourceTreeWidget.cpp',
56 'src/Settings/SqpSettingsDialog.cpp',
56 'src/Settings/SqpSettingsDialog.cpp',
57 'src/Settings/SqpSettingsGeneralWidget.cpp',
57 'src/Settings/SqpSettingsGeneralWidget.cpp',
58 'src/SidePane/SqpSidePane.cpp',
58 'src/SidePane/SqpSidePane.cpp',
59 'src/TimeWidget/TimeWidget.cpp',
59 'src/TimeWidget/TimeWidget.cpp',
60 'src/Variable/VariableInspectorWidget.cpp',
60 'src/Variable/VariableInspectorWidget.cpp',
61 'src/Variable/VariableInspectorTableView.cpp',
61 'src/Variable/VariableInspectorTableView.cpp',
62 'src/Variable/VariableMenuHeaderWidget.cpp',
62 'src/Variable/VariableMenuHeaderWidget.cpp',
63 'src/Variable/RenameVariableDialog.cpp',
63 'src/Variable/RenameVariableDialog.cpp',
64 'src/Visualization/VisualizationGraphHelper.cpp',
64 'src/Visualization/VisualizationGraphHelper.cpp',
65 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
65 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
66 'src/Visualization/VisualizationGraphWidget.cpp',
66 'src/Visualization/VisualizationGraphWidget.cpp',
67 'src/Visualization/VisualizationTabWidget.cpp',
67 'src/Visualization/VisualizationTabWidget.cpp',
68 'src/Visualization/VisualizationWidget.cpp',
68 'src/Visualization/VisualizationWidget.cpp',
69 'src/Visualization/VisualizationZoneWidget.cpp',
69 'src/Visualization/VisualizationZoneWidget.cpp',
70 'src/Visualization/qcustomplot.cpp',
70 'src/Visualization/qcustomplot.cpp',
71 'src/Visualization/QCustomPlotSynchronizer.cpp',
71 'src/Visualization/QCustomPlotSynchronizer.cpp',
72 'src/Visualization/operations/FindVariableOperation.cpp',
72 'src/Visualization/operations/FindVariableOperation.cpp',
73 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
73 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
74 'src/Visualization/operations/MenuBuilder.cpp',
74 'src/Visualization/operations/MenuBuilder.cpp',
75 'src/Visualization/operations/RemoveVariableOperation.cpp',
75 'src/Visualization/operations/RemoveVariableOperation.cpp',
76 'src/Visualization/operations/RescaleAxeOperation.cpp',
76 'src/Visualization/operations/RescaleAxeOperation.cpp',
77 'src/Visualization/VisualizationDragDropContainer.cpp',
77 'src/Visualization/VisualizationDragDropContainer.cpp',
78 'src/Visualization/VisualizationDragWidget.cpp',
78 'src/Visualization/VisualizationDragWidget.cpp',
79 'src/Visualization/AxisRenderingUtils.cpp',
79 'src/Visualization/AxisRenderingUtils.cpp',
80 'src/Visualization/PlottablesRenderingUtils.cpp',
80 'src/Visualization/PlottablesRenderingUtils.cpp',
81 'src/Visualization/MacScrollBarStyle.cpp',
81 'src/Visualization/MacScrollBarStyle.cpp',
82 'src/Visualization/VisualizationCursorItem.cpp',
82 'src/Visualization/VisualizationCursorItem.cpp',
83 'src/Visualization/ColorScaleEditor.cpp',
83 'src/Visualization/ColorScaleEditor.cpp',
84 'src/Visualization/SqpColorScale.cpp',
84 'src/Visualization/SqpColorScale.cpp',
85 'src/Visualization/QCPColorMapIterator.cpp'
85 'src/Visualization/QCPColorMapIterator.cpp',
86 'src/Visualization/VisualizationSelectionZoneItem.cpp'
86 ]
87 ]
87
88
88 gui_inc = include_directories(['include'])
89 gui_inc = include_directories(['include'])
89
90
90 sciqlop_gui_lib = library('sciqlopgui',
91 sciqlop_gui_lib = library('sciqlopgui',
91 gui_sources,
92 gui_sources,
92 gui_moc_files,
93 gui_moc_files,
93 include_directories : [gui_inc],
94 include_directories : [gui_inc],
94 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
95 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
95 install : true
96 install : true
96 )
97 )
97
98
98 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
99 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
99 include_directories : gui_inc,
100 include_directories : gui_inc,
100 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
101 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
101
102
@@ -1,331 +1,333
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 #include "Visualization/AxisRenderingUtils.h"
2 #include "Visualization/AxisRenderingUtils.h"
3 #include "Visualization/ColorScaleEditor.h"
3 #include "Visualization/ColorScaleEditor.h"
4 #include "Visualization/PlottablesRenderingUtils.h"
4 #include "Visualization/PlottablesRenderingUtils.h"
5 #include "Visualization/SqpColorScale.h"
5 #include "Visualization/SqpColorScale.h"
6 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationGraphWidget.h"
7 #include "Visualization/qcustomplot.h"
7 #include "Visualization/qcustomplot.h"
8
8
9 #include <Common/DateUtils.h>
9 #include <Common/DateUtils.h>
10
10
11 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
12
12
13 #include <SqpApplication.h>
13 #include <SqpApplication.h>
14
14
15 namespace {
15 namespace {
16
16
17 /// Name of the axes layer in QCustomPlot
17 /// Name of the axes layer in QCustomPlot
18 const auto AXES_LAYER = QStringLiteral("axes");
18 const auto AXES_LAYER = QStringLiteral("axes");
19
19
20 /// Icon used to show x-axis properties
20 /// Icon used to show x-axis properties
21 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
21 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
22
22
23 /// Name of the overlay layer in QCustomPlot
23 /// Name of the overlay layer in QCustomPlot
24 const auto OVERLAY_LAYER = QStringLiteral("overlay");
24 const auto OVERLAY_LAYER = QStringLiteral("overlay");
25
25
26 /// Pixmap used to show x-axis properties
26 /// Pixmap used to show x-axis properties
27 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
27 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
28
28
29 /// Tooltip format for graphs
29 /// Tooltip format for graphs
30 const auto GRAPH_TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
30 const auto GRAPH_TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
31
31
32 /// Tooltip format for colormaps
32 /// Tooltip format for colormaps
33 const auto COLORMAP_TOOLTIP_FORMAT = QStringLiteral("x: %1\ny: %2\nvalue: %3");
33 const auto COLORMAP_TOOLTIP_FORMAT = QStringLiteral("x: %1\ny: %2\nvalue: %3");
34
34
35 /// Offset used to shift the tooltip of the mouse
35 /// Offset used to shift the tooltip of the mouse
36 const auto TOOLTIP_OFFSET = QPoint{20, 20};
36 const auto TOOLTIP_OFFSET = QPoint{20, 20};
37
37
38 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
38 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
39 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
39 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
40
40
41 /// Timeout after which the tooltip is displayed
41 /// Timeout after which the tooltip is displayed
42 const auto TOOLTIP_TIMEOUT = 500;
42 const auto TOOLTIP_TIMEOUT = 500;
43
43
44 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
44 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
45 {
45 {
46 tracer.setInterpolating(false);
46 tracer.setInterpolating(false);
47 tracer.setStyle(QCPItemTracer::tsCircle);
47 tracer.setStyle(QCPItemTracer::tsCircle);
48 tracer.setSize(3);
48 tracer.setSize(3);
49 tracer.setPen(QPen(Qt::black));
49 tracer.setPen(QPen(Qt::black));
50 tracer.setBrush(Qt::black);
50 tracer.setBrush(Qt::black);
51 tracer.setSelectable(false);
51 }
52 }
52
53
53 QPixmap pixmap(const QString &iconPath) noexcept
54 QPixmap pixmap(const QString &iconPath) noexcept
54 {
55 {
55 return QIcon{iconPath}.pixmap(QSize{16, 16});
56 return QIcon{iconPath}.pixmap(QSize{16, 16});
56 }
57 }
57
58
58 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
59 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
59 {
60 {
60 // Icon
61 // Icon
61 pixmap.setPixmap(
62 pixmap.setPixmap(
62 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
63 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
63
64
64 // Position
65 // Position
65 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
66 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
66 pixmap.topLeft->setCoords(1, 0);
67 pixmap.topLeft->setCoords(1, 0);
67 pixmap.setClipToAxisRect(false);
68 pixmap.setClipToAxisRect(false);
68
69
69 // Can be selected
70 // Can be selected
70 pixmap.setSelectable(true);
71 pixmap.setSelectable(true);
71 }
72 }
72
73
73 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
74 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
74 {
75 {
75 // Icon
76 // Icon
76 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
77 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
77
78
78 // Position
79 // Position
79 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
80 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
80 itemPixmap.topLeft->setCoords(0, 1);
81 itemPixmap.topLeft->setCoords(0, 1);
81 itemPixmap.setClipToAxisRect(false);
82 itemPixmap.setClipToAxisRect(false);
82
83
83 // Can be selected
84 // Can be selected
84 itemPixmap.setSelectable(true);
85 itemPixmap.setSelectable(true);
85 }
86 }
86
87
87 void initTitleTextStyle(QCPItemText &text) noexcept
88 void initTitleTextStyle(QCPItemText &text) noexcept
88 {
89 {
89 // Font and background styles
90 // Font and background styles
90 text.setColor(Qt::gray);
91 text.setColor(Qt::gray);
91 text.setBrush(Qt::white);
92 text.setBrush(Qt::white);
92
93
93 // Position
94 // Position
94 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
95 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
95 text.position->setType(QCPItemPosition::ptAxisRectRatio);
96 text.position->setType(QCPItemPosition::ptAxisRectRatio);
96 text.position->setCoords(0.5, 0);
97 text.position->setCoords(0.5, 0);
98 text.setSelectable(false);
97 }
99 }
98
100
99 /**
101 /**
100 * Returns the cell index (x or y) of a colormap according to the coordinate passed in parameter.
102 * Returns the cell index (x or y) of a colormap according to the coordinate passed in parameter.
101 * This method handles the fact that a colormap axis can be logarithmic or linear.
103 * This method handles the fact that a colormap axis can be logarithmic or linear.
102 * @param colormap the colormap for which to calculate the index
104 * @param colormap the colormap for which to calculate the index
103 * @param coord the coord to convert to cell index
105 * @param coord the coord to convert to cell index
104 * @param xCoord calculates the x index if true, calculates y index if false
106 * @param xCoord calculates the x index if true, calculates y index if false
105 * @return the cell index
107 * @return the cell index
106 */
108 */
107 int colorMapCellIndex(const QCPColorMap &colormap, double coord, bool xCoord)
109 int colorMapCellIndex(const QCPColorMap &colormap, double coord, bool xCoord)
108 {
110 {
109 // Determines the axis of the colormap according to xCoord, and whether it is logarithmic or not
111 // Determines the axis of the colormap according to xCoord, and whether it is logarithmic or not
110 auto isLogarithmic = (xCoord ? colormap.keyAxis() : colormap.valueAxis())->scaleType()
112 auto isLogarithmic = (xCoord ? colormap.keyAxis() : colormap.valueAxis())->scaleType()
111 == QCPAxis::stLogarithmic;
113 == QCPAxis::stLogarithmic;
112
114
113 if (isLogarithmic) {
115 if (isLogarithmic) {
114 // For a logarithmic axis we can't use the conversion method of colormap, so we calculate
116 // For a logarithmic axis we can't use the conversion method of colormap, so we calculate
115 // the index manually based on the position of the coordinate on the axis
117 // the index manually based on the position of the coordinate on the axis
116
118
117 // Gets the axis range and the number of values between range bounds to calculate the step
119 // Gets the axis range and the number of values between range bounds to calculate the step
118 // between each value of the range
120 // between each value of the range
119 auto range = xCoord ? colormap.data()->keyRange() : colormap.data()->valueRange();
121 auto range = xCoord ? colormap.data()->keyRange() : colormap.data()->valueRange();
120 auto nbValues = (xCoord ? colormap.data()->keySize() : colormap.data()->valueSize()) - 1;
122 auto nbValues = (xCoord ? colormap.data()->keySize() : colormap.data()->valueSize()) - 1;
121 auto valueStep
123 auto valueStep
122 = (std::log10(range.upper) - std::log10(range.lower)) / static_cast<double>(nbValues);
124 = (std::log10(range.upper) - std::log10(range.lower)) / static_cast<double>(nbValues);
123
125
124 // According to the coord position, calculates the closest index in the range
126 // According to the coord position, calculates the closest index in the range
125 return std::round((std::log10(coord) - std::log10(range.lower)) / valueStep);
127 return std::round((std::log10(coord) - std::log10(range.lower)) / valueStep);
126 }
128 }
127 else {
129 else {
128 // For a linear axis, we use the conversion method of colormap
130 // For a linear axis, we use the conversion method of colormap
129 int index;
131 int index;
130 if (xCoord) {
132 if (xCoord) {
131 colormap.data()->coordToCell(coord, 0., &index, nullptr);
133 colormap.data()->coordToCell(coord, 0., &index, nullptr);
132 }
134 }
133 else {
135 else {
134 colormap.data()->coordToCell(0., coord, nullptr, &index);
136 colormap.data()->coordToCell(0., coord, nullptr, &index);
135 }
137 }
136
138
137 return index;
139 return index;
138 }
140 }
139 }
141 }
140
142
141 } // namespace
143 } // namespace
142
144
143 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
145 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
144 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
146 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
145 : m_Plot{graphWidget.plot()},
147 : m_Plot{graphWidget.plot()},
146 m_PointTracer{new QCPItemTracer{&m_Plot}},
148 m_PointTracer{new QCPItemTracer{&m_Plot}},
147 m_TracerTimer{},
149 m_TracerTimer{},
148 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
150 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
149 m_TitleText{new QCPItemText{&m_Plot}},
151 m_TitleText{new QCPItemText{&m_Plot}},
150 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
152 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
151 m_ShowXAxis{true},
153 m_ShowXAxis{true},
152 m_XAxisLabel{},
154 m_XAxisLabel{},
153 m_ColorScale{SqpColorScale{m_Plot}}
155 m_ColorScale{SqpColorScale{m_Plot}}
154 {
156 {
155 initPointTracerStyle(*m_PointTracer);
157 initPointTracerStyle(*m_PointTracer);
156
158
157 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
159 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
158 m_TracerTimer.setSingleShot(true);
160 m_TracerTimer.setSingleShot(true);
159
161
160 // Inits "close button" in plot overlay
162 // Inits "close button" in plot overlay
161 m_ClosePixmap->setLayer(OVERLAY_LAYER);
163 m_ClosePixmap->setLayer(OVERLAY_LAYER);
162 initClosePixmapStyle(*m_ClosePixmap);
164 initClosePixmapStyle(*m_ClosePixmap);
163
165
164 // Connects pixmap selection to graph widget closing
166 // Connects pixmap selection to graph widget closing
165 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
167 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
166 [&graphWidget](bool selected) {
168 [&graphWidget](bool selected) {
167 if (selected) {
169 if (selected) {
168 graphWidget.close();
170 graphWidget.close();
169 }
171 }
170 });
172 });
171
173
172 // Inits graph name in plot overlay
174 // Inits graph name in plot overlay
173 m_TitleText->setLayer(OVERLAY_LAYER);
175 m_TitleText->setLayer(OVERLAY_LAYER);
174 m_TitleText->setText(graphWidget.name());
176 m_TitleText->setText(graphWidget.name());
175 initTitleTextStyle(*m_TitleText);
177 initTitleTextStyle(*m_TitleText);
176
178
177 // Inits "show x-axis button" in plot overlay
179 // Inits "show x-axis button" in plot overlay
178 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
180 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
179 initXAxisPixmapStyle(*m_XAxisPixmap);
181 initXAxisPixmapStyle(*m_XAxisPixmap);
180
182
181 // Connects pixmap selection to graph x-axis showing/hiding
183 // Connects pixmap selection to graph x-axis showing/hiding
182 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
184 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
183 if (m_XAxisPixmap->selected()) {
185 if (m_XAxisPixmap->selected()) {
184 // Changes the selection state and refreshes the x-axis
186 // Changes the selection state and refreshes the x-axis
185 m_ShowXAxis = !m_ShowXAxis;
187 m_ShowXAxis = !m_ShowXAxis;
186 updateXAxisState();
188 updateXAxisState();
187 m_Plot.layer(AXES_LAYER)->replot();
189 m_Plot.layer(AXES_LAYER)->replot();
188
190
189 // Deselects the x-axis pixmap and updates icon
191 // Deselects the x-axis pixmap and updates icon
190 m_XAxisPixmap->setSelected(false);
192 m_XAxisPixmap->setSelected(false);
191 m_XAxisPixmap->setPixmap(
193 m_XAxisPixmap->setPixmap(
192 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
194 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
193 m_Plot.layer(OVERLAY_LAYER)->replot();
195 m_Plot.layer(OVERLAY_LAYER)->replot();
194 }
196 }
195 });
197 });
196 }
198 }
197
199
198 /// Updates state of x-axis according to the current selection of x-axis pixmap
200 /// Updates state of x-axis according to the current selection of x-axis pixmap
199 /// @remarks the method doesn't call plot refresh
201 /// @remarks the method doesn't call plot refresh
200 void updateXAxisState() noexcept
202 void updateXAxisState() noexcept
201 {
203 {
202 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
204 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
203 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
205 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
204 }
206 }
205
207
206 QCustomPlot &m_Plot;
208 QCustomPlot &m_Plot;
207 QCPItemTracer *m_PointTracer;
209 QCPItemTracer *m_PointTracer;
208 QTimer m_TracerTimer;
210 QTimer m_TracerTimer;
209 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
211 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
210 QCPItemText *m_TitleText; /// Graph's title
212 QCPItemText *m_TitleText; /// Graph's title
211 QCPItemPixmap *m_XAxisPixmap;
213 QCPItemPixmap *m_XAxisPixmap;
212 bool m_ShowXAxis; /// X-axis properties are shown or hidden
214 bool m_ShowXAxis; /// X-axis properties are shown or hidden
213 QString m_XAxisLabel;
215 QString m_XAxisLabel;
214 SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
216 SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
215 };
217 };
216
218
217 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
219 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
218 VisualizationGraphWidget &graphWidget)
220 VisualizationGraphWidget &graphWidget)
219 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
221 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
220 {
222 {
221 }
223 }
222
224
223 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
225 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
224 {
226 {
225 // Opens color scale editor if color scale is double clicked
227 // Opens color scale editor if color scale is double clicked
226 auto colorScale = static_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()));
228 auto colorScale = static_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()));
227 if (impl->m_ColorScale.m_Scale == colorScale) {
229 if (impl->m_ColorScale.m_Scale == colorScale) {
228 if (ColorScaleEditor{impl->m_ColorScale}.exec() == QDialog::Accepted) {
230 if (ColorScaleEditor{impl->m_ColorScale}.exec() == QDialog::Accepted) {
229 impl->m_Plot.replot();
231 impl->m_Plot.replot();
230 }
232 }
231 }
233 }
232 }
234 }
233
235
234 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
236 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
235 {
237 {
236 // Cancels pending refresh
238 // Cancels pending refresh
237 impl->m_TracerTimer.disconnect();
239 impl->m_TracerTimer.disconnect();
238
240
239 // Reinits tracers
241 // Reinits tracers
240 impl->m_PointTracer->setGraph(nullptr);
242 impl->m_PointTracer->setGraph(nullptr);
241 impl->m_PointTracer->setVisible(false);
243 impl->m_PointTracer->setVisible(false);
242 impl->m_Plot.replot();
244 impl->m_Plot.replot();
243
245
244 QString tooltip{};
246 QString tooltip{};
245
247
246 // Gets the graph under the mouse position
248 // Gets the graph under the mouse position
247 auto eventPos = event->pos();
249 auto eventPos = event->pos();
248 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
250 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
249 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
251 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
250 auto graphData = graph->data();
252 auto graphData = graph->data();
251
253
252 // Gets the closest data point to the mouse
254 // Gets the closest data point to the mouse
253 auto graphDataIt = graphData->findBegin(mouseKey);
255 auto graphDataIt = graphData->findBegin(mouseKey);
254 if (graphDataIt != graphData->constEnd()) {
256 if (graphDataIt != graphData->constEnd()) {
255 // Sets tooltip
257 // Sets tooltip
256 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
258 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
257 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
259 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
258 tooltip = GRAPH_TOOLTIP_FORMAT.arg(key, value);
260 tooltip = GRAPH_TOOLTIP_FORMAT.arg(key, value);
259
261
260 // Displays point tracer
262 // Displays point tracer
261 impl->m_PointTracer->setGraph(graph);
263 impl->m_PointTracer->setGraph(graph);
262 impl->m_PointTracer->setGraphKey(graphDataIt->key);
264 impl->m_PointTracer->setGraphKey(graphDataIt->key);
263 impl->m_PointTracer->setLayer(
265 impl->m_PointTracer->setLayer(
264 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
266 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
265 impl->m_PointTracer->setVisible(true);
267 impl->m_PointTracer->setVisible(true);
266 impl->m_Plot.replot();
268 impl->m_Plot.replot();
267 }
269 }
268 }
270 }
269 else if (auto colorMap = qobject_cast<QCPColorMap *>(impl->m_Plot.plottableAt(eventPos))) {
271 else if (auto colorMap = qobject_cast<QCPColorMap *>(impl->m_Plot.plottableAt(eventPos))) {
270 // Gets x and y coords
272 // Gets x and y coords
271 auto x = colorMap->keyAxis()->pixelToCoord(eventPos.x());
273 auto x = colorMap->keyAxis()->pixelToCoord(eventPos.x());
272 auto y = colorMap->valueAxis()->pixelToCoord(eventPos.y());
274 auto y = colorMap->valueAxis()->pixelToCoord(eventPos.y());
273
275
274 // Calculates x and y cell indexes, and retrieves the underlying value
276 // Calculates x and y cell indexes, and retrieves the underlying value
275 auto xCellIndex = colorMapCellIndex(*colorMap, x, true);
277 auto xCellIndex = colorMapCellIndex(*colorMap, x, true);
276 auto yCellIndex = colorMapCellIndex(*colorMap, y, false);
278 auto yCellIndex = colorMapCellIndex(*colorMap, y, false);
277 auto value = colorMap->data()->cell(xCellIndex, yCellIndex);
279 auto value = colorMap->data()->cell(xCellIndex, yCellIndex);
278
280
279 // Sets tooltips
281 // Sets tooltips
280 tooltip = COLORMAP_TOOLTIP_FORMAT.arg(formatValue(x, *colorMap->keyAxis()),
282 tooltip = COLORMAP_TOOLTIP_FORMAT.arg(formatValue(x, *colorMap->keyAxis()),
281 formatValue(y, *colorMap->valueAxis()),
283 formatValue(y, *colorMap->valueAxis()),
282 formatValue(value, *colorMap->colorScale()->axis()));
284 formatValue(value, *colorMap->colorScale()->axis()));
283 }
285 }
284
286
285 if (!tooltip.isEmpty()) {
287 if (!tooltip.isEmpty()) {
286 // Starts timer to show tooltip after timeout
288 // Starts timer to show tooltip after timeout
287 auto showTooltip = [tooltip, eventPos, this]() {
289 auto showTooltip = [tooltip, eventPos, this]() {
288 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
290 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
289 &impl->m_Plot, TOOLTIP_RECT);
291 &impl->m_Plot, TOOLTIP_RECT);
290 };
292 };
291
293
292 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
294 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
293 impl->m_TracerTimer.start();
295 impl->m_TracerTimer.start();
294 }
296 }
295 }
297 }
296
298
297 void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept
299 void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept
298 {
300 {
299 // Updates color scale bounds
301 // Updates color scale bounds
300 impl->m_ColorScale.updateDataRange();
302 impl->m_ColorScale.updateDataRange();
301 impl->m_Plot.replot();
303 impl->m_Plot.replot();
302 }
304 }
303
305
304 void VisualizationGraphRenderingDelegate::setAxesProperties(
306 void VisualizationGraphRenderingDelegate::setAxesProperties(
305 std::shared_ptr<IDataSeries> dataSeries) noexcept
307 std::shared_ptr<IDataSeries> dataSeries) noexcept
306 {
308 {
307 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
309 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
308 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
310 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
309
311
310 auto axisHelper = IAxisHelperFactory::create(dataSeries);
312 auto axisHelper = IAxisHelperFactory::create(dataSeries);
311 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
313 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
312
314
313 // Updates x-axis state
315 // Updates x-axis state
314 impl->updateXAxisState();
316 impl->updateXAxisState();
315
317
316 impl->m_Plot.layer(AXES_LAYER)->replot();
318 impl->m_Plot.layer(AXES_LAYER)->replot();
317 }
319 }
318
320
319 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
321 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
320 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
322 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
321 {
323 {
322 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
324 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
323 plottablesHelper->setProperties(plottables);
325 plottablesHelper->setProperties(plottables);
324 }
326 }
325
327
326 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
328 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
327 {
329 {
328 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
330 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
329 overlay->setVisible(show);
331 overlay->setVisible(show);
330 overlay->replot();
332 overlay->replot();
331 }
333 }
@@ -1,621 +1,721
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/VisualizationZoneWidget.h"
8 #include "Visualization/VisualizationZoneWidget.h"
8 #include "ui_VisualizationGraphWidget.h"
9 #include "ui_VisualizationGraphWidget.h"
9
10
10 #include <Common/MimeTypesDef.h>
11 #include <Common/MimeTypesDef.h>
11 #include <Data/ArrayData.h>
12 #include <Data/ArrayData.h>
12 #include <Data/IDataSeries.h>
13 #include <Data/IDataSeries.h>
13 #include <Data/SpectrogramSeries.h>
14 #include <Data/SpectrogramSeries.h>
14 #include <DragAndDrop/DragDropHelper.h>
15 #include <DragAndDrop/DragDropHelper.h>
15 #include <Settings/SqpSettingsDefs.h>
16 #include <Settings/SqpSettingsDefs.h>
16 #include <SqpApplication.h>
17 #include <SqpApplication.h>
17 #include <Time/TimeController.h>
18 #include <Time/TimeController.h>
18 #include <Variable/Variable.h>
19 #include <Variable/Variable.h>
19 #include <Variable/VariableController.h>
20 #include <Variable/VariableController.h>
20
21
21 #include <unordered_map>
22 #include <unordered_map>
22
23
23 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
24 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
24
25
25 namespace {
26 namespace {
26
27
27 /// Key pressed to enable zoom on horizontal axis
28 /// Key pressed to enable zoom on horizontal axis
28 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
29 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
29
30
30 /// Key pressed to enable zoom on vertical axis
31 /// Key pressed to enable zoom on vertical axis
31 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
32 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
32
33
33 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
34 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
34 const auto PAN_SPEED = 5;
35 const auto PAN_SPEED = 5;
35
36
36 /// Key pressed to enable a calibration pan
37 /// Key pressed to enable a calibration pan
37 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
38 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
38
39
39 /// Minimum size for the zoom box, in percentage of the axis range
40 /// Minimum size for the zoom box, in percentage of the axis range
40 const auto ZOOM_BOX_MIN_SIZE = 0.8;
41 const auto ZOOM_BOX_MIN_SIZE = 0.8;
41
42
42 /// Format of the dates appearing in the label of a cursor
43 /// Format of the dates appearing in the label of a cursor
43 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
44 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
44
45
45 } // namespace
46 } // namespace
46
47
47 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
48 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
48
49
49 explicit VisualizationGraphWidgetPrivate(const QString &name)
50 explicit VisualizationGraphWidgetPrivate(const QString &name)
50 : m_Name{name},
51 : m_Name{name},
51 m_DoAcquisition{true},
52 m_DoAcquisition{true},
52 m_IsCalibration{false},
53 m_IsCalibration{false},
53 m_RenderingDelegate{nullptr}
54 m_RenderingDelegate{nullptr}
54 {
55 {
55 }
56 }
56
57
57 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
58 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
58 const SqpRange &range)
59 const SqpRange &range)
59 {
60 {
60 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
61 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
61
62
62 // Prevents that data has changed to update rendering
63 // Prevents that data has changed to update rendering
63 m_RenderingDelegate->onPlotUpdated();
64 m_RenderingDelegate->onPlotUpdated();
64 }
65 }
65
66
66 QString m_Name;
67 QString m_Name;
67 // 1 variable -> n qcpplot
68 // 1 variable -> n qcpplot
68 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
69 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
69 bool m_DoAcquisition;
70 bool m_DoAcquisition;
70 bool m_IsCalibration;
71 bool m_IsCalibration;
71 /// Delegate used to attach rendering features to the plot
72 /// Delegate used to attach rendering features to the plot
72 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
73 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
73
74
74 QCPItemRect *m_DrawingRect = nullptr;
75 QCPItemRect *m_DrawingZoomRect = nullptr;
76
75 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
77 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
76 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
78 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
77
79
78 void configureDrawingRect()
80 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
79 {
81 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
80 if (m_DrawingRect) {
82 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
81 QPen p;
82 p.setWidth(2);
83 m_DrawingRect->setPen(p);
84 }
85 }
86
83
87 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
84 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
88 {
85 {
89 removeDrawingRect(plot);
86 removeDrawingRect(plot);
90
87
91 auto axisPos = posToAxisPos(pos, plot);
88 auto axisPos = posToAxisPos(pos, plot);
92
89
93 m_DrawingRect = new QCPItemRect{&plot};
90 m_DrawingZoomRect = new QCPItemRect{&plot};
94 configureDrawingRect();
91 QPen p;
92 p.setWidth(2);
93 m_DrawingZoomRect->setPen(p);
95
94
96 m_DrawingRect->topLeft->setCoords(axisPos);
95 m_DrawingZoomRect->topLeft->setCoords(axisPos);
97 m_DrawingRect->bottomRight->setCoords(axisPos);
96 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
98 }
97 }
99
98
100 void removeDrawingRect(QCustomPlot &plot)
99 void removeDrawingRect(QCustomPlot &plot)
101 {
100 {
102 if (m_DrawingRect) {
101 if (m_DrawingZoomRect) {
103 plot.removeItem(m_DrawingRect); // the item is deleted by QCustomPlot
102 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
104 m_DrawingRect = nullptr;
103 m_DrawingZoomRect = nullptr;
105 plot.replot(QCustomPlot::rpQueuedReplot);
104 plot.replot(QCustomPlot::rpQueuedReplot);
106 }
105 }
107 }
106 }
108
107
108 void startDrawingZone(const QPoint &pos, QCustomPlot &plot)
109 {
110 endDrawingZone(plot);
111
112 auto axisPos = posToAxisPos(pos, plot);
113
114 m_DrawingZone = new VisualizationSelectionZoneItem{&plot};
115 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
116 m_DrawingZone->setEditionEnabled(false);
117 }
118
119 void endDrawingZone(QCustomPlot &plot)
120 {
121 if (m_DrawingZone) {
122 auto drawingZoneRange = m_DrawingZone->range();
123 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
124 m_DrawingZone->setEditionEnabled(true);
125 m_SelectionZones.append(m_DrawingZone);
126 }
127 else {
128 plot.removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
129 }
130
131 plot.replot(QCustomPlot::rpQueuedReplot);
132 m_DrawingZone = nullptr;
133 }
134 }
135
136 void setSelectionZonesEditionEnabled(bool value)
137 {
138 for (auto s : m_SelectionZones) {
139 s->setEditionEnabled(value);
140 }
141 }
142
109 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
143 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
110 {
144 {
111 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
145 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
112 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
146 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
113 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
147 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
114 }
148 }
115
149
116 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
150 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
117 {
151 {
118 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
152 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
119 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
153 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
120
121 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
154 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
122 }
155 }
123 };
156 };
124
157
125 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
158 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
126 : VisualizationDragWidget{parent},
159 : VisualizationDragWidget{parent},
127 ui{new Ui::VisualizationGraphWidget},
160 ui{new Ui::VisualizationGraphWidget},
128 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
161 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
129 {
162 {
130 ui->setupUi(this);
163 ui->setupUi(this);
131
164
132 // 'Close' options : widget is deleted when closed
165 // 'Close' options : widget is deleted when closed
133 setAttribute(Qt::WA_DeleteOnClose);
166 setAttribute(Qt::WA_DeleteOnClose);
134
167
135 // Set qcpplot properties :
168 // Set qcpplot properties :
136 // - Drag (on x-axis) and zoom are enabled
169 // - zoom is enabled
137 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
170 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
138 ui->widget->setInteractions(QCP::iRangeZoom | QCP::iSelectItems);
171 ui->widget->setInteractions(QCP::iRangeZoom | QCP::iSelectItems);
139
172
140 // The delegate must be initialized after the ui as it uses the plot
173 // The delegate must be initialized after the ui as it uses the plot
141 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
174 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
142
175
143 // Init the cursors
176 // Init the cursors
144 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
177 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
145 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
178 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
146 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
179 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
147 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
180 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
148
181
149 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
182 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
150 connect(ui->widget, &QCustomPlot::mouseRelease, this,
183 connect(ui->widget, &QCustomPlot::mouseRelease, this,
151 &VisualizationGraphWidget::onMouseRelease);
184 &VisualizationGraphWidget::onMouseRelease);
152 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
185 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
153 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
186 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
154 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
187 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
155 &VisualizationGraphWidget::onMouseDoubleClick);
188 &VisualizationGraphWidget::onMouseDoubleClick);
156 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
189 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
157 &QCPAxis::rangeChanged),
190 &QCPAxis::rangeChanged),
158 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
191 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
159
192
160 // Activates menu when right clicking on the graph
193 // Activates menu when right clicking on the graph
161 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
194 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
162 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
195 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
163 &VisualizationGraphWidget::onGraphMenuRequested);
196 &VisualizationGraphWidget::onGraphMenuRequested);
164
197
165 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
198 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
166 &VariableController::onRequestDataLoading);
199 &VariableController::onRequestDataLoading);
167
200
168 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
201 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
169 &VisualizationGraphWidget::onUpdateVarDisplaying);
202 &VisualizationGraphWidget::onUpdateVarDisplaying);
170
203
171 #ifdef Q_OS_MAC
204 #ifdef Q_OS_MAC
172 plot().setPlottingHint(QCP::phFastPolylines, true);
205 plot().setPlottingHint(QCP::phFastPolylines, true);
173 #endif
206 #endif
174 }
207 }
175
208
176
209
177 VisualizationGraphWidget::~VisualizationGraphWidget()
210 VisualizationGraphWidget::~VisualizationGraphWidget()
178 {
211 {
179 delete ui;
212 delete ui;
180 }
213 }
181
214
182 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
215 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
183 {
216 {
184 auto parent = parentWidget();
217 auto parent = parentWidget();
185 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
218 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
186 parent = parent->parentWidget();
219 parent = parent->parentWidget();
187 }
220 }
188
221
189 return qobject_cast<VisualizationZoneWidget *>(parent);
222 return qobject_cast<VisualizationZoneWidget *>(parent);
190 }
223 }
191
224
192 void VisualizationGraphWidget::enableAcquisition(bool enable)
225 void VisualizationGraphWidget::enableAcquisition(bool enable)
193 {
226 {
194 impl->m_DoAcquisition = enable;
227 impl->m_DoAcquisition = enable;
195 }
228 }
196
229
197 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
230 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
198 {
231 {
199 // Uses delegate to create the qcpplot components according to the variable
232 // Uses delegate to create the qcpplot components according to the variable
200 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
233 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
201
234
202 if (auto dataSeries = variable->dataSeries()) {
235 if (auto dataSeries = variable->dataSeries()) {
203 // Set axes properties according to the units of the data series
236 // Set axes properties according to the units of the data series
204 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
237 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
205
238
206 // Sets rendering properties for the new plottables
239 // Sets rendering properties for the new plottables
207 // Warning: this method must be called after setAxesProperties(), as it can access to some
240 // Warning: this method must be called after setAxesProperties(), as it can access to some
208 // axes properties that have to be initialized
241 // axes properties that have to be initialized
209 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
242 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
210 }
243 }
211
244
212 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
245 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
213
246
214 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
247 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
215
248
216 this->enableAcquisition(false);
249 this->enableAcquisition(false);
217 this->setGraphRange(range);
250 this->setGraphRange(range);
218 this->enableAcquisition(true);
251 this->enableAcquisition(true);
219
252
220 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
253 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
221
254
222 emit variableAdded(variable);
255 emit variableAdded(variable);
223 }
256 }
224
257
225 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
258 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
226 {
259 {
227 // Each component associated to the variable :
260 // Each component associated to the variable :
228 // - is removed from qcpplot (which deletes it)
261 // - is removed from qcpplot (which deletes it)
229 // - is no longer referenced in the map
262 // - is no longer referenced in the map
230 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
263 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
231 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
264 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
232 emit variableAboutToBeRemoved(variable);
265 emit variableAboutToBeRemoved(variable);
233
266
234 auto &plottablesMap = variableIt->second;
267 auto &plottablesMap = variableIt->second;
235
268
236 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
269 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
237 plottableIt != plottableEnd;) {
270 plottableIt != plottableEnd;) {
238 ui->widget->removePlottable(plottableIt->second);
271 ui->widget->removePlottable(plottableIt->second);
239 plottableIt = plottablesMap.erase(plottableIt);
272 plottableIt = plottablesMap.erase(plottableIt);
240 }
273 }
241
274
242 impl->m_VariableToPlotMultiMap.erase(variableIt);
275 impl->m_VariableToPlotMultiMap.erase(variableIt);
243 }
276 }
244
277
245 // Updates graph
278 // Updates graph
246 ui->widget->replot();
279 ui->widget->replot();
247 }
280 }
248
281
249 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
282 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
250 {
283 {
251 auto variables = QList<std::shared_ptr<Variable> >{};
284 auto variables = QList<std::shared_ptr<Variable> >{};
252 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
285 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
253 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
286 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
254 variables << it->first;
287 variables << it->first;
255 }
288 }
256
289
257 return variables;
290 return variables;
258 }
291 }
259
292
260 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
293 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
261 {
294 {
262 if (!variable) {
295 if (!variable) {
263 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
296 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
264 return;
297 return;
265 }
298 }
266
299
267 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
300 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
268 }
301 }
269
302
270 SqpRange VisualizationGraphWidget::graphRange() const noexcept
303 SqpRange VisualizationGraphWidget::graphRange() const noexcept
271 {
304 {
272 auto graphRange = ui->widget->xAxis->range();
305 auto graphRange = ui->widget->xAxis->range();
273 return SqpRange{graphRange.lower, graphRange.upper};
306 return SqpRange{graphRange.lower, graphRange.upper};
274 }
307 }
275
308
276 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
309 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
277 {
310 {
278 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
311 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
279 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
312 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
280 ui->widget->replot();
313 ui->widget->replot();
281 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
314 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
282 }
315 }
283
316
284 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
317 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
285 {
318 {
286 if (visitor) {
319 if (visitor) {
287 visitor->visit(this);
320 visitor->visit(this);
288 }
321 }
289 else {
322 else {
290 qCCritical(LOG_VisualizationGraphWidget())
323 qCCritical(LOG_VisualizationGraphWidget())
291 << tr("Can't visit widget : the visitor is null");
324 << tr("Can't visit widget : the visitor is null");
292 }
325 }
293 }
326 }
294
327
295 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
328 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
296 {
329 {
297 auto isSpectrogram = [](const auto &variable) {
330 auto isSpectrogram = [](const auto &variable) {
298 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
331 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
299 };
332 };
300
333
301 // - A spectrogram series can't be dropped on graph with existing plottables
334 // - A spectrogram series can't be dropped on graph with existing plottables
302 // - No data series can be dropped on graph with existing spectrogram series
335 // - No data series can be dropped on graph with existing spectrogram series
303 return isSpectrogram(variable)
336 return isSpectrogram(variable)
304 ? impl->m_VariableToPlotMultiMap.empty()
337 ? impl->m_VariableToPlotMultiMap.empty()
305 : std::none_of(
338 : std::none_of(
306 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
339 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
307 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
340 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
308 }
341 }
309
342
310 bool VisualizationGraphWidget::contains(const Variable &variable) const
343 bool VisualizationGraphWidget::contains(const Variable &variable) const
311 {
344 {
312 // Finds the variable among the keys of the map
345 // Finds the variable among the keys of the map
313 auto variablePtr = &variable;
346 auto variablePtr = &variable;
314 auto findVariable
347 auto findVariable
315 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
348 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
316
349
317 auto end = impl->m_VariableToPlotMultiMap.cend();
350 auto end = impl->m_VariableToPlotMultiMap.cend();
318 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
351 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
319 return it != end;
352 return it != end;
320 }
353 }
321
354
322 QString VisualizationGraphWidget::name() const
355 QString VisualizationGraphWidget::name() const
323 {
356 {
324 return impl->m_Name;
357 return impl->m_Name;
325 }
358 }
326
359
327 QMimeData *VisualizationGraphWidget::mimeData() const
360 QMimeData *VisualizationGraphWidget::mimeData() const
328 {
361 {
329 auto mimeData = new QMimeData;
362 auto mimeData = new QMimeData;
330 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
363 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
331
364
332 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
365 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
333 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
366 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
334
367
335 return mimeData;
368 return mimeData;
336 }
369 }
337
370
338 bool VisualizationGraphWidget::isDragAllowed() const
371 bool VisualizationGraphWidget::isDragAllowed() const
339 {
372 {
340 return true;
373 return true;
341 }
374 }
342
375
343 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
376 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
344 {
377 {
345 if (highlighted) {
378 if (highlighted) {
346 plot().setBackground(QBrush(QColor("#BBD5EE")));
379 plot().setBackground(QBrush(QColor("#BBD5EE")));
347 }
380 }
348 else {
381 else {
349 plot().setBackground(QBrush(Qt::white));
382 plot().setBackground(QBrush(Qt::white));
350 }
383 }
351
384
352 plot().update();
385 plot().update();
353 }
386 }
354
387
355 void VisualizationGraphWidget::addVerticalCursor(double time)
388 void VisualizationGraphWidget::addVerticalCursor(double time)
356 {
389 {
357 impl->m_VerticalCursor->setPosition(time);
390 impl->m_VerticalCursor->setPosition(time);
358 impl->m_VerticalCursor->setVisible(true);
391 impl->m_VerticalCursor->setVisible(true);
359
392
360 auto text
393 auto text
361 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
394 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
362 impl->m_VerticalCursor->setLabelText(text);
395 impl->m_VerticalCursor->setLabelText(text);
363 }
396 }
364
397
365 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
398 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
366 {
399 {
367 impl->m_VerticalCursor->setAbsolutePosition(position);
400 impl->m_VerticalCursor->setAbsolutePosition(position);
368 impl->m_VerticalCursor->setVisible(true);
401 impl->m_VerticalCursor->setVisible(true);
369
402
370 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
403 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
371 auto text
404 auto text
372 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
405 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
373 impl->m_VerticalCursor->setLabelText(text);
406 impl->m_VerticalCursor->setLabelText(text);
374 }
407 }
375
408
376 void VisualizationGraphWidget::removeVerticalCursor()
409 void VisualizationGraphWidget::removeVerticalCursor()
377 {
410 {
378 impl->m_VerticalCursor->setVisible(false);
411 impl->m_VerticalCursor->setVisible(false);
379 plot().replot(QCustomPlot::rpQueuedReplot);
412 plot().replot(QCustomPlot::rpQueuedReplot);
380 }
413 }
381
414
382 void VisualizationGraphWidget::addHorizontalCursor(double value)
415 void VisualizationGraphWidget::addHorizontalCursor(double value)
383 {
416 {
384 impl->m_HorizontalCursor->setPosition(value);
417 impl->m_HorizontalCursor->setPosition(value);
385 impl->m_HorizontalCursor->setVisible(true);
418 impl->m_HorizontalCursor->setVisible(true);
386 impl->m_HorizontalCursor->setLabelText(QString::number(value));
419 impl->m_HorizontalCursor->setLabelText(QString::number(value));
387 }
420 }
388
421
389 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
422 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
390 {
423 {
391 impl->m_HorizontalCursor->setAbsolutePosition(position);
424 impl->m_HorizontalCursor->setAbsolutePosition(position);
392 impl->m_HorizontalCursor->setVisible(true);
425 impl->m_HorizontalCursor->setVisible(true);
393
426
394 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
427 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
395 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
428 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
396 }
429 }
397
430
398 void VisualizationGraphWidget::removeHorizontalCursor()
431 void VisualizationGraphWidget::removeHorizontalCursor()
399 {
432 {
400 impl->m_HorizontalCursor->setVisible(false);
433 impl->m_HorizontalCursor->setVisible(false);
401 plot().replot(QCustomPlot::rpQueuedReplot);
434 plot().replot(QCustomPlot::rpQueuedReplot);
402 }
435 }
403
436
404 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
437 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
405 {
438 {
406 Q_UNUSED(event);
439 Q_UNUSED(event);
407
440
408 // Prevents that all variables will be removed from graph when it will be closed
441 // Prevents that all variables will be removed from graph when it will be closed
409 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
442 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
410 emit variableAboutToBeRemoved(variableEntry.first);
443 emit variableAboutToBeRemoved(variableEntry.first);
411 }
444 }
412 }
445 }
413
446
414 void VisualizationGraphWidget::enterEvent(QEvent *event)
447 void VisualizationGraphWidget::enterEvent(QEvent *event)
415 {
448 {
416 Q_UNUSED(event);
449 Q_UNUSED(event);
417 impl->m_RenderingDelegate->showGraphOverlay(true);
450 impl->m_RenderingDelegate->showGraphOverlay(true);
418 }
451 }
419
452
420 void VisualizationGraphWidget::leaveEvent(QEvent *event)
453 void VisualizationGraphWidget::leaveEvent(QEvent *event)
421 {
454 {
422 Q_UNUSED(event);
455 Q_UNUSED(event);
423 impl->m_RenderingDelegate->showGraphOverlay(false);
456 impl->m_RenderingDelegate->showGraphOverlay(false);
424
457
425 if (auto parentZone = parentZoneWidget()) {
458 if (auto parentZone = parentZoneWidget()) {
426 parentZone->notifyMouseLeaveGraph(this);
459 parentZone->notifyMouseLeaveGraph(this);
427 }
460 }
428 else {
461 else {
429 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
462 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
430 }
463 }
464
465 if (impl->m_HoveredZone) {
466 impl->m_HoveredZone->setHovered(false);
467 impl->m_HoveredZone = nullptr;
468 }
431 }
469 }
432
470
433 QCustomPlot &VisualizationGraphWidget::plot() noexcept
471 QCustomPlot &VisualizationGraphWidget::plot() noexcept
434 {
472 {
435 return *ui->widget;
473 return *ui->widget;
436 }
474 }
437
475
438 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
476 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
439 {
477 {
440 QMenu graphMenu{};
478 QMenu graphMenu{};
441
479
442 // Iterates on variables (unique keys)
480 // Iterates on variables (unique keys)
443 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
481 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
444 end = impl->m_VariableToPlotMultiMap.cend();
482 end = impl->m_VariableToPlotMultiMap.cend();
445 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
483 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
446 // 'Remove variable' action
484 // 'Remove variable' action
447 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
485 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
448 [ this, var = it->first ]() { removeVariable(var); });
486 [ this, var = it->first ]() { removeVariable(var); });
449 }
487 }
450
488
451 if (!graphMenu.isEmpty()) {
489 if (!graphMenu.isEmpty()) {
452 graphMenu.exec(QCursor::pos());
490 graphMenu.exec(QCursor::pos());
453 }
491 }
454 }
492 }
455
493
456 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
494 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
457 {
495 {
458 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
496 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
459 << QThread::currentThread()->objectName() << "DoAcqui"
497 << QThread::currentThread()->objectName() << "DoAcqui"
460 << impl->m_DoAcquisition;
498 << impl->m_DoAcquisition;
461
499
462 auto graphRange = SqpRange{t1.lower, t1.upper};
500 auto graphRange = SqpRange{t1.lower, t1.upper};
463 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
501 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
464
502
465 if (impl->m_DoAcquisition) {
503 if (impl->m_DoAcquisition) {
466 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
504 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
467
505
468 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
506 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
469 end = impl->m_VariableToPlotMultiMap.end();
507 end = impl->m_VariableToPlotMultiMap.end();
470 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
508 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
471 variableUnderGraphVector.push_back(it->first);
509 variableUnderGraphVector.push_back(it->first);
472 }
510 }
473 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
511 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
474 !impl->m_IsCalibration);
512 !impl->m_IsCalibration);
475
513
476 if (!impl->m_IsCalibration) {
514 if (!impl->m_IsCalibration) {
477 qCDebug(LOG_VisualizationGraphWidget())
515 qCDebug(LOG_VisualizationGraphWidget())
478 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
516 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
479 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
517 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
480 emit synchronize(graphRange, oldGraphRange);
518 emit synchronize(graphRange, oldGraphRange);
481 }
519 }
482 }
520 }
483
521
484 auto pos = mapFromGlobal(QCursor::pos());
522 auto pos = mapFromGlobal(QCursor::pos());
485 auto axisPos = impl->posToAxisPos(pos, plot());
523 auto axisPos = impl->posToAxisPos(pos, plot());
486 if (auto parentZone = parentZoneWidget()) {
524 if (auto parentZone = parentZoneWidget()) {
487 if (impl->pointIsInAxisRect(axisPos, plot())) {
525 if (impl->pointIsInAxisRect(axisPos, plot())) {
488 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
526 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
489 }
527 }
490 else {
528 else {
491 parentZone->notifyMouseLeaveGraph(this);
529 parentZone->notifyMouseLeaveGraph(this);
492 }
530 }
493 }
531 }
494 else {
532 else {
495 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
533 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
496 }
534 }
497 }
535 }
498
536
499 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
537 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
500 {
538 {
501 impl->m_RenderingDelegate->onMouseDoubleClick(event);
539 impl->m_RenderingDelegate->onMouseDoubleClick(event);
502 }
540 }
503
541
504 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
542 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
505 {
543 {
506 // Handles plot rendering when mouse is moving
544 // Handles plot rendering when mouse is moving
507 impl->m_RenderingDelegate->onMouseMove(event);
545 impl->m_RenderingDelegate->onMouseMove(event);
508
546
509 auto axisPos = impl->posToAxisPos(event->pos(), plot());
547 auto axisPos = impl->posToAxisPos(event->pos(), plot());
510
548
511 if (impl->m_DrawingRect) {
549 // Zoom box and zone drawing
512 impl->m_DrawingRect->bottomRight->setCoords(axisPos);
550 if (impl->m_DrawingZoomRect) {
551 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
552 }
553 else if (impl->m_DrawingZone) {
554 impl->m_DrawingZone->setEnd(axisPos.x());
513 }
555 }
514
556
557 // Cursor
515 if (auto parentZone = parentZoneWidget()) {
558 if (auto parentZone = parentZoneWidget()) {
516 if (impl->pointIsInAxisRect(axisPos, plot())) {
559 if (impl->pointIsInAxisRect(axisPos, plot())) {
517 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
560 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
518 }
561 }
519 else {
562 else {
520 parentZone->notifyMouseLeaveGraph(this);
563 parentZone->notifyMouseLeaveGraph(this);
521 }
564 }
522 }
565 }
523 else {
566 else {
524 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
567 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
525 }
568 }
526
569
570 // Search for the selection zone under the mouse
571 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
572 auto minDistanceToZone = -1;
573 for (auto zone : impl->m_SelectionZones) {
574 auto distanceToZone = zone->selectTest(event->pos(), true);
575 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone) && distanceToZone >= 0
576 && distanceToZone < plot().selectionTolerance()) {
577 selectionZoneItemUnderCursor = zone;
578 }
579 }
580
581 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
582 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
583
584 // Sets the appropriate cursor shape
585 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
586 setCursor(cursorShape);
587
588 // Manages the hovered zone
589 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
590 if (impl->m_HoveredZone) {
591 impl->m_HoveredZone->setHovered(false);
592 }
593 selectionZoneItemUnderCursor->setHovered(true);
594 impl->m_HoveredZone = selectionZoneItemUnderCursor;
595 plot().replot(QCustomPlot::rpQueuedReplot);
596 }
597 }
598 else {
599 // There is no zone under the mouse or the interaction mode is not "selection zones"
600 if (impl->m_HoveredZone) {
601 impl->m_HoveredZone->setHovered(false);
602 impl->m_HoveredZone = nullptr;
603 }
604
605 setCursor(Qt::ArrowCursor);
606 }
607
527 VisualizationDragWidget::mouseMoveEvent(event);
608 VisualizationDragWidget::mouseMoveEvent(event);
528 }
609 }
529
610
530 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
611 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
531 {
612 {
532 auto value = event->angleDelta().x() + event->angleDelta().y();
613 auto value = event->angleDelta().x() + event->angleDelta().y();
533 if (value != 0) {
614 if (value != 0) {
534
615
535 auto direction = value > 0 ? 1.0 : -1.0;
616 auto direction = value > 0 ? 1.0 : -1.0;
536 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
617 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
537 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
618 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
538 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
619 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
539
620
540 auto zoomOrientations = QFlags<Qt::Orientation>{};
621 auto zoomOrientations = QFlags<Qt::Orientation>{};
541 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
622 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
542 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
623 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
543
624
544 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
625 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
545
626
546 if (!isZoomX && !isZoomY) {
627 if (!isZoomX && !isZoomY) {
547 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
628 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
548 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
629 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
549
630
550 axis->setRange(axis->range() + diff);
631 axis->setRange(axis->range() + diff);
551
632
552 if (plot().noAntialiasingOnDrag()) {
633 if (plot().noAntialiasingOnDrag()) {
553 plot().setNotAntialiasedElements(QCP::aeAll);
634 plot().setNotAntialiasedElements(QCP::aeAll);
554 }
635 }
555
636
556 plot().replot(QCustomPlot::rpQueuedReplot);
637 plot().replot(QCustomPlot::rpQueuedReplot);
557 }
638 }
558 }
639 }
559 }
640 }
560
641
561 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
642 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
562 {
643 {
563 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
644 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
645 // Starts a zoom box
564 impl->startDrawingRect(event->pos(), plot());
646 impl->startDrawingRect(event->pos(), plot());
565 }
647 }
648 else if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
649 && impl->m_DrawingZone == nullptr) {
650 // Starts a new selection zone
651 auto itemAtPos = plot().itemAt(event->pos(), true);
652 if (!itemAtPos) {
653 impl->startDrawingZone(event->pos(), plot());
654 }
655 }
656
657 // Allows mouse panning only in default mode
658 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
659 == SqpApplication::PlotsInteractionMode::None);
660
661 // Allows zone edition only in selection zone mode
662 impl->setSelectionZonesEditionEnabled(sqpApp->plotsInteractionMode()
663 == SqpApplication::PlotsInteractionMode::SelectionZones);
566
664
567 VisualizationDragWidget::mousePressEvent(event);
665 VisualizationDragWidget::mousePressEvent(event);
568 }
666 }
569
667
570 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
668 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
571 {
669 {
572 if (impl->m_DrawingRect) {
670 if (impl->m_DrawingZoomRect) {
573
671
574 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
672 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
575 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
673 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
576
674
577 auto newAxisXRange = QCPRange{impl->m_DrawingRect->topLeft->coords().x(),
675 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
578 impl->m_DrawingRect->bottomRight->coords().x()};
676 impl->m_DrawingZoomRect->bottomRight->coords().x()};
579
677
580 auto newAxisYRange = QCPRange{impl->m_DrawingRect->topLeft->coords().y(),
678 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
581 impl->m_DrawingRect->bottomRight->coords().y()};
679 impl->m_DrawingZoomRect->bottomRight->coords().y()};
582
680
583 impl->removeDrawingRect(plot());
681 impl->removeDrawingRect(plot());
584
682
585 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
683 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
586 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
684 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
587 axisX->setRange(newAxisXRange);
685 axisX->setRange(newAxisXRange);
588 axisY->setRange(newAxisYRange);
686 axisY->setRange(newAxisYRange);
589
687
590 plot().replot(QCustomPlot::rpQueuedReplot);
688 plot().replot(QCustomPlot::rpQueuedReplot);
591 }
689 }
592 }
690 }
593
691
692 impl->endDrawingZone(plot());
693
594 impl->m_IsCalibration = false;
694 impl->m_IsCalibration = false;
595 }
695 }
596
696
597 void VisualizationGraphWidget::onDataCacheVariableUpdated()
697 void VisualizationGraphWidget::onDataCacheVariableUpdated()
598 {
698 {
599 auto graphRange = ui->widget->xAxis->range();
699 auto graphRange = ui->widget->xAxis->range();
600 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
700 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
601
701
602 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
702 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
603 auto variable = variableEntry.first;
703 auto variable = variableEntry.first;
604 qCDebug(LOG_VisualizationGraphWidget())
704 qCDebug(LOG_VisualizationGraphWidget())
605 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
705 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
606 qCDebug(LOG_VisualizationGraphWidget())
706 qCDebug(LOG_VisualizationGraphWidget())
607 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
707 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
608 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
708 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
609 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
709 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
610 }
710 }
611 }
711 }
612 }
712 }
613
713
614 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
714 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
615 const SqpRange &range)
715 const SqpRange &range)
616 {
716 {
617 auto it = impl->m_VariableToPlotMultiMap.find(variable);
717 auto it = impl->m_VariableToPlotMultiMap.find(variable);
618 if (it != impl->m_VariableToPlotMultiMap.end()) {
718 if (it != impl->m_VariableToPlotMultiMap.end()) {
619 impl->updateData(it->second, variable->dataSeries(), range);
719 impl->updateData(it->second, variable->dataSeries(), range);
620 }
720 }
621 }
721 }
General Comments 0
You need to be logged in to leave comments. Login now