##// END OF EJS Templates
Tooltip for spectrograms (2)...
Alexandre Leroux -
r1066:e6d0518500ef
parent child
Show More
@@ -1,276 +1,277
1 1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 2 #include "Visualization/AxisRenderingUtils.h"
3 3 #include "Visualization/ColorScaleEditor.h"
4 4 #include "Visualization/PlottablesRenderingUtils.h"
5 5 #include "Visualization/SqpColorScale.h"
6 6 #include "Visualization/VisualizationGraphWidget.h"
7 7 #include "Visualization/qcustomplot.h"
8 8
9 9 #include <Common/DateUtils.h>
10 10
11 11 #include <Data/IDataSeries.h>
12 12
13 13 #include <SqpApplication.h>
14 14
15 15 namespace {
16 16
17 17 /// Name of the axes layer in QCustomPlot
18 18 const auto AXES_LAYER = QStringLiteral("axes");
19 19
20 20 /// Icon used to show x-axis properties
21 21 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
22 22
23 23 /// Name of the overlay layer in QCustomPlot
24 24 const auto OVERLAY_LAYER = QStringLiteral("overlay");
25 25
26 26 /// Pixmap used to show x-axis properties
27 27 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
28 28
29 29 /// Tooltip format for graphs
30 30 const auto GRAPH_TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
31 31
32 32
33 33 /// Offset used to shift the tooltip of the mouse
34 34 const auto TOOLTIP_OFFSET = QPoint{20, 20};
35 35
36 36 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
37 37 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
38 38
39 39 /// Timeout after which the tooltip is displayed
40 40 const auto TOOLTIP_TIMEOUT = 500;
41 41
42 42 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
43 43 {
44 44 tracer.setInterpolating(false);
45 45 tracer.setStyle(QCPItemTracer::tsCircle);
46 46 tracer.setSize(3);
47 47 tracer.setPen(QPen(Qt::black));
48 48 tracer.setBrush(Qt::black);
49 49 }
50 50
51 51 QPixmap pixmap(const QString &iconPath) noexcept
52 52 {
53 53 return QIcon{iconPath}.pixmap(QSize{16, 16});
54 54 }
55 55
56 56 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
57 57 {
58 58 // Icon
59 59 pixmap.setPixmap(
60 60 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
61 61
62 62 // Position
63 63 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
64 64 pixmap.topLeft->setCoords(1, 0);
65 65 pixmap.setClipToAxisRect(false);
66 66
67 67 // Can be selected
68 68 pixmap.setSelectable(true);
69 69 }
70 70
71 71 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
72 72 {
73 73 // Icon
74 74 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
75 75
76 76 // Position
77 77 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
78 78 itemPixmap.topLeft->setCoords(0, 1);
79 79 itemPixmap.setClipToAxisRect(false);
80 80
81 81 // Can be selected
82 82 itemPixmap.setSelectable(true);
83 83 }
84 84
85 85 void initTitleTextStyle(QCPItemText &text) noexcept
86 86 {
87 87 // Font and background styles
88 88 text.setColor(Qt::gray);
89 89 text.setBrush(Qt::white);
90 90
91 91 // Position
92 92 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
93 93 text.position->setType(QCPItemPosition::ptAxisRectRatio);
94 94 text.position->setCoords(0.5, 0);
95 95 }
96 96
97 97 } // namespace
98 98
99 99 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
100 100 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
101 101 : m_Plot{graphWidget.plot()},
102 102 m_PointTracer{new QCPItemTracer{&m_Plot}},
103 103 m_TracerTimer{},
104 104 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
105 105 m_TitleText{new QCPItemText{&m_Plot}},
106 106 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
107 107 m_ShowXAxis{true},
108 108 m_XAxisLabel{},
109 109 m_ColorScale{SqpColorScale{m_Plot}}
110 110 {
111 111 initPointTracerStyle(*m_PointTracer);
112 112
113 113 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
114 114 m_TracerTimer.setSingleShot(true);
115 115
116 116 // Inits "close button" in plot overlay
117 117 m_ClosePixmap->setLayer(OVERLAY_LAYER);
118 118 initClosePixmapStyle(*m_ClosePixmap);
119 119
120 120 // Connects pixmap selection to graph widget closing
121 121 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
122 122 [&graphWidget](bool selected) {
123 123 if (selected) {
124 124 graphWidget.close();
125 125 }
126 126 });
127 127
128 128 // Inits graph name in plot overlay
129 129 m_TitleText->setLayer(OVERLAY_LAYER);
130 130 m_TitleText->setText(graphWidget.name());
131 131 initTitleTextStyle(*m_TitleText);
132 132
133 133 // Inits "show x-axis button" in plot overlay
134 134 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
135 135 initXAxisPixmapStyle(*m_XAxisPixmap);
136 136
137 137 // Connects pixmap selection to graph x-axis showing/hiding
138 138 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
139 139 if (m_XAxisPixmap->selected()) {
140 140 // Changes the selection state and refreshes the x-axis
141 141 m_ShowXAxis = !m_ShowXAxis;
142 142 updateXAxisState();
143 143 m_Plot.layer(AXES_LAYER)->replot();
144 144
145 145 // Deselects the x-axis pixmap and updates icon
146 146 m_XAxisPixmap->setSelected(false);
147 147 m_XAxisPixmap->setPixmap(
148 148 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
149 149 m_Plot.layer(OVERLAY_LAYER)->replot();
150 150 }
151 151 });
152 152 }
153 153
154 154 /// Updates state of x-axis according to the current selection of x-axis pixmap
155 155 /// @remarks the method doesn't call plot refresh
156 156 void updateXAxisState() noexcept
157 157 {
158 158 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
159 159 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
160 160 }
161 161
162 162 QCustomPlot &m_Plot;
163 163 QCPItemTracer *m_PointTracer;
164 164 QTimer m_TracerTimer;
165 165 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
166 166 QCPItemText *m_TitleText; /// Graph's title
167 167 QCPItemPixmap *m_XAxisPixmap;
168 168 bool m_ShowXAxis; /// X-axis properties are shown or hidden
169 169 QString m_XAxisLabel;
170 170 SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
171 171 };
172 172
173 173 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
174 174 VisualizationGraphWidget &graphWidget)
175 175 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
176 176 {
177 177 }
178 178
179 179 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
180 180 {
181 181 // Opens color scale editor if color scale is double clicked
182 182 auto colorScale = dynamic_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()));
183 183 if (impl->m_ColorScale.m_Scale == colorScale) {
184 184 if (ColorScaleEditor{impl->m_ColorScale}.exec() == QDialog::Accepted) {
185 185 impl->m_Plot.replot();
186 186 }
187 187 }
188 188 }
189 189
190 190 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
191 191 {
192 192 // Cancels pending refresh
193 193 impl->m_TracerTimer.disconnect();
194 194
195 195 // Reinits tracers
196 196 impl->m_PointTracer->setGraph(nullptr);
197 197 impl->m_PointTracer->setVisible(false);
198 198 impl->m_Plot.replot();
199 199
200 200 QString tooltip{};
201 201
202 202 // Gets the graph under the mouse position
203 203 auto eventPos = event->pos();
204 204 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
205 205 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
206 206 auto graphData = graph->data();
207 207
208 208 // Gets the closest data point to the mouse
209 209 auto graphDataIt = graphData->findBegin(mouseKey);
210 210 if (graphDataIt != graphData->constEnd()) {
211 211 // Sets tooltip
212 212 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
213 213 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
214 214 tooltip = GRAPH_TOOLTIP_FORMAT.arg(key, value);
215 215
216 216 // Displays point tracer
217 217 impl->m_PointTracer->setGraph(graph);
218 218 impl->m_PointTracer->setGraphKey(graphDataIt->key);
219 219 impl->m_PointTracer->setLayer(
220 220 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
221 221 impl->m_PointTracer->setVisible(true);
222 222 impl->m_Plot.replot();
223 223 }
224 224 }
225 225 else if (auto colorMap = qobject_cast<QCPColorMap *>(impl->m_Plot.plottableAt(eventPos))) {
226 /// @todo
227 tooltip = "TODO";
226 // Gets x and y coords
227 auto x = colorMap->keyAxis()->pixelToCoord(eventPos.x());
228 auto y = colorMap->valueAxis()->pixelToCoord(eventPos.y());
228 229 }
229 230
230 231 if (!tooltip.isEmpty()) {
231 232 // Starts timer to show tooltip after timeout
232 233 auto showTooltip = [tooltip, eventPos, this]() {
233 234 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
234 235 &impl->m_Plot, TOOLTIP_RECT);
235 236 };
236 237
237 238 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
238 239 impl->m_TracerTimer.start();
239 240 }
240 241 }
241 242
242 243 void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept
243 244 {
244 245 // Updates color scale bounds
245 246 impl->m_ColorScale.updateDataRange();
246 247 impl->m_Plot.replot();
247 248 }
248 249
249 250 void VisualizationGraphRenderingDelegate::setAxesProperties(
250 251 std::shared_ptr<IDataSeries> dataSeries) noexcept
251 252 {
252 253 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
253 254 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
254 255
255 256 auto axisHelper = IAxisHelperFactory::create(dataSeries);
256 257 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
257 258
258 259 // Updates x-axis state
259 260 impl->updateXAxisState();
260 261
261 262 impl->m_Plot.layer(AXES_LAYER)->replot();
262 263 }
263 264
264 265 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
265 266 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
266 267 {
267 268 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
268 269 plottablesHelper->setProperties(plottables);
269 270 }
270 271
271 272 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
272 273 {
273 274 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
274 275 overlay->setVisible(show);
275 276 overlay->replot();
276 277 }
General Comments 0
You need to be logged in to leave comments. Login now