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