Mercurial > hg > svgui
comparison layer/TimeRulerLayer.cpp @ 374:64e84e5efb76 spectrogram-cache-rejig
* Merge from trunk
author | Chris Cannam |
---|---|
date | Wed, 27 Feb 2008 11:59:42 +0000 |
parents | c0b9eec70639 |
children |
comparison
equal
deleted
inserted
replaced
332:6440e280122e | 374:64e84e5efb76 |
---|---|
13 COPYING included with this distribution for more information. | 13 COPYING included with this distribution for more information. |
14 */ | 14 */ |
15 | 15 |
16 #include "TimeRulerLayer.h" | 16 #include "TimeRulerLayer.h" |
17 | 17 |
18 #include "LayerFactory.h" | |
19 | |
18 #include "data/model/Model.h" | 20 #include "data/model/Model.h" |
19 #include "base/RealTime.h" | 21 #include "base/RealTime.h" |
20 #include "base/ColourDatabase.h" | 22 #include "base/ColourDatabase.h" |
21 #include "view/View.h" | 23 #include "view/View.h" |
22 | 24 |
23 #include <QPainter> | 25 #include <QPainter> |
24 | 26 |
25 #include <iostream> | 27 #include <iostream> |
26 #include <cmath> | 28 #include <cmath> |
29 | |
30 //#define DEBUG_TIME_RULER_LAYER 1 | |
27 | 31 |
28 using std::cerr; | 32 using std::cerr; |
29 using std::endl; | 33 using std::endl; |
30 | 34 |
31 TimeRulerLayer::TimeRulerLayer() : | 35 TimeRulerLayer::TimeRulerLayer() : |
188 } | 192 } |
189 | 193 |
190 void | 194 void |
191 TimeRulerLayer::paint(View *v, QPainter &paint, QRect rect) const | 195 TimeRulerLayer::paint(View *v, QPainter &paint, QRect rect) const |
192 { | 196 { |
193 // std::cerr << "TimeRulerLayer::paint (" << rect.x() << "," << rect.y() | 197 #ifdef DEBUG_TIME_RULER_LAYER |
194 // << ") [" << rect.width() << "x" << rect.height() << "]" << std::endl; | 198 std::cerr << "TimeRulerLayer::paint (" << rect.x() << "," << rect.y() |
199 << ") [" << rect.width() << "x" << rect.height() << "]" << std::endl; | |
200 #endif | |
195 | 201 |
196 if (!m_model || !m_model->isOK()) return; | 202 if (!m_model || !m_model->isOK()) return; |
197 | 203 |
198 int sampleRate = m_model->getSampleRate(); | 204 int sampleRate = m_model->getSampleRate(); |
199 if (!sampleRate) return; | 205 if (!sampleRate) return; |
200 | 206 |
201 long startFrame = v->getStartFrame(); | 207 long startFrame = v->getFrameForX(rect.x() - 50); |
202 long endFrame = v->getEndFrame(); | 208 |
203 | 209 #ifdef DEBUG_TIME_RULER_LAYER |
204 int zoomLevel = v->getZoomLevel(); | 210 std::cerr << "start frame = " << startFrame << std::endl; |
205 | 211 #endif |
206 long rectStart = startFrame + (rect.x() - 100) * zoomLevel; | |
207 long rectEnd = startFrame + (rect.x() + rect.width() + 100) * zoomLevel; | |
208 | |
209 // std::cerr << "TimeRulerLayer::paint: calling paint.save()" << std::endl; | |
210 paint.save(); | |
211 //!!! paint.setClipRect(v->rect()); | |
212 | |
213 int minPixelSpacing = 50; | |
214 | 212 |
215 bool quarter = false; | 213 bool quarter = false; |
216 int incms = getMajorTickSpacing(v, quarter); | 214 int incms = getMajorTickSpacing(v, quarter); |
217 | 215 |
218 RealTime rt = RealTime::frame2RealTime(rectStart, sampleRate); | 216 int ms = lrint(1000.0 * (double(startFrame) / double(sampleRate))); |
219 long ms = rt.sec * 1000 + rt.msec(); | |
220 ms = (ms / incms) * incms - incms; | 217 ms = (ms / incms) * incms - incms; |
221 | 218 |
222 RealTime incRt = RealTime::fromMilliseconds(incms); | 219 #ifdef DEBUG_TIME_RULER_LAYER |
223 long incFrame = RealTime::realTime2Frame(incRt, sampleRate); | 220 std::cerr << "start ms = " << ms << " at step " << incms << std::endl; |
224 int incX = incFrame / zoomLevel; | 221 #endif |
222 | |
223 // Calculate the number of ticks per increment -- approximate | |
224 // values for x and frame counts here will do, no rounding issue. | |
225 // We always use the exact incms in our calculations for where to | |
226 // draw the actual ticks or lines. | |
227 | |
228 int minPixelSpacing = 50; | |
229 long incFrame = (incms * sampleRate) / 1000; | |
230 int incX = incFrame / v->getZoomLevel(); | |
225 int ticks = 10; | 231 int ticks = 10; |
226 if (incX < minPixelSpacing * 2) { | 232 if (incX < minPixelSpacing * 2) { |
227 ticks = quarter ? 4 : 5; | 233 ticks = quarter ? 4 : 5; |
228 } | 234 } |
229 | 235 |
230 QRect oldClipRect = rect; | |
231 QRect newClipRect(oldClipRect.x() - 25, oldClipRect.y(), | |
232 oldClipRect.width() + 50, oldClipRect.height()); | |
233 paint.setClipRect(newClipRect); | |
234 paint.setClipRect(rect); | |
235 | |
236 QColor greyColour = getPartialShades(v)[1]; | 236 QColor greyColour = getPartialShades(v)[1]; |
237 | 237 |
238 paint.save(); | |
239 | |
238 while (1) { | 240 while (1) { |
239 | 241 |
240 rt = RealTime::fromMilliseconds(ms); | 242 // frame is used to determine where to draw the lines, so it |
243 // needs to correspond to an exact pixel (so that we don't get | |
244 // a different pixel when scrolling a small amount and | |
245 // re-drawing with a different start frame). | |
246 | |
247 double dms = ms; | |
248 long frame = lrint((dms * sampleRate) / 1000.0); | |
249 frame /= v->getZoomLevel(); | |
250 frame *= v->getZoomLevel(); // so frame corresponds to an exact pixel | |
251 | |
241 ms += incms; | 252 ms += incms; |
242 | 253 |
243 long frame = RealTime::realTime2Frame(rt, sampleRate); | 254 int x = v->getXForFrame(frame); |
244 if (frame >= rectEnd) break; | 255 |
245 | 256 #ifdef DEBUG_TIME_RULER_LAYER |
246 int x = (frame - startFrame) / zoomLevel; | 257 std::cerr << "Considering frame = " << frame << ", x = " << x << std::endl; |
247 if (x < rect.x() || x >= rect.x() + rect.width()) continue; | 258 #endif |
259 | |
260 if (x >= rect.x() + rect.width() + 50) { | |
261 #ifdef DEBUG_TIME_RULER_LAYER | |
262 std::cerr << "X well out of range, ending here" << std::endl; | |
263 #endif | |
264 break; | |
265 } | |
266 | |
267 if (x >= rect.x() - 50) { | |
268 | |
269 #ifdef DEBUG_TIME_RULER_LAYER | |
270 std::cerr << "X in range, drawing line here" << std::endl; | |
271 #endif | |
272 | |
273 RealTime rt = RealTime::fromMilliseconds(ms); | |
274 | |
275 QString text(QString::fromStdString(rt.toText())); | |
276 QFontMetrics metrics = paint.fontMetrics(); | |
277 int tw = metrics.width(text); | |
278 | |
279 if (tw < 50 && | |
280 (x < rect.x() - tw/2 || | |
281 x >= rect.x() + rect.width() + tw/2)) { | |
282 #ifdef DEBUG_TIME_RULER_LAYER | |
283 std::cerr << "hm, maybe X isn't in range after all (x = " << x << ", tw = " << tw << ", rect.x() = " << rect.x() << ", rect.width() = " << rect.width() << ")" << std::endl; | |
284 #endif | |
285 } | |
286 | |
287 paint.setPen(greyColour); | |
288 paint.drawLine(x, 0, x, v->height()); | |
289 | |
290 paint.setPen(getBaseQColor()); | |
291 paint.drawLine(x, 0, x, 5); | |
292 paint.drawLine(x, v->height() - 6, x, v->height() - 1); | |
293 | |
294 int y; | |
295 switch (m_labelHeight) { | |
296 default: | |
297 case LabelTop: | |
298 y = 6 + metrics.ascent(); | |
299 break; | |
300 case LabelMiddle: | |
301 y = v->height() / 2 - metrics.height() / 2 + metrics.ascent(); | |
302 break; | |
303 case LabelBottom: | |
304 y = v->height() - metrics.height() + metrics.ascent() - 6; | |
305 } | |
306 | |
307 if (v->getViewManager() && v->getViewManager()->getOverlayMode() != | |
308 ViewManager::NoOverlays) { | |
309 | |
310 if (v->getLayer(0) == this) { | |
311 // backmost layer, don't worry about outlining the text | |
312 paint.drawText(x+2 - tw/2, y, text); | |
313 } else { | |
314 v->drawVisibleText(paint, x+2 - tw/2, y, text, View::OutlinedText); | |
315 } | |
316 } | |
317 } | |
248 | 318 |
249 paint.setPen(greyColour); | 319 paint.setPen(greyColour); |
250 paint.drawLine(x, 0, x, v->height()); | |
251 | |
252 paint.setPen(getBaseQColor()); | |
253 paint.drawLine(x, 0, x, 5); | |
254 paint.drawLine(x, v->height() - 6, x, v->height() - 1); | |
255 | |
256 QString text(QString::fromStdString(rt.toText())); | |
257 | |
258 int y; | |
259 QFontMetrics metrics = paint.fontMetrics(); | |
260 switch (m_labelHeight) { | |
261 default: | |
262 case LabelTop: | |
263 y = 6 + metrics.ascent(); | |
264 break; | |
265 case LabelMiddle: | |
266 y = v->height() / 2 - metrics.height() / 2 + metrics.ascent(); | |
267 break; | |
268 case LabelBottom: | |
269 y = v->height() - metrics.height() + metrics.ascent() - 6; | |
270 } | |
271 | |
272 int tw = metrics.width(text); | |
273 | |
274 if (v->getViewManager() && v->getViewManager()->getOverlayMode() != | |
275 ViewManager::NoOverlays) { | |
276 | |
277 if (v->getLayer(0) == this) { | |
278 // backmost layer, don't worry about outlining the text | |
279 paint.drawText(x+2 - tw/2, y, text); | |
280 } else { | |
281 v->drawVisibleText(paint, x+2 - tw/2, y, text, View::OutlinedText); | |
282 } | |
283 } | |
284 | |
285 paint.setPen(greyColour); | |
286 | 320 |
287 for (int i = 1; i < ticks; ++i) { | 321 for (int i = 1; i < ticks; ++i) { |
288 rt = rt + (incRt / ticks); | 322 |
289 frame = RealTime::realTime2Frame(rt, sampleRate); | 323 dms = ms - incms + (i * double(incms)) / ticks; |
290 x = (frame - startFrame) / zoomLevel; | 324 frame = lrint((dms * sampleRate) / 1000.0); |
325 frame /= v->getZoomLevel(); | |
326 frame *= v->getZoomLevel(); // exact pixel as above | |
327 | |
328 x = v->getXForFrame(frame); | |
329 | |
330 if (x < rect.x() || x >= rect.x() + rect.width()) { | |
331 #ifdef DEBUG_TIME_RULER_LAYER | |
332 // std::cerr << "tick " << i << ": X out of range, going on to next tick" << std::endl; | |
333 #endif | |
334 continue; | |
335 } | |
336 | |
337 #ifdef DEBUG_TIME_RULER_LAYER | |
338 std::cerr << "tick " << i << " in range, drawing at " << x << std::endl; | |
339 #endif | |
340 | |
291 int sz = 5; | 341 int sz = 5; |
292 if (ticks == 10) { | 342 if (ticks == 10) { |
293 if ((i % 2) == 1) { | 343 if ((i % 2) == 1) { |
294 if (i == 5) { | 344 if (i == 5) { |
295 paint.drawLine(x, 0, x, v->height()); | 345 paint.drawLine(x, 0, x, v->height()); |
312 impose = true; | 362 impose = true; |
313 return ColourDatabase::getInstance()->getColourIndex | 363 return ColourDatabase::getInstance()->getColourIndex |
314 (QString(darkbg ? "White" : "Black")); | 364 (QString(darkbg ? "White" : "Black")); |
315 } | 365 } |
316 | 366 |
367 QString TimeRulerLayer::getLayerPresentationName() const | |
368 { | |
369 LayerFactory *factory = LayerFactory::getInstance(); | |
370 QString layerName = factory->getLayerPresentationName | |
371 (factory->getLayerType(this)); | |
372 return layerName; | |
373 } | |
374 | |
317 void | 375 void |
318 TimeRulerLayer::toXml(QTextStream &stream, | 376 TimeRulerLayer::toXml(QTextStream &stream, |
319 QString indent, QString extraAttributes) const | 377 QString indent, QString extraAttributes) const |
320 { | 378 { |
321 SingleColourLayer::toXml(stream, indent, extraAttributes); | 379 SingleColourLayer::toXml(stream, indent, extraAttributes); |