18 #include "data/model/Model.h" 19 #include "base/ZoomConstraint.h" 20 #include "base/RealTime.h" 21 #include "base/Profiler.h" 26 #include "base/Preferences.h" 38 #include "data/model/WaveFileModel.h" 39 #include "data/model/AlignmentModel.h" 41 #include <QPaintEvent> 44 #include <QDragEnterEvent> 47 #include <QTextStream> 49 #include <QApplication> 57 #include <QGridLayout> 58 #include <QPushButton> 75 m_identifyFeatures(false),
76 m_clickedInRange(false),
77 m_shiftPressed(false),
84 m_centreLineVisible(true),
86 m_pendingWheelAngle(0),
87 m_headsUpDisplay(nullptr),
92 m_lastVerticalPannerContextMenu(nullptr),
93 m_mouseInWidget(false),
94 m_playbackFrameMoveScheduled(false),
95 m_playbackFrameMoveTo(0)
97 setObjectName(
"Pane");
98 setMouseTracking(
true);
115 Profiler profiler(
"Pane::updateHeadsUpDisplay");
117 if (!isVisible())
return;
119 Layer *layer =
nullptr;
128 QGridLayout *layout =
new QGridLayout;
129 layout->setMargin(0);
130 layout->setSpacing(0);
134 m_hthumb->setObjectName(tr(
"Horizontal Zoom"));
135 m_hthumb->setCursor(Qt::ArrowCursor);
136 layout->addWidget(
m_hthumb, 1, 0, 1, 2);
141 connect(
m_hthumb, SIGNAL(valueChanged(
int)),
this,
147 m_vpan->setCursor(Qt::ArrowCursor);
148 layout->addWidget(
m_vpan, 0, 1);
152 connect(
m_vpan, SIGNAL(rectExtentsChanged(
float,
float,
float,
float)),
154 connect(
m_vpan, SIGNAL(doubleClicked()),
160 m_vpan->setContextMenuPolicy(Qt::CustomContextMenu);
161 connect(
m_vpan, SIGNAL(customContextMenuRequested(
const QPoint &)),
165 m_vthumb->setObjectName(tr(
"Vertical Zoom"));
166 m_vthumb->setCursor(Qt::ArrowCursor);
170 connect(
m_vthumb, SIGNAL(valueChanged(
int)),
this,
182 m_reset->setCursor(Qt::ArrowCursor);
186 m_reset->setToolTip(tr(
"Reset zoom to default"));
187 layout->addWidget(
m_reset, 1, 2);
189 layout->setColumnStretch(0, 20);
193 connect(
m_reset, SIGNAL(clicked()),
m_vpan, SLOT(resetToDefault()));
209 bool haveVThumb =
false;
269 Layer *layer =
nullptr;
277 double vmin, vmax, dmin, dmax;
279 double y0 = (dmin - vmin) / (vmax - vmin);
280 double y1 = (dmax - vmin) / (vmax - vmin);
281 m_vpan->blockSignals(
true);
283 m_vpan->blockSignals(
false);
317 bool &closeToRight)
const 326 closeToLeft, closeToRight));
367 if (e) r = e->rect();
374 if (e) paint.setClipRect(r);
382 bool haveSomeTimeXAxis =
false;
384 ModelId waveformModelId;
392 if (!haveSomeTimeXAxis && (*vi)->hasTimeXAxis()) {
393 haveSomeTimeXAxis =
true;
396 ModelId modelId = (*vi)->getModel();
397 if (!modelId.isNone()) {
398 if (dynamic_cast<WaveformLayer *>(*vi)) {
399 waveformModelId = modelId;
400 workModelId = modelId;
402 if (ModelById::isa<WaveFileModel>(modelId)) {
403 workModelId = modelId;
405 ModelId sourceId = (*vi)->getSourceModel();
406 if (ModelById::isa<WaveFileModel>(sourceId)) {
407 workModelId = sourceId;
413 if (!waveformModelId.isNone() &&
414 !workModelId.isNone() &&
435 std::vector<QRect> crosshairExtents;
441 }
else if ((*vi)->isLayerOpaque()) {
464 paint.setBrush(Qt::NoBrush);
472 paint.setPen(QColor(50, 50, 50));
474 if (!waveformModelId.isNone() &&
481 bool haveWorkTitle =
false;
483 if (!workModelId.isNone() &&
487 haveWorkTitle =
true;
490 if (!workModelId.isNone() &&
510 paint.setPen(Qt::blue);
519 bool showFocus =
false;
547 Layer *scaleLayer =
nullptr;
550 #ifdef DEBUG_PANE_SCALE_CHOICE 551 SVCERR <<
"Pane[" <<
getId() <<
"]::drawVerticalScale: Have " 573 (
this, includeColourScale, paint);
575 #ifdef DEBUG_PANE_SCALE_CHOICE 576 SVCERR <<
"Pane[" <<
getId() <<
"]::drawVerticalScale: Top layer (" 578 <<
") offers vertical scale width of " << scaleWidth
583 if (scaleWidth > 0) {
584 scaleLayer = topLayer;
586 #ifdef DEBUG_PANE_SCALE_CHOICE 587 SVCERR <<
"Pane[" <<
getId() <<
"]::drawVerticalScale: Accepting that" 596 #ifdef DEBUG_PANE_SCALE_CHOICE 597 SVCERR <<
"Pane[" <<
getId() <<
"]::drawVerticalScale: " 598 <<
"Layer " << layer <<
", " 600 <<
" is dormant, skipping" << endl;
608 #ifdef DEBUG_PANE_SCALE_CHOICE 609 SVCERR <<
"Pane[" <<
getId() <<
"]::drawVerticalScale: " 612 <<
" has value extents (unit = " 613 << unit <<
"), using this layer or unit" << endl;
620 SVCERR <<
"Pane[" <<
getId() <<
"]::drawVerticalScale: " 623 <<
" is opaque, searching no further" << endl;
631 (
this, includeColourScale, paint);
633 #ifdef DEBUG_PANE_SCALE_CHOICE 634 SVCERR <<
"Pane[" <<
getId() <<
"]::drawVerticalScale: Layer " 635 << scaleLayer <<
", " 637 <<
" offers vertical scale width of " 638 << scaleWidth << endl;
642 if (scaleWidth == 0 && unit !=
"") {
643 #ifdef DEBUG_PANE_SCALE_CHOICE 644 SVDEBUG <<
"Pane[" <<
getId()
645 <<
"]::drawVerticalScale: No good scale layer, " 646 <<
"but we have a unit of " << unit
647 <<
" - seeking scale-providing layer for that" << endl;
652 #ifdef DEBUG_PANE_SCALE_CHOICE 653 SVDEBUG <<
"Pane[" <<
getId()
654 <<
"]::drawVerticalScale: That returned layer " 655 << scaleLayer <<
", " 663 if (scaleWidth > 0) {
665 }
else if (scaleLayer) {
667 (
this, includeColourScale, paint);
678 paint.setPen(Qt::NoPen);
685 paint.setBrush(Qt::NoBrush);
687 (
this, includeColourScale, paint,
707 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 710 paint.fontMetrics().width(tr(
"Some lengthy prefix:"));
713 paint.fontMetrics().boundingRect
715 Qt::AlignRight | Qt::AlignTop | Qt::TextExpandTabs,
719 paint.setPen(Qt::NoPen);
720 paint.setBrush(QColor(250, 250, 250, 200));
722 paint.setPen(Qt::NoPen);
723 paint.setBrush(QColor(50, 50, 50, 200));
726 int extra = paint.fontMetrics().descent();
727 paint.drawRect(width() - boundingRect.width() - 10 - extra,
729 boundingRect.width() + 2 * extra,
730 boundingRect.height() + extra);
733 paint.setPen(QColor(150, 20, 0));
735 paint.setPen(QColor(255, 150, 100));
739 option.setWrapMode(QTextOption::NoWrap);
740 option.setAlignment(Qt::AlignRight | Qt::AlignTop);
741 option.setTabStop(tabStop);
742 paint.drawText(QRectF(width() - boundingRect.width() - 10, 10,
743 boundingRect.width(),
744 boundingRect.height()),
759 int fontHeight = paint.fontMetrics().height();
760 int fontAscent = paint.fontMetrics().ascent();
762 QColor c = QColor(0, 0, 0);
764 c = QColor(240, 240, 240);
771 paint.drawLine(x, 0, x, height() - 1);
772 paint.drawLine(x-1, 1, x+1, 1);
773 paint.drawLine(x-2, 0, x+2, 0);
774 paint.drawLine(x-1, height() - 2, x+1, height() - 2);
775 paint.drawLine(x-2, height() - 1, x+2, height() - 1);
778 paint.setPen(QColor(50, 50, 50));
780 int y = height() - fontHeight + fontAscent - 6;
786 switch ((*--vi)->getPreferredFrameCountPosition()) {
793 y = (height() - fontHeight) / 2
807 QString text(QString::fromStdString
808 (RealTime::frame2RealTime
812 int tw = paint.fontMetrics().width(text);
813 int x = width()/2 - 4 - tw;
820 int x = width()/2 + 4;
829 auto model = ModelById::get(modelId);
837 brush = QBrush(QColor(
"#aaf8f8f8"));
838 paint.setPen(Qt::black);
840 brush = QBrush(QColor(
"#aa101010"));
841 paint.setPen(Qt::white);
844 sv_frame_t f0 = model->getStartFrame();
849 paint.fillRect(0, 0, x0, height(), brush);
850 paint.drawLine(x0, 0, x0, height());
854 sv_frame_t f1 = model->getEndFrame();
858 if (x1 < r.x() + r.width()) {
859 paint.fillRect(x1, 0, width() - x1, height(), brush);
860 paint.drawLine(x1, 0, x1, height());
871 auto model = ModelById::get(modelId);
874 ModelId reference = model->getAlignmentReference();
885 int completion = 100;
887 if (reference == modelId) {
888 text = tr(
"Reference");
889 }
else if (reference.isNone()) {
890 text = tr(
"Unaligned");
892 completion = model->getAlignmentCompletion();
893 int relativePitch = 0;
894 if (
auto alignmentModel =
895 ModelById::getAs<AlignmentModel>(model->getAlignment())) {
896 relativePitch = alignmentModel->getRelativePitch();
898 if (completion == 0) {
899 text = tr(
"Unaligned");
900 }
else if (completion < 100) {
901 text = tr(
"Aligning: %1%").arg(completion);
902 }
else if (relativePitch < 0) {
903 text = tr(
"Aligned at -%1 cents").arg(-relativePitch);
904 }
else if (relativePitch > 0) {
905 text = tr(
"Aligned at +%1 cents").arg(relativePitch);
907 text = tr(
"Aligned");
912 QFont font(paint.font());
915 if (completion < 100) paint.setBrush(Qt::red);
918 if (down) y += paint.fontMetrics().height();
919 int w = paint.fontMetrics().width(text);
920 int h = paint.fontMetrics().height();
921 if (r.top() > h + y || r.left() > w +
m_scaleWidth + 5) {
936 update(QRect(0, 0, 300, 100));
942 auto model = ModelById::get(modelId);
945 QString title = model->getTitle();
946 QString maker = model->getMaker();
948 if (title ==
"")
return;
950 QString text = title;
952 text = tr(
"%1 - %2").arg(title).arg(maker);
956 QFont font(paint.font());
957 font.setItalic(
true);
961 int w = paint.fontMetrics().width(text);
962 int h = paint.fontMetrics().height();
963 if (r.top() > h + y || r.left() > w +
m_scaleWidth + 5) {
977 int fontHeight = paint.fontMetrics().height();
978 int fontAscent = paint.fontMetrics().ascent();
980 int lly = height() - 6;
982 int zoomWheelSkip = 0, horizontalScaleSkip = 0;
990 horizontalScaleSkip = (*i)->getHorizontalScaleHeight(
this, paint);
991 if (horizontalScaleSkip > 0) {
994 if ((*i)->isLayerOpaque()) {
999 lly -= std::max(zoomWheelSkip, horizontalScaleSkip);
1001 if (r.y() + r.height() < lly - int(
m_layerStack.size()) * fontHeight) {
1006 std::vector<QPixmap> pixmaps;
1008 texts.push_back((*i)->getLayerPresentationName());
1011 pixmaps.push_back((*i)->getLayerPresentationPixmap
1012 (QSize(fontAscent, fontAscent)));
1015 int maxTextWidth = width() / 3;
1018 int llx = width() - maxTextWidth - 5;
1023 if (r.x() + r.width() >= llx - fontAscent - 3) {
1025 for (
int i = 0; i < texts.size(); ++i) {
1029 if (i + 1 == texts.size()) {
1034 lly - fontHeight + fontAscent,
1037 if (!pixmaps[i].isNull()) {
1038 paint.drawPixmap(llx - fontAscent - 3,
1039 lly - fontHeight + (fontHeight-fontAscent)/2,
1070 int fontHeight = paint.fontMetrics().height();
1071 int fontAscent = paint.fontMetrics().ascent();
1073 QString startText, endText, offsetText;
1074 startText = QString(
"%1").arg(newStart);
1075 endText = QString(
"%1").arg(newEnd);
1076 offsetText = QString(
"%1").arg(newStart - origStart);
1077 if (newStart >= origStart) {
1078 offsetText = tr(
"+%1").arg(offsetText);
1081 startText = QString(
"%1 / %2")
1082 .arg(QString::fromStdString
1083 (RealTime::frame2RealTime(newStart, sampleRate).toText()))
1085 endText = QString(
"%1 / %2")
1086 .arg(QString::fromStdString
1087 (RealTime::frame2RealTime(newEnd, sampleRate).toText()))
1089 offsetText = QString(
"%1 / %2")
1090 .arg(QString::fromStdString
1091 (RealTime::frame2RealTime(newStart - origStart, sampleRate).toText()))
1093 if (newStart >= origStart) {
1094 offsetText = tr(
"+%1").arg(offsetText);
1105 paint.drawLine(p0, 1, p1, 1);
1106 paint.drawLine(p0, 0, p0, height());
1107 paint.drawLine(p0, height() - 1, p1, height() - 1);
1109 paint.drawLine(p0, 1, p1, 1);
1110 paint.drawLine(p1, 0, p1, height());
1111 paint.drawLine(p0, height() - 1, p1, height() - 1);
1113 paint.setBrush(Qt::NoBrush);
1114 paint.drawRect(p0, 1, p1 - p0, height() - 2);
1121 sv_samplerate_t sampleRate, QPainter &paint)
1123 auto waveformModel = ModelById::get(waveformModelId);
1124 if (!waveformModel)
return;
1126 int fontHeight = paint.fontMetrics().height();
1127 int fontAscent = paint.fontMetrics().ascent();
1129 if (r.y() + r.height() < height() - fontHeight - 6)
return;
1131 sv_samplerate_t modelRate = waveformModel->getSampleRate();
1132 sv_samplerate_t nativeRate = waveformModel->getNativeRate();
1135 QString srNote =
"";
1142 if (modelRate != nativeRate) {
1143 if (playbackRate != 0 && modelRate != playbackRate) {
1144 srNote =
" " + tr(
"(X)");
1146 srNote =
" " + tr(
"(R)");
1150 QString desc = tr(
"%1 / %2Hz%3")
1151 .arg(RealTime::frame2RealTime(waveformModel->getEndFrame(),
1153 .toText(
false).c_str())
1159 if (x < pbw + 5) x = pbw + 5;
1161 if (r.x() < x + paint.fontMetrics().width(desc)) {
1163 height() - fontHeight + fontAscent - 6,
1187 paint.setBrush(Qt::NoBrush);
1202 int x0 = int(round(
getZoomLevel().framesToPixels(
double(f0))));
1203 int x1 = int(round(
getZoomLevel().framesToPixels(
double(f1))));
1206 height(), QImage::Format_RGB32);
1213 QPainter paint(image);
1224 height(), QImage::Format_RGB32);
1227 QPainter *paint =
new QPainter(image);
1228 if (!
render(*paint, 0, f0, f1)) {
1242 QImage *image =
new QImage(100, 100, QImage::Format_RGB32);
1243 QPainter paint(image);
1254 return QSize(sw + s.width(), s.height());
1262 if (f0 < 0 || f0 < f)
return f;
1269 closeToLeftEdge = closeToRightEdge =
false;
1274 if (testFrame < 0) {
1276 if (testFrame < 0)
return Selection();
1280 if (selection.isEmpty())
return selection;
1286 if (x < lx - fuzz || x > rx + fuzz)
return Selection();
1288 int width = rx - lx;
1290 if (width < 12) fuzz = width / 4;
1295 if (x < lx + fuzz) closeToLeftEdge =
true;
1296 if (x > rx - fuzz) closeToRightEdge =
true;
1304 double vmin, vmax, dmin, dmax;
1306 if (dmin <= vmin && dmax >= vmax)
return false;
1312 double &dmin,
double &dmax,
1316 if (!layer)
return false;
1321 if (unit) *unit = vunit;
1329 if (!layer)
return false;
1343 tr(
"Zoom in or out in time axis"));
1345 tr(
"Scroll rapidly left or right in time axis"));
1347 tr(
"Zoom in or out in the vertical axis"));
1349 tr(
"Scroll up or down in the vertical axis"));
1351 tr(
"Click middle button and drag to navigate with any tool"));
1353 tr(
"Double-click middle button to relocate with any tool"));
1355 tr(
"Show pane context menu"));
1361 for (
int i =
int(
m_layerStack.size()) - 1; i >= 0; --i) {
1373 if (e->buttons() & Qt::RightButton) {
1400 (e->buttons() & Qt::MidButton) ||
1405 setCursor(Qt::PointingHandCursor);
1412 double vmin, vmax, dmin, dmax;
1429 bool closeToLeft =
false, closeToRight =
false;
1430 Selection selection =
getSelectionAt(e->x(), closeToLeft, closeToRight);
1432 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) {
1449 sv_frame_t snapFrame = mouseFrame;
1453 !qobject_cast<TimeRulerLayer *>(layer)) {
1458 if (snapFrame < 0) snapFrame = 0;
1497 std::cerr <<
"mouse pressed in note edit mode" << std::endl;
1523 QTimer::singleShot(QApplication::doubleClickInterval() + 10,
this,
1539 if (e && (e->buttons() & Qt::RightButton)) {
1544 SVCERR <<
"Pane[" <<
getId() <<
"]::mouseReleaseEvent" << endl;
1557 if (mouseFrame < 0) mouseFrame = 0;
1592 if (selection.getEndFrame() < selection.getStartFrame() + 2) {
1593 selection = Selection();
1669 if (!e || (e->buttons() & Qt::RightButton)) {
1675 QPoint pos = e->pos();
1685 if (!(e->buttons() & Qt::LeftButton) &&
1686 !(e->buttons() & Qt::MidButton)) {
1712 bool closeToLeft =
false, closeToRight =
false;
1714 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) {
1715 setCursor(Qt::SizeHorCursor);
1717 setCursor(Qt::ArrowCursor);
1723 bool updating =
false;
1788 if ((e->modifiers() & Qt::ShiftModifier)) {
1809 QMouseEvent clickEvent(QEvent::MouseButtonPress,
1818 std::cerr <<
"calling edit start" << std::endl;
1837 QMouseEvent moveEvent(QEvent::MouseMove,
1842 std::cerr <<
"calling editDrag" << std::endl;
1852 if ((e->modifiers() & Qt::ShiftModifier)) {
1876 QMouseEvent clickEvent(QEvent::MouseButtonPress,
1903 QMouseEvent moveEvent(QEvent::MouseMove,
1937 int x1 = r.x() + r.width();
1938 int y1 = r.y() + r.height();
1940 SVDEBUG <<
"Pane::zoomToRegion: region defined by pixel rect (" 1941 << r.x() <<
"," << r.y() <<
"), " << r.width() <<
"x" << r.height()
1945 if (interactionLayer && !(interactionLayer->
hasTimeXAxis())) {
1946 SVDEBUG <<
"Interaction layer does not have time X axis - delegating to it to decide what to do" << endl;
1953 sv_frame_t dist = newEndFrame - newStartFrame;
1956 if (newStartFrame <= -visibleFrames) {
1957 newStartFrame = -visibleFrames + 1;
1964 ZoomLevel newZoomLevel = ZoomLevel::fromRatio(width(), dist);
1971 Layer *layer =
nullptr;
1972 for (LayerList::const_iterator i =
m_layerStack.begin();
1974 if ((*i)->getValueExtents(min, max, log, unit) &&
1975 (*i)->getDisplayExtents(min, max)) {
1983 min = (min < 0.0) ? -log10(-min) : (min == 0.0) ? 0.0 : log10(min);
1984 max = (max < 0.0) ? -log10(-max) : (max == 0.0) ? 0.0 : log10(max);
1986 double rmin = min + ((max - min) * (height() - y1)) / height();
1987 double rmax = min + ((max - min) * (height() - y0)) / height();
1988 cerr <<
"min: " << min <<
", max: " << max <<
", y0: " << y0 <<
", y1: " << y1 <<
", h: " << height() <<
", rmin: " << rmin <<
", rmax: " << rmax << endl;
1990 rmin = pow(10, rmin);
1991 rmax = pow(10, rmax);
1993 cerr <<
"finally: rmin: " << rmin <<
", rmax: " << rmax <<
" " << unit << endl;
2042 sv_frame_t frameOff = toFrame - fromFrame;
2046 newCentreFrame -= frameOff;
2047 }
else if (newCentreFrame >= frameOff) {
2048 newCentreFrame -= frameOff;
2054 SVDEBUG <<
"Pane::dragTopLayer: dragged from x = " 2056 <<
", from frame = " << fromFrame
2057 <<
" to " << toFrame
2058 <<
", for frame offset of " << frameOff << endl;
2059 SVDEBUG <<
"Pane::dragTopLayer: newCentreFrame = " << newCentreFrame
2066 if (newCentreFrame > 0) --newCentreFrame;
2077 double vmin = 0.f, vmax = 0.f;
2078 double dmin = 0.f, dmax = 0.f;
2085 double perpix = (dmax - dmin) / height();
2086 double valdiff = ydiff * perpix;
2095 if (newmin < vmin) {
2096 newmax += vmin - newmin;
2097 newmin += vmin - newmin;
2099 if (newmax > vmax) {
2100 newmin -= newmax - vmax;
2101 newmax -= newmax - vmax;
2116 bool canMoveHorizontal,
2117 bool canMoveVertical,
2118 bool resistHorizontal,
2119 bool resistVertical)
2121 int xdiff = point.x() - origin.x();
2122 int ydiff = point.y() - origin.y();
2124 int smallThreshold = 10, bigThreshold = 80;
2136 if (abs(ydiff) > smallThreshold &&
2137 abs(ydiff) > abs(xdiff) * 2 &&
2141 }
else if (abs(xdiff) > smallThreshold &&
2142 abs(xdiff) > abs(ydiff) * 2 &&
2143 canMoveHorizontal) {
2146 }
else if (abs(xdiff) > smallThreshold &&
2147 abs(ydiff) > smallThreshold &&
2149 canMoveHorizontal) {
2156 if (abs(xdiff) > bigThreshold) dragMode =
FreeDrag;
2160 if (abs(ydiff) > bigThreshold) dragMode =
FreeDrag;
2164 if (!resistHorizontal && xdiff != 0) {
2167 if (!resistVertical && ydiff != 0) {
2181 sv_frame_t snapFrameLeft = mouseFrame;
2182 sv_frame_t snapFrameRight = mouseFrame;
2186 !qobject_cast<TimeRulerLayer *>(layer)) {
2195 if (snapFrameLeft < 0) snapFrameLeft = 0;
2196 if (snapFrameRight < 0) snapFrameRight = 0;
2198 sv_frame_t min, max;
2201 min = snapFrameLeft;
2205 max = snapFrameRight;
2207 min = snapFrameLeft;
2208 max = snapFrameRight;
2212 if (min > end) min = end;
2213 if (max > end) max = end;
2242 bool doScroll =
false;
2251 sv_frame_t move = 0;
2252 sv_frame_t rightEdge = available - (available / 20);
2253 sv_frame_t leftEdge = (available / 10);
2254 if (offset >= rightEdge) {
2255 move = offset - rightEdge + 1;
2256 }
else if (offset <= leftEdge) {
2257 move = offset - leftEdge - 1;
2269 if (e->buttons() & Qt::RightButton) {
2273 cerr <<
"mouseDoubleClickEvent" << endl;
2288 (e->buttons() & Qt::MidButton));
2303 if (layer->
editOpen(
this, e)) relocate =
false;
2323 double vmin, vmax, dmin, dmax;
2330 std::cerr <<
"double click in note edit mode" << std::endl;
2352 if (previouslyIdentifying) update();
2369 int dx = e->angleDelta().x();
2370 int dy = e->angleDelta().y();
2372 if (dx == 0 && dy == 0) {
2377 bool horizontal =
false;
2379 if (abs(dx) > abs(dy)) {
2382 }
else if (e->modifiers() & Qt::ControlModifier) {
2387 if (e->phase() == Qt::ScrollBegin ||
2388 std::abs(d) >= 120 ||
2390 (d < 0 && m_pendingWheelAngle > 0)) {
2396 if (horizontal && e->pixelDelta().x() != 0) {
2444 if (mods & Qt::ShiftModifier) {
2452 }
else if (mods & Qt::AltModifier) {
2469 ZoomConstraint::RoundDown);
2472 ZoomConstraint::RoundUp);
2501 int delta = int(round(
m_zoomLevel.pixelsToFrames(pixels)));
2524 Layer *layer =
nullptr;
2527 int defaultStep = 0;
2544 double vmin, vmax, dmin, dmax;
2547 double newmax = vmin + ((1.0 - y0) * (vmax - vmin));
2548 double newmin = vmin + ((1.0 - y1) * (vmax - vmin));
2557 double vmin, vmax, dmin, dmax;
2564 QMenu *m =
new QMenu;
2568 .arg(dmin).arg(dmax).arg(unit));
2573 m->popup(
m_vpan->mapToGlobal(pos));
2582 double vmin, vmax, dmin, dmax;
2590 tr(
"New vertical display range, from %1 to %2 %3:")
2591 .arg(vmin).arg(vmax).arg(unit),
2592 unit,
float(vmin),
float(vmax),
this);
2593 dialog.
setRange(
float(dmin),
float(dmax));
2595 if (dialog.exec() == QDialog::Accepted) {
2596 float newmin, newmax;
2623 QStringList formats(e->mimeData()->formats());
2624 cerr <<
"dragEnterEvent: format: " 2625 << formats.join(
",")
2626 <<
", possibleActions: " << e->possibleActions()
2627 <<
", proposedAction: " << e->proposedAction() << endl;
2629 if (e->mimeData()->hasFormat(
"text/uri-list") ||
2630 e->mimeData()->hasFormat(
"text/plain")) {
2632 if (e->proposedAction() & Qt::CopyAction) {
2633 e->acceptProposedAction();
2635 e->setDropAction(Qt::CopyAction);
2644 cerr <<
"dropEvent: text: \"" << e->mimeData()->text()
2647 if (e->mimeData()->hasFormat(
"text/uri-list") ||
2648 e->mimeData()->hasFormat(
"text/plain")) {
2650 if (e->proposedAction() & Qt::CopyAction) {
2651 e->acceptProposedAction();
2653 e->setDropAction(Qt::CopyAction);
2657 if (e->mimeData()->hasFormat(
"text/uri-list")) {
2659 SVDEBUG <<
"accepting... data is \"" << e->mimeData()->data(
"text/uri-list").data() <<
"\"" << endl;
2661 (e->mimeData()->data(
"text/uri-list").data())
2662 .split(QRegExp(
"[\\r\\n]+"),
2663 QString::SkipEmptyParts));
2666 (e->mimeData()->data(
"text/plain").data()));
2680 bool closeToLeft, closeToRight;
2682 if (s.isEmpty())
return false;
2706 if (offset == 0 || !layer) {
2717 Selection newSelection(f0, f1);
2722 (tr(
"Drag Selection"),
true);
2729 (tr(
"Resize Selection"),
true);
2737 newSelection = Selection(f0, f1);
2758 QBitmap(
":/icons/measure1mask.xbm"),
2761 QBitmap(
":/icons/measure2mask.xbm"),
2768 setCursor(Qt::PointingHandCursor);
2772 setCursor(Qt::ArrowCursor);
2776 setCursor(Qt::UpArrowCursor);
2780 setCursor(Qt::CrossCursor);
2784 setCursor(Qt::CrossCursor);
2793 setCursor(Qt::UpArrowCursor);
2833 Layer *layer =
nullptr;
2845 RangeMapper *rm =
nullptr;
2860 Layer *layer =
nullptr;
2885 bool editable =
false;
2893 help = tr(
"Click and drag to navigate; use mouse-wheel or trackpad-scroll to zoom; hold Shift and drag to zoom to an area");
2901 if (haveSelection) {
2904 help = tr(
"Click and drag to select a range; hold Shift to avoid snapping to items; hold Cmd for multi-select; middle-click and drag to navigate");
2906 help = tr(
"Click and drag to select a range; hold Cmd for multi-select; middle-click and drag to navigate");
2910 help = tr(
"Click and drag to select a range; hold Shift to avoid snapping to items; hold Ctrl for multi-select; middle-click and drag to navigate");
2912 help = tr(
"Click and drag to select a range; hold Ctrl for multi-select; middle-click and drag to navigate");
2917 bool closeToLeft =
false, closeToRight =
false;
2918 Selection selection =
getSelectionAt(pos->x(), closeToLeft, closeToRight);
2919 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) {
2921 help = tr(
"Click and drag to move the selection boundary");
2926 help = tr(
"Click and drag to select a range; hold Shift to avoid snapping to items; middle-click to navigate");
2928 help = tr(
"Click and drag to select a range; middle-click and drag to navigate");
2936 help = tr(
"Click to add a new item in the active layer");
2943 help = tr(
"Click to erase an item from the active layer");
2950 help = tr(
"Click and drag an item in the active layer to move it; hold Shift to override initial resistance");
2952 bool closeToLeft =
false, closeToRight =
false;
2953 Selection selection =
getSelectionAt(pos->x(), closeToLeft, closeToRight);
2954 if (!selection.isEmpty()) {
2955 help = tr(
"Click and drag to move all items in the selected range");
2967 QWidget *w =
dynamic_cast<QWidget *
>(sender());
2971 emit
contextHelpChanged(tr(
"Click and drag to adjust the visible range of the vertical scale"));
2977 emit
contextHelpChanged(tr(
"Reset horizontal and vertical zoom levels to their defaults"));
2989 QString indent, QString extraAttributes)
const 2993 QString(
"type=\"pane\" centreLineVisible=\"%1\" height=\"%2\" %3")
void setDefaultValue(int deft)
static QCursor * m_measureCursor1
!! ugh
virtual void leaveEvent(QEvent *e) override
bool haveInProgressSelection() const
virtual void modelAlignmentCompletionChanged(ModelId) override
void drawFeatureDescription(Layer *, QPainter &)
static LayerFactory * getInstance()
void paintEvent(QPaintEvent *e) override
static void registerShortcuts(KeyReference &kr)
virtual bool isLayerDormant(const LayerGeometryProvider *v) const
Return whether the layer is dormant (i.e.
virtual void paintVerticalScale(LayerGeometryProvider *, bool, QPainter &, QRect) const
virtual bool snapToFeatureFrame(LayerGeometryProvider *, sv_frame_t &, int &resolution, SnapType, int) const
Adjust the given frame to snap to the nearest feature, if possible.
bool m_playbackFrameMoveScheduled
bool hasTopLayerTimeXAxis() const
The base class for visual representations of the data found in a Model.
void setRangeMapper(RangeMapper *mapper)
View scrolls continuously during playback, keeping the playback position at the centre.
NotifyingPushButton * m_reset
void zoomToRegion(QRect r)
virtual void eraseDrag(LayerGeometryProvider *, QMouseEvent *)
bool shouldShowWorkTitle() const
void propertyContainerSelected(PropertyContainer *pc)
int scalePixelSize(int size) const override
void drawLayerNames(QRect, QPainter &)
int getId() const override
Retrieve the id of this object.
Selection getContainingSelection(sv_frame_t frame, bool defaultToFollowing) const override
Return the selection that contains a given frame.
virtual void drawDrag(LayerGeometryProvider *, QMouseEvent *)
static QCursor * m_measureCursor2
static int scalePixelSize(int pixels)
Take a "design pixel" size and scale it for the actual display.
virtual void eraseStart(LayerGeometryProvider *, QMouseEvent *)
bool getAlignMode() const override
virtual void dropEvent(QDropEvent *e) override
ZoomLevel getZoomConstraintLevel(ZoomLevel level, ZoomConstraint::RoundingDirection dir=ZoomConstraint::RoundNearest) const
virtual void dragEnterEvent(QDragEnterEvent *e) override
Selection m_editingSelection
sv_samplerate_t getModelsSampleRate() const
void doubleClickSelectInvoked(sv_frame_t frame)
static QString abbreviate(QString text, int maxLength, Policy policy=ElideEnd, bool fuzzy=true, QString ellipsis="")
Abbreviate the given text to the given maximum length (including ellipsis), using the given abbreviat...
virtual int getLayerCount() const
Return the number of layers, regardless of whether visible or dormant, i.e.
void startCompoundOperation(QString name, bool execute)
Start recording commands to batch up into a single compound command.
void endCompoundOperation()
Finish recording commands and store the compound command.
void edgeScrollMaybe(int x)
int getVerticalScaleWidth() const
virtual QString getFeatureDescription(LayerGeometryProvider *, QPoint &) const
void mouseEnteredWidget()
void drawAlignmentStatus(QRect, QPainter &, ModelId, bool down)
void dragTopLayer(QMouseEvent *e)
bool shouldIlluminateLocalFeatures() const
QColor getForeground() const override
virtual void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const override
virtual void drawEnd(LayerGeometryProvider *, QMouseEvent *)
virtual bool getValueExtents(double &min, double &max, bool &logarithmic, QString &unit) const =0
Return the minimum and maximum values for the y axis of the model in this layer, as well as whether t...
virtual void wheelEvent(QWheelEvent *e) override
sv_frame_t alignToReference(sv_frame_t) const
void scroll(bool up)
Move up (if up is true) or down a bit.
void dropAccepted(QStringList uriList)
sv_samplerate_t getMainModelSampleRate() const
The sample rate of the current main model.
const Selection & getInProgressSelection(bool &exclusive) const
int m_editingSelectionEdge
bool getTopLayerDisplayExtents(double &valueMin, double &valueMax, double &displayMin, double &displayMax, QString *unit=0)
virtual void propertyContainerSelected(View *, PropertyContainer *pc) override
Selection getSelectionAt(int x, bool &closeToLeft, bool &closeToRight) const
void drawVerticalScale(QRect r, Layer *, QPainter &)
virtual RangeMapper * getNewVerticalZoomRangeMapper() const
Create and return a range mapper for vertical zoom step values.
void removeSelection(const Selection &selection)
void addSelection(const Selection &selection)
virtual void measureDoubleClick(LayerGeometryProvider *, QMouseEvent *)
double m_dragStartMinValue
virtual Layer * getTopLayer()
Return the "top" layer in the view, whether visible or dormant.
void verticalPannerContextMenuRequested(const QPoint &)
virtual void toolModeChanged() override
virtual void moveSelection(Selection, sv_frame_t)
virtual void measureDrag(LayerGeometryProvider *, QMouseEvent *)
sv_samplerate_t getPlaybackSampleRate() const
The sample rate that is used for playback.
void drawModelTimeExtents(QRect, QPainter &, ModelId)
void setMinimumValue(int min)
void drawDurationAndRate(QRect, ModelId, sv_samplerate_t, QPainter &)
virtual bool shouldIlluminateLocalSelection(QPoint &pos, bool &closeToLeft, bool &closeToRight) const override
ToolMode getToolModeFor(const View *v) const
Return override mode if it exists for this view or global mode otherwise.
virtual void setPaintFont(QPainter &paint)
virtual sv_frame_t getFirstVisibleFrame() const override
virtual void zoomWheelsEnabledChanged() override
void setMaximumValue(int max)
virtual void zoomToRegion(const LayerGeometryProvider *, QRect)
Update the X and Y axis scales, where appropriate, to focus on the given rectangular region...
sv_frame_t getFrameForX(int x) const override
Return the closest frame to the given pixel x-coordinate.
void drawEditingSelection(QPainter &)
virtual void mouseDoubleClickEvent(QMouseEvent *e) override
ZoomLevel getZoomLevel() const override
Return the zoom level, i.e.
virtual bool render(QPainter &paint, int x0, sv_frame_t f0, sv_frame_t f1)
void schedulePlaybackFrameMove(sv_frame_t frame)
void regionOutlined(QRect rect)
QColor getBackground() const override
void horizontalThumbwheelMoved(int value)
void setStartFrame(sv_frame_t)
Set the widget pan based on the given first visible frame.
virtual void viewZoomLevelChanged(View *, ZoomLevel, bool)
void paneInteractedWith()
int getZoomLevelIndex(ZoomLevel level) const
bool setTopLayerDisplayExtents(double displayMin, double displayMax)
virtual QImage * renderPartToNewImage(sv_frame_t f0, sv_frame_t f1) override
Render the view contents between the given frame extents to a new QImage (which may be wider than the...
virtual void addNote(LayerGeometryProvider *, QMouseEvent *)
void setInProgressSelection(const Selection &selection, bool exclusive)
virtual void paintEvent(QPaintEvent *e) override
virtual void setVerticalZoomStep(int)
Set the vertical zoom step.
Layer * getScaleProvidingLayerForUnit(QString unit) const
void setPlaybackFrame(sv_frame_t)
virtual QString getLayerPresentationName() const
virtual bool isLayerOpaque() const
This should return true if the layer completely obscures any underlying layers.
bool shouldShowFrameCount() const
virtual void mousePressEvent(QMouseEvent *e) override
virtual void setZoomLevel(ZoomLevel z)
Set the zoom level, i.e.
int countZoomLevels() const
void editVerticalPannerExtents()
Layer * getTopFlexiNoteLayer()
virtual void viewZoomLevelChanged(View *, ZoomLevel, bool locked) override
virtual void layerParametersChanged()
virtual void mouseMoveEvent(QMouseEvent *e) override
bool editSelectionDrag(QMouseEvent *e)
void playbackScheduleTimerElapsed()
ZoomLevel getZoomLevelByIndex(int ix) const
bool editSelectionStart(QMouseEvent *e)
virtual QSize getRenderedPartImageSize(sv_frame_t f0, sv_frame_t f1) override
Calculate and return the size of image that will be generated by renderPartToNewImage(f0, f1).
void updateVerticalPanner()
void setCategory(QString category)
void wheelVertical(int sign, Qt::KeyboardModifiers)
void setSpeed(float speed)
virtual void enterEvent(QEvent *e) override
sv_frame_t m_dragCentreFrame
sv_frame_t m_selectionStartFrame
QMenu * m_lastVerticalPannerContextMenu
virtual void resizeEvent(QResizeEvent *e) override
void rightButtonMenuRequested(QPoint position)
bool canTopLayerMoveVertical()
virtual bool shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos) const override
void verticalZoomChanged()
bool shouldShowVerticalColourScale() const
virtual void measureEnd(LayerGeometryProvider *, QMouseEvent *)
static CommandHistory * getInstance()
QWidget * m_headsUpDisplay
virtual void editEnd(LayerGeometryProvider *, QMouseEvent *)
virtual Layer * getLayer(int n)
Return the nth layer, counted in stacking order.
virtual bool render(QPainter &paint, int x0, sv_frame_t f0, sv_frame_t f1) override
bool shouldShowVerticalScale() const
bool editSelectionEnd(QMouseEvent *e)
int getDefaultValue() const
virtual void mouseReleaseEvent(QMouseEvent *e) override
PlaybackFollowMode m_followPlay
void contextHelpChanged(const QString &)
virtual void editDrag(LayerGeometryProvider *, QMouseEvent *)
void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const override
virtual void splitEnd(LayerGeometryProvider *, QMouseEvent *)
bool shouldShowCentreLine() const
void setCentreFrame(sv_frame_t f)
Set the centre frame of the visible widget.
void clearInProgressSelection()
bool shouldShowDuration() const
bool shouldShowLayerNames() const
void updateHeadsUpDisplay()
int getProgressBarWidth() const
bool hasLightBackground() const override
LayerType getLayerType(const Layer *)
virtual void modelAlignmentCompletionChanged(ModelId)
void setSelection(const Selection &selection)
void wheelHorizontal(int sign, Qt::KeyboardModifiers)
virtual bool setDisplayExtents(double, double)
Set the displayed minimum and maximum values for the y axis to the given range, if supported...
View is the base class of widgets that display one or more overlaid views of data against a horizonta...
virtual void editStart(LayerGeometryProvider *, QMouseEvent *)
virtual void splitStart(LayerGeometryProvider *, QMouseEvent *)
virtual int getCurrentVerticalZoomStep() const
Get the current vertical zoom step.
void wheelHorizontalFine(int pixels, Qt::KeyboardModifiers)
virtual bool isLayerEditable() const
This should return true if the layer can be edited by the user.
void verticalThumbwheelMoved(int value)
virtual void mouseMoveEvent(LayerGeometryProvider *v, QMouseEvent *)
virtual int getVerticalZoomSteps(int &) const
Get the number of vertical zoom steps available for this layer.
const MultiSelection::SelectionList & getSelections() const override
virtual bool hasTimeXAxis() const
Return true if the X axis on the layer is time proportional to audio frames, false otherwise...
sv_frame_t getStartFrame() const override
Retrieve the first visible sample frame on the widget.
virtual bool getDisplayExtents(double &, double &) const
Return the minimum and maximum values within the visible area for the y axis of this layer...
void verticalPannerMoved(float x, float y, float w, float h)
void setRectExtents(float x0, float y0, float width, float height)
Set the extents of the panned rectangle within the overall panner widget.
int getMaximumValue() const
static void drawVisibleText(const LayerGeometryProvider *, QPainter &p, int x, int y, QString text, TextStyle style)
virtual void measureStart(LayerGeometryProvider *, QMouseEvent *)
bool getZoomWheelsEnabled() const
sv_frame_t getModelsEndFrame() const override
sv_frame_t getEndFrame() const override
Retrieve the last visible sample frame on the widget.
void registerAlternativeShortcut(QAction *, QString alternative)
virtual void resizeSelection(Selection, Selection)
void resetVerticalPannerExtents()
View follows playback page-by-page, and the play head is moved (by the user) separately from dragging...
QPen scalePen(QPen pen) const override
DragMode updateDragMode(DragMode currentMode, QPoint origin, QPoint currentPoint, bool canMoveHorizontal, bool canMoveVertical, bool resistHorizontal, bool resistVertical)
void updateContextHelp(const QPoint *pos)
virtual int getVerticalScaleWidth(LayerGeometryProvider *, bool detailed, QPainter &) const =0
void registerShortcut(QAction *, QString overrideName="")
void dragExtendSelection(QMouseEvent *e)
virtual sv_frame_t getFirstVisibleFrame() const
void drawWorkTitle(QRect, QPainter &, ModelId)
virtual Layer * getInteractionLayer()
Return the layer currently active for tool interaction.
virtual void layerParametersChanged() override
void setAlpha(int backgroundAlpha, int thumbAlpha)
bool getOpportunisticEditingEnabled() const
virtual void paintMeasurementRects(LayerGeometryProvider *, QPainter &, bool showFocus, QPoint focusPoint) const
bool selectionIsBeingEdited() const
virtual bool nearestMeasurementRectChanged(LayerGeometryProvider *, QPoint prev, QPoint now) const
void drawCentreLine(sv_samplerate_t, QPainter &, bool omitLine)
virtual bool editOpen(LayerGeometryProvider *, QMouseEvent *)
Open an editor on the item under the mouse (e.g.
sv_frame_t m_playbackFrameMoveTo
int getXForFrame(sv_frame_t frame) const override
Return the pixel x-coordinate corresponding to a given sample frame.
virtual void drawStart(LayerGeometryProvider *, QMouseEvent *)
virtual QSize getRenderedPartImageSize(sv_frame_t f0, sv_frame_t f1)
Calculate and return the size of image that will be generated by renderPartToNewImage(f0, f1).
void setCentreLineVisible(bool visible)
virtual void eraseEnd(LayerGeometryProvider *, QMouseEvent *)