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" 26 #include "data/model/PowerOfSqrtTwoZoomConstraint.h" 27 #include "data/model/RangeSummarisableTimeValueModel.h" 32 #include <QPaintEvent> 34 #include <QApplication> 35 #include <QProgressDialog> 36 #include <QTextStream> 38 #include <QMessageBox> 39 #include <QPushButton> 58 m_followPlayIsDetached(false),
59 m_playPointerFrame(0),
60 m_showProgress(showProgress),
62 m_cacheCentreFrame(0),
63 m_cacheZoomLevel(1024),
64 m_selectionCached(false),
66 m_haveSelectedLayer(false),
81 PropertyContainer::PropertyList
84 PropertyContainer::PropertyList list;
85 list.push_back(
"Global Scroll");
86 list.push_back(
"Global Zoom");
87 list.push_back(
"Follow Playback");
94 if (pn ==
"Global Scroll")
return tr(
"Global Scroll");
95 if (pn ==
"Global Zoom")
return tr(
"Global Zoom");
96 if (pn ==
"Follow Playback")
return tr(
"Follow Playback");
100 PropertyContainer::PropertyType
103 if (name ==
"Global Scroll")
return PropertyContainer::ToggleProperty;
104 if (name ==
"Global Zoom")
return PropertyContainer::ToggleProperty;
105 if (name ==
"Follow Playback")
return PropertyContainer::ValueProperty;
106 return PropertyContainer::InvalidProperty;
111 int *min,
int *max,
int *deflt)
const 113 if (deflt) *deflt = 1;
116 if (name ==
"Follow Playback") {
128 if (deflt) *deflt = 0;
136 if (name ==
"Follow Playback") {
139 case 0:
return tr(
"Scroll");
140 case 1:
return tr(
"Page");
141 case 2:
return tr(
"Off");
144 return tr(
"<unknown>");
150 if (name ==
"Global Scroll") {
152 }
else if (name ==
"Global Zoom") {
154 }
else if (name ==
"Follow Playback") {
170 const PropertyContainer *
173 return (
const PropertyContainer *)(((
View *)
this)->
189 for (LayerList::const_iterator i =
m_layerStack.begin();
193 float layerMin = 0.0, layerMax = 0.0;
194 float displayMin = 0.0, displayMax = 0.0;
195 bool layerLog =
false;
197 if ((*i)->getValueExtents(layerMin, layerMax, layerLog, layerUnit) &&
198 layerUnit.toLower() == unit.toLower()) {
200 if ((*i)->getDisplayExtents(displayMin, displayMax)) {
210 if (!have || layerMin < min) min = layerMin;
211 if (!have || layerMax > max) max = layerMax;
212 if (layerLog) log =
true;
224 std::map<int, Layer *> sortedLayers;
226 for (LayerList::const_iterator i =
m_layerStack.begin();
228 if ((*i)->needsTextLabelHeight()) {
229 sortedLayers[getObjectExportId(*i)] = *i;
233 int y = 15 + paint.fontMetrics().ascent();
235 for (std::map<int, Layer *>::const_iterator i = sortedLayers.begin();
236 i != sortedLayers.end(); ++i) {
237 if (i->second == layer)
return y;
238 y += paint.fontMetrics().height();
247 if (client !=
this)
return;
260 Layer *selectedLayer = 0;
322 bool changeVisible =
false;
332 if (newPixel != formerPixel) {
334 #ifdef DEBUG_VIEW_WIDGET_PAINT 335 cout <<
"View(" <<
this <<
")::setCentreFrame: newPixel " << newPixel <<
", formerPixel " << formerPixel << endl;
339 changeVisible =
true;
345 cerr <<
"View[" <<
this <<
"]::setCentreFrame(" << f
346 <<
"): emitting centreFrameChanged(" 347 << rf <<
")" << endl;
353 return changeVisible;
368 #ifdef DEBUG_VIEW_WIDGET_PAINT 369 SVDEBUG <<
"View::getFrameForX(" << x <<
"): z = " << z <<
", m_centreFrame = " <<
m_centreFrame <<
", width() = " << width() <<
", frame = " << frame << endl;
372 frame = (frame / z) * z;
373 return frame + x * z;
380 bool logarithmic)
const 382 Profiler profiler(
"View::getYForFrequency");
388 static float lastminf = 0.0, lastmaxf = 0.0;
389 static float logminf = 0.0, logmaxf = 0.0;
391 if (lastminf != minf) {
392 lastminf = (minf == 0.0 ? 1.0 : minf);
393 logminf = log10f(minf);
395 if (lastmaxf != maxf) {
396 lastmaxf = (maxf < lastminf ? lastminf : maxf);
397 logmaxf = log10f(maxf);
400 if (logminf == logmaxf)
return 0;
401 return h - (h * (log10f(frequency) - logminf)) / (logmaxf - logminf);
405 if (minf == maxf)
return 0;
406 return h - (h * (frequency - minf)) / (maxf - minf);
414 bool logarithmic)
const 420 static float lastminf = 0.0, lastmaxf = 0.0;
421 static float logminf = 0.0, logmaxf = 0.0;
423 if (lastminf != minf) {
424 lastminf = (minf == 0.0 ? 1.0 : minf);
425 logminf = log10f(minf);
427 if (lastmaxf != maxf) {
428 lastmaxf = (maxf < lastminf ? lastminf : maxf);
429 logmaxf = log10f(maxf);
432 if (logminf == logmaxf)
return 0;
433 return pow(10.f, logminf + ((logmaxf - logminf) * (h - y)) / h);
437 if (minf == maxf)
return 0;
438 return minf + ((h - y) * (maxf - minf)) / h;
445 #ifdef DEBUG_VIEW_WIDGET_PAINT 465 bool darkPalette =
false;
469 bool mostSignificantHasDarkBackground =
false;
471 for (LayerList::const_iterator i =
m_layerStack.begin();
475 bool light = (*i)->hasLightBackground();
477 if (
int(s) >
int(maxSignificance)) {
479 mostSignificantHasDarkBackground = !light;
480 }
else if (s == maxSignificance && !light) {
481 mostSignificantHasDarkBackground =
true;
486 return !mostSignificantHasDarkBackground;
497 QColor widgetbg = palette().window().color();
499 (widgetbg.red() + widgetbg.green() + widgetbg.blue()) > 384;
501 if (widgetLight == light) {
503 return widgetbg.light();
505 return widgetbg.dark();
508 else if (light)
return Qt::white;
509 else return Qt::black;
517 QColor widgetfg = palette().text().color();
519 (widgetfg.red() + widgetfg.green() + widgetfg.blue()) > 384;
521 if (widgetLight != light)
return widgetfg;
522 else if (light)
return Qt::black;
523 else return Qt::white;
538 QProgressBar *pb =
new QProgressBar(
this);
541 pb->setFixedWidth(80);
542 pb->setTextVisible(
false);
544 QPushButton *cancel =
new QPushButton(
this);
545 cancel->setIcon(
IconLoader().load(
"fileclose"));
546 cancel->setFlat(
true);
547 cancel->setFixedSize(QSize(20, 20));
548 connect(cancel, SIGNAL(clicked()),
this, SLOT(
cancelClicked()));
555 connect(pbr.
checkTimer, SIGNAL(timeout()),
this,
561 int fs = Preferences::getInstance()->getViewFontSize();
562 f.setPointSize(std::min(fs,
int(ceil(fs * 0.85))));
688 return const_cast<const Layer *>(const_cast<View *>(
this)->
getSelectedLayer());
713 connect(
m_manager, SIGNAL(playbackFrameChanged(
int)),
723 connect(
m_manager, SIGNAL(inProgressSelectionChanged()),
727 connect(
m_manager, SIGNAL(showCentreLineChanged()),
794 QFont f(paint.font());
799 QColor penColour, surroundColour, boxColour;
803 boxColour = surroundColour;
804 boxColour.setAlpha(127);
806 paint.setPen(Qt::NoPen);
807 paint.setBrush(boxColour);
809 QRect r = paint.fontMetrics().boundingRect(text);
810 r.translate(QPoint(x, y));
813 paint.setBrush(Qt::NoBrush);
815 paint.setPen(surroundColour);
817 for (
int dx = -1; dx <= 1; ++dx) {
818 for (
int dy = -1; dy <= 1; ++dy) {
819 if (!(dx || dy))
continue;
820 paint.drawText(x + dx, y + dy, text);
824 paint.setPen(penColour);
826 paint.drawText(x, y, text);
832 cerr <<
"ERROR: View::drawVisibleText: Boxed style not yet implemented!" << endl;
846 QObject *obj = sender();
848 #ifdef DEBUG_VIEW_WIDGET_PAINT 849 cerr <<
"View(" <<
this <<
")::modelChanged()" << endl;
855 bool recreate =
false;
859 for (LayerList::const_iterator i = scrollables.begin();
860 i != scrollables.end(); ++i) {
861 if (*i == obj || (*i)->getModel() == obj) {
882 QObject *obj = sender();
887 #ifdef DEBUG_VIEW_WIDGET_PAINT 888 cerr <<
"View(" <<
this <<
")::modelChangedWithin(" << startFrame <<
"," << endFrame <<
") [me " << myStartFrame <<
"," << myEndFrame <<
"]" << endl;
891 if (myStartFrame > 0 && endFrame <
int(myStartFrame)) {
895 if (startFrame > myEndFrame) {
903 bool recreate =
false;
907 for (LayerList::const_iterator i = scrollables.begin();
908 i != scrollables.end(); ++i) {
909 if (*i == obj || (*i)->getModel() == obj) {
920 if (startFrame < myStartFrame) startFrame = myStartFrame;
921 if (endFrame > myEndFrame) endFrame = myEndFrame;
933 QObject *obj = sender();
942 QObject *obj = sender();
949 #ifdef DEBUG_VIEW_WIDGET_PAINT 950 cerr <<
"View(" <<
this <<
")::modelReplaced()" << endl;
961 Layer *layer = dynamic_cast<Layer *>(sender());
963 #ifdef DEBUG_VIEW_WIDGET_PAINT 964 SVDEBUG <<
"View::layerParametersChanged()" << endl;
979 Layer *layer = dynamic_cast<Layer *>(sender());
986 Layer *layer = dynamic_cast<Layer *>(sender());
993 Layer *layer = dynamic_cast<Layer *>(sender());
1003 cerr <<
"View[" <<
this <<
"]::globalCentreFrameChanged(" << rf
1004 <<
"): setting centre frame to " << f << endl;
1024 cerr <<
"View::viewManagerPlaybackFrameChanged(" << f <<
")" << endl;
1030 cerr <<
" -> aligned frame = " << af << endl;
1040 cerr <<
"View(" <<
this <<
")::movePlayPointer(" << newFrame <<
")" << endl;
1044 bool visibleChange =
1048 if (!visibleChange)
return;
1050 bool somethingGoingOn =
1051 ((QApplication::mouseButtons() != Qt::NoButton) ||
1052 (QApplication::keyboardModifiers() & Qt::AltModifier));
1054 bool pointerInVisibleArea =
1063 if (!somethingGoingOn) {
1071 if (!pointerInVisibleArea && somethingGoingOn) {
1082 update(xold - 4, 0, 9, height());
1092 if (!selections.empty()) {
1093 int selectionStart = selections.begin()->getStartFrame();
1094 if (sf < selectionStart - w / 10) {
1095 sf = selectionStart - w / 10;
1100 #ifdef DEBUG_VIEW_WIDGET_PAINT 1101 cerr <<
"PlaybackScrollPage: f = " <<
m_playPointerFrame <<
", sf = " << sf <<
", start frame " 1110 #ifdef DEBUG_VIEW_WIDGET_PAINT 1111 cerr <<
"xnew = " << xnew <<
", width = " << width() << endl;
1114 bool shouldScroll = (xnew > (width() * 7) / 8);
1117 shouldScroll =
true;
1120 if (xnew > width() / 8) {
1122 }
else if (somethingGoingOn) {
1126 if (!somethingGoingOn && shouldScroll) {
1128 int newCentre = sf + offset;
1132 update(xold - 4, 0, 9, height());
1136 update(xnew - 4, 0, 9, height());
1152 #ifdef DEBUG_VIEW_WIDGET_PAINT 1153 cerr <<
"View[" <<
this <<
"]: viewZoomLevelChanged(" << p <<
", " << z <<
", " << locked <<
")" << endl;
1176 if (f0 < 0 || f0 < f)
return f;
1185 if (f0 > f)
return f;
1197 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
1199 int thisStartFrame = (*i)->getModel()->getStartFrame();
1201 if (first || thisStartFrame < startFrame) {
1202 startFrame = thisStartFrame;
1218 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
1220 int thisEndFrame = (*i)->getModel()->getEndFrame();
1222 if (first || thisEndFrame > endFrame) {
1223 endFrame = thisEndFrame;
1243 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
1244 return (*i)->getModel()->getSampleRate();
1259 if (dynamic_cast<TimeRulerLayer *>(layer)) {
1265 models.insert(model);
1281 Model *anyModel = 0;
1282 Model *alignedModel = 0;
1283 Model *goodModel = 0;
1285 for (LayerList::const_iterator i =
m_layerStack.begin();
1290 if (!layer)
continue;
1291 if (dynamic_cast<TimeRulerLayer *>(layer))
continue;
1294 if (!model)
continue;
1298 if (model->getAlignmentReference()) {
1299 alignedModel = model;
1301 dynamic_cast<RangeSummarisableTimeValueModel *>(model)) {
1307 if (goodModel)
return goodModel;
1308 else if (alignedModel)
return alignedModel;
1309 else return anyModel;
1317 if (!aligningModel)
return f;
1318 return aligningModel->alignFromReference(f);
1326 if (!aligningModel)
return f;
1327 return aligningModel->alignToReference(f);
1338 if (!aligningModel)
return pf;
1340 int af = aligningModel->alignFromReference(pf);
1350 if (!(*i)->isLayerScrollable(
this))
return false;
1364 bool metUnscrollable =
false;
1371 if ((*i)->isLayerDormant(
this))
continue;
1372 if ((*i)->isLayerOpaque()) {
1374 scrollables.clear();
1375 if (metUnscrollable)
break;
1377 if (!metUnscrollable && (*i)->isLayerScrollable(
this)) {
1378 scrollables.push_back(*i);
1380 metUnscrollable =
true;
1400 bool started =
false;
1403 if ((*i)->isLayerDormant(
this))
continue;
1404 if (!started && (*i)->isLayerScrollable(
this)) {
1408 if ((*i)->isLayerOpaque()) {
1410 nonScrollables.clear();
1412 nonScrollables.push_back(*i);
1420 return nonScrollables;
1425 ZoomConstraint::RoundingDirection dir)
1428 int candidate = blockSize;
1429 bool haveCandidate =
false;
1431 PowerOfSqrtTwoZoomConstraint defaultZoomConstraint;
1435 const ZoomConstraint *zoomConstraint = (*i)->getZoomConstraint();
1436 if (!zoomConstraint) zoomConstraint = &defaultZoomConstraint;
1439 zoomConstraint->getNearestBlockSize(blockSize, dir);
1443 if (!haveCandidate ||
1444 (thisBlockSize > blockSize && thisBlockSize > candidate) ||
1445 (thisBlockSize < blockSize && thisBlockSize < candidate)) {
1446 candidate = thisBlockSize;
1447 haveCandidate =
true;
1458 if ((*i)->getLayerColourSignificance() ==
1460 if ((*i)->isLayerOpaque())
break;
1471 return (*i)->hasTimeXAxis();
1481 ZoomConstraint::RoundDown);
1484 ZoomConstraint::RoundUp);
1501 if (right) delta = -delta;
1515 QPushButton *cancel = qobject_cast<QPushButton *>(sender());
1516 if (!cancel)
return;
1521 if (i->second.cancel == cancel) {
1523 Layer *layer = i->first;
1526 if (model) model->abandon();
1541 QProgressBar *pb = i->second.bar;
1542 QPushButton *cancel = i->second.cancel;
1544 if (i->first ==
object) {
1549 QTimer *timer = i->second.checkTimer;
1551 int completion = i->first->getCompletion(
this);
1552 QString text = i->first->getPropertyContainerName();
1553 QString error = i->first->getError(
this);
1556 QMessageBox::critical(
this, tr(
"Layer rendering error"), error);
1560 Model *model = i->first->getModel();
1561 RangeSummarisableTimeValueModel *wfm =
1562 dynamic_cast<RangeSummarisableTimeValueModel *>(model);
1564 if (completion > 0) {
1565 pb->setMaximum(100);
1568 if (completion >= 100) {
1573 (wfm = dynamic_cast<RangeSummarisableTimeValueModel *>
1574 (model->getSourceModel())))) {
1575 completion = wfm->getAlignmentCompletion();
1577 if (completion < 100) {
1578 text = tr(
"Alignment");
1586 if (completion >= 100) {
1596 if (!pb->isVisible()) {
1597 i->second.lastCheck = 0;
1598 timer->setInterval(2000);
1602 cancel->move(0, ph - pb->height()/2 - 10);
1605 pb->setValue(completion);
1606 pb->move(20, ph - pb->height());
1614 if (pb->isVisible()) {
1624 QObject *s = sender();
1625 QTimer *t = qobject_cast<QTimer *>(s);
1629 if (i->second.checkTimer == t) {
1630 int value = i->second.bar->value();
1631 if (value > 0 && value == i->second.lastCheck) {
1632 i->second.bar->setMaximum(0);
1634 i->second.lastCheck = value;
1645 if (i->second.bar && i->second.bar->isVisible()) {
1646 return i->second.bar->width();
1656 QFont font(paint.font());
1657 font.setPointSize(Preferences::getInstance()->getViewFontSize());
1658 paint.setFont(font);
1668 QFrame::paintEvent(e);
1682 bool repaintCache =
false;
1683 bool paintedCacheRect =
false;
1685 QRect cacheRect(rect());
1688 cacheRect &= e->rect();
1689 #ifdef DEBUG_VIEW_WIDGET_PAINT 1690 cerr <<
"paint rect " << cacheRect.width() <<
"x" << cacheRect.height()
1691 <<
", my rect " << width() <<
"x" << height() << endl;
1695 QRect nonCacheRect(cacheRect);
1700 bool layersChanged =
false;
1703 bool selectionCacheable = nonScrollables.empty();
1710 if (!selectionCacheable) {
1711 selectionCacheable =
true;
1712 for (LayerList::const_iterator i = nonScrollables.begin();
1713 i != nonScrollables.end(); ++i) {
1714 if ((*i)->isLayerOpaque()) {
1715 selectionCacheable =
false;
1721 if (selectionCacheable) {
1723 bool closeToLeft, closeToRight;
1725 selectionCacheable =
false;
1729 #ifdef DEBUG_VIEW_WIDGET_PAINT 1730 cerr <<
"View(" <<
this <<
")::paintEvent: have " << scrollables.size()
1731 <<
" scrollable back layers and " << nonScrollables.size()
1732 <<
" non-scrollable front layers" << endl;
1733 cerr <<
"haveSelections " << haveSelections <<
", selectionCacheable " 1737 if (layersChanged || scrollables.empty() ||
1744 if (!scrollables.empty()) {
1746 #ifdef DEBUG_VIEW_WIDGET_PAINT 1747 cerr <<
"View(" <<
this <<
"): cache " <<
m_cache <<
", cache zoom " 1753 width() !=
m_cache->width() ||
1754 height() !=
m_cache->height()) {
1758 if (cacheRect.width() < width()/10) {
1761 #ifdef DEBUG_VIEW_WIDGET_PAINT 1762 cerr <<
"View(" <<
this <<
")::paintEvent: small repaint, not bothering to recreate cache" << endl;
1766 m_cache =
new QPixmap(width(), height());
1767 #ifdef DEBUG_VIEW_WIDGET_PAINT 1768 cerr <<
"View(" <<
this <<
")::paintEvent: recreated cache" << endl;
1771 repaintCache =
true;
1780 if (dx > -width() && dx < width()) {
1781 #ifdef PIXMAP_COPY_TO_SELF 1790 paint.drawPixmap(dx, 0, *
m_cache);
1793 static QPixmap *tmpPixmap = 0;
1795 tmpPixmap->width() != width() ||
1796 tmpPixmap->height() != height()) {
1798 tmpPixmap =
new QPixmap(width(), height());
1800 paint.begin(tmpPixmap);
1801 paint.drawPixmap(0, 0, *
m_cache);
1804 paint.drawPixmap(dx, 0, *tmpPixmap);
1808 cacheRect = QRect(width() + dx, 0, -dx, height());
1810 cacheRect = QRect(0, 0, dx, height());
1812 #ifdef DEBUG_VIEW_WIDGET_PAINT 1813 cerr <<
"View(" <<
this <<
")::paintEvent: scrolled cache by " << dx << endl;
1817 #ifdef DEBUG_VIEW_WIDGET_PAINT 1818 cerr <<
"View(" <<
this <<
")::paintEvent: scrolling too far" << endl;
1821 repaintCache =
true;
1824 #ifdef DEBUG_VIEW_WIDGET_PAINT 1825 cerr <<
"View(" <<
this <<
")::paintEvent: cache is good" << endl;
1828 paint.drawPixmap(cacheRect, *
m_cache, cacheRect);
1830 QFrame::paintEvent(e);
1831 paintedCacheRect =
true;
1838 #ifdef DEBUG_VIEW_WIDGET_PAINT 1844 if (!paintedCacheRect) {
1846 if (repaintCache) paint.begin(
m_cache);
1847 else paint.begin(
this);
1849 paint.setClipRect(cacheRect);
1853 paint.drawRect(cacheRect);
1856 paint.setBrush(Qt::NoBrush);
1858 for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) {
1859 paint.setRenderHint(QPainter::Antialiasing,
false);
1861 (*i)->paint(
this, paint, cacheRect);
1865 if (haveSelections && selectionCacheable) {
1873 cacheRect |= (e ? e->rect() : rect());
1875 paint.drawPixmap(cacheRect, *
m_cache, cacheRect);
1884 nonCacheRect |= cacheRect;
1887 paint.setClipRect(nonCacheRect);
1889 if (scrollables.empty()) {
1892 paint.drawRect(nonCacheRect);
1896 paint.setBrush(Qt::NoBrush);
1898 for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) {
1900 (*i)->paint(
this, paint, nonCacheRect);
1907 if (e) paint.setClipRect(e->rect());
1913 bool showPlayPointer =
true;
1915 showPlayPointer =
false;
1918 showPlayPointer =
false;
1925 showPlayPointer =
false;
1929 if (showPlayPointer) {
1936 paint.drawLine(playx - 1, 0, playx - 1, height() - 1);
1937 paint.drawLine(playx + 1, 0, playx + 1, height() - 1);
1938 paint.drawPoint(playx, 0);
1939 paint.drawPoint(playx, height() - 1);
1941 paint.drawLine(playx, 1, playx, height() - 2);
1946 QFrame::paintEvent(e);
1954 MultiSelection::SelectionList selections;
1960 Selection inProgressSelection =
1962 if (exclusive) selections.clear();
1963 selections.insert(inProgressSelection);
1972 paint.setBrush(QColor(150, 150, 255, 80));
1974 paint.setBrush(Qt::NoBrush);
1980 int illuminateFrame = -1;
1981 bool closeToLeft, closeToRight;
1987 const QFontMetrics &metrics = paint.fontMetrics();
1989 for (MultiSelection::SelectionList::iterator i = selections.begin();
1990 i != selections.end(); ++i) {
1995 if (p1 < 0 || p0 > width())
continue;
1997 #ifdef DEBUG_VIEW_WIDGET_PAINT 1998 SVDEBUG <<
"View::drawSelections: " << p0 <<
",-1 [" << (p1-p0) <<
"x" << (height()+1) <<
"]" << endl;
2001 bool illuminateThis =
2002 (illuminateFrame >= 0 && i->contains(illuminateFrame));
2004 paint.setPen(QColor(150, 150, 255));
2007 paint.drawRect(p0, -1, p1 - p0, height() + 1);
2013 paint.drawRect(p0, 0, p1 - p0, height() - 1);
2016 if (illuminateThis) {
2020 paint.drawLine(p0, 1, p1, 1);
2021 paint.drawLine(p0, 0, p0, height());
2022 paint.drawLine(p0, height() - 1, p1, height() - 1);
2023 }
else if (closeToRight) {
2024 paint.drawLine(p0, 1, p1, 1);
2025 paint.drawLine(p1, 0, p1, height());
2026 paint.drawLine(p0, height() - 1, p1, height() - 1);
2028 paint.setBrush(Qt::NoBrush);
2029 paint.drawRect(p0, 1, p1 - p0, height() - 2);
2037 QString startText = QString(
"%1 / %2")
2038 .arg(QString::fromStdString
2039 (RealTime::frame2RealTime
2040 (i->getStartFrame(), sampleRate).toText(
true)))
2041 .arg(i->getStartFrame());
2043 QString endText = QString(
" %1 / %2")
2044 .arg(QString::fromStdString
2045 (RealTime::frame2RealTime
2046 (i->getEndFrame(), sampleRate).toText(
true)))
2047 .arg(i->getEndFrame());
2049 QString durationText = QString(
"(%1 / %2) ")
2050 .arg(QString::fromStdString
2051 (RealTime::frame2RealTime
2052 (i->getEndFrame() - i->getStartFrame(), sampleRate)
2054 .arg(i->getEndFrame() - i->getStartFrame());
2056 int sw = metrics.width(startText),
2057 ew = metrics.width(endText),
2058 dw = metrics.width(durationText);
2060 int sy = metrics.ascent() + metrics.height() + 4;
2062 int dy = sy + metrics.height();
2068 bool durationBothEnds =
true;
2070 if (sw + ew > (p1 - p0)) {
2071 ey += metrics.height();
2072 dy += metrics.height();
2073 durationBothEnds =
false;
2076 if (ew < (p1 - p0)) {
2080 if (dw < (p1 - p0)) {
2084 paint.drawText(sx, sy, startText);
2085 paint.drawText(ex, ey, endText);
2086 paint.drawText(dx, dy, durationText);
2087 if (durationBothEnds) {
2088 paint.drawText(sx, dy, durationText);
2103 if (r.x() + r.width() < 0 || r.x() >= width())
return;
2105 if (r.width() != 0 || r.height() != 0) {
2108 paint.setPen(Qt::NoPen);
2109 QColor brushColour(Qt::black);
2111 paint.setBrush(brushColour);
2113 paint.drawRect(0, 0, r.x(), height());
2115 if (r.x() + r.width() < width()) {
2116 paint.drawRect(r.x() + r.width(), 0, width()-r.x()-r.width(), height());
2119 paint.drawRect(r.x(), 0, r.width(), r.y());
2121 if (r.y() + r.height() < height()) {
2122 paint.drawRect(r.x(), r.y() + r.height(), r.width(), height()-r.y()-r.height());
2124 paint.setBrush(Qt::NoBrush);
2126 paint.setPen(Qt::green);
2131 paint.setPen(Qt::green);
2132 paint.drawPoint(r.x(), r.y());
2139 QFont fn = paint.font();
2140 if (fn.pointSize() > 8) {
2141 fn.setPointSize(fn.pointSize() - 1);
2145 int fontHeight = paint.fontMetrics().height();
2146 int fontAscent = paint.fontMetrics().ascent();
2150 bool b0 =
false, b1 =
false;
2152 QString axs, ays, bxs, bys, dxs, dys;
2154 int axx, axy, bxx, bxy, dxx, dxy;
2155 int aw = 0, bw = 0, dw = 0;
2162 axs = QString(
"%1 %2").arg(v0).arg(u0);
2163 if (u0 ==
"Hz" && Pitch::isFrequencyInMidiRange(v0)) {
2164 axs = QString(
"%1 (%2)").arg(axs)
2165 .arg(Pitch::getPitchLabelForFrequency(v0));
2167 aw = paint.fontMetrics().width(axs);
2173 if (r.width() > 0) {
2174 if ((b1 = topLayer->
getXScaleValue(
this, r.x() + r.width(), v1, u1))) {
2175 bxs = QString(
"%1 %2").arg(v1).arg(u1);
2176 if (u1 ==
"Hz" && Pitch::isFrequencyInMidiRange(v1)) {
2177 bxs = QString(
"%1 (%2)").arg(bxs)
2178 .arg(Pitch::getPitchLabelForFrequency(v1));
2180 bw = paint.fontMetrics().width(bxs);
2186 if (b0 && b1 && v1 != v0 && u0 == u1) {
2187 dxs = QString(
"[%1 %2]").arg(fabs(v1 - v0)).arg(u1);
2188 dw = paint.fontMetrics().width(dxs);
2197 ays = QString(
"%1 %2").arg(v0).arg(u0);
2198 if (u0 ==
"Hz" && Pitch::isFrequencyInMidiRange(v0)) {
2199 ays = QString(
"%1 (%2)").arg(ays)
2200 .arg(Pitch::getPitchLabelForFrequency(v0));
2202 aw = std::max(aw, paint.fontMetrics().width(ays));
2208 if (r.height() > 0) {
2209 if ((b1 = topLayer->
getYScaleValue(
this, r.y() + r.height(), v1, u1))) {
2210 bys = QString(
"%1 %2").arg(v1).arg(u1);
2211 if (u1 ==
"Hz" && Pitch::isFrequencyInMidiRange(v1)) {
2212 bys = QString(
"%1 (%2)").arg(bys)
2213 .arg(Pitch::getPitchLabelForFrequency(v1));
2215 bw = std::max(bw, paint.fontMetrics().width(bys));
2232 semis = Pitch::getPitchForFrequencyDifference(v0, v1, ¢s);
2233 dys = QString(
"[%1 %2 (%3)]")
2235 .arg(Pitch::getLabelForPitchRange(semis, cents));
2237 dys = QString(
"[%1 %2]").arg(dy).arg(du);
2240 dys = QString(
"[%1]").arg(dy);
2242 dw = std::max(dw, paint.fontMetrics().width(dys));
2246 int mh = r.height();
2248 bool edgeLabelsInside =
false;
2249 bool sizeLabelsInside =
false;
2251 if (mw < std::max(aw, std::max(bw, dw)) + 4) {
2253 }
else if (mw < aw + bw + 4) {
2254 if (mh > fontHeight * labelCount * 3 + 4) {
2255 edgeLabelsInside =
true;
2256 sizeLabelsInside =
true;
2257 }
else if (mh > fontHeight * labelCount * 2 + 4) {
2258 edgeLabelsInside =
true;
2260 }
else if (mw < aw + bw + dw + 4) {
2261 if (mh > fontHeight * labelCount * 3 + 4) {
2262 edgeLabelsInside =
true;
2263 sizeLabelsInside =
true;
2264 }
else if (mh > fontHeight * labelCount + 4) {
2265 edgeLabelsInside =
true;
2268 if (mh > fontHeight * labelCount + 4) {
2269 edgeLabelsInside =
true;
2270 sizeLabelsInside =
true;
2274 if (edgeLabelsInside) {
2277 axy = r.y() + fontAscent + 2;
2279 bxx = r.x() + r.width() - bw - 2;
2280 bxy = r.y() + r.height() - (labelCount-1) * fontHeight - 2;
2284 axx = r.x() - aw - 2;
2285 axy = r.y() + fontAscent;
2287 bxx = r.x() + r.width() + 2;
2288 bxy = r.y() + r.height() - (labelCount-1) * fontHeight;
2291 dxx = r.width()/2 + r.x() - dw/2;
2293 if (sizeLabelsInside) {
2295 dxy = r.height()/2 + r.y() - (labelCount * fontHeight)/2 + fontAscent;
2299 dxy = r.y() + r.height() + fontAscent + 2;
2345 bool someLayersIncomplete =
false;
2350 int c = (*i)->getCompletion(
this);
2352 someLayersIncomplete =
true;
2357 if (someLayersIncomplete) {
2359 QProgressDialog progress(tr(
"Waiting for layers to be ready..."),
2360 tr(
"Cancel"), 0, 100,
this);
2362 int layerCompletion = 0;
2364 while (layerCompletion < 100) {
2369 int c = (*i)->getCompletion(
this);
2370 if (i ==
m_layerStack.begin() || c < layerCompletion) {
2371 layerCompletion = c;
2375 if (layerCompletion >= 100)
break;
2377 progress.setValue(layerCompletion);
2378 qApp->processEvents();
2379 if (progress.wasCanceled()) {
2388 QProgressDialog progress(tr(
"Rendering image..."),
2389 tr(
"Cancel"), 0, w / width(),
this);
2391 for (
int x = 0; x < w; x += width()) {
2393 progress.setValue(x / width());
2394 qApp->processEvents();
2395 if (progress.wasCanceled()) {
2403 QRect chunk(0, 0, width(), height());
2408 paint.drawRect(QRect(xorigin + x, 0, width(), height()));
2411 paint.setBrush(Qt::NoBrush);
2415 if(!((*i)->isLayerDormant(
this))){
2417 paint.setRenderHint(QPainter::Antialiasing,
false);
2420 paint.translate(xorigin + x, 0);
2422 cerr <<
"Centre frame now: " <<
m_centreFrame <<
" drawing to " << chunk.x() + x + xorigin <<
", " << chunk.width() << endl;
2424 (*i)->setSynchronousPainting(
true);
2426 (*i)->paint(
this, paint, chunk);
2428 (*i)->setSynchronousPainting(
false);
2455 QImage *image =
new QImage(x1 - x0, height(), QImage::Format_RGB32);
2457 QPainter *paint =
new QPainter(image);
2458 if (!
render(*paint, 0, f0, f1)) {
2483 return QSize(x1 - x0, height());
2488 QString indent, QString extraAttributes)
const 2492 stream << QString(
"<view " 2496 "followZoom=\"%4\" " 2507 .arg(extraAttributes);
2512 QString(
"visible=\"%1\"")
2513 .arg(visible ?
"true" :
"false"));
2516 stream << indent +
"</view>\n";
2523 connect(
m_v, SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
2524 this, SIGNAL(propertyChanged(PropertyContainer::PropertyName)));
int getFrameForX(int x) const
Return the closest frame to the given pixel x-coordinate.
virtual void globalCentreFrameChanged(int)
virtual void setDefaultColourFor(View *v)
int getPlaybackFrame() const
virtual const PropertyContainer * getPropertyContainer(int i) const
int getModelsSampleRate() const
void propertyContainerNameChanged(PropertyContainer *pc)
The base class for visual representations of the data found in a Model.
int getZoomConstraintBlockSize(int blockSize, ZoomConstraint::RoundingDirection dir=ZoomConstraint::RoundNearest) const
View scrolls continuously during playback, keeping the playback position at the centre.
void checkProgress(void *object)
LayerList m_fixedOrderLayers
void propertyContainerSelected(PropertyContainer *pc)
std::set< Model * > ModelSet
int getGlobalZoom() const
bool m_followPlayIsDetached
bool haveInProgressSelection() const
virtual void setProperty(const PropertyName &, int value)
void propertyContainerRemoved(PropertyContainer *pc)
virtual QColor getForeground() const
float getYForFrequency(float frequency, float minFreq, float maxFreq, bool logarithmic) const
Return the pixel y-coordinate corresponding to a given frequency, if the frequency range is as specif...
virtual bool getValueExtents(QString unit, float &min, float &max, bool &log) const
virtual int getLayerCount() const
Return the number of layers, regardless of whether visible or dormant, i.e.
int getModelsStartFrame() const
virtual PropertyContainer::PropertyType getPropertyType(const PropertyName &) const
virtual void modelReplaced()
Model * getPlaybackModel() const
LayerList getNonScrollableFrontLayers(bool testChanged, bool &changed) const
virtual void zoom(bool in)
Zoom in or out.
virtual ~View()
Deleting a View does not delete any of its layers.
ProgressMap m_progressBars
virtual void viewCentreFrameChanged(View *, int)
virtual int getPropertyRangeAndValue(const PropertyName &, int *min, int *max, int *deflt) const
int getAlignedPlaybackFrame() const
virtual void selectionChanged()
std::vector< Layer * > LayerList
virtual QImage * toNewImage()
void zoomLevelChanged(int, bool)
void propertyContainerPropertyChanged(PropertyContainer *pc)
virtual void paintEvent(QPaintEvent *e)
LayerList getScrollableBackLayers(bool testChanged, bool &changed) const
virtual void layerParameterRangesChanged()
virtual bool hasLightBackground() const
virtual void addLayer(Layer *v)
Add a layer to the view.
virtual bool getYScaleValue(const View *, int, float &, QString &) const
Return the value and unit at the given y coordinate in the given view.
virtual int getTextLabelHeight(const Layer *layer, QPainter &) const
virtual void setViewManager(ViewManager *m)
int getZoomLevel() const
Return the zoom level, i.e.
void propertyContainerAdded(PropertyContainer *pc)
bool hasTopLayerTimeXAxis() const
virtual void setPaintFont(QPainter &paint)
virtual int getFirstVisibleFrame() const
int alignToReference(int) const
View follows playback page-by-page, but dragging the view relocates playback to the centre frame.
virtual void modelAlignmentCompletionChanged()
virtual bool shouldIlluminateLocalSelection(QPoint &, bool &, bool &) const
Model * getAligningModel() const
!!
void movePlayPointer(int f)
virtual void cancelClicked()
const Selection & getInProgressSelection(bool &exclusive) const
virtual QSize getImageSize()
int getStartFrame() const
Retrieve the first visible sample frame on the widget.
int alignFromReference(int) const
virtual int getPropertyContainerCount() const
bool areLayersScrollable() const
View is detached from playback.
virtual void modelCompletionChanged()
virtual void layerParametersChanged()
bool getPlaySelectionMode() const
virtual void modelChanged()
virtual void modelChangedWithin(int startFrame, int endFrame)
virtual ~ViewPropertyContainer()
int getEndFrame() const
Retrieve the last visible sample frame on the widget.
virtual QString getPropertyValueLabel(const PropertyName &, int value) const
bool shouldShowSelectionExtents() const
PropertyContainer::PropertyName PropertyName
virtual void drawSelections(QPainter &)
int getProgressBarWidth() const
virtual void layerNameChanged()
virtual Layer * getLayer(int n)
Return the nth layer, counted in stacking order.
PlaybackFollowMode m_followPlay
virtual bool isLayerOpaque() const
This should return true if the layer completely obscures any underlying layers.
virtual void progressCheckStalledTimerElapsed()
LayerList m_lastScrollableBackLayers
virtual void setFollowGlobalPan(bool f)
virtual bool getYScaleDifference(const View *v, int y0, int y1, float &diff, QString &unit) const
Return the difference between the values at the given y coordinates in the given view,...
virtual bool shouldLabelSelections() const
int getModelsEndFrame() const
void propertyContainerPropertyRangeChanged(PropertyContainer *pc)
virtual void setPlaybackFollow(PlaybackFollowMode m)
virtual const Model * getModel() const =0
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.
The ViewManager manages properties that may need to be synchronised between separate Views.
virtual void toolModeChanged()
virtual void setZoomLevel(int z)
Set the zoom level, i.e.
virtual bool getXScaleValue(const View *v, int x, float &value, QString &unit) const
Return the value and unit at the given x coordinate in the given view.
virtual void zoomWheelsEnabledChanged()
View(QWidget *, bool showProgress)
virtual QString getPropertyLabel(const PropertyName &) const
virtual void viewZoomLevelChanged(View *, int, bool)
virtual void drawVisibleText(QPainter &p, int x, int y, QString text, TextStyle style) const
int getGlobalCentreFrame() const
LayerList m_lastNonScrollableBackLayers
bool shouldShowCentreLine() const
const MultiSelection::SelectionList & getSelections() const
int getCentreFrame() const
Return the centre frame of the visible widget.
virtual void viewManagerPlaybackFrameChanged(int)
virtual Layer * getSelectedLayer()
Return the layer most recently selected by the user.
virtual void overlayModeChanged()
virtual void scroll(bool right, bool lots, bool doEmit=true)
Scroll left or right by a smallish or largish amount.
virtual int getLastVisibleFrame() const
virtual void setFollowGlobalZoom(bool f)
void setCentreFrame(int f)
Set the centre frame of the visible widget.
float getFrequencyForY(int y, float minFreq, float maxFreq, bool logarithmic) const
Return the closest frequency to the given pixel y-coordinate, if the frequency range is as specified.
View follows playback page-by-page, and the play head is moved (by the user) separately from dragging...
virtual bool render(QPainter &paint, int x0, int f0, int f1)
virtual void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const
virtual PropertyContainer::PropertyList getProperties() const
void setStartFrame(int)
Set the widget pan based on the given first visible frame.
bool getAlignMode() const
virtual QColor getBackground() const
bool areLayerColoursSignificant() const
virtual Layer * getInteractionLayer()
Return the layer currently active for tool interaction.
virtual void layerMeasurementRectsChanged()
virtual bool isLayerDormant(const View *v) const
Return whether the layer is dormant (i.e.
int getXForFrame(int frame) const
Return the pixel x-coordinate corresponding to a given sample frame (which may be negative).
virtual void drawMeasurementRect(QPainter &p, const Layer *, QRect rect, bool focus) const
ViewPropertyContainer * m_propertyContainer
ViewPropertyContainer(View *v)
void centreFrameChanged(int frame, bool globalScroll, PlaybackFollowMode followMode)
bool getGlobalDarkBackground() const