comparison layer/TimeValueLayer.cpp @ 1474:36ad3cdabf55 by-id

Further layer updates for ModelById
author Chris Cannam
date Tue, 02 Jul 2019 14:08:44 +0100
parents f2525e6cbdf1
children e540aa5d89cd
comparison
equal deleted inserted replaced
1473:886c1cd48f9d 1474:36ad3cdabf55
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),
166 } 165 }
167 166
168 bool 167 bool
169 TimeValueLayer::needsTextLabelHeight() const 168 TimeValueLayer::needsTextLabelHeight() const
170 { 169 {
171 auto model = ModelById::get(m_model); 170 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
172 if (!model) return false; 171 if (!model) return false;
173 return m_plotStyle == PlotSegmentation && model->hasTextLabels(); 172 return m_plotStyle == PlotSegmentation && model->hasTextLabels();
174 } 173 }
175 174
176 QString 175 QString
177 TimeValueLayer::getScaleUnits() const 176 TimeValueLayer::getScaleUnits() const
178 { 177 {
179 if (m_model) return m_model->getScaleUnits(); 178 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
179 if (model) return model->getScaleUnits();
180 else return ""; 180 else return "";
181 } 181 }
182 182
183 int 183 int
184 TimeValueLayer::getPropertyRangeAndValue(const PropertyName &name, 184 TimeValueLayer::getPropertyRangeAndValue(const PropertyName &name,
211 val = int(m_verticalScale); 211 val = int(m_verticalScale);
212 212
213 } else if (name == "Scale Units") { 213 } else if (name == "Scale Units") {
214 214
215 if (deflt) *deflt = 0; 215 if (deflt) *deflt = 0;
216 if (m_model) { 216 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
217 if (model) {
217 val = UnitDatabase::getInstance()->getUnitId 218 val = UnitDatabase::getInstance()->getUnitId
218 (getScaleUnits()); 219 (getScaleUnits());
219 } 220 }
220 221
221 } else if (name == "Draw Segment Division Lines") { 222 } else if (name == "Draw Segment Division Lines") {
277 } else if (name == "Plot Type") { 278 } else if (name == "Plot Type") {
278 setPlotStyle(PlotStyle(value)); 279 setPlotStyle(PlotStyle(value));
279 } else if (name == "Vertical Scale") { 280 } else if (name == "Vertical Scale") {
280 setVerticalScale(VerticalScale(value)); 281 setVerticalScale(VerticalScale(value));
281 } else if (name == "Scale Units") { 282 } else if (name == "Scale Units") {
282 if (m_model) { 283 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
283 m_model->setScaleUnits 284 if (model) {
285 model->setScaleUnits
284 (UnitDatabase::getInstance()->getUnitById(value)); 286 (UnitDatabase::getInstance()->getUnitById(value));
285 emit modelChanged(); 287 emit modelChanged();
286 } 288 }
287 } else if (name == "Draw Segment Division Lines") { 289 } else if (name == "Draw Segment Division Lines") {
288 setDrawSegmentDivisions(value > 0.5); 290 setDrawSegmentDivisions(value > 0.5);
354 356
355 bool 357 bool
356 TimeValueLayer::getValueExtents(double &min, double &max, 358 TimeValueLayer::getValueExtents(double &min, double &max,
357 bool &logarithmic, QString &unit) const 359 bool &logarithmic, QString &unit) const
358 { 360 {
359 if (!m_model) return false; 361 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
360 362 if (!model) return false;
361 min = m_model->getValueMinimum(); 363
362 max = m_model->getValueMaximum(); 364 min = model->getValueMinimum();
365 max = model->getValueMaximum();
363 366
364 logarithmic = (m_verticalScale == LogScale); 367 logarithmic = (m_verticalScale == LogScale);
365 368
366 unit = getScaleUnits(); 369 unit = getScaleUnits();
367 370
394 } 397 }
395 398
396 bool 399 bool
397 TimeValueLayer::getDisplayExtents(double &min, double &max) const 400 TimeValueLayer::getDisplayExtents(double &min, double &max) const
398 { 401 {
399 if (!m_model || shouldAutoAlign()) return false; 402 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
403 if (!model || shouldAutoAlign()) return false;
400 404
401 if (m_scaleMinimum == m_scaleMaximum) { 405 if (m_scaleMinimum == m_scaleMaximum) {
402 bool log; 406 bool log;
403 QString unit; 407 QString unit;
404 getValueExtents(min, max, log, unit); 408 getValueExtents(min, max, log, unit);
420 } 424 }
421 425
422 bool 426 bool
423 TimeValueLayer::setDisplayExtents(double min, double max) 427 TimeValueLayer::setDisplayExtents(double min, double max)
424 { 428 {
425 if (!m_model) return false; 429 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
430 if (!model) return false;
426 431
427 if (min == max) { 432 if (min == max) {
428 if (min == 0.f) { 433 if (min == 0.f) {
429 max = 1.f; 434 max = 1.f;
430 } else { 435 } else {
445 450
446 int 451 int
447 TimeValueLayer::getVerticalZoomSteps(int &defaultStep) const 452 TimeValueLayer::getVerticalZoomSteps(int &defaultStep) const
448 { 453 {
449 if (shouldAutoAlign()) return 0; 454 if (shouldAutoAlign()) return 0;
450 if (!m_model) return 0; 455 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
456 if (!model) return 0;
451 457
452 defaultStep = 0; 458 defaultStep = 0;
453 return 100; 459 return 100;
454 } 460 }
455 461
456 int 462 int
457 TimeValueLayer::getCurrentVerticalZoomStep() const 463 TimeValueLayer::getCurrentVerticalZoomStep() const
458 { 464 {
459 if (shouldAutoAlign()) return 0; 465 if (shouldAutoAlign()) return 0;
460 if (!m_model) return 0; 466 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
467 if (!model) return 0;
461 468
462 RangeMapper *mapper = getNewVerticalZoomRangeMapper(); 469 RangeMapper *mapper = getNewVerticalZoomRangeMapper();
463 if (!mapper) return 0; 470 if (!mapper) return 0;
464 471
465 double dmin, dmax; 472 double dmin, dmax;
478 485
479 void 486 void
480 TimeValueLayer::setVerticalZoomStep(int step) 487 TimeValueLayer::setVerticalZoomStep(int step)
481 { 488 {
482 if (shouldAutoAlign()) return; 489 if (shouldAutoAlign()) return;
483 if (!m_model) return; 490 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
491 if (!model) return;
484 492
485 RangeMapper *mapper = getNewVerticalZoomRangeMapper(); 493 RangeMapper *mapper = getNewVerticalZoomRangeMapper();
486 if (!mapper) return; 494 if (!mapper) return;
487 495
488 double min, max; 496 double min, max;
530 } 538 }
531 539
532 RangeMapper * 540 RangeMapper *
533 TimeValueLayer::getNewVerticalZoomRangeMapper() const 541 TimeValueLayer::getNewVerticalZoomRangeMapper() const
534 { 542 {
535 if (!m_model) return nullptr; 543 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
544 if (!model) return nullptr;
536 545
537 RangeMapper *mapper; 546 RangeMapper *mapper;
538 547
539 double min, max; 548 double min, max;
540 bool logarithmic; 549 bool logarithmic;
553 } 562 }
554 563
555 EventVector 564 EventVector
556 TimeValueLayer::getLocalPoints(LayerGeometryProvider *v, int x) const 565 TimeValueLayer::getLocalPoints(LayerGeometryProvider *v, int x) const
557 { 566 {
558 if (!m_model) return {}; 567 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
568 if (!model) return {};
559 569
560 // 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
561 // pixel coordinate x whose pixel coordinate is both within a 571 // pixel coordinate x whose pixel coordinate is both within a
562 // small (but somewhat arbitrary) fuzz distance from x and within 572 // small (but somewhat arbitrary) fuzz distance from x and within
563 // 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
564 // vector. 574 // vector.
565 575
566 sv_frame_t frame = v->getFrameForX(x); 576 sv_frame_t frame = v->getFrameForX(x);
567 577
568 EventVector exact = m_model->getEventsStartingAt(frame); 578 EventVector exact = model->getEventsStartingAt(frame);
569 if (!exact.empty()) return exact; 579 if (!exact.empty()) return exact;
570 580
571 // overspill == 1, so one event either side of the given span 581 // overspill == 1, so one event either side of the given span
572 EventVector neighbouring = m_model->getEventsWithin 582 EventVector neighbouring = model->getEventsWithin
573 (frame, m_model->getResolution(), 1); 583 (frame, model->getResolution(), 1);
574 584
575 double fuzz = v->scaleSize(2); 585 double fuzz = v->scaleSize(2);
576 sv_frame_t suitable = 0; 586 sv_frame_t suitable = 0;
577 bool have = false; 587 bool have = false;
578 588
592 suitable = f; 602 suitable = f;
593 } 603 }
594 } 604 }
595 605
596 if (have) { 606 if (have) {
597 return m_model->getEventsStartingAt(suitable); 607 return model->getEventsStartingAt(suitable);
598 } else { 608 } else {
599 return {}; 609 return {};
600 } 610 }
601 } 611 }
602 612
603 QString 613 QString
604 TimeValueLayer::getLabelPreceding(sv_frame_t frame) const 614 TimeValueLayer::getLabelPreceding(sv_frame_t frame) const
605 { 615 {
606 if (!m_model || !m_model->hasTextLabels()) return ""; 616 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
617 if (!model || !model->hasTextLabels()) return "";
607 618
608 Event e; 619 Event e;
609 if (m_model->getNearestEventMatching 620 if (model->getNearestEventMatching
610 (frame, 621 (frame,
611 [](Event e) { return e.hasLabel() && e.getLabel() != ""; }, 622 [](Event e) { return e.hasLabel() && e.getLabel() != ""; },
612 EventSeries::Backward, 623 EventSeries::Backward,
613 e)) { 624 e)) {
614 return e.getLabel(); 625 return e.getLabel();
620 QString 631 QString
621 TimeValueLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const 632 TimeValueLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
622 { 633 {
623 int x = pos.x(); 634 int x = pos.x();
624 635
625 if (!m_model || !m_model->getSampleRate()) return ""; 636 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
637 if (!model || !model->getSampleRate()) return "";
626 638
627 EventVector points = getLocalPoints(v, x); 639 EventVector points = getLocalPoints(v, x);
628 640
629 if (points.empty()) { 641 if (points.empty()) {
630 if (!m_model->isReady()) { 642 if (!model->isReady()) {
631 return tr("In progress"); 643 return tr("In progress");
632 } else { 644 } else {
633 return tr("No local points"); 645 return tr("No local points");
634 } 646 }
635 } 647 }
636 648
637 sv_frame_t useFrame = points.begin()->getFrame(); 649 sv_frame_t useFrame = points.begin()->getFrame();
638 650
639 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); 651 RealTime rt = RealTime::frame2RealTime(useFrame, model->getSampleRate());
640 652
641 QString valueText; 653 QString valueText;
642 float value = points.begin()->getValue(); 654 float value = points.begin()->getValue();
643 QString unit = getScaleUnits(); 655 QString unit = getScaleUnits();
644 656
675 TimeValueLayer::snapToFeatureFrame(LayerGeometryProvider *v, 687 TimeValueLayer::snapToFeatureFrame(LayerGeometryProvider *v,
676 sv_frame_t &frame, 688 sv_frame_t &frame,
677 int &resolution, 689 int &resolution,
678 SnapType snap) const 690 SnapType snap) const
679 { 691 {
680 if (!m_model) { 692 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
693 if (!model) {
681 return Layer::snapToFeatureFrame(v, frame, resolution, snap); 694 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
682 } 695 }
683 696
684 // SnapLeft / SnapRight: return frame of nearest feature in that 697 // SnapLeft / SnapRight: return frame of nearest feature in that
685 // direction no matter how far away 698 // direction no matter how far away
686 // 699 //
687 // SnapNeighbouring: return frame of feature that would be used in 700 // SnapNeighbouring: return frame of feature that would be used in
688 // an editing operation, i.e. closest feature in either direction 701 // an editing operation, i.e. closest feature in either direction
689 // but only if it is "close enough" 702 // but only if it is "close enough"
690 703
691 resolution = m_model->getResolution(); 704 resolution = model->getResolution();
692 705
693 if (snap == SnapNeighbouring) { 706 if (snap == SnapNeighbouring) {
694 EventVector points = getLocalPoints(v, v->getXForFrame(frame)); 707 EventVector points = getLocalPoints(v, v->getXForFrame(frame));
695 if (points.empty()) return false; 708 if (points.empty()) return false;
696 frame = points.begin()->getFrame(); 709 frame = points.begin()->getFrame();
697 return true; 710 return true;
698 } 711 }
699 712
700 Event e; 713 Event e;
701 if (m_model->getNearestEventMatching 714 if (model->getNearestEventMatching
702 (frame, 715 (frame,
703 [](Event) { return true; }, 716 [](Event) { return true; },
704 snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward, 717 snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward,
705 e)) { 718 e)) {
706 frame = e.getFrame(); 719 frame = e.getFrame();
714 TimeValueLayer::snapToSimilarFeature(LayerGeometryProvider *v, 727 TimeValueLayer::snapToSimilarFeature(LayerGeometryProvider *v,
715 sv_frame_t &frame, 728 sv_frame_t &frame,
716 int &resolution, 729 int &resolution,
717 SnapType snap) const 730 SnapType snap) const
718 { 731 {
719 if (!m_model) { 732 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
733 if (!model) {
720 return Layer::snapToSimilarFeature(v, frame, resolution, snap); 734 return Layer::snapToSimilarFeature(v, frame, resolution, snap);
721 } 735 }
722 736
723 // snap is only permitted to be SnapLeft or SnapRight here. 737 // snap is only permitted to be SnapLeft or SnapRight here.
724 738
725 resolution = m_model->getResolution(); 739 resolution = model->getResolution();
726 740
727 Event ref; 741 Event ref;
728 Event e; 742 Event e;
729 float matchvalue; 743 float matchvalue;
730 bool found; 744 bool found;
731 745
732 found = m_model->getNearestEventMatching 746 found = model->getNearestEventMatching
733 (frame, [](Event) { return true; }, EventSeries::Backward, ref); 747 (frame, [](Event) { return true; }, EventSeries::Backward, ref);
734 748
735 if (!found) { 749 if (!found) {
736 return false; 750 return false;
737 } 751 }
738 752
739 matchvalue = ref.getValue(); 753 matchvalue = ref.getValue();
740 754
741 found = m_model->getNearestEventMatching 755 found = model->getNearestEventMatching
742 (frame, 756 (frame,
743 [matchvalue](Event e) { 757 [matchvalue](Event e) {
744 double epsilon = 0.0001; 758 double epsilon = 0.0001;
745 return fabs(e.getValue() - matchvalue) < epsilon; 759 return fabs(e.getValue() - matchvalue) < epsilon;
746 }, 760 },
760 { 774 {
761 min = 0.0; 775 min = 0.0;
762 max = 0.0; 776 max = 0.0;
763 log = false; 777 log = false;
764 778
779 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
780 if (!model) return;
781
765 if (shouldAutoAlign()) { 782 if (shouldAutoAlign()) {
766 783
767 if (!v->getValueExtents(getScaleUnits(), min, max, log)) { 784 if (!v->getValueExtents(getScaleUnits(), min, max, log)) {
768 min = m_model->getValueMinimum(); 785 min = model->getValueMinimum();
769 max = m_model->getValueMaximum(); 786 max = model->getValueMaximum();
770 } else if (log) { 787 } else if (log) {
771 LogRange::mapRange(min, max); 788 LogRange::mapRange(min, max);
772 } 789 }
773 790
774 } else if (m_verticalScale == PlusMinusOneScale) { 791 } else if (m_verticalScale == PlusMinusOneScale) {
831 } 848 }
832 849
833 bool 850 bool
834 TimeValueLayer::shouldAutoAlign() const 851 TimeValueLayer::shouldAutoAlign() const
835 { 852 {
836 if (!m_model) return false;
837 QString unit = getScaleUnits(); 853 QString unit = getScaleUnits();
838 return (m_verticalScale == AutoAlignScale && unit != ""); 854 return (m_verticalScale == AutoAlignScale && unit != "");
839 } 855 }
840 856
841 QColor 857 QColor
870 } 886 }
871 887
872 void 888 void
873 TimeValueLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const 889 TimeValueLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
874 { 890 {
875 if (!m_model || !m_model->isOK()) return; 891 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
876 892 if (!model || !model->isOK()) return;
877 sv_samplerate_t sampleRate = m_model->getSampleRate(); 893
894 sv_samplerate_t sampleRate = model->getSampleRate();
878 if (!sampleRate) return; 895 if (!sampleRate) return;
879 896
880 paint.setRenderHint(QPainter::Antialiasing, false); 897 paint.setRenderHint(QPainter::Antialiasing, false);
881 898
882 // Profiler profiler("TimeValueLayer::paint", true); 899 // Profiler profiler("TimeValueLayer::paint", true);
884 int x0 = rect.left(), x1 = rect.right(); 901 int x0 = rect.left(), x1 = rect.right();
885 sv_frame_t frame0 = v->getFrameForX(x0); 902 sv_frame_t frame0 = v->getFrameForX(x0);
886 sv_frame_t frame1 = v->getFrameForX(x1); 903 sv_frame_t frame1 = v->getFrameForX(x1);
887 if (m_derivative) --frame0; 904 if (m_derivative) --frame0;
888 905
889 EventVector points(m_model->getEventsWithin(frame0, frame1 - frame0, 1)); 906 EventVector points(model->getEventsWithin(frame0, frame1 - frame0, 1));
890 if (points.empty()) return; 907 if (points.empty()) return;
891 908
892 paint.setPen(getBaseQColor()); 909 paint.setPen(getBaseQColor());
893 910
894 QColor brushColour(getBaseQColor()); 911 QColor brushColour(getBaseQColor());
895 brushColour.setAlpha(80); 912 brushColour.setAlpha(80);
896 paint.setBrush(brushColour); 913 paint.setBrush(brushColour);
897 914
898 #ifdef DEBUG_TIME_VALUE_LAYER 915 #ifdef DEBUG_TIME_VALUE_LAYER
899 cerr << "TimeValueLayer::paint: resolution is " 916 cerr << "TimeValueLayer::paint: resolution is "
900 << m_model->getResolution() << " frames" << endl; 917 << model->getResolution() << " frames" << endl;
901 #endif 918 #endif
902 919
903 double min = m_model->getValueMinimum(); 920 double min = model->getValueMinimum();
904 double max = m_model->getValueMaximum(); 921 double max = model->getValueMaximum();
905 if (max == min) max = min + 1.0; 922 if (max == min) max = min + 1.0;
906 923
907 int origin = int(nearbyint(v->getPaintHeight() - 924 int origin = int(nearbyint(v->getPaintHeight() -
908 (-min * v->getPaintHeight()) / (max - min))); 925 (-min * v->getPaintHeight()) / (max - min)));
909 926
919 illuminateFrame = localPoints.begin()->getFrame(); 936 illuminateFrame = localPoints.begin()->getFrame();
920 } 937 }
921 } 938 }
922 939
923 int w = 940 int w =
924 v->getXForFrame(frame0 + m_model->getResolution()) - 941 v->getXForFrame(frame0 + model->getResolution()) -
925 v->getXForFrame(frame0); 942 v->getXForFrame(frame0);
926 943
927 if (m_plotStyle == PlotStems) { 944 if (m_plotStyle == PlotStems) {
928 if (w < 2) w = 2; 945 if (w < 2) w = 2;
929 } else { 946 } else {
972 if (value == 0.0) { 989 if (value == 0.0) {
973 // Treat zeros as gaps 990 // Treat zeros as gaps
974 continue; 991 continue;
975 } 992 }
976 gap = (p.getFrame() > prevFrame && 993 gap = (p.getFrame() > prevFrame &&
977 (p.getFrame() - prevFrame >= m_model->getResolution() * 2)); 994 (p.getFrame() - prevFrame >= model->getResolution() * 2));
978 } 995 }
979 996
980 if (m_plotStyle != PlotSegmentation) { 997 if (m_plotStyle != PlotSegmentation) {
981 textY = y - paint.fontMetrics().height() 998 textY = y - paint.fontMetrics().height()
982 + paint.fontMetrics().ascent() - 1; 999 + paint.fontMetrics().ascent() - 1;
1096 double y1 = ny; 1113 double y1 = ny;
1097 1114
1098 if (m_plotStyle == PlotDiscreteCurves) { 1115 if (m_plotStyle == PlotDiscreteCurves) {
1099 bool nextGap = 1116 bool nextGap =
1100 (nvalue == 0.0) || 1117 (nvalue == 0.0) ||
1101 (nf - p.getFrame() >= m_model->getResolution() * 2); 1118 (nf - p.getFrame() >= model->getResolution() * 2);
1102 if (nextGap) { 1119 if (nextGap) {
1103 x1 = x0; 1120 x1 = x0;
1104 y1 = y0; 1121 y1 = y0;
1105 } 1122 }
1106 } 1123 }
1158 char lc[20]; 1175 char lc[20];
1159 snprintf(lc, 20, "%.3g", p.getValue()); 1176 snprintf(lc, 20, "%.3g", p.getValue());
1160 label = lc; 1177 label = lc;
1161 italic = true; 1178 italic = true;
1162 } 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"
1163 1185
1164 if (label != "") { 1186 if (label != "") {
1165 // 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
1166 bool haveRoom = (nx > x + 20); 1188 bool haveRoom = (nx > x + 20);
1167 haveRoom = (haveRoom && 1189 haveRoom = (haveRoom &&
1198 } 1220 }
1199 1221
1200 int 1222 int
1201 TimeValueLayer::getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &paint) const 1223 TimeValueLayer::getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &paint) const
1202 { 1224 {
1203 if (!m_model) { 1225 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1226 if (!model) {
1204 return 0; 1227 return 0;
1205 } else if (shouldAutoAlign() && !valueExtentsMatchMine(v)) { 1228 } else if (shouldAutoAlign() && !valueExtentsMatchMine(v)) {
1206 return 0; 1229 return 0;
1207 } else if (m_plotStyle == PlotSegmentation) { 1230 } else if (m_plotStyle == PlotSegmentation) {
1208 if (m_verticalScale == LogScale) { 1231 if (m_verticalScale == LogScale) {
1220 } 1243 }
1221 1244
1222 void 1245 void
1223 TimeValueLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const 1246 TimeValueLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const
1224 { 1247 {
1225 if (!m_model || m_model->isEmpty()) return; 1248 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1249 if (!model || model->isEmpty()) return;
1226 1250
1227 QString unit; 1251 QString unit;
1228 double min, max; 1252 double min, max;
1229 bool logarithmic; 1253 bool logarithmic;
1230 1254
1276 { 1300 {
1277 #ifdef DEBUG_TIME_VALUE_LAYER 1301 #ifdef DEBUG_TIME_VALUE_LAYER
1278 cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl; 1302 cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl;
1279 #endif 1303 #endif
1280 1304
1281 if (!m_model) return; 1305 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1306 if (!model) return;
1282 1307
1283 sv_frame_t frame = v->getFrameForX(e->x()); 1308 sv_frame_t frame = v->getFrameForX(e->x());
1284 int resolution = m_model->getResolution(); 1309 int resolution = model->getResolution();
1285 if (frame < 0) frame = 0; 1310 if (frame < 0) frame = 0;
1286 frame = (frame / resolution) * resolution; 1311 frame = (frame / resolution) * resolution;
1287 1312
1288 double value = getValueForY(v, e->y()); 1313 double value = getValueForY(v, e->y());
1289 1314
1309 } 1334 }
1310 1335
1311 m_originalPoint = m_editingPoint; 1336 m_originalPoint = m_editingPoint;
1312 1337
1313 if (m_editingCommand) finish(m_editingCommand); 1338 if (m_editingCommand) finish(m_editingCommand);
1314 m_editingCommand = new ChangeEventsCommand(m_model, tr("Draw Point")); 1339 m_editingCommand = new ChangeEventsCommand(m_model.untyped, tr("Draw Point"));
1315 if (!havePoint) { 1340 if (!havePoint) {
1316 m_editingCommand->add(m_editingPoint); 1341 m_editingCommand->add(m_editingPoint);
1317 } 1342 }
1318 1343
1319 m_editing = true; 1344 m_editing = true;
1324 { 1349 {
1325 #ifdef DEBUG_TIME_VALUE_LAYER 1350 #ifdef DEBUG_TIME_VALUE_LAYER
1326 cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl; 1351 cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl;
1327 #endif 1352 #endif
1328 1353
1329 if (!m_model || !m_editing) return; 1354 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1355 if (!model || !m_editing) return;
1330 1356
1331 sv_frame_t frame = v->getFrameForX(e->x()); 1357 sv_frame_t frame = v->getFrameForX(e->x());
1332 int resolution = m_model->getResolution(); 1358 int resolution = model->getResolution();
1333 if (frame < 0) frame = 0; 1359 if (frame < 0) frame = 0;
1334 frame = (frame / resolution) * resolution; 1360 frame = (frame / resolution) * resolution;
1335 1361
1336 double value = getValueForY(v, e->y()); 1362 double value = getValueForY(v, e->y());
1337 1363
1385 TimeValueLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) 1411 TimeValueLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *)
1386 { 1412 {
1387 #ifdef DEBUG_TIME_VALUE_LAYER 1413 #ifdef DEBUG_TIME_VALUE_LAYER
1388 cerr << "TimeValueLayer::drawEnd" << endl; 1414 cerr << "TimeValueLayer::drawEnd" << endl;
1389 #endif 1415 #endif
1390 if (!m_model || !m_editing) return; 1416 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1417 if (!model || !m_editing) return;
1391 finish(m_editingCommand); 1418 finish(m_editingCommand);
1392 m_editingCommand = nullptr; 1419 m_editingCommand = nullptr;
1393 m_editing = false; 1420 m_editing = false;
1394 } 1421 }
1395 1422
1396 void 1423 void
1397 TimeValueLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e) 1424 TimeValueLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e)
1398 { 1425 {
1399 if (!m_model) return; 1426 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1427 if (!model) return;
1400 1428
1401 EventVector points = getLocalPoints(v, e->x()); 1429 EventVector points = getLocalPoints(v, e->x());
1402 if (points.empty()) return; 1430 if (points.empty()) return;
1403 1431
1404 m_editingPoint = *points.begin(); 1432 m_editingPoint = *points.begin();
1417 } 1445 }
1418 1446
1419 void 1447 void
1420 TimeValueLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e) 1448 TimeValueLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e)
1421 { 1449 {
1422 if (!m_model || !m_editing) return; 1450 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1451 if (!model || !m_editing) return;
1423 1452
1424 m_editing = false; 1453 m_editing = false;
1425 1454
1426 EventVector points = getLocalPoints(v, e->x()); 1455 EventVector points = getLocalPoints(v, e->x());
1427 if (points.empty()) return; 1456 if (points.empty()) return;
1428 if (points.begin()->getFrame() != m_editingPoint.getFrame() || 1457 if (points.begin()->getFrame() != m_editingPoint.getFrame() ||
1429 points.begin()->getValue() != m_editingPoint.getValue()) return; 1458 points.begin()->getValue() != m_editingPoint.getValue()) return;
1430 1459
1431 m_editingCommand = new ChangeEventsCommand(m_model, tr("Erase Point")); 1460 m_editingCommand = new ChangeEventsCommand(m_model.untyped, tr("Erase Point"));
1432 m_editingCommand->remove(m_editingPoint); 1461 m_editingCommand->remove(m_editingPoint);
1433 finish(m_editingCommand); 1462 finish(m_editingCommand);
1434 m_editingCommand = nullptr; 1463 m_editingCommand = nullptr;
1435 m_editing = false; 1464 m_editing = false;
1436 } 1465 }
1440 { 1469 {
1441 #ifdef DEBUG_TIME_VALUE_LAYER 1470 #ifdef DEBUG_TIME_VALUE_LAYER
1442 cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << endl; 1471 cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << endl;
1443 #endif 1472 #endif
1444 1473
1445 if (!m_model) return; 1474 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1475 if (!model) return;
1446 1476
1447 EventVector points = getLocalPoints(v, e->x()); 1477 EventVector points = getLocalPoints(v, e->x());
1448 if (points.empty()) return; 1478 if (points.empty()) return;
1449 1479
1450 m_editingPoint = *points.begin(); 1480 m_editingPoint = *points.begin();
1463 { 1493 {
1464 #ifdef DEBUG_TIME_VALUE_LAYER 1494 #ifdef DEBUG_TIME_VALUE_LAYER
1465 cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << endl; 1495 cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << endl;
1466 #endif 1496 #endif
1467 1497
1468 if (!m_model || !m_editing) return; 1498 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1499 if (!model || !m_editing) return;
1469 1500
1470 sv_frame_t frame = v->getFrameForX(e->x()); 1501 sv_frame_t frame = v->getFrameForX(e->x());
1471 if (frame < 0) frame = 0; 1502 if (frame < 0) frame = 0;
1472 frame = frame / m_model->getResolution() * m_model->getResolution(); 1503 frame = frame / model->getResolution() * model->getResolution();
1473 1504
1474 double value = getValueForY(v, e->y()); 1505 double value = getValueForY(v, e->y());
1475 1506
1476 if (!m_editingCommand) { 1507 if (!m_editingCommand) {
1477 m_editingCommand = new ChangeEventsCommand(m_model, tr("Drag Point")); 1508 m_editingCommand = new ChangeEventsCommand(m_model.untyped, tr("Drag Point"));
1478 } 1509 }
1479 1510
1480 m_editingCommand->remove(m_editingPoint); 1511 m_editingCommand->remove(m_editingPoint);
1481 m_editingPoint = m_editingPoint 1512 m_editingPoint = m_editingPoint
1482 .withFrame(frame) 1513 .withFrame(frame)
1488 TimeValueLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) 1519 TimeValueLayer::editEnd(LayerGeometryProvider *, QMouseEvent *)
1489 { 1520 {
1490 #ifdef DEBUG_TIME_VALUE_LAYER 1521 #ifdef DEBUG_TIME_VALUE_LAYER
1491 cerr << "TimeValueLayer::editEnd" << endl; 1522 cerr << "TimeValueLayer::editEnd" << endl;
1492 #endif 1523 #endif
1493 if (!m_model || !m_editing) return; 1524 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1525 if (!model || !m_editing) return;
1494 1526
1495 if (m_editingCommand) { 1527 if (m_editingCommand) {
1496 1528
1497 QString newName = m_editingCommand->getName(); 1529 QString newName = m_editingCommand->getName();
1498 1530
1515 } 1547 }
1516 1548
1517 bool 1549 bool
1518 TimeValueLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) 1550 TimeValueLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e)
1519 { 1551 {
1520 if (!m_model) return false; 1552 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1553 if (!model) return false;
1521 1554
1522 EventVector points = getLocalPoints(v, e->x()); 1555 EventVector points = getLocalPoints(v, e->x());
1523 if (points.empty()) return false; 1556 if (points.empty()) return false;
1524 1557
1525 Event point = *points.begin(); 1558 Event point = *points.begin();
1526 1559
1527 ItemEditDialog *dialog = new ItemEditDialog 1560 ItemEditDialog *dialog = new ItemEditDialog
1528 (m_model->getSampleRate(), 1561 (model->getSampleRate(),
1529 ItemEditDialog::ShowTime | 1562 ItemEditDialog::ShowTime |
1530 ItemEditDialog::ShowValue | 1563 ItemEditDialog::ShowValue |
1531 ItemEditDialog::ShowText, 1564 ItemEditDialog::ShowText,
1532 getScaleUnits()); 1565 getScaleUnits());
1533 1566
1541 .withFrame(dialog->getFrameTime()) 1574 .withFrame(dialog->getFrameTime())
1542 .withValue(dialog->getValue()) 1575 .withValue(dialog->getValue())
1543 .withLabel(dialog->getText()); 1576 .withLabel(dialog->getText());
1544 1577
1545 ChangeEventsCommand *command = 1578 ChangeEventsCommand *command =
1546 new ChangeEventsCommand(m_model, tr("Edit Point")); 1579 new ChangeEventsCommand(m_model.untyped, tr("Edit Point"));
1547 command->remove(point); 1580 command->remove(point);
1548 command->add(newPoint); 1581 command->add(newPoint);
1549 finish(command); 1582 finish(command);
1550 } 1583 }
1551 1584
1554 } 1587 }
1555 1588
1556 void 1589 void
1557 TimeValueLayer::moveSelection(Selection s, sv_frame_t newStartFrame) 1590 TimeValueLayer::moveSelection(Selection s, sv_frame_t newStartFrame)
1558 { 1591 {
1559 if (!m_model) return; 1592 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1593 if (!model) return;
1560 1594
1561 ChangeEventsCommand *command = 1595 ChangeEventsCommand *command =
1562 new ChangeEventsCommand(m_model, tr("Drag Selection")); 1596 new ChangeEventsCommand(m_model.untyped, tr("Drag Selection"));
1563 1597
1564 EventVector points = 1598 EventVector points =
1565 m_model->getEventsWithin(s.getStartFrame(), s.getDuration()); 1599 model->getEventsWithin(s.getStartFrame(), s.getDuration());
1566 1600
1567 for (Event p: points) { 1601 for (Event p: points) {
1568 1602
1569 Event newPoint = p.withFrame 1603 Event newPoint = p.withFrame
1570 (p.getFrame() + newStartFrame - s.getStartFrame()); 1604 (p.getFrame() + newStartFrame - s.getStartFrame());
1576 } 1610 }
1577 1611
1578 void 1612 void
1579 TimeValueLayer::resizeSelection(Selection s, Selection newSize) 1613 TimeValueLayer::resizeSelection(Selection s, Selection newSize)
1580 { 1614 {
1581 if (!m_model || !s.getDuration()) return; 1615 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1616 if (!model || !s.getDuration()) return;
1582 1617
1583 ChangeEventsCommand *command = 1618 ChangeEventsCommand *command =
1584 new ChangeEventsCommand(m_model, tr("Resize Selection")); 1619 new ChangeEventsCommand(m_model.untyped, tr("Resize Selection"));
1585 1620
1586 EventVector points = 1621 EventVector points =
1587 m_model->getEventsWithin(s.getStartFrame(), s.getDuration()); 1622 model->getEventsWithin(s.getStartFrame(), s.getDuration());
1588 1623
1589 double ratio = double(newSize.getDuration()) / double(s.getDuration()); 1624 double ratio = double(newSize.getDuration()) / double(s.getDuration());
1590 double oldStart = double(s.getStartFrame()); 1625 double oldStart = double(s.getStartFrame());
1591 double newStart = double(newSize.getStartFrame()); 1626 double newStart = double(newSize.getStartFrame());
1592 1627
1604 } 1639 }
1605 1640
1606 void 1641 void
1607 TimeValueLayer::deleteSelection(Selection s) 1642 TimeValueLayer::deleteSelection(Selection s)
1608 { 1643 {
1609 if (!m_model) return; 1644 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1645 if (!model) return;
1610 1646
1611 ChangeEventsCommand *command = 1647 ChangeEventsCommand *command =
1612 new ChangeEventsCommand(m_model, tr("Delete Selected Points")); 1648 new ChangeEventsCommand(m_model.untyped, tr("Delete Selected Points"));
1613 1649
1614 EventVector points = 1650 EventVector points =
1615 m_model->getEventsWithin(s.getStartFrame(), s.getDuration()); 1651 model->getEventsWithin(s.getStartFrame(), s.getDuration());
1616 1652
1617 for (Event p: points) { 1653 for (Event p: points) {
1618 command->remove(p); 1654 command->remove(p);
1619 } 1655 }
1620 1656
1622 } 1658 }
1623 1659
1624 void 1660 void
1625 TimeValueLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) 1661 TimeValueLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to)
1626 { 1662 {
1627 if (!m_model) return; 1663 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1664 if (!model) return;
1628 1665
1629 EventVector points = 1666 EventVector points =
1630 m_model->getEventsWithin(s.getStartFrame(), s.getDuration()); 1667 model->getEventsWithin(s.getStartFrame(), s.getDuration());
1631 1668
1632 for (Event p: points) { 1669 for (Event p: points) {
1633 to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame()))); 1670 to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame())));
1634 } 1671 }
1635 } 1672 }
1636 1673
1637 bool 1674 bool
1638 TimeValueLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, 1675 TimeValueLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */,
1639 bool interactive) 1676 bool interactive)
1640 { 1677 {
1641 if (!m_model) return false; 1678 auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
1679 if (!model) return false;
1642 1680
1643 EventVector points = from.getPoints(); 1681 EventVector points = from.getPoints();
1644 1682
1645 bool realign = false; 1683 bool realign = false;
1646 1684
1660 realign = true; 1698 realign = true;
1661 } 1699 }
1662 } 1700 }
1663 1701
1664 ChangeEventsCommand *command = 1702 ChangeEventsCommand *command =
1665 new ChangeEventsCommand(m_model, tr("Paste")); 1703 new ChangeEventsCommand(m_model.untyped, tr("Paste"));
1666 1704
1667 enum ValueAvailability { 1705 enum ValueAvailability {
1668 UnknownAvailability, 1706 UnknownAvailability,
1669 NoValues, 1707 NoValues,
1670 SomeValues, 1708 SomeValues,
1673 1711
1674 Labeller::ValueType generation = Labeller::ValueNone; 1712 Labeller::ValueType generation = Labeller::ValueNone;
1675 1713
1676 bool haveUsableLabels = false; 1714 bool haveUsableLabels = false;
1677 Labeller labeller; 1715 Labeller labeller;
1678 labeller.setSampleRate(m_model->getSampleRate()); 1716 labeller.setSampleRate(model->getSampleRate());
1679 1717
1680 if (interactive) { 1718 if (interactive) {
1681 1719
1682 ValueAvailability availability = UnknownAvailability; 1720 ValueAvailability availability = UnknownAvailability;
1683 1721