Mercurial > hg > svgui
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()); |