Mercurial > hg > svgui
comparison layer/TimeValueLayer.cpp @ 0:2a4f26e85b4c
initial import
author | Chris Cannam |
---|---|
date | Tue, 10 Jan 2006 16:33:16 +0000 |
parents | |
children | 7af44e8578c8 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:2a4f26e85b4c |
---|---|
1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 A waveform viewer and audio annotation editor. | |
5 Chris Cannam, Queen Mary University of London, 2005 | |
6 | |
7 This is experimental software. Not for distribution. | |
8 */ | |
9 | |
10 #include "TimeValueLayer.h" | |
11 | |
12 #include "base/Model.h" | |
13 #include "base/RealTime.h" | |
14 #include "base/Profiler.h" | |
15 #include "base/View.h" | |
16 | |
17 #include "model/SparseTimeValueModel.h" | |
18 | |
19 #include <QPainter> | |
20 | |
21 #include <iostream> | |
22 #include <cmath> | |
23 | |
24 TimeValueLayer::TimeValueLayer(View *w) : | |
25 Layer(w), | |
26 m_model(0), | |
27 m_colour(Qt::black), | |
28 m_plotStyle(PlotLines) | |
29 { | |
30 m_view->addLayer(this); | |
31 } | |
32 | |
33 void | |
34 TimeValueLayer::setModel(SparseTimeValueModel *model) | |
35 { | |
36 if (m_model == model) return; | |
37 m_model = model; | |
38 | |
39 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); | |
40 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), | |
41 this, SIGNAL(modelChanged(size_t, size_t))); | |
42 | |
43 connect(m_model, SIGNAL(completionChanged()), | |
44 this, SIGNAL(modelCompletionChanged())); | |
45 | |
46 std::cerr << "TimeValueLayer::setModel(" << model << ")" << std::endl; | |
47 | |
48 emit modelReplaced(); | |
49 } | |
50 | |
51 Layer::PropertyList | |
52 TimeValueLayer::getProperties() const | |
53 { | |
54 PropertyList list; | |
55 list.push_back(tr("Colour")); | |
56 list.push_back(tr("Plot Type")); | |
57 return list; | |
58 } | |
59 | |
60 Layer::PropertyType | |
61 TimeValueLayer::getPropertyType(const PropertyName &name) const | |
62 { | |
63 return ValueProperty; | |
64 } | |
65 | |
66 int | |
67 TimeValueLayer::getPropertyRangeAndValue(const PropertyName &name, | |
68 int *min, int *max) const | |
69 { | |
70 //!!! factor this colour handling stuff out into a colour manager class | |
71 | |
72 int deft = 0; | |
73 | |
74 if (name == tr("Colour")) { | |
75 | |
76 *min = 0; | |
77 *max = 5; | |
78 | |
79 if (m_colour == Qt::black) deft = 0; | |
80 else if (m_colour == Qt::darkRed) deft = 1; | |
81 else if (m_colour == Qt::darkBlue) deft = 2; | |
82 else if (m_colour == Qt::darkGreen) deft = 3; | |
83 else if (m_colour == QColor(200, 50, 255)) deft = 4; | |
84 else if (m_colour == QColor(255, 150, 50)) deft = 5; | |
85 | |
86 } else if (name == tr("Plot Type")) { | |
87 | |
88 *min = 0; | |
89 *max = 2; | |
90 | |
91 deft = int(m_plotStyle); | |
92 | |
93 } else { | |
94 | |
95 deft = Layer::getPropertyRangeAndValue(name, min, max); | |
96 } | |
97 | |
98 return deft; | |
99 } | |
100 | |
101 QString | |
102 TimeValueLayer::getPropertyValueLabel(const PropertyName &name, | |
103 int value) const | |
104 { | |
105 if (name == tr("Colour")) { | |
106 switch (value) { | |
107 default: | |
108 case 0: return tr("Black"); | |
109 case 1: return tr("Red"); | |
110 case 2: return tr("Blue"); | |
111 case 3: return tr("Green"); | |
112 case 4: return tr("Purple"); | |
113 case 5: return tr("Orange"); | |
114 } | |
115 } else if (name == tr("Plot Type")) { | |
116 switch (value) { | |
117 default: | |
118 case 0: return tr("Points"); | |
119 case 1: return tr("Stems"); | |
120 case 2: return tr("Lines"); | |
121 } | |
122 } | |
123 return tr("<unknown>"); | |
124 } | |
125 | |
126 void | |
127 TimeValueLayer::setProperty(const PropertyName &name, int value) | |
128 { | |
129 if (name == tr("Colour")) { | |
130 switch (value) { | |
131 default: | |
132 case 0: setBaseColour(Qt::black); break; | |
133 case 1: setBaseColour(Qt::darkRed); break; | |
134 case 2: setBaseColour(Qt::darkBlue); break; | |
135 case 3: setBaseColour(Qt::darkGreen); break; | |
136 case 4: setBaseColour(QColor(200, 50, 255)); break; | |
137 case 5: setBaseColour(QColor(255, 150, 50)); break; | |
138 } | |
139 } else if (name == tr("Plot Type")) { | |
140 setPlotStyle(PlotStyle(value)); | |
141 } | |
142 } | |
143 | |
144 void | |
145 TimeValueLayer::setBaseColour(QColor colour) | |
146 { | |
147 if (m_colour == colour) return; | |
148 m_colour = colour; | |
149 emit layerParametersChanged(); | |
150 } | |
151 | |
152 void | |
153 TimeValueLayer::setPlotStyle(PlotStyle style) | |
154 { | |
155 if (m_plotStyle == style) return; | |
156 m_plotStyle = style; | |
157 emit layerParametersChanged(); | |
158 } | |
159 | |
160 bool | |
161 TimeValueLayer::isLayerScrollable() const | |
162 { | |
163 QPoint discard; | |
164 return !m_view->shouldIlluminateLocalFeatures(this, discard); | |
165 } | |
166 | |
167 QRect | |
168 TimeValueLayer::getFeatureDescriptionRect(QPainter &paint, QPoint pos) const | |
169 { | |
170 return QRect(0, 0, | |
171 std::max(100, paint.fontMetrics().width(tr("No local points"))), | |
172 70); //!!! | |
173 } | |
174 | |
175 //!!! too much in common with TimeInstantLayer | |
176 | |
177 SparseTimeValueModel::PointList | |
178 TimeValueLayer::getLocalPoints(int x) const | |
179 { | |
180 if (!m_model) return SparseTimeValueModel::PointList(); | |
181 | |
182 long startFrame = m_view->getStartFrame(); | |
183 long endFrame = m_view->getEndFrame(); | |
184 int zoomLevel = m_view->getZoomLevel(); | |
185 long frame = startFrame + x * zoomLevel; | |
186 | |
187 SparseTimeValueModel::PointList onPoints = | |
188 m_model->getPoints(frame); | |
189 | |
190 if (!onPoints.empty()) { | |
191 return onPoints; | |
192 } | |
193 | |
194 SparseTimeValueModel::PointList prevPoints = | |
195 m_model->getPreviousPoints(frame); | |
196 SparseTimeValueModel::PointList nextPoints = | |
197 m_model->getNextPoints(frame); | |
198 | |
199 SparseTimeValueModel::PointList usePoints = prevPoints; | |
200 | |
201 if (prevPoints.empty()) { | |
202 usePoints = nextPoints; | |
203 } else if (prevPoints.begin()->frame < startFrame && | |
204 !(nextPoints.begin()->frame > endFrame)) { | |
205 usePoints = nextPoints; | |
206 } else if (nextPoints.begin()->frame - frame < | |
207 frame - prevPoints.begin()->frame) { | |
208 usePoints = nextPoints; | |
209 } | |
210 | |
211 return usePoints; | |
212 } | |
213 | |
214 void | |
215 TimeValueLayer::paintLocalFeatureDescription(QPainter &paint, QRect rect, | |
216 QPoint pos) const | |
217 { | |
218 //!!! bleagh | |
219 | |
220 int x = pos.x(); | |
221 | |
222 if (!m_model || !m_model->getSampleRate()) return; | |
223 | |
224 SparseTimeValueModel::PointList points = getLocalPoints(x); | |
225 | |
226 QFontMetrics metrics = paint.fontMetrics(); | |
227 int xbase = rect.x() + 5; | |
228 int ybase = rect.y() + 5; | |
229 | |
230 if (points.empty()) { | |
231 QString label = tr("No local points"); | |
232 if (!m_model->isReady()) { | |
233 label = tr("In progress"); | |
234 } | |
235 paint.drawText(xbase + 5, ybase + 5 + metrics.ascent(), label); | |
236 return; | |
237 } | |
238 | |
239 long useFrame = points.begin()->frame; | |
240 | |
241 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); | |
242 QString timeText = QString("%1").arg(rt.toText(true).c_str()); | |
243 QString valueText = QString("%1").arg(points.begin()->value); | |
244 | |
245 int timewidth = metrics.width(timeText); | |
246 int valuewidth = metrics.width(valueText); | |
247 int labelwidth = metrics.width(points.begin()->label); | |
248 | |
249 int boxheight = metrics.height() * 3 + 4; | |
250 int boxwidth = std::max(std::max(timewidth, labelwidth), valuewidth); | |
251 | |
252 paint.drawRect(xbase, ybase, boxwidth + 10, | |
253 boxheight + 10 - metrics.descent() + 1); | |
254 | |
255 paint.drawText(xbase + 5, ybase + 5 + metrics.ascent(), timeText); | |
256 paint.drawText(xbase + 5, ybase + 7 + metrics.ascent() + metrics.height(), | |
257 valueText); | |
258 paint.drawText(xbase + 5, ybase + 9 + metrics.ascent() + 2*metrics.height(), | |
259 points.begin()->label); | |
260 } | |
261 | |
262 void | |
263 TimeValueLayer::paint(QPainter &paint, QRect rect) const | |
264 { | |
265 if (!m_model || !m_model->isOK()) return; | |
266 | |
267 int sampleRate = m_model->getSampleRate(); | |
268 if (!sampleRate) return; | |
269 | |
270 // Profiler profiler("TimeValueLayer::paint", true); | |
271 | |
272 long startFrame = m_view->getStartFrame(); | |
273 int zoomLevel = m_view->getZoomLevel(); | |
274 | |
275 int x0 = rect.left(), x1 = rect.right(); | |
276 long frame0 = startFrame + x0 * zoomLevel; | |
277 long frame1 = startFrame + x1 * zoomLevel; | |
278 | |
279 SparseTimeValueModel::PointList points(m_model->getPoints | |
280 (frame0, frame1)); | |
281 | |
282 paint.setPen(m_colour); | |
283 | |
284 QColor brushColour(m_colour); | |
285 brushColour.setAlpha(80); | |
286 paint.setBrush(brushColour); | |
287 | |
288 // std::cerr << "TimeValueLayer::paint: resolution is " | |
289 // << m_model->getResolution() << " frames" << std::endl; | |
290 | |
291 float min = m_model->getValueMinimum(); | |
292 float max = m_model->getValueMaximum(); | |
293 if (max == min) max = min + 1.0; | |
294 | |
295 int origin = int(nearbyint(m_view->height() - | |
296 (-min * m_view->height()) / (max - min))); | |
297 | |
298 QPoint localPos; | |
299 long illuminateFrame = -1; | |
300 | |
301 if (m_view->shouldIlluminateLocalFeatures(this, localPos)) { | |
302 SparseTimeValueModel::PointList localPoints = | |
303 getLocalPoints(localPos.x()); | |
304 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame; | |
305 } | |
306 | |
307 for (SparseTimeValueModel::PointList::const_iterator i = points.begin(); | |
308 i != points.end(); ++i) { | |
309 | |
310 const SparseTimeValueModel::Point &p(*i); | |
311 | |
312 int x = (p.frame - startFrame) / zoomLevel; | |
313 int y = int(nearbyint(m_view->height() - | |
314 ((p.value - min) * m_view->height()) / | |
315 (max - min))); | |
316 int w = m_model->getResolution() / zoomLevel; | |
317 | |
318 if (w < 1) w = 1; | |
319 | |
320 paint.setPen(m_colour); | |
321 paint.setBrush(brushColour); | |
322 | |
323 if (m_plotStyle == PlotStems) { | |
324 paint.setPen(brushColour); | |
325 if (y < origin - 1) { | |
326 paint.drawRect(x + w/2, y + 1, 1, origin - y); | |
327 } else if (y > origin + 1) { | |
328 paint.drawRect(x + w/2, origin, 1, y - origin - 1); | |
329 } | |
330 paint.setPen(m_colour); | |
331 } | |
332 | |
333 if (illuminateFrame == p.frame) { | |
334 //!!! aside from the problem of choosing a colour, it'd be | |
335 //better to save the highlighted rects and draw them at | |
336 //the end perhaps | |
337 paint.setPen(Qt::black);//!!! | |
338 paint.setBrush(Qt::black);//!!! | |
339 } | |
340 | |
341 paint.drawRect(x, y - 1, w, 2); | |
342 | |
343 // if (w > 1) { | |
344 // paint.setPen(brushColour); | |
345 // paint.drawRect(x, y - 1, w - 1, 2); | |
346 // paint.setPen(m_colour); | |
347 // } | |
348 // paint.drawLine(x, 0, x, m_view->height()); | |
349 | |
350 if (m_plotStyle == PlotLines) { | |
351 | |
352 paint.setPen(brushColour); | |
353 SparseTimeValueModel::PointList::const_iterator j = i; | |
354 ++j; | |
355 if (j != points.end()) { | |
356 const SparseTimeValueModel::Point &q(*j); | |
357 int nx = (q.frame - startFrame) / zoomLevel; | |
358 int ny = int(nearbyint(m_view->height() - | |
359 ((q.value - min) * m_view->height()) / | |
360 (max - min))); | |
361 paint.drawLine(x + w, y, nx, ny); | |
362 } | |
363 } | |
364 | |
365 | |
366 /// if (p.label != "") { | |
367 /// paint.drawText(x + 5, y - paint.fontMetrics().height() + paint.fontMetrics().ascent(), p.label); | |
368 /// } | |
369 } | |
370 | |
371 | |
372 } | |
373 | |
374 | |
375 #ifdef INCLUDE_MOCFILES | |
376 #include "TimeValueLayer.moc.cpp" | |
377 #endif | |
378 |