Mercurial > hg > svgui
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 |