comparison layer/TimeRulerLayer.cpp @ 370:8ebc2ce2a210 sv1-v1.2pre5

* Fix drawing of time ruler during scrolling (bits were being missed)
author Chris Cannam
date Wed, 13 Feb 2008 13:49:33 +0000
parents 2f83b6e3b8ca
children daaf1c435d98
comparison
equal deleted inserted replaced
369:63971199663a 370:8ebc2ce2a210
24 24
25 #include <QPainter> 25 #include <QPainter>
26 26
27 #include <iostream> 27 #include <iostream>
28 #include <cmath> 28 #include <cmath>
29
30 //#define DEBUG_TIME_RULER_LAYER 1
29 31
30 using std::cerr; 32 using std::cerr;
31 using std::endl; 33 using std::endl;
32 34
33 TimeRulerLayer::TimeRulerLayer() : 35 TimeRulerLayer::TimeRulerLayer() :
190 } 192 }
191 193
192 void 194 void
193 TimeRulerLayer::paint(View *v, QPainter &paint, QRect rect) const 195 TimeRulerLayer::paint(View *v, QPainter &paint, QRect rect) const
194 { 196 {
195 // std::cerr << "TimeRulerLayer::paint (" << rect.x() << "," << rect.y() 197 #ifdef DEBUG_TIME_RULER_LAYER
196 // << ") [" << 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
197 201
198 if (!m_model || !m_model->isOK()) return; 202 if (!m_model || !m_model->isOK()) return;
199 203
200 int sampleRate = m_model->getSampleRate(); 204 int sampleRate = m_model->getSampleRate();
201 if (!sampleRate) return; 205 if (!sampleRate) return;
202 206
203 long startFrame = v->getStartFrame(); 207 long startFrame = v->getFrameForX(rect.x() - 50);
204 long endFrame = v->getEndFrame(); 208
205 209 #ifdef DEBUG_TIME_RULER_LAYER
206 int zoomLevel = v->getZoomLevel(); 210 std::cerr << "start frame = " << startFrame << std::endl;
207 211 #endif
208 long rectStart = startFrame + (rect.x() - 100) * zoomLevel;
209 long rectEnd = startFrame + (rect.x() + rect.width() + 100) * zoomLevel;
210
211 // std::cerr << "TimeRulerLayer::paint: calling paint.save()" << std::endl;
212 paint.save();
213 //!!! paint.setClipRect(v->rect());
214
215 int minPixelSpacing = 50;
216 212
217 bool quarter = false; 213 bool quarter = false;
218 int incms = getMajorTickSpacing(v, quarter); 214 int incms = getMajorTickSpacing(v, quarter);
219 215
220 RealTime rt = RealTime::frame2RealTime(rectStart, sampleRate); 216 int ms = lrint(1000.0 * (double(startFrame) / double(sampleRate)));
221 long ms = rt.sec * 1000 + rt.msec();
222 ms = (ms / incms) * incms - incms; 217 ms = (ms / incms) * incms - incms;
223 218
224 RealTime incRt = RealTime::fromMilliseconds(incms); 219 #ifdef DEBUG_TIME_RULER_LAYER
225 long incFrame = RealTime::realTime2Frame(incRt, sampleRate); 220 std::cerr << "start ms = " << ms << " at step " << incms << std::endl;
226 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();
227 int ticks = 10; 231 int ticks = 10;
228 if (incX < minPixelSpacing * 2) { 232 if (incX < minPixelSpacing * 2) {
229 ticks = quarter ? 4 : 5; 233 ticks = quarter ? 4 : 5;
230 } 234 }
231 235
232 QRect oldClipRect = rect;
233 QRect newClipRect(oldClipRect.x() - 25, oldClipRect.y(),
234 oldClipRect.width() + 50, oldClipRect.height());
235 paint.setClipRect(newClipRect);
236 paint.setClipRect(rect);
237
238 QColor greyColour = getPartialShades(v)[1]; 236 QColor greyColour = getPartialShades(v)[1];
239 237
238 paint.save();
239
240 while (1) { 240 while (1) {
241 241
242 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
243 ms += incms; 252 ms += incms;
244 253
245 long frame = RealTime::realTime2Frame(rt, sampleRate); 254 int x = v->getXForFrame(frame);
246 if (frame >= rectEnd) break; 255
247 256 #ifdef DEBUG_TIME_RULER_LAYER
248 int x = (frame - startFrame) / zoomLevel; 257 std::cerr << "Considering frame = " << frame << ", x = " << x << std::endl;
249 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 }
250 318
251 paint.setPen(greyColour); 319 paint.setPen(greyColour);
252 paint.drawLine(x, 0, x, v->height());
253
254 paint.setPen(getBaseQColor());
255 paint.drawLine(x, 0, x, 5);
256 paint.drawLine(x, v->height() - 6, x, v->height() - 1);
257
258 QString text(QString::fromStdString(rt.toText()));
259
260 int y;
261 QFontMetrics metrics = paint.fontMetrics();
262 switch (m_labelHeight) {
263 default:
264 case LabelTop:
265 y = 6 + metrics.ascent();
266 break;
267 case LabelMiddle:
268 y = v->height() / 2 - metrics.height() / 2 + metrics.ascent();
269 break;
270 case LabelBottom:
271 y = v->height() - metrics.height() + metrics.ascent() - 6;
272 }
273
274 int tw = metrics.width(text);
275
276 if (v->getViewManager() && v->getViewManager()->getOverlayMode() !=
277 ViewManager::NoOverlays) {
278
279 if (v->getLayer(0) == this) {
280 // backmost layer, don't worry about outlining the text
281 paint.drawText(x+2 - tw/2, y, text);
282 } else {
283 v->drawVisibleText(paint, x+2 - tw/2, y, text, View::OutlinedText);
284 }
285 }
286
287 paint.setPen(greyColour);
288 320
289 for (int i = 1; i < ticks; ++i) { 321 for (int i = 1; i < ticks; ++i) {
290 rt = rt + (incRt / ticks); 322
291 frame = RealTime::realTime2Frame(rt, sampleRate); 323 dms = ms - incms + (i * double(incms)) / ticks;
292 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
293 int sz = 5; 341 int sz = 5;
294 if (ticks == 10) { 342 if (ticks == 10) {
295 if ((i % 2) == 1) { 343 if ((i % 2) == 1) {
296 if (i == 5) { 344 if (i == 5) {
297 paint.drawLine(x, 0, x, v->height()); 345 paint.drawLine(x, 0, x, v->height());