comparison layer/TimeValueLayer.cpp @ 44:ad214997dddb

* Refactor Layer classes so as no longer to store a single View pointer; instead they need to be able to draw themselves on any View on demand. Layers with caches (e.g. spectrogram) will need to be further refactored so as to maintain a per-View cache * Begin refactoring MainWindow by pulling out the document stuff (set of layers, models etc) into a Document class. Not yet in use. This revision is fairly unstable.
author Chris Cannam
date Thu, 02 Mar 2006 16:58:49 +0000
parents 78515b1e29eb
children 128ebfeeebee
comparison
equal deleted inserted replaced
43:78515b1e29eb 44:ad214997dddb
21 #include <QMouseEvent> 21 #include <QMouseEvent>
22 22
23 #include <iostream> 23 #include <iostream>
24 #include <cmath> 24 #include <cmath>
25 25
26 TimeValueLayer::TimeValueLayer(View *w) : 26 TimeValueLayer::TimeValueLayer() :
27 Layer(w), 27 Layer(),
28 m_model(0), 28 m_model(0),
29 m_editing(false), 29 m_editing(false),
30 m_originalPoint(0, 0.0, tr("New Point")), 30 m_originalPoint(0, 0.0, tr("New Point")),
31 m_editingPoint(0, 0.0, tr("New Point")), 31 m_editingPoint(0, 0.0, tr("New Point")),
32 m_editingCommand(0), 32 m_editingCommand(0),
33 m_colour(Qt::black), 33 m_colour(Qt::black),
34 m_plotStyle(PlotConnectedPoints) 34 m_plotStyle(PlotConnectedPoints)
35 { 35 {
36 m_view->addLayer(this); 36
37 } 37 }
38 38
39 void 39 void
40 TimeValueLayer::setModel(SparseTimeValueModel *model) 40 TimeValueLayer::setModel(SparseTimeValueModel *model)
41 { 41 {
165 m_plotStyle = style; 165 m_plotStyle = style;
166 emit layerParametersChanged(); 166 emit layerParametersChanged();
167 } 167 }
168 168
169 bool 169 bool
170 TimeValueLayer::isLayerScrollable() const 170 TimeValueLayer::isLayerScrollable(const View *v) const
171 { 171 {
172 // We don't illuminate sections in the line or curve modes, so 172 // We don't illuminate sections in the line or curve modes, so
173 // they're always scrollable 173 // they're always scrollable
174 174
175 if (m_plotStyle == PlotLines || 175 if (m_plotStyle == PlotLines ||
176 m_plotStyle == PlotCurve) return true; 176 m_plotStyle == PlotCurve) return true;
177 177
178 QPoint discard; 178 QPoint discard;
179 return !m_view->shouldIlluminateLocalFeatures(this, discard); 179 return !v->shouldIlluminateLocalFeatures(this, discard);
180 } 180 }
181 181
182 SparseTimeValueModel::PointList 182 SparseTimeValueModel::PointList
183 TimeValueLayer::getLocalPoints(int x) const 183 TimeValueLayer::getLocalPoints(View *v, int x) const
184 { 184 {
185 if (!m_model) return SparseTimeValueModel::PointList(); 185 if (!m_model) return SparseTimeValueModel::PointList();
186 186
187 long frame = getFrameForX(x); 187 long frame = v->getFrameForX(x);
188 188
189 SparseTimeValueModel::PointList onPoints = 189 SparseTimeValueModel::PointList onPoints =
190 m_model->getPoints(frame); 190 m_model->getPoints(frame);
191 191
192 if (!onPoints.empty()) { 192 if (!onPoints.empty()) {
200 200
201 SparseTimeValueModel::PointList usePoints = prevPoints; 201 SparseTimeValueModel::PointList usePoints = prevPoints;
202 202
203 if (prevPoints.empty()) { 203 if (prevPoints.empty()) {
204 usePoints = nextPoints; 204 usePoints = nextPoints;
205 } else if (prevPoints.begin()->frame < m_view->getStartFrame() && 205 } else if (prevPoints.begin()->frame < v->getStartFrame() &&
206 !(nextPoints.begin()->frame > m_view->getEndFrame())) { 206 !(nextPoints.begin()->frame > v->getEndFrame())) {
207 usePoints = nextPoints; 207 usePoints = nextPoints;
208 } else if (nextPoints.begin()->frame - frame < 208 } else if (nextPoints.begin()->frame - frame <
209 frame - prevPoints.begin()->frame) { 209 frame - prevPoints.begin()->frame) {
210 usePoints = nextPoints; 210 usePoints = nextPoints;
211 } 211 }
212 212
213 if (!usePoints.empty()) { 213 if (!usePoints.empty()) {
214 int fuzz = 2; 214 int fuzz = 2;
215 int px = getXForFrame(usePoints.begin()->frame); 215 int px = v->getXForFrame(usePoints.begin()->frame);
216 if ((px > x && px - x > fuzz) || 216 if ((px > x && px - x > fuzz) ||
217 (px < x && x - px > fuzz + 1)) { 217 (px < x && x - px > fuzz + 1)) {
218 usePoints.clear(); 218 usePoints.clear();
219 } 219 }
220 } 220 }
221 221
222 return usePoints; 222 return usePoints;
223 } 223 }
224 224
225 QString 225 QString
226 TimeValueLayer::getFeatureDescription(QPoint &pos) const 226 TimeValueLayer::getFeatureDescription(View *v, QPoint &pos) const
227 { 227 {
228 int x = pos.x(); 228 int x = pos.x();
229 229
230 if (!m_model || !m_model->getSampleRate()) return ""; 230 if (!m_model || !m_model->getSampleRate()) return "";
231 231
232 SparseTimeValueModel::PointList points = getLocalPoints(x); 232 SparseTimeValueModel::PointList points = getLocalPoints(v, x);
233 233
234 if (points.empty()) { 234 if (points.empty()) {
235 if (!m_model->isReady()) { 235 if (!m_model->isReady()) {
236 return tr("In progress"); 236 return tr("In progress");
237 } else { 237 } else {
254 .arg(rt.toText(true).c_str()) 254 .arg(rt.toText(true).c_str())
255 .arg(points.begin()->value) 255 .arg(points.begin()->value)
256 .arg(points.begin()->label); 256 .arg(points.begin()->label);
257 } 257 }
258 258
259 pos = QPoint(getXForFrame(useFrame), getYForValue(points.begin()->value)); 259 pos = QPoint(v->getXForFrame(useFrame),
260 getYForValue(v, points.begin()->value));
260 return text; 261 return text;
261 } 262 }
262 263
263 bool 264 bool
264 TimeValueLayer::snapToFeatureFrame(int &frame, 265 TimeValueLayer::snapToFeatureFrame(View *v, int &frame,
265 size_t &resolution, 266 size_t &resolution,
266 SnapType snap) const 267 SnapType snap) const
267 { 268 {
268 if (!m_model) { 269 if (!m_model) {
269 return Layer::snapToFeatureFrame(frame, resolution, snap); 270 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
270 } 271 }
271 272
272 resolution = m_model->getResolution(); 273 resolution = m_model->getResolution();
273 SparseTimeValueModel::PointList points; 274 SparseTimeValueModel::PointList points;
274 275
275 if (snap == SnapNeighbouring) { 276 if (snap == SnapNeighbouring) {
276 277
277 points = getLocalPoints(getXForFrame(frame)); 278 points = getLocalPoints(v, v->getXForFrame(frame));
278 if (points.empty()) return false; 279 if (points.empty()) return false;
279 frame = points.begin()->frame; 280 frame = points.begin()->frame;
280 return true; 281 return true;
281 } 282 }
282 283
331 frame = snapped; 332 frame = snapped;
332 return found; 333 return found;
333 } 334 }
334 335
335 int 336 int
336 TimeValueLayer::getYForValue(float value) const 337 TimeValueLayer::getYForValue(View *v, float value) const
337 { 338 {
338 float min = m_model->getValueMinimum(); 339 float min = m_model->getValueMinimum();
339 float max = m_model->getValueMaximum(); 340 float max = m_model->getValueMaximum();
340 if (max == min) max = min + 1.0; 341 if (max == min) max = min + 1.0;
341 342
342 int h = m_view->height(); 343 int h = v->height();
343 344
344 return int(h - ((value - min) * h) / (max - min)); 345 return int(h - ((value - min) * h) / (max - min));
345 } 346 }
346 347
347 float 348 float
348 TimeValueLayer::getValueForY(int y) const 349 TimeValueLayer::getValueForY(View *v, int y) const
349 { 350 {
350 float min = m_model->getValueMinimum(); 351 float min = m_model->getValueMinimum();
351 float max = m_model->getValueMaximum(); 352 float max = m_model->getValueMaximum();
352 if (max == min) max = min + 1.0; 353 if (max == min) max = min + 1.0;
353 354
354 int h = m_view->height(); 355 int h = v->height();
355 356
356 return min + (float(h - y) * float(max - min)) / h; 357 return min + (float(h - y) * float(max - min)) / h;
357 } 358 }
358 359
359 void 360 void
360 TimeValueLayer::paint(QPainter &paint, QRect rect) const 361 TimeValueLayer::paint(View *v, QPainter &paint, QRect rect) const
361 { 362 {
362 if (!m_model || !m_model->isOK()) return; 363 if (!m_model || !m_model->isOK()) return;
363 364
364 int sampleRate = m_model->getSampleRate(); 365 int sampleRate = m_model->getSampleRate();
365 if (!sampleRate) return; 366 if (!sampleRate) return;
366 367
367 // Profiler profiler("TimeValueLayer::paint", true); 368 // Profiler profiler("TimeValueLayer::paint", true);
368 369
369 int x0 = rect.left(), x1 = rect.right(); 370 int x0 = rect.left(), x1 = rect.right();
370 long frame0 = getFrameForX(x0); 371 long frame0 = v->getFrameForX(x0);
371 long frame1 = getFrameForX(x1); 372 long frame1 = v->getFrameForX(x1);
372 373
373 SparseTimeValueModel::PointList points(m_model->getPoints 374 SparseTimeValueModel::PointList points(m_model->getPoints
374 (frame0, frame1)); 375 (frame0, frame1));
375 if (points.empty()) return; 376 if (points.empty()) return;
376 377
385 386
386 float min = m_model->getValueMinimum(); 387 float min = m_model->getValueMinimum();
387 float max = m_model->getValueMaximum(); 388 float max = m_model->getValueMaximum();
388 if (max == min) max = min + 1.0; 389 if (max == min) max = min + 1.0;
389 390
390 int origin = int(nearbyint(m_view->height() - 391 int origin = int(nearbyint(v->height() -
391 (-min * m_view->height()) / (max - min))); 392 (-min * v->height()) / (max - min)));
392 393
393 QPoint localPos; 394 QPoint localPos;
394 long illuminateFrame = -1; 395 long illuminateFrame = -1;
395 396
396 if (m_view->shouldIlluminateLocalFeatures(this, localPos)) { 397 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
397 SparseTimeValueModel::PointList localPoints = 398 SparseTimeValueModel::PointList localPoints =
398 getLocalPoints(localPos.x()); 399 getLocalPoints(v, localPos.x());
399 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame; 400 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
400 } 401 }
401 402
402 int w = 403 int w =
403 getXForFrame(frame0 + m_model->getResolution()) - 404 v->getXForFrame(frame0 + m_model->getResolution()) -
404 getXForFrame(frame0); 405 v->getXForFrame(frame0);
405 406
406 paint.save(); 407 paint.save();
407 408
408 if (w > 1 && 409 if (w > 1 &&
409 (m_plotStyle == PlotLines || 410 (m_plotStyle == PlotLines ||
415 for (SparseTimeValueModel::PointList::const_iterator i = points.begin(); 416 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
416 i != points.end(); ++i) { 417 i != points.end(); ++i) {
417 418
418 const SparseTimeValueModel::Point &p(*i); 419 const SparseTimeValueModel::Point &p(*i);
419 420
420 int x = getXForFrame(p.frame); 421 int x = v->getXForFrame(p.frame);
421 int y = getYForValue(p.value); 422 int y = getYForValue(v, p.value);
422 423
423 bool haveNext = false; 424 bool haveNext = false;
424 int nx = getXForFrame(m_model->getEndFrame()); 425 int nx = v->getXForFrame(m_model->getEndFrame());
425 int ny = y; 426 int ny = y;
426 427
427 SparseTimeValueModel::PointList::const_iterator j = i; 428 SparseTimeValueModel::PointList::const_iterator j = i;
428 ++j; 429 ++j;
429 430
430 if (j != points.end()) { 431 if (j != points.end()) {
431 const SparseTimeValueModel::Point &q(*j); 432 const SparseTimeValueModel::Point &q(*j);
432 nx = getXForFrame(q.frame); 433 nx = v->getXForFrame(q.frame);
433 ny = getYForValue(q.value); 434 ny = getYForValue(v, q.value);
434 haveNext = true; 435 haveNext = true;
435 } 436 }
436 437
437 int labelY = y; 438 int labelY = y;
438 439
442 if (m_plotStyle == PlotSegmentation) { 443 if (m_plotStyle == PlotSegmentation) {
443 int value = ((p.value - min) / (max - min)) * 255.999; 444 int value = ((p.value - min) / (max - min)) * 255.999;
444 QColor colour = QColor::fromHsv(256 - value, value / 2 + 128, value); 445 QColor colour = QColor::fromHsv(256 - value, value / 2 + 128, value);
445 paint.setBrush(QColor(colour.red(), colour.green(), colour.blue(), 446 paint.setBrush(QColor(colour.red(), colour.green(), colour.blue(),
446 120)); 447 120));
447 labelY = m_view->height(); 448 labelY = v->height();
448 } else if (m_plotStyle == PlotLines || 449 } else if (m_plotStyle == PlotLines ||
449 m_plotStyle == PlotCurve) { 450 m_plotStyle == PlotCurve) {
450 paint.setBrush(Qt::NoBrush); 451 paint.setBrush(Qt::NoBrush);
451 } else { 452 } else {
452 paint.setBrush(brushColour); 453 paint.setBrush(brushColour);
519 if (m_plotStyle == PlotSegmentation) { 520 if (m_plotStyle == PlotSegmentation) {
520 521
521 if (nx <= x) continue; 522 if (nx <= x) continue;
522 523
523 if (illuminateFrame != p.frame && 524 if (illuminateFrame != p.frame &&
524 (nx < x + 5 || x >= m_view->width() - 1)) { 525 (nx < x + 5 || x >= v->width() - 1)) {
525 paint.setPen(Qt::NoPen); 526 paint.setPen(Qt::NoPen);
526 } 527 }
527 528
528 paint.drawRect(x, -1, nx - x, m_view->height() + 1); 529 paint.drawRect(x, -1, nx - x, v->height() + 1);
529 } 530 }
530 531
531 /// if (p.label != "") { 532 /// if (p.label != "") {
532 /// paint.drawText(x + 5, y - paint.fontMetrics().height() + paint.fontMetrics().ascent(), p.label); 533 /// paint.drawText(x + 5, y - paint.fontMetrics().height() + paint.fontMetrics().ascent(), p.label);
533 /// } 534 /// }
542 // looks like save/restore doesn't deal with this: 543 // looks like save/restore doesn't deal with this:
543 paint.setRenderHint(QPainter::Antialiasing, false); 544 paint.setRenderHint(QPainter::Antialiasing, false);
544 } 545 }
545 546
546 int 547 int
547 TimeValueLayer::getVerticalScaleWidth(QPainter &paint) const 548 TimeValueLayer::getVerticalScaleWidth(View *v, QPainter &paint) const
548 { 549 {
549 return 100; //!!! 550 return 100; //!!!
550 } 551 }
551 552
552 void 553 void
553 TimeValueLayer::paintVerticalScale(QPainter &paint, QRect rect) const 554 TimeValueLayer::paintVerticalScale(View *v, QPainter &paint, QRect rect) const
554 { 555 {
555 if (!m_model) return; 556 if (!m_model) return;
556 557
557 float v = m_model->getValueMinimum(); 558 float val = m_model->getValueMinimum();
558 float inc = (m_model->getValueMaximum() - v) / 10; 559 float inc = (m_model->getValueMaximum() - val) / 10;
559 560
560 while (v < m_model->getValueMaximum()) { 561 while (val < m_model->getValueMaximum()) {
561 int y = getYForValue(v); 562 int y = getYForValue(v, val);
562 QString label = QString("%1").arg(v); 563 QString label = QString("%1").arg(val);
563 paint.drawLine(100 - 10, y, 100, y); 564 paint.drawLine(100 - 10, y, 100, y);
564 paint.drawText(100 - 15 - paint.fontMetrics().width(label), 565 paint.drawText(100 - 15 - paint.fontMetrics().width(label),
565 y - paint.fontMetrics().height() /2 + paint.fontMetrics().ascent(), 566 y - paint.fontMetrics().height() /2 + paint.fontMetrics().ascent(),
566 label); 567 label);
567 v += inc; 568 val += inc;
568 } 569 }
569 570
570 } 571 }
571 572
572 void 573 void
573 TimeValueLayer::drawStart(QMouseEvent *e) 574 TimeValueLayer::drawStart(View *v, QMouseEvent *e)
574 { 575 {
575 std::cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl; 576 std::cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl;
576 577
577 if (!m_model) return; 578 if (!m_model) return;
578 579
579 long frame = getFrameForX(e->x()); 580 long frame = v->getFrameForX(e->x());
580 if (frame < 0) frame = 0; 581 if (frame < 0) frame = 0;
581 frame = frame / m_model->getResolution() * m_model->getResolution(); 582 frame = frame / m_model->getResolution() * m_model->getResolution();
582 583
583 float value = getValueForY(e->y()); 584 float value = getValueForY(v, e->y());
584 585
585 m_editingPoint = SparseTimeValueModel::Point(frame, value, tr("New Point")); 586 m_editingPoint = SparseTimeValueModel::Point(frame, value, tr("New Point"));
586 m_originalPoint = m_editingPoint; 587 m_originalPoint = m_editingPoint;
587 588
588 if (m_editingCommand) m_editingCommand->finish(); 589 if (m_editingCommand) m_editingCommand->finish();
592 593
593 m_editing = true; 594 m_editing = true;
594 } 595 }
595 596
596 void 597 void
597 TimeValueLayer::drawDrag(QMouseEvent *e) 598 TimeValueLayer::drawDrag(View *v, QMouseEvent *e)
598 { 599 {
599 std::cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl; 600 std::cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl;
600 601
601 if (!m_model || !m_editing) return; 602 if (!m_model || !m_editing) return;
602 603
603 long frame = getFrameForX(e->x()); 604 long frame = v->getFrameForX(e->x());
604 if (frame < 0) frame = 0; 605 if (frame < 0) frame = 0;
605 frame = frame / m_model->getResolution() * m_model->getResolution(); 606 frame = frame / m_model->getResolution() * m_model->getResolution();
606 607
607 float value = getValueForY(e->y()); 608 float value = getValueForY(v, e->y());
608 609
609 m_editingCommand->deletePoint(m_editingPoint); 610 m_editingCommand->deletePoint(m_editingPoint);
610 m_editingPoint.frame = frame; 611 m_editingPoint.frame = frame;
611 m_editingPoint.value = value; 612 m_editingPoint.value = value;
612 m_editingCommand->addPoint(m_editingPoint); 613 m_editingCommand->addPoint(m_editingPoint);
613 } 614 }
614 615
615 void 616 void
616 TimeValueLayer::drawEnd(QMouseEvent *e) 617 TimeValueLayer::drawEnd(View *v, QMouseEvent *e)
617 { 618 {
618 std::cerr << "TimeValueLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl; 619 std::cerr << "TimeValueLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl;
619 if (!m_model || !m_editing) return; 620 if (!m_model || !m_editing) return;
620 m_editingCommand->finish(); 621 m_editingCommand->finish();
621 m_editingCommand = 0; 622 m_editingCommand = 0;
622 m_editing = false; 623 m_editing = false;
623 } 624 }
624 625
625 void 626 void
626 TimeValueLayer::editStart(QMouseEvent *e) 627 TimeValueLayer::editStart(View *v, QMouseEvent *e)
627 { 628 {
628 std::cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl; 629 std::cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
629 630
630 if (!m_model) return; 631 if (!m_model) return;
631 632
632 SparseTimeValueModel::PointList points = getLocalPoints(e->x()); 633 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
633 if (points.empty()) return; 634 if (points.empty()) return;
634 635
635 m_editingPoint = *points.begin(); 636 m_editingPoint = *points.begin();
636 m_originalPoint = m_editingPoint; 637 m_originalPoint = m_editingPoint;
637 638
642 643
643 m_editing = true; 644 m_editing = true;
644 } 645 }
645 646
646 void 647 void
647 TimeValueLayer::editDrag(QMouseEvent *e) 648 TimeValueLayer::editDrag(View *v, QMouseEvent *e)
648 { 649 {
649 std::cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl; 650 std::cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl;
650 651
651 if (!m_model || !m_editing) return; 652 if (!m_model || !m_editing) return;
652 653
653 long frame = getFrameForX(e->x()); 654 long frame = v->getFrameForX(e->x());
654 if (frame < 0) frame = 0; 655 if (frame < 0) frame = 0;
655 frame = frame / m_model->getResolution() * m_model->getResolution(); 656 frame = frame / m_model->getResolution() * m_model->getResolution();
656 657
657 float value = getValueForY(e->y()); 658 float value = getValueForY(v, e->y());
658 659
659 if (!m_editingCommand) { 660 if (!m_editingCommand) {
660 m_editingCommand = new SparseTimeValueModel::EditCommand(m_model, 661 m_editingCommand = new SparseTimeValueModel::EditCommand(m_model,
661 tr("Drag Point")); 662 tr("Drag Point"));
662 } 663 }
666 m_editingPoint.value = value; 667 m_editingPoint.value = value;
667 m_editingCommand->addPoint(m_editingPoint); 668 m_editingCommand->addPoint(m_editingPoint);
668 } 669 }
669 670
670 void 671 void
671 TimeValueLayer::editEnd(QMouseEvent *e) 672 TimeValueLayer::editEnd(View *v, QMouseEvent *e)
672 { 673 {
673 std::cerr << "TimeValueLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl; 674 std::cerr << "TimeValueLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
674 if (!m_model || !m_editing) return; 675 if (!m_model || !m_editing) return;
675 676
676 if (m_editingCommand) { 677 if (m_editingCommand) {