Mercurial > hg > svgui
comparison layer/TimeRulerLayer.cpp @ 1341:ab2cafd3a7cb zoom
Fixes for TimeRuler spacing and for the boundaries of the WaveformLayer paint area
author | Chris Cannam |
---|---|
date | Thu, 27 Sep 2018 15:20:25 +0100 |
parents | 97c68bffbda6 |
children | ed6400d5b571 |
comparison
equal
deleted
inserted
replaced
1340:fc3c9971a43a | 1341:ab2cafd3a7cb |
---|---|
57 resolution = 1; | 57 resolution = 1; |
58 return false; | 58 return false; |
59 } | 59 } |
60 | 60 |
61 bool q; | 61 bool q; |
62 int tick = getMajorTickSpacing(v, q); | 62 int tickUSec = getMajorTickUSec(v, q); |
63 RealTime rtick = RealTime::fromMilliseconds(tick); | 63 RealTime rtick = RealTime(0, tickUSec * 1000); |
64 sv_samplerate_t rate = m_model->getSampleRate(); | 64 sv_samplerate_t rate = m_model->getSampleRate(); |
65 | 65 |
66 RealTime rt = RealTime::frame2RealTime(frame, rate); | 66 RealTime rt = RealTime::frame2RealTime(frame, rate); |
67 double ratio = rt / rtick; | 67 double ratio = rt / rtick; |
68 | 68 |
140 | 140 |
141 return true; | 141 return true; |
142 } | 142 } |
143 | 143 |
144 int | 144 int |
145 TimeRulerLayer::getMajorTickSpacing(LayerGeometryProvider *v, bool &quarterTicks) const | 145 TimeRulerLayer::getMajorTickUSec(LayerGeometryProvider *v, |
146 { | 146 bool &quarterTicks) const |
147 // return value is in milliseconds | 147 { |
148 | 148 // return value is in microseconds |
149 if (!m_model || !v) return 1000; | 149 if (!m_model || !v) return 1000 * 1000; |
150 | 150 |
151 sv_samplerate_t sampleRate = m_model->getSampleRate(); | 151 sv_samplerate_t sampleRate = m_model->getSampleRate(); |
152 if (!sampleRate) return 1000; | 152 if (!sampleRate) return 1000 * 1000; |
153 | 153 |
154 sv_frame_t startFrame = v->getStartFrame(); | 154 sv_frame_t startFrame = v->getStartFrame(); |
155 sv_frame_t endFrame = v->getEndFrame(); | 155 sv_frame_t endFrame = v->getEndFrame(); |
156 | 156 |
157 int minPixelSpacing = 50; | 157 int minPixelSpacing = ViewManager::scalePixelSize(50); |
158 | 158 |
159 RealTime rtStart = RealTime::frame2RealTime(startFrame, sampleRate); | 159 RealTime rtStart = RealTime::frame2RealTime(startFrame, sampleRate); |
160 RealTime rtEnd = RealTime::frame2RealTime(endFrame, sampleRate); | 160 RealTime rtEnd = RealTime::frame2RealTime(endFrame, sampleRate); |
161 | 161 |
162 int count = v->getPaintWidth() / minPixelSpacing; | 162 int count = v->getPaintWidth() / minPixelSpacing; |
163 if (count < 1) count = 1; | 163 if (count < 1) count = 1; |
164 RealTime rtGap = (rtEnd - rtStart) / count; | 164 RealTime rtGap = (rtEnd - rtStart) / count; |
165 | 165 |
166 int incms; | 166 int incus; |
167 quarterTicks = false; | 167 quarterTicks = false; |
168 | 168 |
169 if (rtGap.sec > 0) { | 169 if (rtGap.sec > 0) { |
170 incms = 1000; | 170 incus = 1000 * 1000; |
171 int s = rtGap.sec; | 171 int s = rtGap.sec; |
172 if (s > 0) { incms *= 5; s /= 5; } | 172 if (s > 0) { incus *= 5; s /= 5; } |
173 if (s > 0) { incms *= 2; s /= 2; } | 173 if (s > 0) { incus *= 2; s /= 2; } |
174 if (s > 0) { incms *= 6; s /= 6; quarterTicks = true; } | 174 if (s > 0) { incus *= 6; s /= 6; quarterTicks = true; } |
175 if (s > 0) { incms *= 5; s /= 5; quarterTicks = false; } | 175 if (s > 0) { incus *= 5; s /= 5; quarterTicks = false; } |
176 if (s > 0) { incms *= 2; s /= 2; } | 176 if (s > 0) { incus *= 2; s /= 2; } |
177 if (s > 0) { incms *= 6; s /= 6; quarterTicks = true; } | 177 if (s > 0) { incus *= 6; s /= 6; quarterTicks = true; } |
178 while (s > 0) { | 178 while (s > 0) { |
179 incms *= 10; | 179 incus *= 10; |
180 s /= 10; | 180 s /= 10; |
181 quarterTicks = false; | 181 quarterTicks = false; |
182 } | 182 } |
183 } else if (rtGap.msec() > 0) { | |
184 incus = 1000; | |
185 int ms = rtGap.msec(); | |
186 if (ms > 0) { incus *= 10; ms /= 10; } | |
187 if (ms > 0) { incus *= 10; ms /= 10; } | |
188 if (ms > 0) { incus *= 5; ms /= 5; } | |
189 if (ms > 0) { incus *= 2; ms /= 2; } | |
183 } else { | 190 } else { |
184 incms = 1; | 191 incus = 1; |
185 int ms = rtGap.msec(); | 192 int us = rtGap.usec(); |
186 // cerr << "rtGap.msec = " << ms << ", rtGap = " << rtGap << ", count = " << count << endl; | 193 if (us > 0) { incus *= 10; us /= 10; } |
187 // cerr << "startFrame = " << startFrame << ", endFrame = " << endFrame << " rtStart = " << rtStart << ", rtEnd = " << rtEnd << endl; | 194 if (us > 0) { incus *= 10; us /= 10; } |
188 if (ms > 0) { incms *= 10; ms /= 10; } | 195 if (us > 0) { incus *= 5; us /= 5; } |
189 if (ms > 0) { incms *= 10; ms /= 10; } | 196 if (us > 0) { incus *= 2; us /= 2; } |
190 if (ms > 0) { incms *= 5; ms /= 5; } | 197 } |
191 if (ms > 0) { incms *= 2; ms /= 2; } | 198 |
192 } | 199 return incus; |
193 | 200 } |
194 return incms; | 201 |
202 int | |
203 TimeRulerLayer::getXForUSec(LayerGeometryProvider *v, double us) const | |
204 { | |
205 sv_samplerate_t sampleRate = m_model->getSampleRate(); | |
206 double dframe = (us * sampleRate) / 1000000.0; | |
207 double eps = 1e-7; | |
208 sv_frame_t frame = sv_frame_t(floor(dframe + eps)); | |
209 int x; | |
210 | |
211 ZoomLevel zoom = v->getZoomLevel(); | |
212 | |
213 if (zoom.zone == ZoomLevel::FramesPerPixel) { | |
214 | |
215 frame /= zoom.level; | |
216 frame *= zoom.level; // so frame corresponds to an exact pixel | |
217 | |
218 x = v->getXForFrame(frame); | |
219 | |
220 } else { | |
221 | |
222 double off = dframe - double(frame); | |
223 int x0 = v->getXForFrame(frame); | |
224 int x1 = v->getXForFrame(frame + 1); | |
225 | |
226 x = int(x0 + off * (x1 - x0)); | |
227 } | |
228 | |
229 #ifdef DEBUG_TIME_RULER_LAYER | |
230 cerr << "Considering frame = " << frame << ", x = " << x << endl; | |
231 #endif | |
232 | |
233 return x; | |
195 } | 234 } |
196 | 235 |
197 void | 236 void |
198 TimeRulerLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const | 237 TimeRulerLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const |
199 { | 238 { |
212 #ifdef DEBUG_TIME_RULER_LAYER | 251 #ifdef DEBUG_TIME_RULER_LAYER |
213 cerr << "start frame = " << startFrame << endl; | 252 cerr << "start frame = " << startFrame << endl; |
214 #endif | 253 #endif |
215 | 254 |
216 bool quarter = false; | 255 bool quarter = false; |
217 int incms = getMajorTickSpacing(v, quarter); | 256 int incus = getMajorTickUSec(v, quarter); |
218 | 257 |
219 int ms = int(lrint(1000.0 * (double(startFrame) / double(sampleRate)))); | 258 int us = int(lrint(1000.0 * 1000.0 * (double(startFrame) / |
220 ms = (ms / incms) * incms - incms; | 259 double(sampleRate)))); |
221 | 260 us = (us / incus) * incus - incus; |
222 #ifdef DEBUG_TIME_RULER_LAYER | 261 |
223 cerr << "start ms = " << ms << " at step " << incms << endl; | 262 #ifdef DEBUG_TIME_RULER_LAYER |
263 cerr << "start us = " << us << " at step " << incus << endl; | |
224 #endif | 264 #endif |
225 | 265 |
226 // Calculate the number of ticks per increment -- approximate | 266 // Calculate the number of ticks per increment -- approximate |
227 // values for x and frame counts here will do, no rounding issue. | 267 // values for x and frame counts here will do, no rounding issue. |
228 // We always use the exact incms in our calculations for where to | 268 // We always use the exact incus in our calculations for where to |
229 // draw the actual ticks or lines. | 269 // draw the actual ticks or lines. |
230 | 270 |
231 int minPixelSpacing = 50; | 271 int minPixelSpacing = 50; |
232 sv_frame_t incFrame = lrint((incms * sampleRate) / 1000); | 272 sv_frame_t incFrame = lrint((incus * sampleRate) / 1000000); |
233 int incX = int(round(v->getZoomLevel().framesToPixels(double(incFrame)))); | 273 int incX = int(round(v->getZoomLevel().framesToPixels(double(incFrame)))); |
234 int ticks = 10; | 274 int ticks = 10; |
235 if (incX < minPixelSpacing * 2) { | 275 if (incX < minPixelSpacing * 2) { |
236 ticks = quarter ? 4 : 5; | 276 ticks = quarter ? 4 : 5; |
237 } | 277 } |
240 | 280 |
241 paint.save(); | 281 paint.save(); |
242 | 282 |
243 // Do not label time zero - we now overlay an opaque area over | 283 // Do not label time zero - we now overlay an opaque area over |
244 // time < 0 which would cut it in half | 284 // time < 0 which would cut it in half |
245 int minlabel = 1; // ms | 285 int minlabel = 1; // us |
246 | |
247 // used for a sanity check | |
248 sv_frame_t prevframe = 0; | |
249 | 286 |
250 while (1) { | 287 while (1) { |
251 | 288 |
252 // frame is used to determine where to draw the lines, so it | 289 // frame is used to determine where to draw the lines, so it |
253 // needs to correspond to an exact pixel (so that we don't get | 290 // needs to correspond to an exact pixel (so that we don't get |
254 // a different pixel when scrolling a small amount and | 291 // a different pixel when scrolling a small amount and |
255 // re-drawing with a different start frame). | 292 // re-drawing with a different start frame). |
256 | 293 |
257 double dms = ms; | 294 double dus = us; |
258 sv_frame_t frame = lrint((dms * sampleRate) / 1000.0); | 295 |
259 ZoomLevel zoom = v->getZoomLevel(); | 296 int x = getXForUSec(v, dus); |
260 if (zoom.zone == ZoomLevel::FramesPerPixel) { | |
261 frame /= zoom.level; | |
262 frame *= zoom.level; // so frame corresponds to an exact pixel | |
263 } | |
264 | |
265 if (frame == prevframe && prevframe != 0) { | |
266 cerr << "ERROR: frame == prevframe (== " << frame | |
267 << ") in TimeRulerLayer::paint" << endl; | |
268 throw std::logic_error("frame == prevframe in TimeRulerLayer::paint"); | |
269 } | |
270 prevframe = frame; | |
271 | |
272 int x = v->getXForFrame(frame); | |
273 | |
274 #ifdef DEBUG_TIME_RULER_LAYER | |
275 cerr << "Considering frame = " << frame << ", x = " << x << endl; | |
276 #endif | |
277 | 297 |
278 if (x >= rect.x() + rect.width() + 50) { | 298 if (x >= rect.x() + rect.width() + 50) { |
279 #ifdef DEBUG_TIME_RULER_LAYER | 299 #ifdef DEBUG_TIME_RULER_LAYER |
280 cerr << "X well out of range, ending here" << endl; | 300 cerr << "X well out of range, ending here" << endl; |
281 #endif | 301 #endif |
282 break; | 302 break; |
283 } | 303 } |
284 | 304 |
285 if (x >= rect.x() - 50 && ms >= minlabel) { | 305 if (x >= rect.x() - 50 && us >= minlabel) { |
286 | 306 |
287 RealTime rt = RealTime::fromMilliseconds(ms); | 307 RealTime rt = RealTime(0, us * 1000); |
288 | 308 |
289 #ifdef DEBUG_TIME_RULER_LAYER | 309 #ifdef DEBUG_TIME_RULER_LAYER |
290 cerr << "X in range, drawing line here for time " << rt.toText() << endl; | 310 cerr << "X in range, drawing line here for time " << rt.toText() << endl; |
291 #endif | 311 #endif |
292 | 312 |
336 | 356 |
337 paint.setPen(greyColour); | 357 paint.setPen(greyColour); |
338 | 358 |
339 for (int i = 1; i < ticks; ++i) { | 359 for (int i = 1; i < ticks; ++i) { |
340 | 360 |
341 dms = ms + (i * double(incms)) / ticks; | 361 dus = us + (i * double(incus)) / ticks; |
342 frame = lrint((dms * sampleRate) / 1000.0); | 362 |
343 if (zoom.zone == ZoomLevel::FramesPerPixel) { | 363 x = getXForUSec(v, dus); |
344 frame /= zoom.level; | |
345 frame *= zoom.level; // exact pixel as above | |
346 } | |
347 | |
348 x = v->getXForFrame(frame); | |
349 | 364 |
350 if (x < rect.x() || x >= rect.x() + rect.width()) { | 365 if (x < rect.x() || x >= rect.x() + rect.width()) { |
351 #ifdef DEBUG_TIME_RULER_LAYER | 366 #ifdef DEBUG_TIME_RULER_LAYER |
352 // cerr << "tick " << i << ": X out of range, going on to next tick" << endl; | 367 // cerr << "tick " << i << ": X out of range, going on to next tick" << endl; |
353 #endif | 368 #endif |
370 } | 385 } |
371 paint.drawLine(x, 0, x, sz); | 386 paint.drawLine(x, 0, x, sz); |
372 paint.drawLine(x, v->getPaintHeight() - sz - 1, x, v->getPaintHeight() - 1); | 387 paint.drawLine(x, v->getPaintHeight() - sz - 1, x, v->getPaintHeight() - 1); |
373 } | 388 } |
374 | 389 |
375 ms += incms; | 390 us += incus; |
376 } | 391 } |
377 | 392 |
378 paint.restore(); | 393 paint.restore(); |
379 } | 394 } |
380 | 395 |