18 #include "data/model/Model.h" 19 #include "base/ZoomConstraint.h" 20 #include "base/Profiler.h" 21 #include "base/Pitch.h" 22 #include "base/Preferences.h" 23 #include "base/HitCount.h" 30 #include "data/model/RelativelyFineZoomConstraint.h" 31 #include "data/model/RangeSummarisableTimeValueModel.h" 36 #include <QPaintEvent> 38 #include <QApplication> 39 #include <QProgressDialog> 40 #include <QTextStream> 42 #include <QMessageBox> 43 #include <QPushButton> 45 #include <QSvgGenerator> 60 m_zoomLevel(ZoomLevel::FramesPerPixel, 1024),
64 m_followPlayIsDetached(false),
65 m_playPointerFrame(0),
66 m_showProgress(showProgress),
70 m_cacheCentreFrame(0),
71 m_cacheZoomLevel(ZoomLevel::FramesPerPixel, 1024),
72 m_selectionCached(false),
74 m_haveSelectedLayer(false),
75 m_useAligningProxy(false),
76 m_alignmentProgressBar({ {},
nullptr }),
93 PropertyContainer::PropertyList
96 PropertyContainer::PropertyList list;
97 list.push_back(
"Global Scroll");
98 list.push_back(
"Global Zoom");
99 list.push_back(
"Follow Playback");
106 if (pn ==
"Global Scroll")
return tr(
"Global Scroll");
107 if (pn ==
"Global Zoom")
return tr(
"Global Zoom");
108 if (pn ==
"Follow Playback")
return tr(
"Follow Playback");
112 PropertyContainer::PropertyType
115 if (name ==
"Global Scroll")
return PropertyContainer::ToggleProperty;
116 if (name ==
"Global Zoom")
return PropertyContainer::ToggleProperty;
117 if (name ==
"Follow Playback")
return PropertyContainer::ValueProperty;
118 return PropertyContainer::InvalidProperty;
123 int *min,
int *max,
int *deflt)
const 125 if (deflt) *deflt = 1;
128 if (name ==
"Follow Playback") {
140 if (deflt) *deflt = 0;
148 if (name ==
"Follow Playback") {
151 case 0:
return tr(
"Scroll");
152 case 1:
return tr(
"Page");
153 case 2:
return tr(
"Off");
156 return tr(
"<unknown>");
162 if (name ==
"Global Scroll") {
164 }
else if (name ==
"Global Zoom") {
166 }
else if (name ==
"Follow Playback") {
182 const PropertyContainer *
185 return (
const PropertyContainer *)(((
View *)
this)->
198 double &min,
double &max,
201 #ifdef DEBUG_VIEW_SCALE_CHOICE 202 SVCERR <<
"View[" <<
getId() <<
"]::getVisibleExtentsForUnit(" 203 << unit <<
")" << endl;
209 double layerMin, layerMax;
212 #ifdef DEBUG_VIEW_SCALE_CHOICE 213 SVCERR <<
"View[" <<
getId() <<
"]::getVisibleExtentsForUnit(" 214 << unit <<
"): No scale-providing layer for this unit, " 215 <<
"taking union of extents of layers with this unit" << endl;
217 bool haveAny =
false;
222 layerLog, layerUnit)) {
223 if (unit.toLower() != layerUnit.toLower()) {
226 if (!haveAny || layerMin < min) {
229 if (!haveAny || layerMax > max) {
232 if (!haveAny || layerLog) {
265 Layer *dormantOption =
nullptr;
271 #ifdef DEBUG_VIEW_SCALE_CHOICE 272 SVCERR <<
"View[" <<
getId() <<
"]::getScaleProvidingLayerForUnit(" 273 << unit <<
"): Looking at layer " << layer
278 double layerMin = 0.0, layerMax = 0.0;
279 bool layerLog =
false;
281 if (!layer->
getValueExtents(layerMin, layerMax, layerLog, layerUnit)) {
282 #ifdef DEBUG_VIEW_SCALE_CHOICE 283 SVCERR <<
"... it has no value extents" << endl;
288 if (layerUnit.toLower() != unit.toLower()) {
289 #ifdef DEBUG_VIEW_SCALE_CHOICE 290 SVCERR <<
"... it has the wrong unit (" << layerUnit <<
")" << endl;
295 double displayMin = 0.0, displayMax = 0.0;
297 #ifdef DEBUG_VIEW_SCALE_CHOICE 298 SVCERR <<
"... it has no display extents (is auto-aligning or not alignable)" << endl;
304 #ifdef DEBUG_VIEW_SCALE_CHOICE 305 SVCERR <<
"... it's dormant" << endl;
307 if (!dormantOption) {
308 dormantOption = layer;
313 #ifdef DEBUG_VIEW_SCALE_CHOICE 314 SVCERR <<
"... it's good" << endl;
319 return dormantOption;
324 bool &log, QString &unit)
const 340 double layerMin = 0.0, layerMax = 0.0;
341 bool layerLog =
false;
343 if (!layer->
getValueExtents(layerMin, layerMax, layerLog, layerUnit)) {
346 if (layerUnit ==
"") {
350 double displayMin = 0.0, displayMax = 0.0;
369 std::map<int, Layer *> sortedLayers;
371 for (LayerList::const_iterator i =
m_layerStack.begin();
373 if ((*i)->needsTextLabelHeight()) {
374 sortedLayers[(*i)->getExportId()] = *i;
380 for (std::map<int, Layer *>::const_iterator i = sortedLayers.begin();
381 i != sortedLayers.end(); ++i) {
382 if (i->second == layer)
break;
383 y += paint.fontMetrics().height();
392 if (client !=
this)
return;
404 Layer *selectedLayer =
nullptr;
466 bool changeVisible =
false;
470 <<
" to " << f << endl;
478 if (
m_zoomLevel.zone == ZoomLevel::PixelsPerFrame) {
481 SVCERR <<
"View[" <<
getId() <<
"]::setCentreFrame: in PixelsPerFrame zone, so change must be visible" << endl;
484 changeVisible =
true;
488 int formerPixel = int(formerCentre /
m_zoomLevel.level);
491 if (newPixel != formerPixel) {
494 SVCERR <<
"View[" <<
getId() <<
"]::setCentreFrame: newPixel " << newPixel <<
", formerPixel " << formerPixel << endl;
500 SVCERR <<
"View[" <<
getId()
501 <<
"]::setCentreFrame: centre frame rounded to " 507 changeVisible =
true;
514 SVCERR <<
"View[" <<
getId() <<
"]::setCentreFrame(" << f
516 <<
", emitting centreFrameChanged with aligned frame " 523 return changeVisible;
537 bool inRange =
false;
538 if (
m_zoomLevel.zone == ZoomLevel::FramesPerPixel) {
539 inRange = ((fdiff / level) < sv_frame_t(INT_MAX) &&
540 (fdiff / level) > sv_frame_t(INT_MIN));
542 inRange = (fdiff < sv_frame_t(INT_MAX) / level &&
543 fdiff > sv_frame_t(INT_MIN) / level);
550 if (
m_zoomLevel.zone == ZoomLevel::FramesPerPixel) {
551 sv_frame_t roundedCentreFrame = (m_centreFrame / level) * level;
552 fdiff = frame - roundedCentreFrame;
553 adjusted = fdiff / level;
554 if ((fdiff < 0) && ((fdiff % level) != 0)) {
558 adjusted = fdiff * level;
561 adjusted = adjusted + (width()/2);
563 if (adjusted > INT_MAX || adjusted < INT_MIN) {
566 result = int(adjusted);
571 SVCERR <<
"ERROR: Frame " << frame
572 <<
" is out of range in View::getXForFrame" << endl;
573 SVCERR <<
"ERROR: (centre frame = " <<
getCentreFrame() <<
", fdiff = " 574 << fdiff <<
", zoom level = " <<
m_zoomLevel <<
")" << endl;
575 SVCERR <<
"ERROR: This is a logic error: getXForFrame should not be " 576 <<
"called for locations unadjacent to the current view" 582 if (
m_zoomLevel.zone == ZoomLevel::PixelsPerFrame) {
584 if (reversed != frame) {
585 SVCERR <<
"View[" <<
getId() <<
"]::getXForFrame: WARNING: Converted frame " << frame <<
" to x " << result <<
" in PixelsPerFrame zone, but the reverse conversion gives frame " << reversed <<
" (error = " << reversed - frame <<
")" << endl;
587 << fdiff <<
", level = " << level <<
", centre % level = " 589 << (fdiff % level) <<
", frame % level = " 590 << (frame % level) <<
", reversed % level = " 591 << (reversed % level) <<
")" << endl;
617 int diff = x - (width()/2);
619 sv_frame_t fdiff, result;
621 if (
m_zoomLevel.zone == ZoomLevel::FramesPerPixel) {
622 sv_frame_t roundedCentreFrame = (
m_centreFrame / level) * level;
623 fdiff = diff * level;
624 result = fdiff + roundedCentreFrame;
626 fdiff = diff / level;
627 if ((diff < 0) && ((diff % level) != 0)) {
633 #ifdef DEBUG_VIEW_WIDGET_PAINT 648 if (
m_zoomLevel.zone == ZoomLevel::FramesPerPixel) {
651 SVCERR <<
"View[" <<
getId() <<
"]::getFrameForX: WARNING: Converted pixel " << x <<
" to frame " << result <<
" in FramesPerPixel zone, but the reverse conversion gives pixel " << reversed <<
" (error = " << reversed - x <<
")" << endl;
653 <<
", width/2 = " << width()/2 <<
", diff = " << diff
654 <<
", fdiff = " << fdiff <<
", level = " << level
656 <<
", fdiff % level = " << (fdiff % level)
657 <<
", frame % level = " << (result % level) <<
")" << endl;
669 bool logarithmic)
const 671 Profiler profiler(
"View::getYForFrequency");
677 static double lastminf = 0.0, lastmaxf = 0.0;
678 static double logminf = 0.0, logmaxf = 0.0;
680 if (lastminf != minf) {
681 lastminf = (minf == 0.0 ? 1.0 : minf);
682 logminf = log10(minf);
684 if (lastmaxf != maxf) {
685 lastmaxf = (maxf < lastminf ? lastminf : maxf);
686 logmaxf = log10(maxf);
689 if (logminf == logmaxf)
return 0;
690 return h - (h * (log10(frequency) - logminf)) / (logmaxf - logminf);
694 if (minf == maxf)
return 0;
695 return h - (h * (frequency - minf)) / (maxf - minf);
703 bool logarithmic)
const 709 static double lastminf = 0.0, lastmaxf = 0.0;
710 static double logminf = 0.0, logmaxf = 0.0;
712 if (lastminf != minf) {
713 lastminf = (minf == 0.0 ? 1.0 : minf);
714 logminf = log10(minf);
716 if (lastmaxf != maxf) {
717 lastmaxf = (maxf < lastminf ? lastminf : maxf);
718 logmaxf = log10(maxf);
721 if (logminf == logmaxf)
return 0;
722 return pow(10.0, logminf + ((logmaxf - logminf) * (h - y)) / h);
726 if (minf == maxf)
return 0;
727 return minf + ((h - y) * (maxf - minf)) / h;
734 #ifdef DEBUG_VIEW_WIDGET_PAINT 744 int dpratio = devicePixelRatio();
747 settings.beginGroup(
"Preferences");
748 if (!settings.value(
"scaledHiDpi",
true).toBool()) {
776 bool darkPalette =
false;
780 bool mostSignificantHasDarkBackground =
false;
782 for (LayerList::const_iterator i =
m_layerStack.begin();
786 bool light = (*i)->hasLightBackground();
788 if (
int(s) >
int(maxSignificance)) {
790 mostSignificantHasDarkBackground = !light;
791 }
else if (s == maxSignificance && !light) {
792 mostSignificantHasDarkBackground =
true;
797 return !mostSignificantHasDarkBackground;
808 QColor widgetbg = palette().window().color();
810 (widgetbg.red() + widgetbg.green() + widgetbg.blue()) > 384;
812 if (widgetLight == light) {
814 return widgetbg.lighter();
816 return widgetbg.darker();
819 else if (light)
return Qt::white;
820 else return Qt::black;
828 QColor widgetfg = palette().text().color();
830 (widgetfg.red() + widgetfg.green() + widgetfg.blue()) > 384;
832 if (widgetLight != light)
return widgetfg;
833 else if (light)
return Qt::black;
834 else return Qt::white;
848 QProgressBar *pb =
new QProgressBar(
this);
851 pb->setFixedWidth(80);
852 pb->setTextVisible(
false);
854 QPushButton *cancel =
new QPushButton(
this);
856 cancel->setFlat(
true);
858 cancel->setFixedSize(QSize(scaled20, scaled20));
859 connect(cancel, SIGNAL(clicked()),
this, SLOT(
cancelClicked()));
872 int fs = Preferences::getInstance()->getViewFontSize();
873 f.setPointSize(std::min(fs,
int(ceil(fs * 0.85))));
1023 connect(
m_manager, SIGNAL(playbackFrameChanged(sv_frame_t)),
1033 connect(
m_manager, SIGNAL(inProgressSelectionChanged()),
1037 connect(
m_manager, SIGNAL(showCentreLineChanged()),
1106 #if defined(DEBUG_VIEW_WIDGET_PAINT) || defined(DEBUG_PROGRESS_STUFF) 1107 SVCERR <<
"View[" <<
getId() <<
"]::modelChanged(" << modelId <<
")" << endl;
1113 bool recreate =
false;
1117 for (LayerList::const_iterator i = scrollables.begin();
1118 i != scrollables.end(); ++i) {
1119 if ((*i)->getModel() == modelId) {
1138 sv_frame_t startFrame, sv_frame_t endFrame)
1143 #ifdef DEBUG_VIEW_WIDGET_PAINT 1144 SVCERR <<
"View[" <<
getId() <<
"]::modelChangedWithin(" << startFrame <<
"," << endFrame <<
") [me " << myStartFrame <<
"," << myEndFrame <<
"]" << endl;
1147 if (myStartFrame > 0 && endFrame < myStartFrame) {
1151 if (startFrame > myEndFrame) {
1159 bool recreate =
false;
1163 for (LayerList::const_iterator i = scrollables.begin();
1164 i != scrollables.end(); ++i) {
1165 if ((*i)->getModel() == modelId) {
1175 if (startFrame < myStartFrame) startFrame = myStartFrame;
1176 if (endFrame > myEndFrame) endFrame = myEndFrame;
1186 #ifdef DEBUG_PROGRESS_STUFF 1187 SVCERR <<
"View[" <<
getId() <<
"]::modelCompletionChanged(" << modelId <<
")" << endl;
1195 #ifdef DEBUG_PROGRESS_STUFF 1196 SVCERR <<
"View[" <<
getId() <<
"]::modelAlignmentCompletionChanged(" << modelId <<
")" << endl;
1204 #ifdef DEBUG_VIEW_WIDGET_PAINT 1205 SVCERR <<
"View[" <<
getId() <<
"]::modelReplaced()" << endl;
1214 Layer *layer =
dynamic_cast<Layer *
>(sender());
1216 #ifdef DEBUG_VIEW_WIDGET_PAINT 1217 SVDEBUG <<
"View::layerParametersChanged()" << endl;
1231 Layer *layer =
dynamic_cast<Layer *
>(sender());
1238 Layer *layer =
dynamic_cast<Layer *
>(sender());
1239 if (layer) update();
1245 Layer *layer =
dynamic_cast<Layer *
>(sender());
1255 SVCERR <<
"View[" <<
getId() <<
"]::globalCentreFrameChanged(" << rf
1256 <<
"): setting centre frame to " << f << endl;
1276 SVCERR <<
"View[" <<
getId() <<
"]::viewManagerPlaybackFrameChanged(" << f <<
")" << endl;
1282 SVCERR <<
" -> aligned frame = " << f << endl;
1292 SVCERR <<
"View[" <<
getId() <<
"]::movePlayPointer(" << newFrame <<
")" << endl;
1296 bool visibleChange =
1299 #ifdef DEBUG_VIEW_WIDGET_PAINT 1300 SVCERR <<
"View[" <<
getId() <<
"]::movePlayPointer: moving from " 1302 << visibleChange << endl;
1307 if (!visibleChange)
return;
1309 bool somethingGoingOn =
1310 ((QApplication::mouseButtons() != Qt::NoButton) ||
1311 (QApplication::keyboardModifiers() & Qt::AltModifier));
1313 bool pointerInVisibleArea =
1322 if (!somethingGoingOn) {
1330 if (!pointerInVisibleArea && somethingGoingOn) {
1341 update(xold - 4, 0, 9, height());
1347 sf = (sf / w) * w - w/8;
1354 if (!selections.empty()) {
1355 sv_frame_t selectionStart = selections.begin()->getStartFrame();
1356 if (sf < selectionStart - w / 10) {
1357 sf = selectionStart - w / 10;
1362 #ifdef DEBUG_VIEW_WIDGET_PAINT 1363 SVCERR <<
"PlaybackScrollPage: f = " <<
m_playPointerFrame <<
", sf = " << sf <<
", start frame " 1372 #ifdef DEBUG_VIEW_WIDGET_PAINT 1373 SVCERR <<
"xnew = " << xnew <<
", width = " << width() << endl;
1376 bool shouldScroll = (xnew > (width() * 7) / 8);
1379 shouldScroll =
true;
1382 if (xnew > width() / 8) {
1384 }
else if (somethingGoingOn) {
1388 if (!somethingGoingOn && shouldScroll) {
1390 sv_frame_t newCentre = sf + offset;
1394 update(xold - 4, 0, 9, height());
1398 update(xnew - 4, 0, 9, height());
1414 #ifdef DEBUG_VIEW_WIDGET_PAINT 1415 SVCERR <<
"View[" <<
getId() <<
"]: viewZoomLevelChanged(" << p <<
", " << z <<
", " << locked <<
")" << endl;
1437 if (f0 < 0 || f0 < f)
return f;
1446 if (f0 > f)
return f;
1454 sv_frame_t startFrame = 0;
1458 auto model = ModelById::get(layer->getModel());
1460 if (model && model->isOK()) {
1462 sv_frame_t thisStartFrame = model->getStartFrame();
1464 if (first || thisStartFrame < startFrame) {
1465 startFrame = thisStartFrame;
1478 sv_frame_t endFrame = 0;
1482 auto model = ModelById::get(layer->getModel());
1484 if (model && model->isOK()) {
1486 sv_frame_t thisEndFrame = model->getEndFrame();
1488 if (first || thisEndFrame > endFrame) {
1489 endFrame = thisEndFrame;
1510 auto model = ModelById::get(layer->getModel());
1512 if (model && model->isOK()) {
1513 return model->getSampleRate();
1529 if (dynamic_cast<TimeRulerLayer *>(layer)) {
1533 if (layer && !layer->
getModel().isNone()) {
1544 ModelId aligning, reference;
1551 ModelId &reference)
const 1563 if (!layer)
continue;
1564 if (dynamic_cast<TimeRulerLayer *>(layer))
continue;
1566 ModelId thisId = layer->getModel();
1567 auto model = ModelById::get(thisId);
1568 if (!model)
continue;
1572 if (!model->getAlignmentReference().isNone()) {
1574 if (layer->isLayerOpaque() ||
1575 std::dynamic_pointer_cast
1576 <RangeSummarisableTimeValueModel>(model)) {
1579 reference = model->getAlignmentReference();
1582 }
else if (aligning.isNone()) {
1585 reference = model->getAlignmentReference();
1590 if (aligning.isNone()) {
1591 aligning = anyModel;
1601 if (!aligningModel)
return f;
1602 return aligningModel->alignFromReference(f);
1610 if (!aligningModel)
return f;
1611 return aligningModel->alignToReference(f);
1622 if (!aligningModel)
return pf;
1624 sv_frame_t af = aligningModel->alignFromReference(pf);
1634 if (!(*i)->isLayerScrollable(
this))
return false;
1648 bool metUnscrollable =
false;
1655 if ((*i)->isLayerDormant(
this))
continue;
1656 if ((*i)->isLayerOpaque()) {
1658 scrollables.clear();
1659 if (metUnscrollable)
break;
1661 if (!metUnscrollable && (*i)->isLayerScrollable(
this)) {
1662 scrollables.push_back(*i);
1664 metUnscrollable =
true;
1684 bool started =
false;
1687 if ((*i)->isLayerDormant(
this))
continue;
1688 if (!started && (*i)->isLayerScrollable(
this)) {
1692 if ((*i)->isLayerOpaque()) {
1694 nonScrollables.clear();
1696 nonScrollables.push_back(*i);
1704 return nonScrollables;
1709 ZoomConstraint::RoundingDirection dir)
1714 ZoomLevel candidate =
1715 RelativelyFineZoomConstraint().getNearestZoomLevel(zoomLevel, dir);
1719 if (i->supportsOtherZoomLevels() || !(i->getZoomConstraint())) {
1723 ZoomLevel thisLevel =
1724 i->getZoomConstraint()->getNearestZoomLevel(zoomLevel, dir);
1728 if ((thisLevel > zoomLevel && thisLevel > candidate) ||
1729 (thisLevel < zoomLevel && thisLevel < candidate)) {
1730 candidate = thisLevel;
1741 ZoomLevel min = ZoomConstraint().getMinZoomLevel();
1742 ZoomLevel max = ZoomConstraint().getMaxZoomLevel();
1743 ZoomLevel level = min;
1750 (level.incremented(), ZoomConstraint::RoundUp);
1760 ZoomLevel min = ZoomConstraint().getMinZoomLevel();
1761 ZoomLevel max = ZoomConstraint().getMaxZoomLevel();
1762 ZoomLevel level = min;
1774 (level.incremented(), ZoomConstraint::RoundUp);
1785 ZoomLevel min = ZoomConstraint().getMinZoomLevel();
1786 ZoomLevel max = ZoomConstraint().getMaxZoomLevel();
1787 ZoomLevel level = min;
1799 (level.incremented(), ZoomConstraint::RoundUp);
1809 static double ratio = 0.0;
1818 double em = QFontMetrics(QFont()).height();
1819 ratio = em / baseEm;
1821 SVDEBUG <<
"View::scaleSize: ratio is " << ratio
1822 <<
" (em = " << em <<
")" << endl;
1825 SVDEBUG <<
"View::scaleSize: rounding ratio up to 1.0" << endl;
1830 return size * ratio;
1837 int i = int(d + 0.5);
1838 if (size != 0 && i == 0) i = 1;
1849 return width * sqrt(ratio);
1862 if ((*i)->getLayerColourSignificance() ==
1864 if ((*i)->isLayerOpaque())
break;
1875 return (*i)->hasTimeXAxis();
1885 ZoomConstraint::RoundDown);
1888 ZoomConstraint::RoundUp);
1907 if (right) delta = -delta;
1910 SVCERR <<
"View::scroll(" << right <<
", " << lots <<
", " << e <<
"): " 1911 <<
"delta = " << delta <<
", m_centreFrame = " <<
m_centreFrame 1927 QPushButton *cancel = qobject_cast<QPushButton *>(sender());
1928 if (!cancel)
return;
1930 Layer *layer =
nullptr;
1934 if (i->second.cancel == cancel) {
1949 #ifdef DEBUG_PROGRESS_STUFF 1950 SVCERR <<
"View[" <<
getId() <<
"]::checkProgress(" << modelId <<
"): " 1951 <<
"m_showProgress is off" << endl;
1956 #ifdef DEBUG_PROGRESS_STUFF 1957 SVCERR <<
"View[" <<
getId() <<
"]::checkProgress(" << modelId <<
")" << endl;
1961 settings.beginGroup(
"View");
1962 bool showCancelButton = settings.value(
"showcancelbuttons",
true).toBool();
1963 settings.endGroup();
1975 QProgressBar *pb = i->second.bar;
1976 QPushButton *cancel = i->second.cancel;
1978 if (i->first && i->first->getModel() == modelId) {
1985 QTimer *timer = i->second.stallCheckTimer;
1987 int completion = i->first->getCompletion(
this);
1988 QString error = i->first->getError(
this);
1990 #ifdef DEBUG_PROGRESS_STUFF 1991 SVCERR <<
"View[" <<
getId() <<
"]::checkProgress(" << modelId <<
"): " 1992 <<
"found progress bar " << pb <<
" for layer at height " << ph
1993 <<
": completion = " << completion << endl;
1997 QMessageBox::critical(
this, tr(
"Layer rendering error"), error);
2001 if (completion > 0) {
2002 pb->setMaximum(100);
2005 if (completion < 100 &&
2006 ModelById::isa<RangeSummarisableTimeValueModel>(modelId)) {
2010 if (completion >= 100) {
2016 }
else if (i->first->isLayerDormant(
this)) {
2022 #ifdef DEBUG_PROGRESS_STUFF 2023 SVCERR <<
"View[" <<
getId() <<
"]::checkProgress(" 2024 << modelId <<
"): layer is dormant" << endl;
2032 if (!pb->isVisible()) {
2033 i->second.lastStallCheckValue = 0;
2034 timer->setInterval(2000);
2038 if (showCancelButton) {
2042 cancel->move(0, ph - pb->height()/2 - scaled20/2);
2045 pb->setValue(completion);
2046 pb->move(scaled20, ph - pb->height());
2052 pb->setValue(completion);
2053 pb->move(0, ph - pb->height());
2059 if (pb->isVisible()) {
2064 if (pb->isVisible()) {
2071 #ifdef DEBUG_PROGRESS_STUFF 2072 SVCERR <<
"View[" <<
getId() <<
"]::checkProgress(" << modelId <<
"): " 2073 <<
"failed to find layer for model in progress map" 2083 #ifdef DEBUG_PROGRESS_STUFF 2084 SVCERR <<
"View[" <<
getId() <<
"]::checkAlignmentProgress(" << modelId <<
"): " 2085 <<
"m_showProgress is off" << endl;
2090 #ifdef DEBUG_PROGRESS_STUFF 2091 SVCERR <<
"View[" <<
getId() <<
"]::checkAlignmentProgress(" << modelId <<
")" << endl;
2096 #ifdef DEBUG_PROGRESS_STUFF 2097 SVCERR <<
"View[" <<
getId() <<
"]::checkAlignmentProgress(" << modelId <<
"): Different model (we're currently showing alignment progress for " << modelId <<
", ignoring" << endl;
2102 auto model = ModelById::get(modelId);
2104 #ifdef DEBUG_PROGRESS_STUFF 2105 SVCERR <<
"View[" <<
getId() <<
"]::checkAlignmentProgress(" << modelId <<
"): Model gone" << endl;
2113 int completion = model->getAlignmentCompletion();
2115 #ifdef DEBUG_PROGRESS_STUFF 2116 SVCERR <<
"View[" <<
getId() <<
"]::checkAlignmentProgress(" << modelId <<
"): Completion is " << completion << endl;
2121 if (completion >= 100) {
2130 pb =
new QProgressBar(
this);
2132 pb->setMaximum(100);
2133 pb->setFixedWidth(80);
2134 pb->setTextVisible(
false);
2139 pb->setValue(completion);
2140 pb->move(0, ph - pb->height());
2148 QObject *s = sender();
2149 QTimer *t = qobject_cast<QTimer *>(s);
2155 if (i->second.stallCheckTimer == t) {
2157 int value = i->second.bar->value();
2159 #ifdef DEBUG_PROGRESS_STUFF 2160 SVCERR <<
"View[" <<
getId() <<
"]::progressCheckStalledTimerElapsed for layer " << i->first <<
": value is " << value << endl;
2163 if (value > 0 && value == i->second.lastStallCheckValue) {
2164 i->second.bar->setMaximum(0);
2166 i->second.lastStallCheckValue = value;
2181 if (i->second.bar && i->second.bar->isVisible()) {
2182 return i->second.bar->width();
2192 int scaleFactor = 1;
2195 QPaintDevice *dev = paint.device();
2196 if (dynamic_cast<QPixmap *>(dev) || dynamic_cast<QImage *>(dev)) {
2197 scaleFactor = dpratio;
2201 QFont font(paint.font());
2202 int pointSize = Preferences::getInstance()->getViewFontSize() * scaleFactor;
2203 font.setPointSize(pointSize);
2206 int fh = QFontMetrics(font).height();
2207 if (pointSize > 6) {
2209 font.setPointSize(pointSize - 2);
2210 }
else if (h < fh * 3.1) {
2211 font.setPointSize(pointSize - 1);
2215 paint.setFont(font);
2229 #ifdef DEBUG_VIEW_WIDGET_PAINT 2232 SVCERR <<
"View[" <<
getId() <<
"]::paintEvent: centre frame is " <<
m_centreFrame <<
" (start frame " << startFrame <<
", height " << height() <<
")" << endl;
2237 QFrame::paintEvent(e);
2286 QRect requestedPaintArea(
scaledRect(rect(), dpratio));
2289 requestedPaintArea &=
scaledRect(e->rect(), dpratio);
2295 bool layersChanged =
false;
2299 #ifdef DEBUG_VIEW_WIDGET_PAINT 2300 SVCERR <<
"View[" <<
getId() <<
"]::paintEvent: have " << scrollables.size()
2301 <<
" scrollable back layers and " << nonScrollables.size()
2302 <<
" non-scrollable front layers" << endl;
2305 if (layersChanged || scrollables.empty()) {
2309 QRect wholeArea(
scaledRect(rect(), dpratio));
2310 QSize wholeSize(
scaledSize(size(), dpratio));
2317 bool shouldUseCache =
false;
2318 bool shouldRepaintCache =
false;
2319 QRect cacheAreaToRepaint;
2321 static HitCount count(
"View cache");
2323 if (!scrollables.empty()) {
2325 shouldUseCache =
true;
2326 shouldRepaintCache =
true;
2327 cacheAreaToRepaint = wholeArea;
2329 #ifdef DEBUG_VIEW_WIDGET_PAINT 2330 SVCERR <<
"View[" <<
getId() <<
"]: cache " <<
m_cache <<
", cache zoom " 2339 m_cache->size() != wholeSize) {
2343 if (requestedPaintArea.width() < wholeSize.width() / 10) {
2346 shouldUseCache =
false;
2347 shouldRepaintCache =
false;
2349 #ifdef DEBUG_VIEW_WIDGET_PAINT 2350 SVCERR <<
"View[" <<
getId() <<
"]::paintEvent: cache is invalid but only small area requested, will repaint directly instead" << endl;
2355 m_cache->size() != wholeSize) {
2357 m_cache =
new QPixmap(wholeSize);
2360 #ifdef DEBUG_VIEW_WIDGET_PAINT 2361 SVCERR <<
"View[" <<
getId() <<
"]::paintEvent: cache is invalid, will repaint whole" << endl;
2369 #ifdef DEBUG_VIEW_WIDGET_PAINT 2381 cacheAreaToRepaint =
2384 cacheAreaToRepaint =
2385 QRect(0, 0, dx,
m_cache->height());
2390 #ifdef DEBUG_VIEW_WIDGET_PAINT 2391 SVCERR <<
"View[" <<
getId() <<
"]::paintEvent: scrolled cache by " << dx << endl;
2395 #ifdef DEBUG_VIEW_WIDGET_PAINT 2396 SVCERR <<
"View[" <<
getId() <<
"]::paintEvent: scrolling too far" << endl;
2401 #ifdef DEBUG_VIEW_WIDGET_PAINT 2402 SVCERR <<
"View[" <<
getId() <<
"]::paintEvent: cache is good" << endl;
2405 shouldRepaintCache =
false;
2409 #ifdef DEBUG_VIEW_WIDGET_PAINT 2410 SVCERR <<
"View[" <<
getId() <<
"]::paintEvent: m_cacheValid = " <<
m_cacheValid <<
", shouldUseCache = " << shouldUseCache <<
", shouldRepaintCache = " << shouldRepaintCache <<
", cacheAreaToRepaint = " << cacheAreaToRepaint.x() <<
"," << cacheAreaToRepaint.y() <<
" " << cacheAreaToRepaint.width() <<
"x" << cacheAreaToRepaint.height() << endl;
2413 if (shouldRepaintCache && !shouldUseCache) {
2418 throw std::logic_error(
"ERROR: shouldRepaintCache is true, but shouldUseCache is false: this can't lead to the correct result");
2433 ModelId alignmentModelId;
2434 ModelId alignmentReferenceId;
2436 if (aligningModel) {
2437 alignmentModelId = aligningModel->getAlignment();
2438 alignmentReferenceId = aligningModel->getAlignmentReference();
2439 #ifdef DEBUG_VIEW_WIDGET_PAINT 2440 SVCERR <<
"alignmentModelId = " << alignmentModelId <<
" (reference = " << alignmentReferenceId <<
")" << endl;
2443 #ifdef DEBUG_VIEW_WIDGET_PAINT 2444 SVCERR <<
"no aligningModel" << endl;
2447 ViewProxy aligningProxy(
this, dpratio, alignmentModelId);
2455 if (shouldRepaintCache) {
2457 areaToPaint = cacheAreaToRepaint;
2460 areaToPaint = requestedPaintArea;
2464 paint.setClipRect(areaToPaint);
2468 paint.drawRect(areaToPaint);
2471 paint.setBrush(Qt::NoBrush);
2473 for (LayerList::iterator i = scrollables.begin();
2474 i != scrollables.end(); ++i) {
2476 paint.setRenderHint(QPainter::Antialiasing,
false);
2481 bool useAligningProxy =
false;
2483 if (layer->
getModel() == alignmentReferenceId ||
2485 useAligningProxy =
true;
2489 #ifdef DEBUG_VIEW_WIDGET_PAINT 2490 SVCERR <<
"Painting scrollable layer " << layer <<
" (model " << layer->
getModel() <<
", source model " << layer->
getSourceModel() <<
") with shouldRepaintCache = " << shouldRepaintCache <<
", useAligningProxy = " << useAligningProxy <<
", dpratio = " << dpratio <<
", areaToPaint = " << areaToPaint.x() <<
"," << areaToPaint.y() <<
" " << areaToPaint.width() <<
"x" << areaToPaint.height() << endl;
2493 layer->
paint(useAligningProxy ? &aligningProxy : &proxy,
2494 paint, areaToPaint);
2501 if (shouldRepaintCache) {
2508 if (shouldUseCache) {
2510 paint.drawPixmap(requestedPaintArea, *
m_cache, requestedPaintArea);
2517 paint.setClipRect(requestedPaintArea);
2519 if (scrollables.empty()) {
2522 paint.drawRect(requestedPaintArea);
2526 paint.setBrush(Qt::NoBrush);
2528 for (LayerList::iterator i = nonScrollables.begin();
2529 i != nonScrollables.end(); ++i) {
2533 bool useAligningProxy =
false;
2535 if (layer->
getModel() == alignmentReferenceId ||
2537 useAligningProxy =
true;
2541 #ifdef DEBUG_VIEW_WIDGET_PAINT 2542 SVCERR <<
"Painting non-scrollable layer " << layer <<
" (model " << layer->
getModel() <<
", source model " << layer->
getSourceModel() <<
") with shouldRepaintCache = " << shouldRepaintCache <<
", useAligningProxy = " << useAligningProxy <<
", dpratio = " << dpratio <<
", requestedPaintArea = " << requestedPaintArea.x() <<
"," << requestedPaintArea.y() <<
" " << requestedPaintArea.width() <<
"x" << requestedPaintArea.height() << endl;
2545 layer->
paint(useAligningProxy ? &aligningProxy : &proxy,
2546 paint, requestedPaintArea);
2556 if (e) paint.setClipRect(e->rect());
2558 QRect finalPaintRect = e ? e->rect() : rect();
2559 paint.drawPixmap(finalPaintRect, *
m_buffer,
2567 QFrame::paintEvent(e);
2575 MultiSelection::SelectionList selections;
2581 Selection inProgressSelection =
2583 if (exclusive) selections.clear();
2584 selections.insert(inProgressSelection);
2593 paint.setBrush(QColor(150, 150, 255, 80));
2595 paint.setBrush(Qt::NoBrush);
2601 sv_frame_t illuminateFrame = -1;
2602 bool closeToLeft, closeToRight;
2608 const QFontMetrics &metrics = paint.fontMetrics();
2610 for (MultiSelection::SelectionList::iterator i = selections.begin();
2611 i != selections.end(); ++i) {
2616 if (p1 < 0 || p0 > width())
continue;
2618 #ifdef DEBUG_VIEW_WIDGET_PAINT 2619 SVDEBUG <<
"View::drawSelections: " << p0 <<
",-1 [" << (p1-p0) <<
"x" << (height()+1) <<
"]" << endl;
2622 bool illuminateThis =
2623 (illuminateFrame >= 0 && i->contains(illuminateFrame));
2625 double h = height();
2627 double half = penWidth/2.0;
2629 paint.setPen(QPen(QColor(150, 150, 255), penWidth));
2632 paint.drawRect(QRectF(p0, -penWidth, p1 - p0, h + 2*penWidth));
2638 paint.drawRect(QRectF(p0, half, p1 - p0, h - penWidth));
2641 if (illuminateThis) {
2644 half = penWidth/2.0;
2647 paint.drawLine(QLineF(p0, half, p1, half));
2648 paint.drawLine(QLineF(p0, half, p0, h - half));
2649 paint.drawLine(QLineF(p0, h - half, p1, h - half));
2650 }
else if (closeToRight) {
2651 paint.drawLine(QLineF(p0, half, p1, half));
2652 paint.drawLine(QLineF(p1, half, p1, h - half));
2653 paint.drawLine(QLineF(p0, h - half, p1, h - half));
2655 paint.setBrush(Qt::NoBrush);
2656 paint.drawRect(QRectF(p0, half, p1 - p0, h - penWidth));
2664 QString startText = QString(
"%1 / %2")
2665 .arg(QString::fromStdString
2666 (RealTime::frame2RealTime
2667 (i->getStartFrame(), sampleRate).toText(
true)))
2668 .arg(i->getStartFrame());
2670 QString endText = QString(
" %1 / %2")
2671 .arg(QString::fromStdString
2672 (RealTime::frame2RealTime
2673 (i->getEndFrame(), sampleRate).toText(
true)))
2674 .arg(i->getEndFrame());
2676 QString durationText = QString(
"(%1 / %2) ")
2677 .arg(QString::fromStdString
2678 (RealTime::frame2RealTime
2679 (i->getEndFrame() - i->getStartFrame(), sampleRate)
2681 .arg(i->getEndFrame() - i->getStartFrame());
2686 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 2688 int sw = metrics.width(startText),
2689 ew = metrics.width(endText),
2690 dw = metrics.width(durationText);
2692 int sy = metrics.ascent() + metrics.height() + 4;
2694 int dy = sy + metrics.height();
2700 bool durationBothEnds =
true;
2702 if (sw + ew > (p1 - p0)) {
2703 ey += metrics.height();
2704 dy += metrics.height();
2705 durationBothEnds =
false;
2708 if (ew < (p1 - p0)) {
2712 if (dw < (p1 - p0)) {
2722 if (durationBothEnds) {
2735 bool showPlayPointer =
true;
2738 showPlayPointer =
false;
2741 showPlayPointer =
false;
2748 showPlayPointer =
false;
2752 if (showPlayPointer) {
2757 paint.drawLine(playx - 1, 0, playx - 1, height() - 1);
2758 paint.drawLine(playx + 1, 0, playx + 1, height() - 1);
2759 paint.drawPoint(playx, 0);
2760 paint.drawPoint(playx, height() - 1);
2762 paint.drawLine(playx, 1, playx, height() - 2);
2773 if (r.x() + r.width() < 0 || r.x() >= width())
return;
2775 if (r.width() != 0 || r.height() != 0) {
2778 paint.setPen(Qt::NoPen);
2779 QColor brushColour(Qt::black);
2781 paint.setBrush(brushColour);
2783 paint.drawRect(0, 0, r.x(), height());
2785 if (r.x() + r.width() < width()) {
2786 paint.drawRect(r.x() + r.width(), 0, width()-r.x()-r.width(), height());
2789 paint.drawRect(r.x(), 0, r.width(), r.y());
2791 if (r.y() + r.height() < height()) {
2792 paint.drawRect(r.x(), r.y() + r.height(), r.width(), height()-r.y()-r.height());
2794 paint.setBrush(Qt::NoBrush);
2796 paint.setPen(Qt::green);
2801 paint.setPen(Qt::green);
2802 paint.drawPoint(r.x(), r.y());
2809 QFont fn = paint.font();
2810 if (fn.pointSize() > 8) {
2811 fn.setPointSize(fn.pointSize() - 1);
2815 int fontHeight = paint.fontMetrics().height();
2816 int fontAscent = paint.fontMetrics().ascent();
2820 bool b0 =
false, b1 =
false;
2822 QString axs, ays, bxs, bys, dxs, dys;
2824 int axx, axy, bxx, bxy, dxx, dxy;
2825 int aw = 0, bw = 0, dw = 0;
2832 axs = QString(
"%1 %2").arg(v0).arg(u0);
2833 if (u0 ==
"Hz" && Pitch::isFrequencyInMidiRange(v0)) {
2834 axs = QString(
"%1 (%2)").arg(axs)
2835 .arg(Pitch::getPitchLabelForFrequency(v0));
2837 aw = paint.fontMetrics().width(axs);
2843 if (r.width() > 0) {
2844 if ((b1 = topLayer->
getXScaleValue(
this, r.x() + r.width(), v1, u1))) {
2845 bxs = QString(
"%1 %2").arg(v1).arg(u1);
2846 if (u1 ==
"Hz" && Pitch::isFrequencyInMidiRange(v1)) {
2847 bxs = QString(
"%1 (%2)").arg(bxs)
2848 .arg(Pitch::getPitchLabelForFrequency(v1));
2850 bw = paint.fontMetrics().width(bxs);
2856 if (b0 && b1 && v1 != v0 && u0 == u1) {
2857 dxs = QString(
"[%1 %2]").arg(fabs(v1 - v0)).arg(u1);
2858 dw = paint.fontMetrics().width(dxs);
2867 ays = QString(
"%1 %2").arg(v0).arg(u0);
2868 if (u0 ==
"Hz" && Pitch::isFrequencyInMidiRange(v0)) {
2869 ays = QString(
"%1 (%2)").arg(ays)
2870 .arg(Pitch::getPitchLabelForFrequency(v0));
2872 aw = std::max(aw, paint.fontMetrics().width(ays));
2878 if (r.height() > 0) {
2879 if ((b1 = topLayer->
getYScaleValue(
this, r.y() + r.height(), v1, u1))) {
2880 bys = QString(
"%1 %2").arg(v1).arg(u1);
2881 if (u1 ==
"Hz" && Pitch::isFrequencyInMidiRange(v1)) {
2882 bys = QString(
"%1 (%2)").arg(bys)
2883 .arg(Pitch::getPitchLabelForFrequency(v1));
2885 bw = std::max(bw, paint.fontMetrics().width(bys));
2902 semis = Pitch::getPitchForFrequencyDifference(v0, v1, ¢s);
2903 dys = QString(
"[%1 %2 (%3)]")
2905 .arg(Pitch::getLabelForPitchRange(semis, cents));
2907 dys = QString(
"[%1 %2]").arg(dy).arg(du);
2910 dys = QString(
"[%1]").arg(dy);
2912 dw = std::max(dw, paint.fontMetrics().width(dys));
2916 int mh = r.height();
2918 bool edgeLabelsInside =
false;
2919 bool sizeLabelsInside =
false;
2921 if (mw < std::max(aw, std::max(bw, dw)) + 4) {
2923 }
else if (mw < aw + bw + 4) {
2924 if (mh > fontHeight * labelCount * 3 + 4) {
2925 edgeLabelsInside =
true;
2926 sizeLabelsInside =
true;
2927 }
else if (mh > fontHeight * labelCount * 2 + 4) {
2928 edgeLabelsInside =
true;
2930 }
else if (mw < aw + bw + dw + 4) {
2931 if (mh > fontHeight * labelCount * 3 + 4) {
2932 edgeLabelsInside =
true;
2933 sizeLabelsInside =
true;
2934 }
else if (mh > fontHeight * labelCount + 4) {
2935 edgeLabelsInside =
true;
2938 if (mh > fontHeight * labelCount + 4) {
2939 edgeLabelsInside =
true;
2940 sizeLabelsInside =
true;
2944 if (edgeLabelsInside) {
2947 axy = r.y() + fontAscent + 2;
2949 bxx = r.x() + r.width() - bw - 2;
2950 bxy = r.y() + r.height() - (labelCount-1) * fontHeight - 2;
2954 axx = r.x() - aw - 2;
2955 axy = r.y() + fontAscent;
2957 bxx = r.x() + r.width() + 2;
2958 bxy = r.y() + r.height() - (labelCount-1) * fontHeight;
2961 dxx = r.width()/2 + r.x() - dw/2;
2963 if (sizeLabelsInside) {
2965 dxy = r.height()/2 + r.y() - (labelCount * fontHeight)/2 + fontAscent;
2969 dxy = r.y() + r.height() + fontAscent + 2;
3008 bool someLayersIncomplete =
false;
3011 SVDEBUG <<
"View::waitForLayersToBeReady: checking completion" << endl;
3017 int c = (*i)->getCompletion(
this);
3020 SVDEBUG <<
"layer " << (*i)->getLayerPresentationName() <<
" says " 3025 someLayersIncomplete =
true;
3030 if (someLayersIncomplete) {
3032 QProgressDialog progress(tr(
"Waiting for layers to be ready..."),
3033 tr(
"Cancel"), 0, 100,
this);
3035 int layerCompletion = 0;
3037 while (layerCompletion < 100) {
3040 SVDEBUG <<
"View::render: checking completion (again)" << endl;
3046 int c = (*i)->getCompletion(
this);
3047 if (i ==
m_layerStack.begin() || c < layerCompletion) {
3048 layerCompletion = c;
3052 SVDEBUG <<
"layer " << (*i)->getLayerPresentationName() <<
" says " 3053 << c <<
", layerCompletion now " << layerCompletion << endl;
3057 if (layerCompletion >= 100)
break;
3059 progress.setValue(layerCompletion);
3060 qApp->processEvents();
3061 if (progress.wasCanceled()) {
3071 SVDEBUG <<
"View::waitForLayersToBeReady: ok, we're ready" << endl;
3080 int x0 = int(round(
m_zoomLevel.framesToPixels(
double(f0))));
3081 int x1 = int(round(
m_zoomLevel.framesToPixels(
double(f1))));
3086 SVDEBUG <<
"View::render: Render request is for frames " << f0
3087 <<
" to " << f1 <<
" (pixels " << x0 <<
" to " << x1
3088 <<
", width " << w <<
")" << endl;
3097 QProgressDialog progress(tr(
"Rendering image..."),
3098 tr(
"Cancel"), 0, w / width(),
this);
3100 for (
int x = 0; x < w; x += width()) {
3102 progress.setValue(x / width());
3103 qApp->processEvents();
3104 if (progress.wasCanceled()) {
3113 QRect chunk(0, 0, width(), height());
3118 paint.drawRect(QRect(xorigin + x, 0, width(), height()));
3121 paint.setBrush(Qt::NoBrush);
3125 if (!((*i)->isLayerDormant(
this))){
3127 paint.setRenderHint(QPainter::Antialiasing,
false);
3130 paint.translate(xorigin + x, 0);
3132 SVCERR <<
"Centre frame now: " <<
m_centreFrame <<
" drawing to " << chunk.x() + x + xorigin <<
", " << chunk.width() << endl;
3134 (*i)->setSynchronousPainting(
true);
3136 (*i)->paint(
this, paint, chunk);
3138 (*i)->setSynchronousPainting(
false);
3166 int x0 = int(round(
getZoomLevel().framesToPixels(
double(f0))));
3167 int x1 = int(round(
getZoomLevel().framesToPixels(
double(f1))));
3169 QImage *image =
new QImage(x1 - x0, height(), QImage::Format_RGB32);
3171 QPainter *paint =
new QPainter(image);
3172 if (!
render(*paint, 0, f0, f1)) {
3194 int x0 = int(round(
getZoomLevel().framesToPixels(
double(f0))));
3195 int x1 = int(round(
getZoomLevel().framesToPixels(
double(f1))));
3197 return QSize(x1 - x0, height());
3212 int x0 = int(round(
getZoomLevel().framesToPixels(
double(f0))));
3213 int x1 = int(round(
getZoomLevel().framesToPixels(
double(f1))));
3215 QSvgGenerator generator;
3216 generator.setFileName(filename);
3217 generator.setSize(QSize(x1 - x0, height()));
3218 generator.setViewBox(QRect(0, 0, x1 - x0, height()));
3219 generator.setTitle(tr(
"Exported image from %1")
3220 .arg(QApplication::applicationName()));
3223 paint.begin(&generator);
3224 bool result =
render(paint, 0, f0, f1);
3231 QString indent, QString extraAttributes)
const 3235 int classicZoomValue, deepZoomValue;
3237 if (
m_zoomLevel.zone == ZoomLevel::FramesPerPixel) {
3241 classicZoomValue = 1;
3245 stream << QString(
"<view " 3250 "followZoom=\"%5\" " 3254 .arg(classicZoomValue)
3262 .arg(extraAttributes);
3267 QString(
"visible=\"%1\"")
3268 .arg(visible ?
"true" :
"false"));
3271 stream << indent +
"</view>\n";
3278 connect(
m_v, SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
3279 this, SIGNAL(propertyChanged(PropertyContainer::PropertyName)));
void getAligningAndReferenceModels(ModelId &aligning, ModelId &reference) const
virtual QString getPropertyValueLabel(const PropertyName &, int value) const
bool haveInProgressSelection() const
void paintEvent(QPaintEvent *e) override
virtual bool isLayerDormant(const LayerGeometryProvider *v) const
Return whether the layer is dormant (i.e.
bool areLayersScrollable() const
bool hasTopLayerTimeXAxis() const
virtual const PropertyContainer * getPropertyContainer(int i) const
void propertyContainerNameChanged(PropertyContainer *pc)
sv_frame_t alignFromReference(sv_frame_t) const
The base class for visual representations of the data found in a Model.
sv_frame_t m_playPointerFrame
AlignmentProgressBarRec m_alignmentProgressBar
virtual QImage * renderToNewImage()
Render the view contents to a new QImage (which may be wider than the visible View).
bool waitForLayersToBeReady()
virtual void modelChangedWithin(ModelId, sv_frame_t startFrame, sv_frame_t endFrame)
void movePlayPointer(sv_frame_t f)
virtual bool getXScaleValue(const LayerGeometryProvider *v, int x, double &value, QString &unit) const
Return the value and unit at the given x coordinate in the given view.
View scrolls continuously during playback, keeping the playback position at the centre.
void checkAlignmentProgress(ModelId)
LayerList m_fixedOrderLayers
bool getGlobalDarkBackground() const
void propertyContainerSelected(PropertyContainer *pc)
bool m_followPlayIsDetached
int scalePixelSize(int size) const override
int getId() const override
Retrieve the id of this object.
LayerList getNonScrollableFrontLayers(bool testChanged, bool &changed) const
virtual void setProperty(const PropertyName &, int value)
void propertyContainerRemoved(PropertyContainer *pc)
bool getVisibleExtentsForUnit(QString unit, double &min, double &max, bool &log) const override
Return the visible vertical extents for the given unit, if any.
bool getAlignMode() const override
ZoomLevel getZoomConstraintLevel(ZoomLevel level, ZoomConstraint::RoundingDirection dir=ZoomConstraint::RoundNearest) const
sv_samplerate_t getModelsSampleRate() const
double getFrequencyForY(double y, double minFreq, double maxFreq, bool logarithmic) const override
Return the closest frequency to the given pixel y-coordinate, if the frequency range is as specified...
ZoomLevel m_cacheZoomLevel
sv_frame_t getGlobalCentreFrame() const
virtual void modelReplaced()
virtual int getLayerCount() const
Return the number of layers, regardless of whether visible or dormant, i.e.
int effectiveDevicePixelRatio() const
virtual void modelChanged(ModelId)
double scalePenWidth(double width) const override
virtual void zoom(bool in)
Zoom in or out.
virtual ~View()
Deleting a View does not delete any of its layers.
sv_frame_t getCentreFrame() const override
Return the centre frame of the visible widget.
QColor getForeground() const override
ProgressMap m_progressBars
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...
sv_frame_t alignToReference(sv_frame_t) const
virtual void selectionChanged()
const Selection & getInProgressSelection(bool &exclusive) const
std::vector< Layer * > LayerList
void propertyContainerPropertyChanged(PropertyContainer *pc)
ModelId getSourceModel() const
Return the ID of the source model for the model represented in this layer.
virtual void layerParameterRangesChanged()
virtual int getPropertyRangeAndValue(const PropertyName &, int *min, int *max, int *deflt) const
virtual void paint(LayerGeometryProvider *, QPainter &, QRect) const =0
Paint the given rectangle of this layer onto the given view using the given painter, superimposing it on top of any existing material in that view.
virtual void addLayer(Layer *v)
Add a layer to the view.
sv_frame_t getPlaybackFrame() const
bool areLayerColoursSignificant() const
virtual void drawPlayPointer(QPainter &)
void checkProgress(ModelId)
bool getPlaySelectionMode() const override
virtual void setViewManager(ViewManager *m)
virtual bool shouldLabelSelections() const
void propertyContainerAdded(PropertyContainer *pc)
sv_frame_t m_cacheCentreFrame
QRect scaledRect(const QRect &r, int factor)
virtual void setPaintFont(QPainter &paint)
virtual QSize getRenderedImageSize()
Calculate and return the size of image that will be generated by renderToNewImage().
void centreFrameChanged(sv_frame_t frame, bool globalScroll, PlaybackFollowMode followMode)
virtual QImage * renderPartToNewImage(sv_frame_t f0, sv_frame_t f1)
Render the view contents between the given frame extents to a new QImage (which may be wider than the...
View follows playback page-by-page, but dragging the view relocates playback to the centre frame...
sv_frame_t getFrameForX(int x) const override
Return the closest frame to the given pixel x-coordinate.
ZoomLevel getGlobalZoom() const
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)
virtual PropertyContainer::PropertyType getPropertyType(const PropertyName &) const
QColor getBackground() const override
void setStartFrame(sv_frame_t)
Set the widget pan based on the given first visible frame.
virtual void viewZoomLevelChanged(View *, ZoomLevel, bool)
virtual void modelCompletionChanged(ModelId)
int getZoomLevelIndex(ZoomLevel level) const
virtual void cancelClicked()
sv_frame_t getAlignedPlaybackFrame() const
Layer * getScaleProvidingLayerForUnit(QString unit) const
void cancelButtonPressed(Layer *)
int getTextLabelYCoord(const Layer *layer, QPainter &) const override
Return a y-coordinate at which text labels for individual items in a layer may be drawn...
virtual QString getLayerPresentationName() const
virtual void setZoomLevel(ZoomLevel z)
Set the zoom level, i.e.
virtual bool getYScaleValue(const LayerGeometryProvider *, int, double &, QString &) const
Return the value and unit at the given y coordinate in the given view.
View is detached from playback.
QSize scaledSize(const QSize &s, int factor)
int countZoomLevels() const
LayerList getScrollableBackLayers(bool testChanged, bool &changed) const
virtual void layerParametersChanged()
virtual bool renderToSvgFile(QString filename)
Render the view contents to a new SVG file.
ZoomLevel getZoomLevelByIndex(int ix) const
virtual ~ViewPropertyContainer()
ModelId getAligningModel() const
!!
QRect getPaintRect() const override
To be called from a layer, to obtain the extent of the surface that the layer is currently painting t...
virtual bool shouldIlluminateLocalSelection(QPoint &, bool &, bool &) const
virtual sv_frame_t getLastVisibleFrame() const
PropertyContainer::PropertyName PropertyName
virtual void drawSelections(QPainter &)
virtual void setDefaultColourFor(LayerGeometryProvider *v)
virtual void layerNameChanged()
virtual Layer * getLayer(int n)
Return the nth layer, counted in stacking order.
PlaybackFollowMode m_followPlay
void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const override
virtual void progressCheckStalledTimerElapsed()
bool shouldShowCentreLine() const
void setCentreFrame(sv_frame_t f)
Set the centre frame of the visible widget.
virtual int getPropertyContainerCount() const
ModelId getPlaybackModel() const
LayerList m_lastScrollableBackLayers
virtual void setFollowGlobalPan(bool f)
virtual PropertyContainer::PropertyList getProperties() const
int getProgressBarWidth() const
sv_frame_t getModelsStartFrame() const override
bool hasLightBackground() const override
void propertyContainerPropertyRangeChanged(PropertyContainer *pc)
virtual void setPlaybackFollow(PlaybackFollowMode m)
virtual void modelAlignmentCompletionChanged(ModelId)
virtual QString getPropertyLabel(const PropertyName &) const
View is the base class of widgets that display one or more overlaid views of data against a horizonta...
virtual void removeLayer(Layer *v)
Remove a layer from the view.
virtual void viewManagerPlaybackFrameChanged(sv_frame_t)
The ViewManager manages properties that may need to be synchronised between separate Views...
virtual void toolModeChanged()
virtual void zoomWheelsEnabledChanged()
View(QWidget *, bool showProgress)
const MultiSelection::SelectionList & getSelections() const override
bool shouldShowSelectionExtents() const
LayerList m_lastNonScrollableBackLayers
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...
double scaleSize(double size) const override
virtual Layer * getSelectedLayer()
Return the layer most recently selected by the user.
virtual ModelId getModel() const =0
Return the ID of the model represented in this layer.
virtual void overlayModeChanged()
static void drawVisibleText(const LayerGeometryProvider *, QPainter &p, int x, int y, QString text, TextStyle style)
sv_frame_t getModelsEndFrame() const override
bool getVisibleExtentsForAnyUnit(double &min, double &max, bool &logarithmic, QString &unit) const
Return some visible vertical extents and unit.
virtual void scroll(bool right, bool lots, bool doEmit=true)
Scroll left or right by a smallish or largish amount.
sv_frame_t getEndFrame() const override
Retrieve the last visible sample frame on the widget.
virtual void setFollowGlobalZoom(bool f)
View follows playback page-by-page, and the play head is moved (by the user) separately from dragging...
QPen scalePen(QPen pen) const override
double getYForFrequency(double frequency, double minFreq, double maxFreq, bool logarithmic) const override
Return the pixel y-coordinate corresponding to a given frequency, if the frequency range is as specif...
virtual void viewCentreFrameChanged(View *, sv_frame_t)
void drawMeasurementRect(QPainter &p, const Layer *, QRect rect, bool focus) const override
virtual sv_frame_t getFirstVisibleFrame() const
virtual Layer * getInteractionLayer()
Return the layer currently active for tool interaction.
void zoomLevelChanged(ZoomLevel level, bool locked)
virtual bool getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1, double &diff, QString &unit) const
Return the difference between the values at the given y coordinates in the given view, and the unit of the difference.
virtual void layerMeasurementRectsChanged()
virtual void globalCentreFrameChanged(sv_frame_t)
virtual bool renderPartToSvgFile(QString filename, sv_frame_t f0, sv_frame_t f1)
Render the view contents between the given frame extents to a new SVG file.
int getXForFrame(sv_frame_t frame) const override
Return the pixel x-coordinate corresponding to a given sample frame.
ViewPropertyContainer * m_propertyContainer
ViewPropertyContainer(View *v)
std::set< ModelId > ModelSet
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).