##// END OF EJS Templates
Refactoring handling of axes properties (2)...
Alexandre Leroux -
r917:3bf91527f27d
parent child
Show More
@@ -1,31 +1,34
1 #ifndef SCIQLOP_AXISRENDERINGUTILS_H
1 #ifndef SCIQLOP_AXISRENDERINGUTILS_H
2 #define SCIQLOP_AXISRENDERINGUTILS_H
2 #define SCIQLOP_AXISRENDERINGUTILS_H
3
3
4 #include <memory>
4 #include <memory>
5
5
6 #include <QtCore/QString>
6 #include <QtCore/QString>
7
7
8 class IDataSeries;
8 class IDataSeries;
9 class QCPAxis;
9 class QCPAxis;
10 class QCPColorScale;
10 class QCPColorScale;
11 class QCustomPlot;
11 class QCustomPlot;
12
12
13 /// Formats a data value according to the axis on which it is present
14 QString formatValue(double value, const QCPAxis &axis);
15
13 /**
16 /**
14 * Helper used to handle axes rendering
17 * Helper used to handle axes rendering
15 */
18 */
16 struct IAxisHelper {
19 struct IAxisHelper {
17 virtual ~IAxisHelper() noexcept = default;
20 virtual ~IAxisHelper() noexcept = default;
18
21
19 /// Set properties of the plot's axes and the color scale associated to plot passed as
22 /// Set properties of the plot's axes and the color scale associated to plot passed as
20 /// parameters
23 /// parameters
21 /// @param plot the plot for which to set axe properties
24 /// @param plot the plot for which to set axe properties
22 /// @param colorScale the color scale for which to set properties
25 /// @param colorScale the color scale for which to set properties
23 virtual void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) = 0;
26 virtual void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) = 0;
24 };
27 };
25
28
26 struct IAxisHelperFactory {
29 struct IAxisHelperFactory {
27 /// Creates IAxisHelper according to a data series
30 /// Creates IAxisHelper according to a data series
28 static std::unique_ptr<IAxisHelper> create(std::shared_ptr<IDataSeries> dataSeries) noexcept;
31 static std::unique_ptr<IAxisHelper> create(std::shared_ptr<IDataSeries> dataSeries) noexcept;
29 };
32 };
30
33
31 #endif // SCIQLOP_AXISRENDERINGUTILS_H
34 #endif // SCIQLOP_AXISRENDERINGUTILS_H
@@ -1,31 +1,35
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
2 #define SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
2 #define SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5
5
6 #include <Visualization/VisualizationDefs.h>
7
8 class IDataSeries;
6 class QCustomPlot;
9 class QCustomPlot;
7 class QMouseEvent;
10 class QMouseEvent;
8 class Unit;
11 class Unit;
9 class VisualizationGraphWidget;
12 class VisualizationGraphWidget;
10
13
11 class VisualizationGraphRenderingDelegate {
14 class VisualizationGraphRenderingDelegate {
12 public:
15 public:
13 /// Ctor
16 /// Ctor
14 /// @param graphWidget the graph widget to which the delegate is associated
17 /// @param graphWidget the graph widget to which the delegate is associated
15 /// @remarks the graph widget must exist throughout the life cycle of the delegate
18 /// @remarks the graph widget must exist throughout the life cycle of the delegate
16 explicit VisualizationGraphRenderingDelegate(VisualizationGraphWidget &graphWidget);
19 explicit VisualizationGraphRenderingDelegate(VisualizationGraphWidget &graphWidget);
17
20
18 void onMouseMove(QMouseEvent *event) noexcept;
21 void onMouseMove(QMouseEvent *event) noexcept;
19
22
20 /// Sets properties of the plot's axes
23 /// Sets properties of the plot's axes from the data series passed as parameter
21 void setAxesProperties(const Unit &xAxisUnit, const Unit &valuesUnit) noexcept;
24 void setAxesProperties(std::shared_ptr<IDataSeries> dataSeries) noexcept;
25
22
26
23 /// Shows or hides graph overlay (name, close button, etc.)
27 /// Shows or hides graph overlay (name, close button, etc.)
24 void showGraphOverlay(bool show) noexcept;
28 void showGraphOverlay(bool show) noexcept;
25
29
26 private:
30 private:
27 class VisualizationGraphRenderingDelegatePrivate;
31 class VisualizationGraphRenderingDelegatePrivate;
28 spimpl::unique_impl_ptr<VisualizationGraphRenderingDelegatePrivate> impl;
32 spimpl::unique_impl_ptr<VisualizationGraphRenderingDelegatePrivate> impl;
29 };
33 };
30
34
31 #endif // SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
35 #endif // SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
@@ -1,65 +1,123
1 #include "Visualization/AxisRenderingUtils.h"
1 #include "Visualization/AxisRenderingUtils.h"
2
2
3 #include <Data/ScalarSeries.h>
3 #include <Data/ScalarSeries.h>
4 #include <Data/VectorSeries.h>
4 #include <Data/VectorSeries.h>
5
5
6 #include <Visualization/qcustomplot.h>
6 #include <Visualization/qcustomplot.h>
7
7
8 namespace {
8 namespace {
9
9
10 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
11
12 /// Format for datetimes on a axis
13 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
14
15 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
16 /// non-time data
17 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
18 {
19 if (isTimeAxis) {
20 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
21 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
22 dateTicker->setDateTimeSpec(Qt::UTC);
23
24 return dateTicker;
25 }
26 else {
27 // default ticker
28 return QSharedPointer<QCPAxisTicker>::create();
29 }
30 }
31
32 /**
33 * Sets properties of the axis passed as parameter
34 * @param axis the axis to set
35 * @param unit the unit to set for the axis
36 * @param scaleType the scale type to set for the axis
37 */
38 void setAxisProperties(QCPAxis &axis, const Unit &unit,
39 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
40 {
41 // label (unit name)
42 axis.setLabel(unit.m_Name);
43
44 // scale type
45 axis.setScaleType(scaleType);
46
47 // ticker (depending on the type of unit)
48 axis.setTicker(axisTicker(unit.m_TimeUnit));
49 }
50
10 /**
51 /**
11 * Delegate used to set axes properties
52 * Delegate used to set axes properties
12 */
53 */
13 template <typename T, typename Enabled = void>
54 template <typename T, typename Enabled = void>
14 struct AxisSetter {
55 struct AxisSetter {
15 static void setProperties(T &, QCustomPlot &, QCPColorScale &)
56 static void setProperties(T &, QCustomPlot &, QCPColorScale &)
16 {
57 {
17 // Default implementation does nothing
58 // Default implementation does nothing
18 }
59 }
19 };
60 };
20
61
21 /**
62 /**
22 * Specialization of AxisSetter for scalars and vectors
63 * Specialization of AxisSetter for scalars and vectors
23 * @sa ScalarSeries
64 * @sa ScalarSeries
24 * @sa VectorSeries
65 * @sa VectorSeries
25 */
66 */
26 template <typename T>
67 template <typename T>
27 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
68 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
28 or std::is_base_of<VectorSeries, T>::value> > {
69 or std::is_base_of<VectorSeries, T>::value> > {
29 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &)
70 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &)
30 {
71 {
31 /// @todo ALX
72 dataSeries.lockRead();
73 auto xAxisUnit = dataSeries.xAxisUnit();
74 auto valuesUnit = dataSeries.valuesUnit();
75 dataSeries.unlock();
76
77 setAxisProperties(*plot.xAxis, xAxisUnit);
78 setAxisProperties(*plot.yAxis, valuesUnit);
32 }
79 }
33 };
80 };
34
81
35 /**
82 /**
36 * Default implementation of IAxisHelper, which takes data series to set axes properties
83 * Default implementation of IAxisHelper, which takes data series to set axes properties
37 * @tparam T the data series' type
84 * @tparam T the data series' type
38 */
85 */
39 template <typename T>
86 template <typename T>
40 struct AxisHelper : public IAxisHelper {
87 struct AxisHelper : public IAxisHelper {
41 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
88 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
42
89
43 void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) override
90 void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) override
44 {
91 {
45 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
92 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
46 }
93 }
47
94
48 T &m_DataSeries;
95 T &m_DataSeries;
49 };
96 };
50
97
51 } // namespace
98 } // namespace
52
99
100 QString formatValue(double value, const QCPAxis &axis)
101 {
102 // If the axis is a time axis, formats the value as a date
103 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
104 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
105 }
106 else {
107 return QString::number(value);
108 }
109 }
110
53 std::unique_ptr<IAxisHelper>
111 std::unique_ptr<IAxisHelper>
54 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
112 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
55 {
113 {
56 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
114 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
57 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
115 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
58 }
116 }
59 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
117 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
60 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
118 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
61 }
119 }
62 else {
120 else {
63 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
121 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
64 }
122 }
65 }
123 }
@@ -1,275 +1,235
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 #include "Visualization/AxisRenderingUtils.h"
2 #include "Visualization/VisualizationGraphWidget.h"
3 #include "Visualization/VisualizationGraphWidget.h"
3 #include "Visualization/qcustomplot.h"
4 #include "Visualization/qcustomplot.h"
4
5
5 #include <Common/DateUtils.h>
6 #include <Common/DateUtils.h>
6
7
7 #include <Data/IDataSeries.h>
8 #include <Data/IDataSeries.h>
8
9
9 #include <SqpApplication.h>
10 #include <SqpApplication.h>
10
11
11 namespace {
12 namespace {
12
13
13 /// Name of the axes layer in QCustomPlot
14 /// Name of the axes layer in QCustomPlot
14 const auto AXES_LAYER = QStringLiteral("axes");
15 const auto AXES_LAYER = QStringLiteral("axes");
15
16
16 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
17
18 /// Format for datetimes on a axis
19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
20
21 /// Icon used to show x-axis properties
17 /// Icon used to show x-axis properties
22 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
18 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
23
19
24 /// Name of the overlay layer in QCustomPlot
20 /// Name of the overlay layer in QCustomPlot
25 const auto OVERLAY_LAYER = QStringLiteral("overlay");
21 const auto OVERLAY_LAYER = QStringLiteral("overlay");
26
22
27 /// Pixmap used to show x-axis properties
23 /// Pixmap used to show x-axis properties
28 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
24 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
29
25
30 const auto TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
26 const auto TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
31
27
32 /// Offset used to shift the tooltip of the mouse
28 /// Offset used to shift the tooltip of the mouse
33 const auto TOOLTIP_OFFSET = QPoint{20, 20};
29 const auto TOOLTIP_OFFSET = QPoint{20, 20};
34
30
35 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
31 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
36 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
32 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
37
33
38 /// Timeout after which the tooltip is displayed
34 /// Timeout after which the tooltip is displayed
39 const auto TOOLTIP_TIMEOUT = 500;
35 const auto TOOLTIP_TIMEOUT = 500;
40
36
41 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
42 /// non-time data
43 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
44 {
45 if (isTimeAxis) {
46 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
47 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
48 dateTicker->setDateTimeSpec(Qt::UTC);
49
50 return dateTicker;
51 }
52 else {
53 // default ticker
54 return QSharedPointer<QCPAxisTicker>::create();
55 }
56 }
57
58 /// Formats a data value according to the axis on which it is present
59 QString formatValue(double value, const QCPAxis &axis)
60 {
61 // If the axis is a time axis, formats the value as a date
62 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
63 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
64 }
65 else {
66 return QString::number(value);
67 }
68 }
69
70 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
37 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
71 {
38 {
72 tracer.setInterpolating(false);
39 tracer.setInterpolating(false);
73 tracer.setStyle(QCPItemTracer::tsCircle);
40 tracer.setStyle(QCPItemTracer::tsCircle);
74 tracer.setSize(3);
41 tracer.setSize(3);
75 tracer.setPen(QPen(Qt::black));
42 tracer.setPen(QPen(Qt::black));
76 tracer.setBrush(Qt::black);
43 tracer.setBrush(Qt::black);
77 }
44 }
78
45
79 QPixmap pixmap(const QString &iconPath) noexcept
46 QPixmap pixmap(const QString &iconPath) noexcept
80 {
47 {
81 return QIcon{iconPath}.pixmap(QSize{16, 16});
48 return QIcon{iconPath}.pixmap(QSize{16, 16});
82 }
49 }
83
50
84 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
51 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
85 {
52 {
86 // Icon
53 // Icon
87 pixmap.setPixmap(
54 pixmap.setPixmap(
88 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
55 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
89
56
90 // Position
57 // Position
91 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
58 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
92 pixmap.topLeft->setCoords(1, 0);
59 pixmap.topLeft->setCoords(1, 0);
93 pixmap.setClipToAxisRect(false);
60 pixmap.setClipToAxisRect(false);
94
61
95 // Can be selected
62 // Can be selected
96 pixmap.setSelectable(true);
63 pixmap.setSelectable(true);
97 }
64 }
98
65
99 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
66 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
100 {
67 {
101 // Icon
68 // Icon
102 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
69 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
103
70
104 // Position
71 // Position
105 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
72 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
106 itemPixmap.topLeft->setCoords(0, 1);
73 itemPixmap.topLeft->setCoords(0, 1);
107 itemPixmap.setClipToAxisRect(false);
74 itemPixmap.setClipToAxisRect(false);
108
75
109 // Can be selected
76 // Can be selected
110 itemPixmap.setSelectable(true);
77 itemPixmap.setSelectable(true);
111 }
78 }
112
79
113 void initTitleTextStyle(QCPItemText &text) noexcept
80 void initTitleTextStyle(QCPItemText &text) noexcept
114 {
81 {
115 // Font and background styles
82 // Font and background styles
116 text.setColor(Qt::gray);
83 text.setColor(Qt::gray);
117 text.setBrush(Qt::white);
84 text.setBrush(Qt::white);
118
85
119 // Position
86 // Position
120 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
87 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
121 text.position->setType(QCPItemPosition::ptAxisRectRatio);
88 text.position->setType(QCPItemPosition::ptAxisRectRatio);
122 text.position->setCoords(0.5, 0);
89 text.position->setCoords(0.5, 0);
123 }
90 }
124
91
125 } // namespace
92 } // namespace
126
93
127 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
94 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
128 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
95 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
129 : m_Plot{graphWidget.plot()},
96 : m_Plot{graphWidget.plot()},
130 m_PointTracer{new QCPItemTracer{&m_Plot}},
97 m_PointTracer{new QCPItemTracer{&m_Plot}},
131 m_TracerTimer{},
98 m_TracerTimer{},
132 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
99 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
133 m_TitleText{new QCPItemText{&m_Plot}},
100 m_TitleText{new QCPItemText{&m_Plot}},
134 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
101 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
135 m_ShowXAxis{true},
102 m_ShowXAxis{true},
136 m_XAxisLabel{}
103 m_XAxisLabel{}
137 {
104 {
138 initPointTracerStyle(*m_PointTracer);
105 initPointTracerStyle(*m_PointTracer);
139
106
140 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
107 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
141 m_TracerTimer.setSingleShot(true);
108 m_TracerTimer.setSingleShot(true);
142
109
143 // Inits "close button" in plot overlay
110 // Inits "close button" in plot overlay
144 m_ClosePixmap->setLayer(OVERLAY_LAYER);
111 m_ClosePixmap->setLayer(OVERLAY_LAYER);
145 initClosePixmapStyle(*m_ClosePixmap);
112 initClosePixmapStyle(*m_ClosePixmap);
146
113
147 // Connects pixmap selection to graph widget closing
114 // Connects pixmap selection to graph widget closing
148 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
115 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
149 [&graphWidget](bool selected) {
116 [&graphWidget](bool selected) {
150 if (selected) {
117 if (selected) {
151 graphWidget.close();
118 graphWidget.close();
152 }
119 }
153 });
120 });
154
121
155 // Inits graph name in plot overlay
122 // Inits graph name in plot overlay
156 m_TitleText->setLayer(OVERLAY_LAYER);
123 m_TitleText->setLayer(OVERLAY_LAYER);
157 m_TitleText->setText(graphWidget.name());
124 m_TitleText->setText(graphWidget.name());
158 initTitleTextStyle(*m_TitleText);
125 initTitleTextStyle(*m_TitleText);
159
126
160 // Inits "show x-axis button" in plot overlay
127 // Inits "show x-axis button" in plot overlay
161 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
128 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
162 initXAxisPixmapStyle(*m_XAxisPixmap);
129 initXAxisPixmapStyle(*m_XAxisPixmap);
163
130
164 // Connects pixmap selection to graph x-axis showing/hiding
131 // Connects pixmap selection to graph x-axis showing/hiding
165 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
132 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
166 if (m_XAxisPixmap->selected()) {
133 if (m_XAxisPixmap->selected()) {
167 // Changes the selection state and refreshes the x-axis
134 // Changes the selection state and refreshes the x-axis
168 m_ShowXAxis = !m_ShowXAxis;
135 m_ShowXAxis = !m_ShowXAxis;
169 updateXAxisState();
136 updateXAxisState();
170 m_Plot.layer(AXES_LAYER)->replot();
137 m_Plot.layer(AXES_LAYER)->replot();
171
138
172 // Deselects the x-axis pixmap and updates icon
139 // Deselects the x-axis pixmap and updates icon
173 m_XAxisPixmap->setSelected(false);
140 m_XAxisPixmap->setSelected(false);
174 m_XAxisPixmap->setPixmap(
141 m_XAxisPixmap->setPixmap(
175 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
142 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
176 m_Plot.layer(OVERLAY_LAYER)->replot();
143 m_Plot.layer(OVERLAY_LAYER)->replot();
177 }
144 }
178 });
145 });
179 }
146 }
180
147
181 /// Updates state of x-axis according to the current selection of x-axis pixmap
148 /// Updates state of x-axis according to the current selection of x-axis pixmap
182 /// @remarks the method doesn't call plot refresh
149 /// @remarks the method doesn't call plot refresh
183 void updateXAxisState() noexcept
150 void updateXAxisState() noexcept
184 {
151 {
185 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
152 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
186 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
153 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
187 }
154 }
188
155
189 QCustomPlot &m_Plot;
156 QCustomPlot &m_Plot;
190 QCPItemTracer *m_PointTracer;
157 QCPItemTracer *m_PointTracer;
191 QTimer m_TracerTimer;
158 QTimer m_TracerTimer;
192 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
159 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
193 QCPItemText *m_TitleText; /// Graph's title
160 QCPItemText *m_TitleText; /// Graph's title
194 QCPItemPixmap *m_XAxisPixmap;
161 QCPItemPixmap *m_XAxisPixmap;
195 bool m_ShowXAxis; /// X-axis properties are shown or hidden
162 bool m_ShowXAxis; /// X-axis properties are shown or hidden
196 QString m_XAxisLabel;
163 QString m_XAxisLabel;
197 };
164 };
198
165
199 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
166 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
200 VisualizationGraphWidget &graphWidget)
167 VisualizationGraphWidget &graphWidget)
201 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
168 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
202 {
169 {
203 }
170 }
204
171
205 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
172 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
206 {
173 {
207 // Cancels pending refresh
174 // Cancels pending refresh
208 impl->m_TracerTimer.disconnect();
175 impl->m_TracerTimer.disconnect();
209
176
210 // Reinits tracers
177 // Reinits tracers
211 impl->m_PointTracer->setGraph(nullptr);
178 impl->m_PointTracer->setGraph(nullptr);
212 impl->m_PointTracer->setVisible(false);
179 impl->m_PointTracer->setVisible(false);
213 impl->m_Plot.replot();
180 impl->m_Plot.replot();
214
181
215 // Gets the graph under the mouse position
182 // Gets the graph under the mouse position
216 auto eventPos = event->pos();
183 auto eventPos = event->pos();
217 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
184 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
218 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
185 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
219 auto graphData = graph->data();
186 auto graphData = graph->data();
220
187
221 // Gets the closest data point to the mouse
188 // Gets the closest data point to the mouse
222 auto graphDataIt = graphData->findBegin(mouseKey);
189 auto graphDataIt = graphData->findBegin(mouseKey);
223 if (graphDataIt != graphData->constEnd()) {
190 if (graphDataIt != graphData->constEnd()) {
224 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
191 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
225 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
192 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
226
193
227 // Displays point tracer
194 // Displays point tracer
228 impl->m_PointTracer->setGraph(graph);
195 impl->m_PointTracer->setGraph(graph);
229 impl->m_PointTracer->setGraphKey(graphDataIt->key);
196 impl->m_PointTracer->setGraphKey(graphDataIt->key);
230 impl->m_PointTracer->setLayer(
197 impl->m_PointTracer->setLayer(
231 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
198 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
232 impl->m_PointTracer->setVisible(true);
199 impl->m_PointTracer->setVisible(true);
233 impl->m_Plot.replot();
200 impl->m_Plot.replot();
234
201
235 // Starts timer to show tooltip after timeout
202 // Starts timer to show tooltip after timeout
236 auto showTooltip = [ tooltip = TOOLTIP_FORMAT.arg(key, value), eventPos, this ]()
203 auto showTooltip = [ tooltip = TOOLTIP_FORMAT.arg(key, value), eventPos, this ]()
237 {
204 {
238 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
205 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
239 &impl->m_Plot, TOOLTIP_RECT);
206 &impl->m_Plot, TOOLTIP_RECT);
240 };
207 };
241
208
242 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
209 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
243 impl->m_TracerTimer.start();
210 impl->m_TracerTimer.start();
244 }
211 }
245 }
212 }
246 }
213 }
247
214
248 void VisualizationGraphRenderingDelegate::setAxesProperties(const Unit &xAxisUnit,
215 void VisualizationGraphRenderingDelegate::setAxesProperties(
249 const Unit &valuesUnit) noexcept
216 std::shared_ptr<IDataSeries> dataSeries) noexcept
250 {
217 {
251 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
218 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
252 impl->m_XAxisLabel = xAxisUnit.m_Name;
219 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
253
254 auto setAxisProperties = [](auto axis, const auto &unit) {
255 // label (unit name)
256 axis->setLabel(unit.m_Name);
257
220
258 // ticker (depending on the type of unit)
221 auto axisHelper = IAxisHelperFactory::create(dataSeries);
259 axis->setTicker(axisTicker(unit.m_TimeUnit));
222 axisHelper->setProperties(impl->m_Plot, *impl->m_ColorScale);
260 };
261 setAxisProperties(impl->m_Plot.xAxis, xAxisUnit);
262 setAxisProperties(impl->m_Plot.yAxis, valuesUnit);
263
223
264 // Updates x-axis state
224 // Updates x-axis state
265 impl->updateXAxisState();
225 impl->updateXAxisState();
266
226
267 impl->m_Plot.layer(AXES_LAYER)->replot();
227 impl->m_Plot.layer(AXES_LAYER)->replot();
268 }
228 }
269
229
270 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
230 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
271 {
231 {
272 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
232 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
273 overlay->setVisible(show);
233 overlay->setVisible(show);
274 overlay->replot();
234 overlay->replot();
275 }
235 }
@@ -1,405 +1,397
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationDefs.h"
3 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationGraphHelper.h"
4 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
7 #include "ui_VisualizationGraphWidget.h"
7 #include "ui_VisualizationGraphWidget.h"
8
8
9 #include <Common/MimeTypesDef.h>
9 #include <Common/MimeTypesDef.h>
10 #include <Data/ArrayData.h>
10 #include <Data/ArrayData.h>
11 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
12 #include <DragAndDrop/DragDropHelper.h>
12 #include <DragAndDrop/DragDropHelper.h>
13 #include <Settings/SqpSettingsDefs.h>
13 #include <Settings/SqpSettingsDefs.h>
14 #include <SqpApplication.h>
14 #include <SqpApplication.h>
15 #include <Time/TimeController.h>
15 #include <Time/TimeController.h>
16 #include <Variable/Variable.h>
16 #include <Variable/Variable.h>
17 #include <Variable/VariableController.h>
17 #include <Variable/VariableController.h>
18
18
19 #include <unordered_map>
19 #include <unordered_map>
20
20
21 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
21 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
22
22
23 namespace {
23 namespace {
24
24
25 /// Key pressed to enable zoom on horizontal axis
25 /// Key pressed to enable zoom on horizontal axis
26 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
26 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
27
27
28 /// Key pressed to enable zoom on vertical axis
28 /// Key pressed to enable zoom on vertical axis
29 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
29 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
30
30
31 } // namespace
31 } // namespace
32
32
33 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
33 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
34
34
35 explicit VisualizationGraphWidgetPrivate(const QString &name)
35 explicit VisualizationGraphWidgetPrivate(const QString &name)
36 : m_Name{name},
36 : m_Name{name},
37 m_DoAcquisition{true},
37 m_DoAcquisition{true},
38 m_IsCalibration{false},
38 m_IsCalibration{false},
39 m_RenderingDelegate{nullptr}
39 m_RenderingDelegate{nullptr}
40 {
40 {
41 }
41 }
42
42
43 QString m_Name;
43 QString m_Name;
44 // 1 variable -> n qcpplot
44 // 1 variable -> n qcpplot
45 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
45 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
46 bool m_DoAcquisition;
46 bool m_DoAcquisition;
47 bool m_IsCalibration;
47 bool m_IsCalibration;
48 /// Delegate used to attach rendering features to the plot
48 /// Delegate used to attach rendering features to the plot
49 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
49 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
50 };
50 };
51
51
52 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
52 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
53 : VisualizationDragWidget{parent},
53 : VisualizationDragWidget{parent},
54 ui{new Ui::VisualizationGraphWidget},
54 ui{new Ui::VisualizationGraphWidget},
55 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
55 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
56 {
56 {
57 ui->setupUi(this);
57 ui->setupUi(this);
58
58
59 // 'Close' options : widget is deleted when closed
59 // 'Close' options : widget is deleted when closed
60 setAttribute(Qt::WA_DeleteOnClose);
60 setAttribute(Qt::WA_DeleteOnClose);
61
61
62 // Set qcpplot properties :
62 // Set qcpplot properties :
63 // - Drag (on x-axis) and zoom are enabled
63 // - Drag (on x-axis) and zoom are enabled
64 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
64 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
65 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
65 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
66 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
66 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
67
67
68 // The delegate must be initialized after the ui as it uses the plot
68 // The delegate must be initialized after the ui as it uses the plot
69 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
69 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
70
70
71 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
71 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
72 connect(ui->widget, &QCustomPlot::mouseRelease, this,
72 connect(ui->widget, &QCustomPlot::mouseRelease, this,
73 &VisualizationGraphWidget::onMouseRelease);
73 &VisualizationGraphWidget::onMouseRelease);
74 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
74 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
75 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
75 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
76 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
76 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
77 &QCPAxis::rangeChanged),
77 &QCPAxis::rangeChanged),
78 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
78 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
79
79
80 // Activates menu when right clicking on the graph
80 // Activates menu when right clicking on the graph
81 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
81 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
82 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
82 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
83 &VisualizationGraphWidget::onGraphMenuRequested);
83 &VisualizationGraphWidget::onGraphMenuRequested);
84
84
85 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
85 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
86 &VariableController::onRequestDataLoading);
86 &VariableController::onRequestDataLoading);
87
87
88 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
88 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
89 &VisualizationGraphWidget::onUpdateVarDisplaying);
89 &VisualizationGraphWidget::onUpdateVarDisplaying);
90 }
90 }
91
91
92
92
93 VisualizationGraphWidget::~VisualizationGraphWidget()
93 VisualizationGraphWidget::~VisualizationGraphWidget()
94 {
94 {
95 delete ui;
95 delete ui;
96 }
96 }
97
97
98 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
98 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
99 {
99 {
100 auto parent = parentWidget();
100 auto parent = parentWidget();
101 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
101 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
102 parent = parent->parentWidget();
102 parent = parent->parentWidget();
103 }
103 }
104
104
105 return qobject_cast<VisualizationZoneWidget *>(parent);
105 return qobject_cast<VisualizationZoneWidget *>(parent);
106 }
106 }
107
107
108 void VisualizationGraphWidget::enableAcquisition(bool enable)
108 void VisualizationGraphWidget::enableAcquisition(bool enable)
109 {
109 {
110 impl->m_DoAcquisition = enable;
110 impl->m_DoAcquisition = enable;
111 }
111 }
112
112
113 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
113 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
114 {
114 {
115 // Uses delegate to create the qcpplot components according to the variable
115 // Uses delegate to create the qcpplot components according to the variable
116 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
116 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
117 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
118
119 // Set axes properties according to the units of the data series
120 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
121 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
122 auto xAxisUnit = Unit{};
123 auto valuesUnit = Unit{};
124
117
125 if (auto dataSeries = variable->dataSeries()) {
118 if (auto dataSeries = variable->dataSeries()) {
126 dataSeries->lockRead();
119 // Set axes properties according to the units of the data series
127 xAxisUnit = dataSeries->xAxisUnit();
120 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
128 valuesUnit = dataSeries->valuesUnit();
129 dataSeries->unlock();
130 }
121 }
131 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
122
123 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
132
124
133 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
125 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
134
126
135 this->enableAcquisition(false);
127 this->enableAcquisition(false);
136 this->setGraphRange(range);
128 this->setGraphRange(range);
137 this->enableAcquisition(true);
129 this->enableAcquisition(true);
138
130
139 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
131 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
140
132
141 emit variableAdded(variable);
133 emit variableAdded(variable);
142 }
134 }
143
135
144 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
136 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
145 {
137 {
146 // Each component associated to the variable :
138 // Each component associated to the variable :
147 // - is removed from qcpplot (which deletes it)
139 // - is removed from qcpplot (which deletes it)
148 // - is no longer referenced in the map
140 // - is no longer referenced in the map
149 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
141 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
150 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
142 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
151 emit variableAboutToBeRemoved(variable);
143 emit variableAboutToBeRemoved(variable);
152
144
153 auto &plottablesMap = variableIt->second;
145 auto &plottablesMap = variableIt->second;
154
146
155 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
147 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
156 plottableIt != plottableEnd;) {
148 plottableIt != plottableEnd;) {
157 ui->widget->removePlottable(plottableIt->second);
149 ui->widget->removePlottable(plottableIt->second);
158 plottableIt = plottablesMap.erase(plottableIt);
150 plottableIt = plottablesMap.erase(plottableIt);
159 }
151 }
160
152
161 impl->m_VariableToPlotMultiMap.erase(variableIt);
153 impl->m_VariableToPlotMultiMap.erase(variableIt);
162 }
154 }
163
155
164 // Updates graph
156 // Updates graph
165 ui->widget->replot();
157 ui->widget->replot();
166 }
158 }
167
159
168 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
160 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
169 {
161 {
170 auto variables = QList<std::shared_ptr<Variable> >{};
162 auto variables = QList<std::shared_ptr<Variable> >{};
171 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
163 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
172 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
164 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
173 variables << it->first;
165 variables << it->first;
174 }
166 }
175
167
176 return variables;
168 return variables;
177 }
169 }
178
170
179 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
171 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
180 {
172 {
181 if (!variable) {
173 if (!variable) {
182 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
174 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
183 return;
175 return;
184 }
176 }
185
177
186 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
178 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
187 }
179 }
188
180
189 SqpRange VisualizationGraphWidget::graphRange() const noexcept
181 SqpRange VisualizationGraphWidget::graphRange() const noexcept
190 {
182 {
191 auto graphRange = ui->widget->xAxis->range();
183 auto graphRange = ui->widget->xAxis->range();
192 return SqpRange{graphRange.lower, graphRange.upper};
184 return SqpRange{graphRange.lower, graphRange.upper};
193 }
185 }
194
186
195 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
187 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
196 {
188 {
197 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
189 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
198 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
190 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
199 ui->widget->replot();
191 ui->widget->replot();
200 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
192 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
201 }
193 }
202
194
203 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
195 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
204 {
196 {
205 if (visitor) {
197 if (visitor) {
206 visitor->visit(this);
198 visitor->visit(this);
207 }
199 }
208 else {
200 else {
209 qCCritical(LOG_VisualizationGraphWidget())
201 qCCritical(LOG_VisualizationGraphWidget())
210 << tr("Can't visit widget : the visitor is null");
202 << tr("Can't visit widget : the visitor is null");
211 }
203 }
212 }
204 }
213
205
214 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
206 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
215 {
207 {
216 /// @todo : for the moment, a graph can always accomodate a variable
208 /// @todo : for the moment, a graph can always accomodate a variable
217 Q_UNUSED(variable);
209 Q_UNUSED(variable);
218 return true;
210 return true;
219 }
211 }
220
212
221 bool VisualizationGraphWidget::contains(const Variable &variable) const
213 bool VisualizationGraphWidget::contains(const Variable &variable) const
222 {
214 {
223 // Finds the variable among the keys of the map
215 // Finds the variable among the keys of the map
224 auto variablePtr = &variable;
216 auto variablePtr = &variable;
225 auto findVariable
217 auto findVariable
226 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
218 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
227
219
228 auto end = impl->m_VariableToPlotMultiMap.cend();
220 auto end = impl->m_VariableToPlotMultiMap.cend();
229 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
221 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
230 return it != end;
222 return it != end;
231 }
223 }
232
224
233 QString VisualizationGraphWidget::name() const
225 QString VisualizationGraphWidget::name() const
234 {
226 {
235 return impl->m_Name;
227 return impl->m_Name;
236 }
228 }
237
229
238 QMimeData *VisualizationGraphWidget::mimeData() const
230 QMimeData *VisualizationGraphWidget::mimeData() const
239 {
231 {
240 auto mimeData = new QMimeData;
232 auto mimeData = new QMimeData;
241 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
233 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
242
234
243 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
235 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
244 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
236 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
245
237
246 return mimeData;
238 return mimeData;
247 }
239 }
248
240
249 bool VisualizationGraphWidget::isDragAllowed() const
241 bool VisualizationGraphWidget::isDragAllowed() const
250 {
242 {
251 return true;
243 return true;
252 }
244 }
253
245
254 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
246 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
255 {
247 {
256 if (highlighted) {
248 if (highlighted) {
257 plot().setBackground(QBrush(QColor("#BBD5EE")));
249 plot().setBackground(QBrush(QColor("#BBD5EE")));
258 }
250 }
259 else {
251 else {
260 plot().setBackground(QBrush(Qt::white));
252 plot().setBackground(QBrush(Qt::white));
261 }
253 }
262
254
263 plot().update();
255 plot().update();
264 }
256 }
265
257
266 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
258 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
267 {
259 {
268 Q_UNUSED(event);
260 Q_UNUSED(event);
269
261
270 // Prevents that all variables will be removed from graph when it will be closed
262 // Prevents that all variables will be removed from graph when it will be closed
271 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
263 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
272 emit variableAboutToBeRemoved(variableEntry.first);
264 emit variableAboutToBeRemoved(variableEntry.first);
273 }
265 }
274 }
266 }
275
267
276 void VisualizationGraphWidget::enterEvent(QEvent *event)
268 void VisualizationGraphWidget::enterEvent(QEvent *event)
277 {
269 {
278 Q_UNUSED(event);
270 Q_UNUSED(event);
279 impl->m_RenderingDelegate->showGraphOverlay(true);
271 impl->m_RenderingDelegate->showGraphOverlay(true);
280 }
272 }
281
273
282 void VisualizationGraphWidget::leaveEvent(QEvent *event)
274 void VisualizationGraphWidget::leaveEvent(QEvent *event)
283 {
275 {
284 Q_UNUSED(event);
276 Q_UNUSED(event);
285 impl->m_RenderingDelegate->showGraphOverlay(false);
277 impl->m_RenderingDelegate->showGraphOverlay(false);
286 }
278 }
287
279
288 QCustomPlot &VisualizationGraphWidget::plot() noexcept
280 QCustomPlot &VisualizationGraphWidget::plot() noexcept
289 {
281 {
290 return *ui->widget;
282 return *ui->widget;
291 }
283 }
292
284
293 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
285 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
294 {
286 {
295 QMenu graphMenu{};
287 QMenu graphMenu{};
296
288
297 // Iterates on variables (unique keys)
289 // Iterates on variables (unique keys)
298 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
290 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
299 end = impl->m_VariableToPlotMultiMap.cend();
291 end = impl->m_VariableToPlotMultiMap.cend();
300 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
292 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
301 // 'Remove variable' action
293 // 'Remove variable' action
302 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
294 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
303 [ this, var = it->first ]() { removeVariable(var); });
295 [ this, var = it->first ]() { removeVariable(var); });
304 }
296 }
305
297
306 if (!graphMenu.isEmpty()) {
298 if (!graphMenu.isEmpty()) {
307 graphMenu.exec(QCursor::pos());
299 graphMenu.exec(QCursor::pos());
308 }
300 }
309 }
301 }
310
302
311 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
303 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
312 {
304 {
313 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
305 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
314 << QThread::currentThread()->objectName() << "DoAcqui"
306 << QThread::currentThread()->objectName() << "DoAcqui"
315 << impl->m_DoAcquisition;
307 << impl->m_DoAcquisition;
316
308
317 auto graphRange = SqpRange{t1.lower, t1.upper};
309 auto graphRange = SqpRange{t1.lower, t1.upper};
318 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
310 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
319
311
320 if (impl->m_DoAcquisition) {
312 if (impl->m_DoAcquisition) {
321 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
313 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
322
314
323 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
315 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
324 end = impl->m_VariableToPlotMultiMap.end();
316 end = impl->m_VariableToPlotMultiMap.end();
325 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
317 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
326 variableUnderGraphVector.push_back(it->first);
318 variableUnderGraphVector.push_back(it->first);
327 }
319 }
328 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
320 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
329 !impl->m_IsCalibration);
321 !impl->m_IsCalibration);
330
322
331 if (!impl->m_IsCalibration) {
323 if (!impl->m_IsCalibration) {
332 qCDebug(LOG_VisualizationGraphWidget())
324 qCDebug(LOG_VisualizationGraphWidget())
333 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
325 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
334 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
326 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
335 emit synchronize(graphRange, oldGraphRange);
327 emit synchronize(graphRange, oldGraphRange);
336 }
328 }
337 }
329 }
338 }
330 }
339
331
340 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
332 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
341 {
333 {
342 // Handles plot rendering when mouse is moving
334 // Handles plot rendering when mouse is moving
343 impl->m_RenderingDelegate->onMouseMove(event);
335 impl->m_RenderingDelegate->onMouseMove(event);
344
336
345 VisualizationDragWidget::mouseMoveEvent(event);
337 VisualizationDragWidget::mouseMoveEvent(event);
346 }
338 }
347
339
348 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
340 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
349 {
341 {
350 auto zoomOrientations = QFlags<Qt::Orientation>{};
342 auto zoomOrientations = QFlags<Qt::Orientation>{};
351
343
352 // Lambda that enables a zoom orientation if the key modifier related to this orientation
344 // Lambda that enables a zoom orientation if the key modifier related to this orientation
353 // has
345 // has
354 // been pressed
346 // been pressed
355 auto enableOrientation
347 auto enableOrientation
356 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
348 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
357 auto orientationEnabled = event->modifiers().testFlag(modifier);
349 auto orientationEnabled = event->modifiers().testFlag(modifier);
358 zoomOrientations.setFlag(orientation, orientationEnabled);
350 zoomOrientations.setFlag(orientation, orientationEnabled);
359 };
351 };
360 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
352 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
361 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
353 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
362
354
363 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
355 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
364 }
356 }
365
357
366 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
358 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
367 {
359 {
368 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
360 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
369
361
370 plot().setInteraction(QCP::iRangeDrag, !event->modifiers().testFlag(Qt::AltModifier));
362 plot().setInteraction(QCP::iRangeDrag, !event->modifiers().testFlag(Qt::AltModifier));
371
363
372 VisualizationDragWidget::mousePressEvent(event);
364 VisualizationDragWidget::mousePressEvent(event);
373 }
365 }
374
366
375 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
367 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
376 {
368 {
377 impl->m_IsCalibration = false;
369 impl->m_IsCalibration = false;
378 }
370 }
379
371
380 void VisualizationGraphWidget::onDataCacheVariableUpdated()
372 void VisualizationGraphWidget::onDataCacheVariableUpdated()
381 {
373 {
382 auto graphRange = ui->widget->xAxis->range();
374 auto graphRange = ui->widget->xAxis->range();
383 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
375 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
384
376
385 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
377 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
386 auto variable = variableEntry.first;
378 auto variable = variableEntry.first;
387 qCDebug(LOG_VisualizationGraphWidget())
379 qCDebug(LOG_VisualizationGraphWidget())
388 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
380 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
389 qCDebug(LOG_VisualizationGraphWidget())
381 qCDebug(LOG_VisualizationGraphWidget())
390 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
382 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
391 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
383 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
392 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
384 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
393 variable->range());
385 variable->range());
394 }
386 }
395 }
387 }
396 }
388 }
397
389
398 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
390 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
399 const SqpRange &range)
391 const SqpRange &range)
400 {
392 {
401 auto it = impl->m_VariableToPlotMultiMap.find(variable);
393 auto it = impl->m_VariableToPlotMultiMap.find(variable);
402 if (it != impl->m_VariableToPlotMultiMap.end()) {
394 if (it != impl->m_VariableToPlotMultiMap.end()) {
403 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
395 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
404 }
396 }
405 }
397 }
General Comments 0
You need to be logged in to leave comments. Login now