comparison layer/TimeFrequencyBoxLayer.cpp @ 1514:e453053a44dc time-frequency-boxes

Fixes to drag and paint in time-freq box layer
author Chris Cannam
date Fri, 20 Sep 2019 11:25:47 +0100
parents a473b73fb045
children 0fa49a6ce64f
comparison
equal deleted inserted replaced
1513:0586e6492785 1514:e453053a44dc
522 wholeFrame1 - wholeFrame0)); 522 wholeFrame1 - wholeFrame0));
523 if (points.empty()) return; 523 if (points.empty()) return;
524 524
525 paint.setPen(getBaseQColor()); 525 paint.setPen(getBaseQColor());
526 526
527 QColor brushColour(getBaseQColor());
528 brushColour.setAlpha(80);
529
530 // SVDEBUG << "TimeFrequencyBoxLayer::paint: resolution is " 527 // SVDEBUG << "TimeFrequencyBoxLayer::paint: resolution is "
531 // << model->getResolution() << " frames" << endl; 528 // << model->getResolution() << " frames" << endl;
532 529
533 double min = model->getFrequencyMinimum(); 530 double min = model->getFrequencyMinimum();
534 double max = model->getFrequencyMaximum(); 531 double max = model->getFrequencyMaximum();
544 } 541 }
545 542
546 paint.save(); 543 paint.save();
547 paint.setRenderHint(QPainter::Antialiasing, false); 544 paint.setRenderHint(QPainter::Antialiasing, false);
548 545
546 QFontMetrics fm = paint.fontMetrics();
547
549 for (EventVector::const_iterator i = points.begin(); 548 for (EventVector::const_iterator i = points.begin();
550 i != points.end(); ++i) { 549 i != points.end(); ++i) {
551 550
552 const Event &p(*i); 551 const Event &p(*i);
553 552
554 int x = v->getXForFrame(p.getFrame()); 553 int x = v->getXForFrame(p.getFrame());
555 int w = v->getXForFrame(p.getFrame() + p.getDuration()) - x; 554 int w = v->getXForFrame(p.getFrame() + p.getDuration()) - x;
556 int y = getYForValue(v, p.getValue()); 555 int y = getYForValue(v, p.getValue());
557 int h = getYForValue(v, p.getValue() + fabsf(p.getLevel())); 556 int h = getYForValue(v, p.getValue() + fabsf(p.getLevel())) - y;
558 int ex = x + w; 557 int ex = x + w;
559
560 int gap = v->scalePixelSize(2); 558 int gap = v->scalePixelSize(2);
561 559
562 EventVector::const_iterator j = i; 560 EventVector::const_iterator j = i;
563 ++j; 561 ++j;
564 562
565 if (j != points.end()) { 563 if (j != points.end()) {
566 const Event &q(*j); 564 const Event &q(*j);
567 int nx = v->getXForFrame(q.getFrame()); 565 int nx = v->getXForFrame(q.getFrame());
568 if (nx < ex) ex = nx; 566 if (nx < ex) ex = nx;
569 } 567 }
570 568
571 if (w < 1) w = 1; 569 if (w < 1) w = 1;
572 if (h < 1) h = 1;
573 570
574 paint.setPen(getBaseQColor()); 571 paint.setPen(getBaseQColor());
575 paint.setBrush(brushColour); 572 paint.setBrush(Qt::NoBrush);
576 573
577 if (shouldIlluminate && illuminatePoint == p) { 574 if ((shouldIlluminate && illuminatePoint == p) ||
578 575 (m_editing && m_editingPoint == p)) {
579 paint.setPen(v->getForeground()); 576
580 paint.setBrush(v->getForeground()); 577 paint.setPen(QPen(getBaseQColor(), v->scalePixelSize(2)));
581 578
582 // Qt 5.13 deprecates QFontMetrics::width(), but its suggested 579 // Qt 5.13 deprecates QFontMetrics::width(), but its suggested
583 // replacement (horizontalAdvance) was only added in Qt 5.11 580 // replacement (horizontalAdvance) was only added in Qt 5.11
584 // which is too new for us 581 // which is too new for us
585 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 582 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
586 583
587 QString vlabel = 584 if (abs(h) > 2 * fm.height()) {
588 QString("%1%2 - %3%4") 585
589 .arg(p.getValue()).arg(getScaleUnits()) 586 QString y0label = QString("%1 %2")
590 .arg(p.getValue() + fabsf(p.getLevel())).arg(getScaleUnits()); 587 .arg(p.getValue())
588 .arg(getScaleUnits());
589
590 QString y1label = QString("%1 %2")
591 .arg(p.getValue() + fabsf(p.getLevel()))
592 .arg(getScaleUnits());
593
594 PaintAssistant::drawVisibleText
595 (v, paint,
596 x - fm.width(y0label) - gap,
597 y - fm.descent(),
598 y0label, PaintAssistant::OutlinedText);
599
600 PaintAssistant::drawVisibleText
601 (v, paint,
602 x - fm.width(y1label) - gap,
603 y + h + fm.ascent(),
604 y1label, PaintAssistant::OutlinedText);
605
606 } else {
607
608 QString ylabel = QString("%1 %2 - %3 %4")
609 .arg(p.getValue())
610 .arg(getScaleUnits())
611 .arg(p.getValue() + fabsf(p.getLevel()))
612 .arg(getScaleUnits());
613
614 PaintAssistant::drawVisibleText
615 (v, paint,
616 x - fm.width(ylabel) - gap,
617 y - fm.descent(),
618 ylabel, PaintAssistant::OutlinedText);
619 }
620
621 QString t0label = RealTime::frame2RealTime
622 (p.getFrame(), model->getSampleRate()).toText(true).c_str();
623
624 QString t1label = RealTime::frame2RealTime
625 (p.getFrame() + p.getDuration(), model->getSampleRate())
626 .toText(true).c_str();
627
591 PaintAssistant::drawVisibleText 628 PaintAssistant::drawVisibleText
592 (v, paint, 629 (v, paint, x, y + fm.ascent() + gap,
593 x - paint.fontMetrics().width(vlabel) - gap, 630 t0label, PaintAssistant::OutlinedText);
594 y + paint.fontMetrics().height()/2 631
595 - paint.fontMetrics().descent(), 632 if (w > fm.width(t0label) + fm.width(t1label) + gap * 3) {
596 vlabel, PaintAssistant::OutlinedText); 633
597 634 PaintAssistant::drawVisibleText
598 QString hlabel = RealTime::frame2RealTime 635 (v, paint,
599 (p.getFrame(), model->getSampleRate()).toText(true).c_str(); 636 x + w - fm.width(t1label),
600 PaintAssistant::drawVisibleText 637 y + fm.ascent() + gap,
601 (v, paint, 638 t1label, PaintAssistant::OutlinedText);
602 x, 639
603 y - h/2 - paint.fontMetrics().descent() - gap, 640 } else {
604 hlabel, PaintAssistant::OutlinedText); 641
642 PaintAssistant::drawVisibleText
643 (v, paint,
644 x + w - fm.width(t1label),
645 y + fm.ascent() + fm.height() + gap,
646 t1label, PaintAssistant::OutlinedText);
647 }
605 } 648 }
606 649
607 paint.drawRect(x, y, w, h); 650 paint.drawRect(x, y, w, h);
608 } 651 }
609 652
610 for (EventVector::const_iterator i = points.begin(); 653 for (EventVector::const_iterator i = points.begin();
611 i != points.end(); ++i) { 654 i != points.end(); ++i) {
612 655
613 const Event &p(*i); 656 const Event &p(*i);
614 657
658 QString label = p.getLabel();
659 if (label == "") continue;
660
661 if (shouldIlluminate && illuminatePoint == p) {
662 continue; // already handled this in illumination special case
663 }
664
615 int x = v->getXForFrame(p.getFrame()); 665 int x = v->getXForFrame(p.getFrame());
616 int w = v->getXForFrame(p.getFrame() + p.getDuration()) - x; 666 int w = v->getXForFrame(p.getFrame() + p.getDuration()) - x;
617 int y = getYForValue(v, p.getValue()); 667 int y = getYForValue(v, p.getValue());
618 668
619 QString label = p.getLabel(); 669 int labelWidth = fm.width(label);
620 if (label == "") {
621 label =
622 QString("%1%2 - %3%4")
623 .arg(p.getValue()).arg(getScaleUnits())
624 .arg(p.getValue() + fabsf(p.getLevel())).arg(getScaleUnits());
625 }
626 int labelWidth = paint.fontMetrics().width(label);
627 670
628 int gap = v->scalePixelSize(2); 671 int gap = v->scalePixelSize(2);
629 672
630 if (x + w < x0 || x - labelWidth - gap > x1) { 673 if (x + w < x0 || x - labelWidth - gap > x1) {
631 continue; 674 continue;
632 } 675 }
633 676
634 bool illuminated = false; 677 int labelX, labelY;
635 678
636 if (shouldIlluminate && illuminatePoint == p) { 679 labelX = x - labelWidth - gap;
637 illuminated = true; 680 labelY = y - fm.descent();
638 } 681
639 682 PaintAssistant::drawVisibleText(v, paint, labelX, labelY, label,
640 if (!illuminated) { 683 PaintAssistant::OutlinedText);
641
642 int labelX, labelY;
643
644 labelX = x - labelWidth - gap;
645 labelY = y + paint.fontMetrics().height()/2
646 - paint.fontMetrics().descent();
647
648 PaintAssistant::drawVisibleText(v, paint, labelX, labelY, label,
649 PaintAssistant::OutlinedText);
650 }
651 } 684 }
652 685
653 paint.restore(); 686 paint.restore();
654 } 687 }
655 688
698 paint.fontMetrics(), 731 paint.fontMetrics(),
699 mw)); 732 mw));
700 } 733 }
701 } 734 }
702 735
703 //!!! All of the editing operations still need to be updated for
704 //!!! vertical frequency range instead of just value
705
706 void 736 void
707 TimeFrequencyBoxLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e) 737 TimeFrequencyBoxLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e)
708 { 738 {
709 auto model = ModelById::getAs<TimeFrequencyBoxModel>(m_model); 739 auto model = ModelById::getAs<TimeFrequencyBoxModel>(m_model);
710 if (!model) return; 740 if (!model) return;
711 741
712 sv_frame_t frame = v->getFrameForX(e->x()); 742 sv_frame_t frame = v->getFrameForX(e->x());
713 if (frame < 0) frame = 0; 743 if (frame < 0) frame = 0;
714 frame = frame / model->getResolution() * model->getResolution(); 744 frame = frame / model->getResolution() * model->getResolution();
715 745
716 double value = getValueForY(v, e->y()); 746 double frequency = getValueForY(v, e->y());
717 747
718 m_editingPoint = Event(frame, float(value), 0, ""); 748 m_editingPoint = Event(frame, float(frequency), 0, "");
719 m_originalPoint = m_editingPoint; 749 m_originalPoint = m_editingPoint;
720 750
721 if (m_editingCommand) finish(m_editingCommand); 751 if (m_editingCommand) finish(m_editingCommand);
722 m_editingCommand = new ChangeEventsCommand(m_model.untyped, 752 m_editingCommand = new ChangeEventsCommand(m_model.untyped,
723 tr("Draw Time-Frequency Box")); 753 tr("Draw Time-Frequency Box"));
730 TimeFrequencyBoxLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e) 760 TimeFrequencyBoxLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e)
731 { 761 {
732 auto model = ModelById::getAs<TimeFrequencyBoxModel>(m_model); 762 auto model = ModelById::getAs<TimeFrequencyBoxModel>(m_model);
733 if (!model || !m_editing) return; 763 if (!model || !m_editing) return;
734 764
735 sv_frame_t frame = v->getFrameForX(e->x()); 765 sv_frame_t dragFrame = v->getFrameForX(e->x());
736 if (frame < 0) frame = 0; 766 if (dragFrame < 0) dragFrame = 0;
737 frame = frame / model->getResolution() * model->getResolution(); 767 dragFrame = dragFrame / model->getResolution() * model->getResolution();
738 768
739 double newValue = getValueForY(v, e->y()); 769 sv_frame_t eventFrame = m_originalPoint.getFrame();
740 770 sv_frame_t eventDuration = dragFrame - eventFrame;
741 sv_frame_t newFrame = m_editingPoint.getFrame(); 771 if (eventDuration < 0) {
742 sv_frame_t newDuration = frame - newFrame; 772 eventFrame = eventFrame + eventDuration;
743 if (newDuration < 0) { 773 eventDuration = -eventDuration;
744 newFrame = frame; 774 } else if (eventDuration == 0) {
745 newDuration = -newDuration; 775 eventDuration = model->getResolution();
746 } else if (newDuration == 0) { 776 }
747 newDuration = 1; 777
778 double dragFrequency = getValueForY(v, e->y());
779
780 double eventFrequency = m_originalPoint.getValue();
781 double eventFreqDiff = dragFrequency - eventFrequency;
782 if (eventFreqDiff < 0) {
783 eventFrequency = eventFrequency + eventFreqDiff;
784 eventFreqDiff = -eventFreqDiff;
748 } 785 }
749 786
750 m_editingCommand->remove(m_editingPoint); 787 m_editingCommand->remove(m_editingPoint);
751 m_editingPoint = m_editingPoint 788 m_editingPoint = m_editingPoint
752 .withFrame(newFrame) 789 .withFrame(eventFrame)
753 .withValue(float(newValue)) 790 .withDuration(eventDuration)
754 .withDuration(newDuration); 791 .withValue(float(eventFrequency))
792 .withLevel(float(eventFreqDiff));
755 m_editingCommand->add(m_editingPoint); 793 m_editingCommand->add(m_editingPoint);
756 } 794 }
757 795
758 void 796 void
759 TimeFrequencyBoxLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) 797 TimeFrequencyBoxLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *)