##// END OF EJS Templates
Tooltip for spectrograms (4)...
Alexandre Leroux -
r1068:e3aea966fca1
parent child
Show More
@@ -1,173 +1,176
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/SpectrogramSeries.h>
4 #include <Data/SpectrogramSeries.h>
5 #include <Data/VectorSeries.h>
5 #include <Data/VectorSeries.h>
6
6
7 #include <Visualization/SqpColorScale.h>
7 #include <Visualization/SqpColorScale.h>
8 #include <Visualization/qcustomplot.h>
8 #include <Visualization/qcustomplot.h>
9
9
10 Q_LOGGING_CATEGORY(LOG_AxisRenderingUtils, "AxisRenderingUtils")
10 Q_LOGGING_CATEGORY(LOG_AxisRenderingUtils, "AxisRenderingUtils")
11
11
12 namespace {
12 namespace {
13
13
14 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
14 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
15
15
16 /// Format for datetimes on a axis
16 /// Format for datetimes on a axis
17 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
17 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
18
18
19 const auto NUMBER_FORMAT = 'g';
20 const auto NUMBER_PRECISION = 9;
21
19 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
22 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
20 /// non-time data
23 /// non-time data
21 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis, QCPAxis::ScaleType scaleType)
24 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis, QCPAxis::ScaleType scaleType)
22 {
25 {
23 if (isTimeAxis) {
26 if (isTimeAxis) {
24 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
27 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
25 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
28 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
26 dateTicker->setDateTimeSpec(Qt::UTC);
29 dateTicker->setDateTimeSpec(Qt::UTC);
27
30
28 return dateTicker;
31 return dateTicker;
29 }
32 }
30 else if (scaleType == QCPAxis::stLogarithmic) {
33 else if (scaleType == QCPAxis::stLogarithmic) {
31 return QSharedPointer<QCPAxisTickerLog>::create();
34 return QSharedPointer<QCPAxisTickerLog>::create();
32 }
35 }
33 else {
36 else {
34 // default ticker
37 // default ticker
35 return QSharedPointer<QCPAxisTicker>::create();
38 return QSharedPointer<QCPAxisTicker>::create();
36 }
39 }
37 }
40 }
38
41
39 /**
42 /**
40 * Sets properties of the axis passed as parameter
43 * Sets properties of the axis passed as parameter
41 * @param axis the axis to set
44 * @param axis the axis to set
42 * @param unit the unit to set for the axis
45 * @param unit the unit to set for the axis
43 * @param scaleType the scale type to set for the axis
46 * @param scaleType the scale type to set for the axis
44 */
47 */
45 void setAxisProperties(QCPAxis &axis, const Unit &unit,
48 void setAxisProperties(QCPAxis &axis, const Unit &unit,
46 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
49 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
47 {
50 {
48 // label (unit name)
51 // label (unit name)
49 axis.setLabel(unit.m_Name);
52 axis.setLabel(unit.m_Name);
50
53
51 // scale type
54 // scale type
52 axis.setScaleType(scaleType);
55 axis.setScaleType(scaleType);
53 if (scaleType == QCPAxis::stLogarithmic) {
56 if (scaleType == QCPAxis::stLogarithmic) {
54 // Scientific notation
57 // Scientific notation
55 axis.setNumberPrecision(0);
58 axis.setNumberPrecision(0);
56 axis.setNumberFormat("eb");
59 axis.setNumberFormat("eb");
57 }
60 }
58
61
59 // ticker (depending on the type of unit)
62 // ticker (depending on the type of unit)
60 axis.setTicker(axisTicker(unit.m_TimeUnit, scaleType));
63 axis.setTicker(axisTicker(unit.m_TimeUnit, scaleType));
61 }
64 }
62
65
63 /**
66 /**
64 * Delegate used to set axes properties
67 * Delegate used to set axes properties
65 */
68 */
66 template <typename T, typename Enabled = void>
69 template <typename T, typename Enabled = void>
67 struct AxisSetter {
70 struct AxisSetter {
68 static void setProperties(T &, QCustomPlot &, SqpColorScale &)
71 static void setProperties(T &, QCustomPlot &, SqpColorScale &)
69 {
72 {
70 // Default implementation does nothing
73 // Default implementation does nothing
71 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
74 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
72 }
75 }
73 };
76 };
74
77
75 /**
78 /**
76 * Specialization of AxisSetter for scalars and vectors
79 * Specialization of AxisSetter for scalars and vectors
77 * @sa ScalarSeries
80 * @sa ScalarSeries
78 * @sa VectorSeries
81 * @sa VectorSeries
79 */
82 */
80 template <typename T>
83 template <typename T>
81 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
84 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
82 or std::is_base_of<VectorSeries, T>::value> > {
85 or std::is_base_of<VectorSeries, T>::value> > {
83 static void setProperties(T &dataSeries, QCustomPlot &plot, SqpColorScale &)
86 static void setProperties(T &dataSeries, QCustomPlot &plot, SqpColorScale &)
84 {
87 {
85 dataSeries.lockRead();
88 dataSeries.lockRead();
86 auto xAxisUnit = dataSeries.xAxisUnit();
89 auto xAxisUnit = dataSeries.xAxisUnit();
87 auto valuesUnit = dataSeries.valuesUnit();
90 auto valuesUnit = dataSeries.valuesUnit();
88 dataSeries.unlock();
91 dataSeries.unlock();
89
92
90 setAxisProperties(*plot.xAxis, xAxisUnit);
93 setAxisProperties(*plot.xAxis, xAxisUnit);
91 setAxisProperties(*plot.yAxis, valuesUnit);
94 setAxisProperties(*plot.yAxis, valuesUnit);
92 }
95 }
93 };
96 };
94
97
95 /**
98 /**
96 * Specialization of AxisSetter for spectrograms
99 * Specialization of AxisSetter for spectrograms
97 * @sa SpectrogramSeries
100 * @sa SpectrogramSeries
98 */
101 */
99 template <typename T>
102 template <typename T>
100 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
103 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
101 static void setProperties(T &dataSeries, QCustomPlot &plot, SqpColorScale &colorScale)
104 static void setProperties(T &dataSeries, QCustomPlot &plot, SqpColorScale &colorScale)
102 {
105 {
103 dataSeries.lockRead();
106 dataSeries.lockRead();
104 auto xAxisUnit = dataSeries.xAxisUnit();
107 auto xAxisUnit = dataSeries.xAxisUnit();
105 auto yAxisUnit = dataSeries.yAxisUnit();
108 auto yAxisUnit = dataSeries.yAxisUnit();
106 auto valuesUnit = dataSeries.valuesUnit();
109 auto valuesUnit = dataSeries.valuesUnit();
107 dataSeries.unlock();
110 dataSeries.unlock();
108
111
109 setAxisProperties(*plot.xAxis, xAxisUnit);
112 setAxisProperties(*plot.xAxis, xAxisUnit);
110 setAxisProperties(*plot.yAxis, yAxisUnit, QCPAxis::stLogarithmic);
113 setAxisProperties(*plot.yAxis, yAxisUnit, QCPAxis::stLogarithmic);
111
114
112 // Displays color scale in plot
115 // Displays color scale in plot
113 plot.plotLayout()->insertRow(0);
116 plot.plotLayout()->insertRow(0);
114 plot.plotLayout()->addElement(0, 0, colorScale.m_Scale);
117 plot.plotLayout()->addElement(0, 0, colorScale.m_Scale);
115 colorScale.m_Scale->setType(QCPAxis::atTop);
118 colorScale.m_Scale->setType(QCPAxis::atTop);
116 colorScale.m_Scale->setMinimumMargins(QMargins{0, 0, 0, 0});
119 colorScale.m_Scale->setMinimumMargins(QMargins{0, 0, 0, 0});
117
120
118 // Aligns color scale with axes
121 // Aligns color scale with axes
119 auto marginGroups = plot.axisRect()->marginGroups();
122 auto marginGroups = plot.axisRect()->marginGroups();
120 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it) {
123 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it) {
121 colorScale.m_Scale->setMarginGroup(it.key(), it.value());
124 colorScale.m_Scale->setMarginGroup(it.key(), it.value());
122 }
125 }
123
126
124 // Set color scale properties
127 // Set color scale properties
125 setAxisProperties(*colorScale.m_Scale->axis(), valuesUnit, QCPAxis::stLogarithmic);
128 setAxisProperties(*colorScale.m_Scale->axis(), valuesUnit, QCPAxis::stLogarithmic);
126 }
129 }
127 };
130 };
128
131
129 /**
132 /**
130 * Default implementation of IAxisHelper, which takes data series to set axes properties
133 * Default implementation of IAxisHelper, which takes data series to set axes properties
131 * @tparam T the data series' type
134 * @tparam T the data series' type
132 */
135 */
133 template <typename T>
136 template <typename T>
134 struct AxisHelper : public IAxisHelper {
137 struct AxisHelper : public IAxisHelper {
135 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
138 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
136
139
137 void setProperties(QCustomPlot &plot, SqpColorScale &colorScale) override
140 void setProperties(QCustomPlot &plot, SqpColorScale &colorScale) override
138 {
141 {
139 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
142 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
140 }
143 }
141
144
142 T &m_DataSeries;
145 T &m_DataSeries;
143 };
146 };
144
147
145 } // namespace
148 } // namespace
146
149
147 QString formatValue(double value, const QCPAxis &axis)
150 QString formatValue(double value, const QCPAxis &axis)
148 {
151 {
149 // If the axis is a time axis, formats the value as a date
152 // If the axis is a time axis, formats the value as a date
150 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
153 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
151 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
154 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
152 }
155 }
153 else {
156 else {
154 return QString::number(value);
157 return QString::number(value, NUMBER_FORMAT, NUMBER_PRECISION);
155 }
158 }
156 }
159 }
157
160
158 std::unique_ptr<IAxisHelper>
161 std::unique_ptr<IAxisHelper>
159 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
162 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
160 {
163 {
161 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
164 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
162 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
165 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
163 }
166 }
164 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
167 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
165 return std::make_unique<AxisHelper<SpectrogramSeries> >(*spectrogramSeries);
168 return std::make_unique<AxisHelper<SpectrogramSeries> >(*spectrogramSeries);
166 }
169 }
167 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
170 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
168 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
171 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
169 }
172 }
170 else {
173 else {
171 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
174 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
172 }
175 }
173 }
176 }
@@ -1,325 +1,331
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
33 const auto COLORMAP_TOOLTIP_FORMAT = QStringLiteral("x: %1\ny: %2\nvalue: %3");
32
34
33 /// Offset used to shift the tooltip of the mouse
35 /// Offset used to shift the tooltip of the mouse
34 const auto TOOLTIP_OFFSET = QPoint{20, 20};
36 const auto TOOLTIP_OFFSET = QPoint{20, 20};
35
37
36 /// 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)
37 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
39 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
38
40
39 /// Timeout after which the tooltip is displayed
41 /// Timeout after which the tooltip is displayed
40 const auto TOOLTIP_TIMEOUT = 500;
42 const auto TOOLTIP_TIMEOUT = 500;
41
43
42 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
44 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
43 {
45 {
44 tracer.setInterpolating(false);
46 tracer.setInterpolating(false);
45 tracer.setStyle(QCPItemTracer::tsCircle);
47 tracer.setStyle(QCPItemTracer::tsCircle);
46 tracer.setSize(3);
48 tracer.setSize(3);
47 tracer.setPen(QPen(Qt::black));
49 tracer.setPen(QPen(Qt::black));
48 tracer.setBrush(Qt::black);
50 tracer.setBrush(Qt::black);
49 }
51 }
50
52
51 QPixmap pixmap(const QString &iconPath) noexcept
53 QPixmap pixmap(const QString &iconPath) noexcept
52 {
54 {
53 return QIcon{iconPath}.pixmap(QSize{16, 16});
55 return QIcon{iconPath}.pixmap(QSize{16, 16});
54 }
56 }
55
57
56 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
58 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
57 {
59 {
58 // Icon
60 // Icon
59 pixmap.setPixmap(
61 pixmap.setPixmap(
60 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
62 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
61
63
62 // Position
64 // Position
63 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
65 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
64 pixmap.topLeft->setCoords(1, 0);
66 pixmap.topLeft->setCoords(1, 0);
65 pixmap.setClipToAxisRect(false);
67 pixmap.setClipToAxisRect(false);
66
68
67 // Can be selected
69 // Can be selected
68 pixmap.setSelectable(true);
70 pixmap.setSelectable(true);
69 }
71 }
70
72
71 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
73 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
72 {
74 {
73 // Icon
75 // Icon
74 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
76 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
75
77
76 // Position
78 // Position
77 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
79 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
78 itemPixmap.topLeft->setCoords(0, 1);
80 itemPixmap.topLeft->setCoords(0, 1);
79 itemPixmap.setClipToAxisRect(false);
81 itemPixmap.setClipToAxisRect(false);
80
82
81 // Can be selected
83 // Can be selected
82 itemPixmap.setSelectable(true);
84 itemPixmap.setSelectable(true);
83 }
85 }
84
86
85 void initTitleTextStyle(QCPItemText &text) noexcept
87 void initTitleTextStyle(QCPItemText &text) noexcept
86 {
88 {
87 // Font and background styles
89 // Font and background styles
88 text.setColor(Qt::gray);
90 text.setColor(Qt::gray);
89 text.setBrush(Qt::white);
91 text.setBrush(Qt::white);
90
92
91 // Position
93 // Position
92 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
94 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
93 text.position->setType(QCPItemPosition::ptAxisRectRatio);
95 text.position->setType(QCPItemPosition::ptAxisRectRatio);
94 text.position->setCoords(0.5, 0);
96 text.position->setCoords(0.5, 0);
95 }
97 }
96
98
97 /**
99 /**
98 * Returns the cell index (x or y) of a colormap according to the coordinate passed in parameter.
100 * Returns the cell index (x or y) of a colormap according to the coordinate passed in parameter.
99 * This method handles the fact that a colormap axis can be logarithmic or linear.
101 * This method handles the fact that a colormap axis can be logarithmic or linear.
100 * @param colormap the colormap for which to calculate the index
102 * @param colormap the colormap for which to calculate the index
101 * @param coord the coord to convert to cell index
103 * @param coord the coord to convert to cell index
102 * @param xCoord calculates the x index if true, calculates y index if false
104 * @param xCoord calculates the x index if true, calculates y index if false
103 * @return the cell index
105 * @return the cell index
104 */
106 */
105 int colorMapCellIndex(const QCPColorMap &colormap, double coord, bool xCoord)
107 int colorMapCellIndex(const QCPColorMap &colormap, double coord, bool xCoord)
106 {
108 {
107 // Determines the axis of the colormap according to xCoord, and whether it is logarithmic or not
109 // Determines the axis of the colormap according to xCoord, and whether it is logarithmic or not
108 auto isLogarithmic = (xCoord ? colormap.keyAxis() : colormap.valueAxis())->scaleType()
110 auto isLogarithmic = (xCoord ? colormap.keyAxis() : colormap.valueAxis())->scaleType()
109 == QCPAxis::stLogarithmic;
111 == QCPAxis::stLogarithmic;
110
112
111 if (isLogarithmic) {
113 if (isLogarithmic) {
112 // For a logarithmic axis we can't use the conversion method of colormap, so we calculate
114 // For a logarithmic axis we can't use the conversion method of colormap, so we calculate
113 // the index manually based on the position of the coordinate on the axis
115 // the index manually based on the position of the coordinate on the axis
114
116
115 // Gets the axis range and the number of values between range bounds to calculate the step
117 // Gets the axis range and the number of values between range bounds to calculate the step
116 // between each value of the range
118 // between each value of the range
117 auto range = xCoord ? colormap.data()->keyRange() : colormap.data()->valueRange();
119 auto range = xCoord ? colormap.data()->keyRange() : colormap.data()->valueRange();
118 auto nbValues = (xCoord ? colormap.data()->keySize() : colormap.data()->valueSize()) - 1;
120 auto nbValues = (xCoord ? colormap.data()->keySize() : colormap.data()->valueSize()) - 1;
119 auto valueStep
121 auto valueStep
120 = (std::log10(range.upper) - std::log10(range.lower)) / static_cast<double>(nbValues);
122 = (std::log10(range.upper) - std::log10(range.lower)) / static_cast<double>(nbValues);
121
123
122 // According to the coord position, calculates the closest index in the range
124 // According to the coord position, calculates the closest index in the range
123 return std::round((std::log10(coord) - std::log10(range.lower)) / valueStep);
125 return std::round((std::log10(coord) - std::log10(range.lower)) / valueStep);
124 }
126 }
125 else {
127 else {
126 // For a linear axis, we use the conversion method of colormap
128 // For a linear axis, we use the conversion method of colormap
127 int index;
129 int index;
128 if (xCoord) {
130 if (xCoord) {
129 colormap.data()->coordToCell(coord, 0., &index, nullptr);
131 colormap.data()->coordToCell(coord, 0., &index, nullptr);
130 }
132 }
131 else {
133 else {
132 colormap.data()->coordToCell(0., coord, nullptr, &index);
134 colormap.data()->coordToCell(0., coord, nullptr, &index);
133 }
135 }
134
136
135 return index;
137 return index;
136 }
138 }
137 }
139 }
138
140
139 } // namespace
141 } // namespace
140
142
141 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
143 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
142 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
144 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
143 : m_Plot{graphWidget.plot()},
145 : m_Plot{graphWidget.plot()},
144 m_PointTracer{new QCPItemTracer{&m_Plot}},
146 m_PointTracer{new QCPItemTracer{&m_Plot}},
145 m_TracerTimer{},
147 m_TracerTimer{},
146 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
148 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
147 m_TitleText{new QCPItemText{&m_Plot}},
149 m_TitleText{new QCPItemText{&m_Plot}},
148 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
150 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
149 m_ShowXAxis{true},
151 m_ShowXAxis{true},
150 m_XAxisLabel{},
152 m_XAxisLabel{},
151 m_ColorScale{SqpColorScale{m_Plot}}
153 m_ColorScale{SqpColorScale{m_Plot}}
152 {
154 {
153 initPointTracerStyle(*m_PointTracer);
155 initPointTracerStyle(*m_PointTracer);
154
156
155 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
157 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
156 m_TracerTimer.setSingleShot(true);
158 m_TracerTimer.setSingleShot(true);
157
159
158 // Inits "close button" in plot overlay
160 // Inits "close button" in plot overlay
159 m_ClosePixmap->setLayer(OVERLAY_LAYER);
161 m_ClosePixmap->setLayer(OVERLAY_LAYER);
160 initClosePixmapStyle(*m_ClosePixmap);
162 initClosePixmapStyle(*m_ClosePixmap);
161
163
162 // Connects pixmap selection to graph widget closing
164 // Connects pixmap selection to graph widget closing
163 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
165 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
164 [&graphWidget](bool selected) {
166 [&graphWidget](bool selected) {
165 if (selected) {
167 if (selected) {
166 graphWidget.close();
168 graphWidget.close();
167 }
169 }
168 });
170 });
169
171
170 // Inits graph name in plot overlay
172 // Inits graph name in plot overlay
171 m_TitleText->setLayer(OVERLAY_LAYER);
173 m_TitleText->setLayer(OVERLAY_LAYER);
172 m_TitleText->setText(graphWidget.name());
174 m_TitleText->setText(graphWidget.name());
173 initTitleTextStyle(*m_TitleText);
175 initTitleTextStyle(*m_TitleText);
174
176
175 // Inits "show x-axis button" in plot overlay
177 // Inits "show x-axis button" in plot overlay
176 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
178 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
177 initXAxisPixmapStyle(*m_XAxisPixmap);
179 initXAxisPixmapStyle(*m_XAxisPixmap);
178
180
179 // Connects pixmap selection to graph x-axis showing/hiding
181 // Connects pixmap selection to graph x-axis showing/hiding
180 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
182 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
181 if (m_XAxisPixmap->selected()) {
183 if (m_XAxisPixmap->selected()) {
182 // Changes the selection state and refreshes the x-axis
184 // Changes the selection state and refreshes the x-axis
183 m_ShowXAxis = !m_ShowXAxis;
185 m_ShowXAxis = !m_ShowXAxis;
184 updateXAxisState();
186 updateXAxisState();
185 m_Plot.layer(AXES_LAYER)->replot();
187 m_Plot.layer(AXES_LAYER)->replot();
186
188
187 // Deselects the x-axis pixmap and updates icon
189 // Deselects the x-axis pixmap and updates icon
188 m_XAxisPixmap->setSelected(false);
190 m_XAxisPixmap->setSelected(false);
189 m_XAxisPixmap->setPixmap(
191 m_XAxisPixmap->setPixmap(
190 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
192 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
191 m_Plot.layer(OVERLAY_LAYER)->replot();
193 m_Plot.layer(OVERLAY_LAYER)->replot();
192 }
194 }
193 });
195 });
194 }
196 }
195
197
196 /// Updates state of x-axis according to the current selection of x-axis pixmap
198 /// Updates state of x-axis according to the current selection of x-axis pixmap
197 /// @remarks the method doesn't call plot refresh
199 /// @remarks the method doesn't call plot refresh
198 void updateXAxisState() noexcept
200 void updateXAxisState() noexcept
199 {
201 {
200 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
202 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
201 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
203 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
202 }
204 }
203
205
204 QCustomPlot &m_Plot;
206 QCustomPlot &m_Plot;
205 QCPItemTracer *m_PointTracer;
207 QCPItemTracer *m_PointTracer;
206 QTimer m_TracerTimer;
208 QTimer m_TracerTimer;
207 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
209 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
208 QCPItemText *m_TitleText; /// Graph's title
210 QCPItemText *m_TitleText; /// Graph's title
209 QCPItemPixmap *m_XAxisPixmap;
211 QCPItemPixmap *m_XAxisPixmap;
210 bool m_ShowXAxis; /// X-axis properties are shown or hidden
212 bool m_ShowXAxis; /// X-axis properties are shown or hidden
211 QString m_XAxisLabel;
213 QString m_XAxisLabel;
212 SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
214 SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
213 };
215 };
214
216
215 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
217 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
216 VisualizationGraphWidget &graphWidget)
218 VisualizationGraphWidget &graphWidget)
217 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
219 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
218 {
220 {
219 }
221 }
220
222
221 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
223 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
222 {
224 {
223 // Opens color scale editor if color scale is double clicked
225 // Opens color scale editor if color scale is double clicked
224 auto colorScale = dynamic_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()));
226 auto colorScale = dynamic_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()));
225 if (impl->m_ColorScale.m_Scale == colorScale) {
227 if (impl->m_ColorScale.m_Scale == colorScale) {
226 if (ColorScaleEditor{impl->m_ColorScale}.exec() == QDialog::Accepted) {
228 if (ColorScaleEditor{impl->m_ColorScale}.exec() == QDialog::Accepted) {
227 impl->m_Plot.replot();
229 impl->m_Plot.replot();
228 }
230 }
229 }
231 }
230 }
232 }
231
233
232 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
234 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
233 {
235 {
234 // Cancels pending refresh
236 // Cancels pending refresh
235 impl->m_TracerTimer.disconnect();
237 impl->m_TracerTimer.disconnect();
236
238
237 // Reinits tracers
239 // Reinits tracers
238 impl->m_PointTracer->setGraph(nullptr);
240 impl->m_PointTracer->setGraph(nullptr);
239 impl->m_PointTracer->setVisible(false);
241 impl->m_PointTracer->setVisible(false);
240 impl->m_Plot.replot();
242 impl->m_Plot.replot();
241
243
242 QString tooltip{};
244 QString tooltip{};
243
245
244 // Gets the graph under the mouse position
246 // Gets the graph under the mouse position
245 auto eventPos = event->pos();
247 auto eventPos = event->pos();
246 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
248 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
247 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
249 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
248 auto graphData = graph->data();
250 auto graphData = graph->data();
249
251
250 // Gets the closest data point to the mouse
252 // Gets the closest data point to the mouse
251 auto graphDataIt = graphData->findBegin(mouseKey);
253 auto graphDataIt = graphData->findBegin(mouseKey);
252 if (graphDataIt != graphData->constEnd()) {
254 if (graphDataIt != graphData->constEnd()) {
253 // Sets tooltip
255 // Sets tooltip
254 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
256 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
255 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
257 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
256 tooltip = GRAPH_TOOLTIP_FORMAT.arg(key, value);
258 tooltip = GRAPH_TOOLTIP_FORMAT.arg(key, value);
257
259
258 // Displays point tracer
260 // Displays point tracer
259 impl->m_PointTracer->setGraph(graph);
261 impl->m_PointTracer->setGraph(graph);
260 impl->m_PointTracer->setGraphKey(graphDataIt->key);
262 impl->m_PointTracer->setGraphKey(graphDataIt->key);
261 impl->m_PointTracer->setLayer(
263 impl->m_PointTracer->setLayer(
262 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
264 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
263 impl->m_PointTracer->setVisible(true);
265 impl->m_PointTracer->setVisible(true);
264 impl->m_Plot.replot();
266 impl->m_Plot.replot();
265 }
267 }
266 }
268 }
267 else if (auto colorMap = qobject_cast<QCPColorMap *>(impl->m_Plot.plottableAt(eventPos))) {
269 else if (auto colorMap = qobject_cast<QCPColorMap *>(impl->m_Plot.plottableAt(eventPos))) {
268 // Gets x and y coords
270 // Gets x and y coords
269 auto x = colorMap->keyAxis()->pixelToCoord(eventPos.x());
271 auto x = colorMap->keyAxis()->pixelToCoord(eventPos.x());
270 auto y = colorMap->valueAxis()->pixelToCoord(eventPos.y());
272 auto y = colorMap->valueAxis()->pixelToCoord(eventPos.y());
271
273
272 // Calculates x and y cell indexes, and retrieves the underlying value
274 // Calculates x and y cell indexes, and retrieves the underlying value
273 auto xCellIndex = colorMapCellIndex(*colorMap, x, true);
275 auto xCellIndex = colorMapCellIndex(*colorMap, x, true);
274 auto yCellIndex = colorMapCellIndex(*colorMap, y, false);
276 auto yCellIndex = colorMapCellIndex(*colorMap, y, false);
275 auto value = colorMap->data()->cell(xCellIndex, yCellIndex);
277 auto value = colorMap->data()->cell(xCellIndex, yCellIndex);
276
278
279 // Sets tooltips
280 tooltip = COLORMAP_TOOLTIP_FORMAT.arg(formatValue(x, *colorMap->keyAxis()),
281 formatValue(y, *colorMap->valueAxis()),
282 formatValue(value, *colorMap->colorScale()->axis()));
277 }
283 }
278
284
279 if (!tooltip.isEmpty()) {
285 if (!tooltip.isEmpty()) {
280 // Starts timer to show tooltip after timeout
286 // Starts timer to show tooltip after timeout
281 auto showTooltip = [tooltip, eventPos, this]() {
287 auto showTooltip = [tooltip, eventPos, this]() {
282 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
288 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
283 &impl->m_Plot, TOOLTIP_RECT);
289 &impl->m_Plot, TOOLTIP_RECT);
284 };
290 };
285
291
286 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
292 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
287 impl->m_TracerTimer.start();
293 impl->m_TracerTimer.start();
288 }
294 }
289 }
295 }
290
296
291 void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept
297 void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept
292 {
298 {
293 // Updates color scale bounds
299 // Updates color scale bounds
294 impl->m_ColorScale.updateDataRange();
300 impl->m_ColorScale.updateDataRange();
295 impl->m_Plot.replot();
301 impl->m_Plot.replot();
296 }
302 }
297
303
298 void VisualizationGraphRenderingDelegate::setAxesProperties(
304 void VisualizationGraphRenderingDelegate::setAxesProperties(
299 std::shared_ptr<IDataSeries> dataSeries) noexcept
305 std::shared_ptr<IDataSeries> dataSeries) noexcept
300 {
306 {
301 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
307 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
302 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
308 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
303
309
304 auto axisHelper = IAxisHelperFactory::create(dataSeries);
310 auto axisHelper = IAxisHelperFactory::create(dataSeries);
305 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
311 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
306
312
307 // Updates x-axis state
313 // Updates x-axis state
308 impl->updateXAxisState();
314 impl->updateXAxisState();
309
315
310 impl->m_Plot.layer(AXES_LAYER)->replot();
316 impl->m_Plot.layer(AXES_LAYER)->replot();
311 }
317 }
312
318
313 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
319 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
314 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
320 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
315 {
321 {
316 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
322 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
317 plottablesHelper->setProperties(plottables);
323 plottablesHelper->setProperties(plottables);
318 }
324 }
319
325
320 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
326 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
321 {
327 {
322 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
328 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
323 overlay->setVisible(show);
329 overlay->setVisible(show);
324 overlay->replot();
330 overlay->replot();
325 }
331 }
General Comments 0
You need to be logged in to leave comments. Login now