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);