comparison layer/TimeValueLayer.cpp @ 1486:ac0a8addabcf

Merge from branch by-id
author Chris Cannam
date Wed, 17 Jul 2019 14:25:16 +0100
parents e540aa5d89cd
children a2fbcfeb2572
comparison
equal deleted inserted replaced
1468:de41a11cabc2 1486:ac0a8addabcf
52 52
53 //#define DEBUG_TIME_VALUE_LAYER 1 53 //#define DEBUG_TIME_VALUE_LAYER 1
54 54
55 TimeValueLayer::TimeValueLayer() : 55 TimeValueLayer::TimeValueLayer() :
56 SingleColourLayer(), 56 SingleColourLayer(),
57 m_model(nullptr),
58 m_editing(false), 57 m_editing(false),
59 m_originalPoint(0, 0.0, tr("New Point")), 58 m_originalPoint(0, 0.0, tr("New Point")),
60 m_editingPoint(0, 0.0, tr("New Point")), 59 m_editingPoint(0, 0.0, tr("New Point")),
61 m_editingCommand(nullptr), 60 m_editingCommand(nullptr),
62 m_colourMap(0), 61 m_colourMap(0),
69 m_scaleMaximum(0) 68 m_scaleMaximum(0)
70 { 69 {
71 70
72 } 71 }
73 72
74 void 73 int
75 TimeValueLayer::setModel(SparseTimeValueModel *model) 74 TimeValueLayer::getCompletion(LayerGeometryProvider *) const
76 { 75 {
77 if (m_model == model) return; 76 auto model = ModelById::get(m_model);
78 m_model = model; 77 if (model) return model->getCompletion();
79 78 else return 0;
80 connectSignals(m_model); 79 }
81 80
82 m_scaleMinimum = 0; 81 void
83 m_scaleMaximum = 0; 82 TimeValueLayer::setModel(ModelId modelId)
84 83 {
85 if (m_model && m_model->getRDFTypeURI().endsWith("Segment")) { 84 auto newModel = ModelById::getAs<SparseTimeValueModel>(modelId);
86 setPlotStyle(PlotSegmentation); 85
87 } 86 if (!modelId.isNone() && !newModel) {
88 if (m_model && m_model->getRDFTypeURI().endsWith("Change")) { 87 throw std::logic_error("Not a SparseTimeValueModel");
89 setPlotStyle(PlotSegmentation); 88 }
90 } 89
91 90 if (m_model == modelId) return;
92 #ifdef DEBUG_TIME_VALUE_LAYER 91 m_model = modelId;
93 cerr << "TimeValueLayer::setModel(" << model << ")" << endl; 92
94 #endif 93 if (newModel) {
95 94
95 connectSignals(m_model);
96
97 m_scaleMinimum = 0;
98 m_scaleMaximum = 0;
99
100 if (newModel->getRDFTypeURI().endsWith("Segment")) {
101 setPlotStyle(PlotSegmentation);
102 }
103 if (newModel->getRDFTypeURI().endsWith("Change")) {
104 setPlotStyle(PlotSegmentation);
105 }
106 }
107
96 emit modelReplaced(); 108 emit modelReplaced();
97 } 109 }
98 110
99 Layer::PropertyList 111 Layer::PropertyList
100 TimeValueLayer::getProperties() const 112 TimeValueLayer::getProperties() const
150 return tr("Plot Type"); 162 return tr("Plot Type");
151 } 163 }
152 return SingleColourLayer::getPropertyGroupName(name); 164 return SingleColourLayer::getPropertyGroupName(name);
153 } 165 }
154 166
167 bool
168 TimeValueLayer::needsTextLabelHeight() const
169 {
170 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
171 if (!model) return false;
172 return m_plotStyle == PlotSegmentation && model->hasTextLabels();
173 }
174
155 QString 175 QString
156 TimeValueLayer::getScaleUnits() const 176 TimeValueLayer::getScaleUnits() const
157 { 177 {
158 if (m_model) return m_model->getScaleUnits(); 178 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
179 if (model) return model->getScaleUnits();
159 else return ""; 180 else return "";
160 } 181 }
161 182
162 int 183 int
163 TimeValueLayer::getPropertyRangeAndValue(const PropertyName &name, 184 TimeValueLayer::getPropertyRangeAndValue(const PropertyName &name,
190 val = int(m_verticalScale); 211 val = int(m_verticalScale);
191 212
192 } else if (name == "Scale Units") { 213 } else if (name == "Scale Units") {
193 214
194 if (deflt) *deflt = 0; 215 if (deflt) *deflt = 0;
195 if (m_model) { 216 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
217 if (model) {
196 val = UnitDatabase::getInstance()->getUnitId 218 val = UnitDatabase::getInstance()->getUnitId
197 (getScaleUnits()); 219 (getScaleUnits());
198 } 220 }
199 221
200 } else if (name == "Draw Segment Division Lines") { 222 } else if (name == "Draw Segment Division Lines") {
256 } else if (name == "Plot Type") { 278 } else if (name == "Plot Type") {
257 setPlotStyle(PlotStyle(value)); 279 setPlotStyle(PlotStyle(value));
258 } else if (name == "Vertical Scale") { 280 } else if (name == "Vertical Scale") {
259 setVerticalScale(VerticalScale(value)); 281 setVerticalScale(VerticalScale(value));
260 } else if (name == "Scale Units") { 282 } else if (name == "Scale Units") {
261 if (m_model) { 283 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
262 m_model->setScaleUnits 284 if (model) {
285 model->setScaleUnits
263 (UnitDatabase::getInstance()->getUnitById(value)); 286 (UnitDatabase::getInstance()->getUnitById(value));
264 emit modelChanged(); 287 emit modelChanged(m_model);
265 } 288 }
266 } else if (name == "Draw Segment Division Lines") { 289 } else if (name == "Draw Segment Division Lines") {
267 setDrawSegmentDivisions(value > 0.5); 290 setDrawSegmentDivisions(value > 0.5);
268 } else if (name == "Show Derivative") { 291 } else if (name == "Show Derivative") {
269 setShowDerivative(value > 0.5); 292 setShowDerivative(value > 0.5);
333 356
334 bool 357 bool
335 TimeValueLayer::getValueExtents(double &min, double &max, 358 TimeValueLayer::getValueExtents(double &min, double &max,
336 bool &logarithmic, QString &unit) const 359 bool &logarithmic, QString &unit) const
337 { 360 {
338 if (!m_model) return false; 361 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
339 362 if (!model) return false;
340 min = m_model->getValueMinimum(); 363
341 max = m_model->getValueMaximum(); 364 min = model->getValueMinimum();
365 max = model->getValueMaximum();
342 366
343 logarithmic = (m_verticalScale == LogScale); 367 logarithmic = (m_verticalScale == LogScale);
344 368
345 unit = getScaleUnits(); 369 unit = getScaleUnits();
346 370
373 } 397 }
374 398
375 bool 399 bool
376 TimeValueLayer::getDisplayExtents(double &min, double &max) const 400 TimeValueLayer::getDisplayExtents(double &min, double &max) const
377 { 401 {
378 if (!m_model || shouldAutoAlign()) return false; 402 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
403 if (!model || shouldAutoAlign()) return false;
379 404
380 if (m_scaleMinimum == m_scaleMaximum) { 405 if (m_scaleMinimum == m_scaleMaximum) {
381 bool log; 406 bool log;
382 QString unit; 407 QString unit;
383 getValueExtents(min, max, log, unit); 408 getValueExtents(min, max, log, unit);
399 } 424 }
400 425
401 bool 426 bool
402 TimeValueLayer::setDisplayExtents(double min, double max) 427 TimeValueLayer::setDisplayExtents(double min, double max)
403 { 428 {
404 if (!m_model) return false; 429 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
430 if (!model) return false;
405 431
406 if (min == max) { 432 if (min == max) {
407 if (min == 0.f) { 433 if (min == 0.f) {
408 max = 1.f; 434 max = 1.f;
409 } else { 435 } else {
424 450
425 int 451 int
426 TimeValueLayer::getVerticalZoomSteps(int &defaultStep) const 452 TimeValueLayer::getVerticalZoomSteps(int &defaultStep) const
427 { 453 {
428 if (shouldAutoAlign()) return 0; 454 if (shouldAutoAlign()) return 0;
429 if (!m_model) return 0; 455 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
456 if (!model) return 0;
430 457
431 defaultStep = 0; 458 defaultStep = 0;
432 return 100; 459 return 100;
433 } 460 }
434 461
435 int 462 int
436 TimeValueLayer::getCurrentVerticalZoomStep() const 463 TimeValueLayer::getCurrentVerticalZoomStep() const
437 { 464 {
438 if (shouldAutoAlign()) return 0; 465 if (shouldAutoAlign()) return 0;
439 if (!m_model) return 0; 466 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
467 if (!model) return 0;
440 468
441 RangeMapper *mapper = getNewVerticalZoomRangeMapper(); 469 RangeMapper *mapper = getNewVerticalZoomRangeMapper();
442 if (!mapper) return 0; 470 if (!mapper) return 0;
443 471
444 double dmin, dmax; 472 double dmin, dmax;
457 485
458 void 486 void
459 TimeValueLayer::setVerticalZoomStep(int step) 487 TimeValueLayer::setVerticalZoomStep(int step)
460 { 488 {
461 if (shouldAutoAlign()) return; 489 if (shouldAutoAlign()) return;
462 if (!m_model) return; 490 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
491 if (!model) return;
463 492
464 RangeMapper *mapper = getNewVerticalZoomRangeMapper(); 493 RangeMapper *mapper = getNewVerticalZoomRangeMapper();
465 if (!mapper) return; 494 if (!mapper) return;
466 495
467 double min, max; 496 double min, max;
509 } 538 }
510 539
511 RangeMapper * 540 RangeMapper *
512 TimeValueLayer::getNewVerticalZoomRangeMapper() const 541 TimeValueLayer::getNewVerticalZoomRangeMapper() const
513 { 542 {
514 if (!m_model) return nullptr; 543 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
544 if (!model) return nullptr;
515 545
516 RangeMapper *mapper; 546 RangeMapper *mapper;
517 547
518 double min, max; 548 double min, max;
519 bool logarithmic; 549 bool logarithmic;
532 } 562 }
533 563
534 EventVector 564 EventVector
535 TimeValueLayer::getLocalPoints(LayerGeometryProvider *v, int x) const 565 TimeValueLayer::getLocalPoints(LayerGeometryProvider *v, int x) const
536 { 566 {
537 if (!m_model) return {}; 567 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
568 if (!model) return {};
538 569
539 // Return all points at a frame f, where f is the closest frame to 570 // Return all points at a frame f, where f is the closest frame to
540 // pixel coordinate x whose pixel coordinate is both within a 571 // pixel coordinate x whose pixel coordinate is both within a
541 // small (but somewhat arbitrary) fuzz distance from x and within 572 // small (but somewhat arbitrary) fuzz distance from x and within
542 // the current view. If there is no such frame, return an empty 573 // the current view. If there is no such frame, return an empty
543 // vector. 574 // vector.
544 575
545 sv_frame_t frame = v->getFrameForX(x); 576 sv_frame_t frame = v->getFrameForX(x);
546 577
547 EventVector exact = m_model->getEventsStartingAt(frame); 578 EventVector exact = model->getEventsStartingAt(frame);
548 if (!exact.empty()) return exact; 579 if (!exact.empty()) return exact;
549 580
550 // overspill == 1, so one event either side of the given span 581 // overspill == 1, so one event either side of the given span
551 EventVector neighbouring = m_model->getEventsWithin 582 EventVector neighbouring = model->getEventsWithin
552 (frame, m_model->getResolution(), 1); 583 (frame, model->getResolution(), 1);
553 584
554 double fuzz = v->scaleSize(2); 585 double fuzz = v->scaleSize(2);
555 sv_frame_t suitable = 0; 586 sv_frame_t suitable = 0;
556 bool have = false; 587 bool have = false;
557 588
571 suitable = f; 602 suitable = f;
572 } 603 }
573 } 604 }
574 605
575 if (have) { 606 if (have) {
576 return m_model->getEventsStartingAt(suitable); 607 return model->getEventsStartingAt(suitable);
577 } else { 608 } else {
578 return {}; 609 return {};
579 } 610 }
580 } 611 }
581 612
582 QString 613 QString
583 TimeValueLayer::getLabelPreceding(sv_frame_t frame) const 614 TimeValueLayer::getLabelPreceding(sv_frame_t frame) const
584 { 615 {
585 if (!m_model || !m_model->hasTextLabels()) return ""; 616 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
617 if (!model || !model->hasTextLabels()) return "";
586 618
587 Event e; 619 Event e;
588 if (m_model->getNearestEventMatching 620 if (model->getNearestEventMatching
589 (frame, 621 (frame,
590 [](Event e) { return e.hasLabel() && e.getLabel() != ""; }, 622 [](Event e) { return e.hasLabel() && e.getLabel() != ""; },
591 EventSeries::Backward, 623 EventSeries::Backward,
592 e)) { 624 e)) {
593 return e.getLabel(); 625 return e.getLabel();
599 QString 631 QString
600 TimeValueLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const 632 TimeValueLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
601 { 633 {
602 int x = pos.x(); 634 int x = pos.x();
603 635
604 if (!m_model || !m_model->getSampleRate()) return ""; 636 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
637 if (!model || !model->getSampleRate()) return "";
605 638
606 EventVector points = getLocalPoints(v, x); 639 EventVector points = getLocalPoints(v, x);
607 640
608 if (points.empty()) { 641 if (points.empty()) {
609 if (!m_model->isReady()) { 642 if (!model->isReady()) {
610 return tr("In progress"); 643 return tr("In progress");
611 } else { 644 } else {
612 return tr("No local points"); 645 return tr("No local points");
613 } 646 }
614 } 647 }
615 648
616 sv_frame_t useFrame = points.begin()->getFrame(); 649 sv_frame_t useFrame = points.begin()->getFrame();
617 650
618 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); 651 RealTime rt = RealTime::frame2RealTime(useFrame, model->getSampleRate());
619 652
620 QString valueText; 653 QString valueText;
621 float value = points.begin()->getValue(); 654 float value = points.begin()->getValue();
622 QString unit = getScaleUnits(); 655 QString unit = getScaleUnits();
623 656
654 TimeValueLayer::snapToFeatureFrame(LayerGeometryProvider *v, 687 TimeValueLayer::snapToFeatureFrame(LayerGeometryProvider *v,
655 sv_frame_t &frame, 688 sv_frame_t &frame,
656 int &resolution, 689 int &resolution,
657 SnapType snap) const 690 SnapType snap) const
658 { 691 {
659 if (!m_model) { 692 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
693 if (!model) {
660 return Layer::snapToFeatureFrame(v, frame, resolution, snap); 694 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
661 } 695 }
662 696
663 // SnapLeft / SnapRight: return frame of nearest feature in that 697 // SnapLeft / SnapRight: return frame of nearest feature in that
664 // direction no matter how far away 698 // direction no matter how far away
665 // 699 //
666 // SnapNeighbouring: return frame of feature that would be used in 700 // SnapNeighbouring: return frame of feature that would be used in
667 // an editing operation, i.e. closest feature in either direction 701 // an editing operation, i.e. closest feature in either direction
668 // but only if it is "close enough" 702 // but only if it is "close enough"
669 703
670 resolution = m_model->getResolution(); 704 resolution = model->getResolution();
671 705
672 if (snap == SnapNeighbouring) { 706 if (snap == SnapNeighbouring) {
673 EventVector points = getLocalPoints(v, v->getXForFrame(frame)); 707 EventVector points = getLocalPoints(v, v->getXForFrame(frame));
674 if (points.empty()) return false; 708 if (points.empty()) return false;
675 frame = points.begin()->getFrame(); 709 frame = points.begin()->getFrame();
676 return true; 710 return true;
677 } 711 }
678 712
679 Event e; 713 Event e;
680 if (m_model->getNearestEventMatching 714 if (model->getNearestEventMatching
681 (frame, 715 (frame,
682 [](Event) { return true; }, 716 [](Event) { return true; },
683 snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward, 717 snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward,
684 e)) { 718 e)) {
685 frame = e.getFrame(); 719 frame = e.getFrame();
693 TimeValueLayer::snapToSimilarFeature(LayerGeometryProvider *v, 727 TimeValueLayer::snapToSimilarFeature(LayerGeometryProvider *v,
694 sv_frame_t &frame, 728 sv_frame_t &frame,
695 int &resolution, 729 int &resolution,
696 SnapType snap) const 730 SnapType snap) const
697 { 731 {
698 if (!m_model) { 732 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
733 if (!model) {
699 return Layer::snapToSimilarFeature(v, frame, resolution, snap); 734 return Layer::snapToSimilarFeature(v, frame, resolution, snap);
700 } 735 }
701 736
702 // snap is only permitted to be SnapLeft or SnapRight here. 737 // snap is only permitted to be SnapLeft or SnapRight here.
703 738
704 resolution = m_model->getResolution(); 739 resolution = model->getResolution();
705 740
706 Event ref; 741 Event ref;
707 Event e; 742 Event e;
708 float matchvalue; 743 float matchvalue;
709 bool found; 744 bool found;
710 745
711 found = m_model->getNearestEventMatching 746 found = model->getNearestEventMatching
712 (frame, [](Event) { return true; }, EventSeries::Backward, ref); 747 (frame, [](Event) { return true; }, EventSeries::Backward, ref);
713 748
714 if (!found) { 749 if (!found) {
715 return false; 750 return false;
716 } 751 }
717 752
718 matchvalue = ref.getValue(); 753 matchvalue = ref.getValue();
719 754
720 found = m_model->getNearestEventMatching 755 found = model->getNearestEventMatching
721 (frame, 756 (frame,
722 [matchvalue](Event e) { 757 [matchvalue](Event e) {
723 double epsilon = 0.0001; 758 double epsilon = 0.0001;
724 return fabs(e.getValue() - matchvalue) < epsilon; 759 return fabs(e.getValue() - matchvalue) < epsilon;
725 }, 760 },
739 { 774 {
740 min = 0.0; 775 min = 0.0;
741 max = 0.0; 776 max = 0.0;
742 log = false; 777 log = false;
743 778
779 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
780 if (!model) return;
781
744 if (shouldAutoAlign()) { 782 if (shouldAutoAlign()) {
745 783
746 if (!v->getValueExtents(getScaleUnits(), min, max, log)) { 784 if (!v->getValueExtents(getScaleUnits(), min, max, log)) {
747 min = m_model->getValueMinimum(); 785 min = model->getValueMinimum();
748 max = m_model->getValueMaximum(); 786 max = model->getValueMaximum();
749 } else if (log) { 787 } else if (log) {
750 LogRange::mapRange(min, max); 788 LogRange::mapRange(min, max);
751 } 789 }
752 790
753 } else if (m_verticalScale == PlusMinusOneScale) { 791 } else if (m_verticalScale == PlusMinusOneScale) {
810 } 848 }
811 849
812 bool 850 bool
813 TimeValueLayer::shouldAutoAlign() const 851 TimeValueLayer::shouldAutoAlign() const
814 { 852 {
815 if (!m_model) return false;
816 QString unit = getScaleUnits(); 853 QString unit = getScaleUnits();
817 return (m_verticalScale == AutoAlignScale && unit != ""); 854 return (m_verticalScale == AutoAlignScale && unit != "");
818 } 855 }
819 856
820 QColor 857 QColor
849 } 886 }
850 887
851 void 888 void
852 TimeValueLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const 889 TimeValueLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
853 { 890 {
854 if (!m_model || !m_model->isOK()) return; 891 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
855 892 if (!model || !model->isOK()) return;
856 sv_samplerate_t sampleRate = m_model->getSampleRate(); 893
894 sv_samplerate_t sampleRate = model->getSampleRate();
857 if (!sampleRate) return; 895 if (!sampleRate) return;
858 896
859 paint.setRenderHint(QPainter::Antialiasing, false); 897 paint.setRenderHint(QPainter::Antialiasing, false);
860 898
861 // Profiler profiler("TimeValueLayer::paint", true); 899 // Profiler profiler("TimeValueLayer::paint", true);
863 int x0 = rect.left(), x1 = rect.right(); 901 int x0 = rect.left(), x1 = rect.right();
864 sv_frame_t frame0 = v->getFrameForX(x0); 902 sv_frame_t frame0 = v->getFrameForX(x0);
865 sv_frame_t frame1 = v->getFrameForX(x1); 903 sv_frame_t frame1 = v->getFrameForX(x1);
866 if (m_derivative) --frame0; 904 if (m_derivative) --frame0;
867 905
868 EventVector points(m_model->getEventsWithin(frame0, frame1 - frame0, 1)); 906 EventVector points(model->getEventsWithin(frame0, frame1 - frame0, 1));
869 if (points.empty()) return; 907 if (points.empty()) return;
870 908
871 paint.setPen(getBaseQColor()); 909 paint.setPen(getBaseQColor());
872 910
873 QColor brushColour(getBaseQColor()); 911 QColor brushColour(getBaseQColor());
874 brushColour.setAlpha(80); 912 brushColour.setAlpha(80);
875 paint.setBrush(brushColour); 913 paint.setBrush(brushColour);
876 914
877 #ifdef DEBUG_TIME_VALUE_LAYER 915 #ifdef DEBUG_TIME_VALUE_LAYER
878 cerr << "TimeValueLayer::paint: resolution is " 916 cerr << "TimeValueLayer::paint: resolution is "
879 << m_model->getResolution() << " frames" << endl; 917 << model->getResolution() << " frames" << endl;
880 #endif 918 #endif
881 919
882 double min = m_model->getValueMinimum(); 920 double min = model->getValueMinimum();
883 double max = m_model->getValueMaximum(); 921 double max = model->getValueMaximum();
884 if (max == min) max = min + 1.0; 922 if (max == min) max = min + 1.0;
885 923
886 int origin = int(nearbyint(v->getPaintHeight() - 924 int origin = int(nearbyint(v->getPaintHeight() -
887 (-min * v->getPaintHeight()) / (max - min))); 925 (-min * v->getPaintHeight()) / (max - min)));
888 926
898 illuminateFrame = localPoints.begin()->getFrame(); 936 illuminateFrame = localPoints.begin()->getFrame();
899 } 937 }
900 } 938 }
901 939
902 int w = 940 int w =
903 v->getXForFrame(frame0 + m_model->getResolution()) - 941 v->getXForFrame(frame0 + model->getResolution()) -
904 v->getXForFrame(frame0); 942 v->getXForFrame(frame0);
905 943
906 if (m_plotStyle == PlotStems) { 944 if (m_plotStyle == PlotStems) {
907 if (w < 2) w = 2; 945 if (w < 2) w = 2;
908 } else { 946 } else {
951 if (value == 0.0) { 989 if (value == 0.0) {
952 // Treat zeros as gaps 990 // Treat zeros as gaps
953 continue; 991 continue;
954 } 992 }
955 gap = (p.getFrame() > prevFrame && 993 gap = (p.getFrame() > prevFrame &&
956 (p.getFrame() - prevFrame >= m_model->getResolution() * 2)); 994 (p.getFrame() - prevFrame >= model->getResolution() * 2));
957 } 995 }
958 996
959 if (m_plotStyle != PlotSegmentation) { 997 if (m_plotStyle != PlotSegmentation) {
960 textY = y - paint.fontMetrics().height() 998 textY = y - paint.fontMetrics().height()
961 + paint.fontMetrics().ascent() - 1; 999 + paint.fontMetrics().ascent() - 1;
1075 double y1 = ny; 1113 double y1 = ny;
1076 1114
1077 if (m_plotStyle == PlotDiscreteCurves) { 1115 if (m_plotStyle == PlotDiscreteCurves) {
1078 bool nextGap = 1116 bool nextGap =
1079 (nvalue == 0.0) || 1117 (nvalue == 0.0) ||
1080 (nf - p.getFrame() >= m_model->getResolution() * 2); 1118 (nf - p.getFrame() >= model->getResolution() * 2);
1081 if (nextGap) { 1119 if (nextGap) {
1082 x1 = x0; 1120 x1 = x0;
1083 y1 = y0; 1121 y1 = y0;
1084 } 1122 }
1085 } 1123 }
1137 char lc[20]; 1175 char lc[20];
1138 snprintf(lc, 20, "%.3g", p.getValue()); 1176 snprintf(lc, 20, "%.3g", p.getValue());
1139 label = lc; 1177 label = lc;
1140 italic = true; 1178 italic = true;
1141 } 1179 }
1180
1181 // Qt 5.13 deprecates QFontMetrics::width(), but its suggested
1182 // replacement (horizontalAdvance) was only added in Qt 5.11
1183 // which is too new for us
1184 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1142 1185
1143 if (label != "") { 1186 if (label != "") {
1144 // Quick test for 20px before we do the slower test using metrics 1187 // Quick test for 20px before we do the slower test using metrics
1145 bool haveRoom = (nx > x + 20); 1188 bool haveRoom = (nx > x + 20);
1146 haveRoom = (haveRoom && 1189 haveRoom = (haveRoom &&
1177 } 1220 }
1178 1221
1179 int 1222 int
1180 TimeValueLayer::getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &paint) const 1223 TimeValueLayer::getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &paint) const
1181 { 1224 {
1182 if (!m_model) { 1225 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1226 if (!model) {
1183 return 0; 1227 return 0;
1184 } else if (shouldAutoAlign() && !valueExtentsMatchMine(v)) { 1228 } else if (shouldAutoAlign() && !valueExtentsMatchMine(v)) {
1185 return 0; 1229 return 0;
1186 } else if (m_plotStyle == PlotSegmentation) { 1230 } else if (m_plotStyle == PlotSegmentation) {
1187 if (m_verticalScale == LogScale) { 1231 if (m_verticalScale == LogScale) {
1199 } 1243 }
1200 1244
1201 void 1245 void
1202 TimeValueLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const 1246 TimeValueLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const
1203 { 1247 {
1204 if (!m_model || m_model->isEmpty()) return; 1248 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1249 if (!model || model->isEmpty()) return;
1205 1250
1206 QString unit; 1251 QString unit;
1207 double min, max; 1252 double min, max;
1208 bool logarithmic; 1253 bool logarithmic;
1209 1254
1255 { 1300 {
1256 #ifdef DEBUG_TIME_VALUE_LAYER 1301 #ifdef DEBUG_TIME_VALUE_LAYER
1257 cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl; 1302 cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl;
1258 #endif 1303 #endif
1259 1304
1260 if (!m_model) return; 1305 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1306 if (!model) return;
1261 1307
1262 sv_frame_t frame = v->getFrameForX(e->x()); 1308 sv_frame_t frame = v->getFrameForX(e->x());
1263 int resolution = m_model->getResolution(); 1309 int resolution = model->getResolution();
1264 if (frame < 0) frame = 0; 1310 if (frame < 0) frame = 0;
1265 frame = (frame / resolution) * resolution; 1311 frame = (frame / resolution) * resolution;
1266 1312
1267 double value = getValueForY(v, e->y()); 1313 double value = getValueForY(v, e->y());
1268 1314
1288 } 1334 }
1289 1335
1290 m_originalPoint = m_editingPoint; 1336 m_originalPoint = m_editingPoint;
1291 1337
1292 if (m_editingCommand) finish(m_editingCommand); 1338 if (m_editingCommand) finish(m_editingCommand);
1293 m_editingCommand = new ChangeEventsCommand(m_model, tr("Draw Point")); 1339 m_editingCommand = new ChangeEventsCommand(m_model.untyped, tr("Draw Point"));
1294 if (!havePoint) { 1340 if (!havePoint) {
1295 m_editingCommand->add(m_editingPoint); 1341 m_editingCommand->add(m_editingPoint);
1296 } 1342 }
1297 1343
1298 m_editing = true; 1344 m_editing = true;
1303 { 1349 {
1304 #ifdef DEBUG_TIME_VALUE_LAYER 1350 #ifdef DEBUG_TIME_VALUE_LAYER
1305 cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl; 1351 cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl;
1306 #endif 1352 #endif
1307 1353
1308 if (!m_model || !m_editing) return; 1354 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1355 if (!model || !m_editing) return;
1309 1356
1310 sv_frame_t frame = v->getFrameForX(e->x()); 1357 sv_frame_t frame = v->getFrameForX(e->x());
1311 int resolution = m_model->getResolution(); 1358 int resolution = model->getResolution();
1312 if (frame < 0) frame = 0; 1359 if (frame < 0) frame = 0;
1313 frame = (frame / resolution) * resolution; 1360 frame = (frame / resolution) * resolution;
1314 1361
1315 double value = getValueForY(v, e->y()); 1362 double value = getValueForY(v, e->y());
1316 1363
1364 TimeValueLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) 1411 TimeValueLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *)
1365 { 1412 {
1366 #ifdef DEBUG_TIME_VALUE_LAYER 1413 #ifdef DEBUG_TIME_VALUE_LAYER
1367 cerr << "TimeValueLayer::drawEnd" << endl; 1414 cerr << "TimeValueLayer::drawEnd" << endl;
1368 #endif 1415 #endif
1369 if (!m_model || !m_editing) return; 1416 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1417 if (!model || !m_editing) return;
1370 finish(m_editingCommand); 1418 finish(m_editingCommand);
1371 m_editingCommand = nullptr; 1419 m_editingCommand = nullptr;
1372 m_editing = false; 1420 m_editing = false;
1373 } 1421 }
1374 1422
1375 void 1423 void
1376 TimeValueLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e) 1424 TimeValueLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e)
1377 { 1425 {
1378 if (!m_model) return; 1426 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1427 if (!model) return;
1379 1428
1380 EventVector points = getLocalPoints(v, e->x()); 1429 EventVector points = getLocalPoints(v, e->x());
1381 if (points.empty()) return; 1430 if (points.empty()) return;
1382 1431
1383 m_editingPoint = *points.begin(); 1432 m_editingPoint = *points.begin();
1396 } 1445 }
1397 1446
1398 void 1447 void
1399 TimeValueLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e) 1448 TimeValueLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e)
1400 { 1449 {
1401 if (!m_model || !m_editing) return; 1450 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1451 if (!model || !m_editing) return;
1402 1452
1403 m_editing = false; 1453 m_editing = false;
1404 1454
1405 EventVector points = getLocalPoints(v, e->x()); 1455 EventVector points = getLocalPoints(v, e->x());
1406 if (points.empty()) return; 1456 if (points.empty()) return;
1407 if (points.begin()->getFrame() != m_editingPoint.getFrame() || 1457 if (points.begin()->getFrame() != m_editingPoint.getFrame() ||
1408 points.begin()->getValue() != m_editingPoint.getValue()) return; 1458 points.begin()->getValue() != m_editingPoint.getValue()) return;
1409 1459
1410 m_editingCommand = new ChangeEventsCommand(m_model, tr("Erase Point")); 1460 m_editingCommand = new ChangeEventsCommand(m_model.untyped, tr("Erase Point"));
1411 m_editingCommand->remove(m_editingPoint); 1461 m_editingCommand->remove(m_editingPoint);
1412 finish(m_editingCommand); 1462 finish(m_editingCommand);
1413 m_editingCommand = nullptr; 1463 m_editingCommand = nullptr;
1414 m_editing = false; 1464 m_editing = false;
1415 } 1465 }
1419 { 1469 {
1420 #ifdef DEBUG_TIME_VALUE_LAYER 1470 #ifdef DEBUG_TIME_VALUE_LAYER
1421 cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << endl; 1471 cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << endl;
1422 #endif 1472 #endif
1423 1473
1424 if (!m_model) return; 1474 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1475 if (!model) return;
1425 1476
1426 EventVector points = getLocalPoints(v, e->x()); 1477 EventVector points = getLocalPoints(v, e->x());
1427 if (points.empty()) return; 1478 if (points.empty()) return;
1428 1479
1429 m_editingPoint = *points.begin(); 1480 m_editingPoint = *points.begin();
1442 { 1493 {
1443 #ifdef DEBUG_TIME_VALUE_LAYER 1494 #ifdef DEBUG_TIME_VALUE_LAYER
1444 cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << endl; 1495 cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << endl;
1445 #endif 1496 #endif
1446 1497
1447 if (!m_model || !m_editing) return; 1498 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1499 if (!model || !m_editing) return;
1448 1500
1449 sv_frame_t frame = v->getFrameForX(e->x()); 1501 sv_frame_t frame = v->getFrameForX(e->x());
1450 if (frame < 0) frame = 0; 1502 if (frame < 0) frame = 0;
1451 frame = frame / m_model->getResolution() * m_model->getResolution(); 1503 frame = frame / model->getResolution() * model->getResolution();
1452 1504
1453 double value = getValueForY(v, e->y()); 1505 double value = getValueForY(v, e->y());
1454 1506
1455 if (!m_editingCommand) { 1507 if (!m_editingCommand) {
1456 m_editingCommand = new ChangeEventsCommand(m_model, tr("Drag Point")); 1508 m_editingCommand = new ChangeEventsCommand(m_model.untyped, tr("Drag Point"));
1457 } 1509 }
1458 1510
1459 m_editingCommand->remove(m_editingPoint); 1511 m_editingCommand->remove(m_editingPoint);
1460 m_editingPoint = m_editingPoint 1512 m_editingPoint = m_editingPoint
1461 .withFrame(frame) 1513 .withFrame(frame)
1467 TimeValueLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) 1519 TimeValueLayer::editEnd(LayerGeometryProvider *, QMouseEvent *)
1468 { 1520 {
1469 #ifdef DEBUG_TIME_VALUE_LAYER 1521 #ifdef DEBUG_TIME_VALUE_LAYER
1470 cerr << "TimeValueLayer::editEnd" << endl; 1522 cerr << "TimeValueLayer::editEnd" << endl;
1471 #endif 1523 #endif
1472 if (!m_model || !m_editing) return; 1524 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1525 if (!model || !m_editing) return;
1473 1526
1474 if (m_editingCommand) { 1527 if (m_editingCommand) {
1475 1528
1476 QString newName = m_editingCommand->getName(); 1529 QString newName = m_editingCommand->getName();
1477 1530
1494 } 1547 }
1495 1548
1496 bool 1549 bool
1497 TimeValueLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) 1550 TimeValueLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e)
1498 { 1551 {
1499 if (!m_model) return false; 1552 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1553 if (!model) return false;
1500 1554
1501 EventVector points = getLocalPoints(v, e->x()); 1555 EventVector points = getLocalPoints(v, e->x());
1502 if (points.empty()) return false; 1556 if (points.empty()) return false;
1503 1557
1504 Event point = *points.begin(); 1558 Event point = *points.begin();
1505 1559
1506 ItemEditDialog *dialog = new ItemEditDialog 1560 ItemEditDialog *dialog = new ItemEditDialog
1507 (m_model->getSampleRate(), 1561 (model->getSampleRate(),
1508 ItemEditDialog::ShowTime | 1562 ItemEditDialog::ShowTime |
1509 ItemEditDialog::ShowValue | 1563 ItemEditDialog::ShowValue |
1510 ItemEditDialog::ShowText, 1564 ItemEditDialog::ShowText,
1511 getScaleUnits()); 1565 getScaleUnits());
1512 1566
1520 .withFrame(dialog->getFrameTime()) 1574 .withFrame(dialog->getFrameTime())
1521 .withValue(dialog->getValue()) 1575 .withValue(dialog->getValue())
1522 .withLabel(dialog->getText()); 1576 .withLabel(dialog->getText());
1523 1577
1524 ChangeEventsCommand *command = 1578 ChangeEventsCommand *command =
1525 new ChangeEventsCommand(m_model, tr("Edit Point")); 1579 new ChangeEventsCommand(m_model.untyped, tr("Edit Point"));
1526 command->remove(point); 1580 command->remove(point);
1527 command->add(newPoint); 1581 command->add(newPoint);
1528 finish(command); 1582 finish(command);
1529 } 1583 }
1530 1584
1533 } 1587 }
1534 1588
1535 void 1589 void
1536 TimeValueLayer::moveSelection(Selection s, sv_frame_t newStartFrame) 1590 TimeValueLayer::moveSelection(Selection s, sv_frame_t newStartFrame)
1537 { 1591 {
1538 if (!m_model) return; 1592 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1593 if (!model) return;
1539 1594
1540 ChangeEventsCommand *command = 1595 ChangeEventsCommand *command =
1541 new ChangeEventsCommand(m_model, tr("Drag Selection")); 1596 new ChangeEventsCommand(m_model.untyped, tr("Drag Selection"));
1542 1597
1543 EventVector points = 1598 EventVector points =
1544 m_model->getEventsWithin(s.getStartFrame(), s.getDuration()); 1599 model->getEventsWithin(s.getStartFrame(), s.getDuration());
1545 1600
1546 for (Event p: points) { 1601 for (Event p: points) {
1547 1602
1548 Event newPoint = p.withFrame 1603 Event newPoint = p.withFrame
1549 (p.getFrame() + newStartFrame - s.getStartFrame()); 1604 (p.getFrame() + newStartFrame - s.getStartFrame());
1555 } 1610 }
1556 1611
1557 void 1612 void
1558 TimeValueLayer::resizeSelection(Selection s, Selection newSize) 1613 TimeValueLayer::resizeSelection(Selection s, Selection newSize)
1559 { 1614 {
1560 if (!m_model || !s.getDuration()) return; 1615 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1616 if (!model || !s.getDuration()) return;
1561 1617
1562 ChangeEventsCommand *command = 1618 ChangeEventsCommand *command =
1563 new ChangeEventsCommand(m_model, tr("Resize Selection")); 1619 new ChangeEventsCommand(m_model.untyped, tr("Resize Selection"));
1564 1620
1565 EventVector points = 1621 EventVector points =
1566 m_model->getEventsWithin(s.getStartFrame(), s.getDuration()); 1622 model->getEventsWithin(s.getStartFrame(), s.getDuration());
1567 1623
1568 double ratio = double(newSize.getDuration()) / double(s.getDuration()); 1624 double ratio = double(newSize.getDuration()) / double(s.getDuration());
1569 double oldStart = double(s.getStartFrame()); 1625 double oldStart = double(s.getStartFrame());
1570 double newStart = double(newSize.getStartFrame()); 1626 double newStart = double(newSize.getStartFrame());
1571 1627
1583 } 1639 }
1584 1640
1585 void 1641 void
1586 TimeValueLayer::deleteSelection(Selection s) 1642 TimeValueLayer::deleteSelection(Selection s)
1587 { 1643 {
1588 if (!m_model) return; 1644 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1645 if (!model) return;
1589 1646
1590 ChangeEventsCommand *command = 1647 ChangeEventsCommand *command =
1591 new ChangeEventsCommand(m_model, tr("Delete Selected Points")); 1648 new ChangeEventsCommand(m_model.untyped, tr("Delete Selected Points"));
1592 1649
1593 EventVector points = 1650 EventVector points =
1594 m_model->getEventsWithin(s.getStartFrame(), s.getDuration()); 1651 model->getEventsWithin(s.getStartFrame(), s.getDuration());
1595 1652
1596 for (Event p: points) { 1653 for (Event p: points) {
1597 command->remove(p); 1654 command->remove(p);
1598 } 1655 }
1599 1656
1601 } 1658 }
1602 1659
1603 void 1660 void
1604 TimeValueLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) 1661 TimeValueLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to)
1605 { 1662 {
1606 if (!m_model) return; 1663 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1664 if (!model) return;
1607 1665
1608 EventVector points = 1666 EventVector points =
1609 m_model->getEventsWithin(s.getStartFrame(), s.getDuration()); 1667 model->getEventsWithin(s.getStartFrame(), s.getDuration());
1610 1668
1611 for (Event p: points) { 1669 for (Event p: points) {
1612 to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame()))); 1670 to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame())));
1613 } 1671 }
1614 } 1672 }
1615 1673
1616 bool 1674 bool
1617 TimeValueLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, 1675 TimeValueLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */,
1618 bool interactive) 1676 bool interactive)
1619 { 1677 {
1620 if (!m_model) return false; 1678 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1679 if (!model) return false;
1621 1680
1622 EventVector points = from.getPoints(); 1681 EventVector points = from.getPoints();
1623 1682
1624 bool realign = false; 1683 bool realign = false;
1625 1684
1639 realign = true; 1698 realign = true;
1640 } 1699 }
1641 } 1700 }
1642 1701
1643 ChangeEventsCommand *command = 1702 ChangeEventsCommand *command =
1644 new ChangeEventsCommand(m_model, tr("Paste")); 1703 new ChangeEventsCommand(m_model.untyped, tr("Paste"));
1645 1704
1646 enum ValueAvailability { 1705 enum ValueAvailability {
1647 UnknownAvailability, 1706 UnknownAvailability,
1648 NoValues, 1707 NoValues,
1649 SomeValues, 1708 SomeValues,
1652 1711
1653 Labeller::ValueType generation = Labeller::ValueNone; 1712 Labeller::ValueType generation = Labeller::ValueNone;
1654 1713
1655 bool haveUsableLabels = false; 1714 bool haveUsableLabels = false;
1656 Labeller labeller; 1715 Labeller labeller;
1657 labeller.setSampleRate(m_model->getSampleRate()); 1716 labeller.setSampleRate(model->getSampleRate());
1658 1717
1659 if (interactive) { 1718 if (interactive) {
1660 1719
1661 ValueAvailability availability = UnknownAvailability; 1720 ValueAvailability availability = UnknownAvailability;
1662 1721